Title: OW Forms
Author: OptionWeb
Published: <strong>May 28, 2026</strong>
Last modified: May 28, 2026

---

Search plugins

![](https://ps.w.org/ow-forms/assets/banner-772x250.png?rev=3551482)

![](https://ps.w.org/ow-forms/assets/icon-256x256.png?rev=3551482)

# OW Forms

 By [OptionWeb](https://profiles.wordpress.org/optionweb/)

[Download](https://downloads.wordpress.org/plugin/ow-forms.1.1.0.zip)

 * [Details](https://wordpress.org/plugins/ow-forms/#description)
 * [Reviews](https://wordpress.org/plugins/ow-forms/#reviews)
 *  [Installation](https://wordpress.org/plugins/ow-forms/#installation)
 * [Development](https://wordpress.org/plugins/ow-forms/#developers)

 [Support](https://wordpress.org/support/plugin/ow-forms/)

## Description

OW Forms is a modern WordPress form builder for sites that prioritize performance,
accessibility, and GDPR compliance. Built by OptionWeb for production use on client
sites, it ships with a JSON-driven schema engine, a REST-based submission pipeline,
and a curated set of 16 field types — text, email, tel, URL, number, textarea, select,
radio, checkbox, checkbox-group, date, time, datetime, file upload, hidden, and 
rating — plus auto-injected GDPR consent and anti-spam fields.

The anti-spam stack runs four layers in parallel: a visually-hidden honeypot input
that bots fill but humans never see, a time-trap that rejects submissions completed
faster than a configurable threshold, a multi-provider CAPTCHA layer (Cloudflare
Turnstile, Google reCAPTCHA v3, hCaptcha, or Friendly Captcha), and optional OW 
Shield IP reputation scoring with a disposable-email blocklist. Every signal is 
logged so you can tune thresholds without flying blind. Submissions that score above
80 are silently rejected — no error message, no honeypot leak.

GDPR compliance is native, not bolted on. Every form gets a consent checkbox linked
to your privacy policy, IP addresses can be stored pseudonymized or not at all, 
user agents are SHA-256 hashed by default, and a daily cron purges submissions older
than your retention window (CNIL default: 1095 days). When OW Consent is active,
OW Forms wires into its DSAR endpoint — erasure requests automatically delete matching
submissions by email hash, with full audit trail. Submission emails are SHA-256 
hashed with a plugin-owned salt (option `owfo_dsar_salt`, generated once at activation)
so the database never holds plaintext PII linkable across systems, and DSAR erasure
keeps working even after `wp config shuffle-salts`.

The one-click Contact Form 7 importer parses every CF7 form in your database, builds
the equivalent OW Forms schema (preserving recipient, subject, and field types),
and rewrites every `[contact-form-7 id="..."]` shortcode in your posts to `[owfo_form
id="..."]`. Email notifications support HTML or plain text with `{{token}}` interpolation,
optional auto-reply, signed outbound webhooks (HMAC-SHA256), and a Gutenberg block
in addition to the shortcode and REST API.

### External services

OW Forms relies on optional third-party CAPTCHA services to protect form submissions

from spam. **None of these services are contacted unless you explicitly enable a
CAPTCHA provider in OW Forms  Settings  Anti-spam.

The OW Shield integration is fully local — when the OW Shield plugin is installed

and active on the same site, OW Forms reads its IP reputation score from the local
database/cache. No request leaves your server for this lookup; OW Shield itself 
may contact its own reputation service, which is disclosed in the OW Shield readme.

The Friendly Captcha widget JavaScript is bundled with OW Forms under
 assets/js/
vendor/ (no external CDN is hit at page render). Source: the upstream MIT-licensed
package at https://github.com/FriendlyCaptcha/friendly-challenge — the files shipped
here are the official npm `friendly-challenge@0.9.18` build outputs (`widget.module.
js` and `widget.module.min.js`, unmodified, renamed to friendly-challenge-0.9.18.
module.js / `friendly-challenge-0.9.18.module.min.js` to make the version explicit
in the filename). Both the minified and the human-readable non-minified source are
shipped per WordPress.org Plugin Check requirements.

When a CAPTCHA provider is enabled, OW Forms loads the vendor’s JavaScript widget

on pages that render a form, and posts the challenge solution back to the vendor’s
verification API when a visitor submits the form. The data sent to the vendor is
limited to: (a) the challenge token generated client-side by the vendor’s widget,(
b) the visitor’s IP address (passed through to the vendor for fraud scoring), and(
c) the site’s API secret key configured in the settings.

#### Cloudflare Turnstile

 * What it is: a CAPTCHA / bot-mitigation service by Cloudflare, Inc.
 * When data is sent: only when `spam_captcha_provider` is set to `turnstile`, and
   
   only on form submission. The widget JS is also loaded on every page that renders
   a form.
 * Data sent: Turnstile challenge token, visitor IP, your Turnstile secret key.
 * Terms of service: https://www.cloudflare.com/website-terms/
 * Privacy policy: https://www.cloudflare.com/privacypolicy/

#### Google reCAPTCHA v3

 * What it is: an invisible CAPTCHA / risk-scoring service by Google LLC.
 * When data is sent: only when `spam_captcha_provider` is set to `recaptcha_v3`,
   and
    only on form submission. The widget JS is also loaded on every page that
   renders a form (this is how reCAPTCHA v3 builds its risk score).
 * Data sent: reCAPTCHA token, visitor IP, your reCAPTCHA secret key. Google may
   
   also collect additional telemetry as described in their privacy policy.
 * Terms of service: https://policies.google.com/terms
 * Privacy policy: https://policies.google.com/privacy

#### hCaptcha

 * What it is: a privacy-focused CAPTCHA service by Intuition Machines, Inc.
 * When data is sent: only when `spam_captcha_provider` is set to `hcaptcha`, and
   
   only on form submission. The widget JS is also loaded on every page that renders
   a form.
 * Data sent: hCaptcha token, visitor IP, your hCaptcha secret key.
 * Terms of service: https://www.hcaptcha.com/terms
 * Privacy policy: https://www.hcaptcha.com/privacy

#### Friendly Captcha

 * What it is: a privacy-first, proof-of-work CAPTCHA service by Friendly Captcha
   GmbH
    (Germany). No user puzzle, no tracking cookies.
 * When data is sent: only when `spam_captcha_provider` is set to `friendly_captcha`,
   
   and only on form submission. The widget JS itself is bundled with OW Forms (not
   loaded from an external CDN); only the verification request reaches the vendor.
 * Data sent: Friendly Captcha challenge token, visitor IP, your Friendly Captcha
   
   secret key.
 * Terms of service: https://friendlycaptcha.com/legal/terms/
 * Privacy policy: https://friendlycaptcha.com/legal/privacy-end-users/

#### Outgoing webhook (admin-configured)

 * What it is: a URL of your choosing that OW Forms POSTs to after each submission.
   
   No data leaves your site until you fill the `webhook_url` setting in OW Forms
   Settings  Notifications.
 * When data is sent: on every form submission, immediately after the admin
    notification
   email is dispatched. Non-blocking — your visitor’s submission response is not
   delayed by the webhook endpoint’s latency.
 * Data sent: form id, submission id, sanitized field payload (the same data
    stored
   in your `wp_owfo_submissions` table), site URL, ISO 8601 timestamp. If a webhook
   secret is configured, an `X-OWFO-Signature` HMAC-SHA256 header is added so the
   receiver can verify the payload origin.
 * Vendor: whoever owns the URL you configured. OW Forms has no built-in vendor
   
   for this — it is your responsibility to ensure the receiving endpoint complies
   with applicable privacy regulations for your submissions.

## Installation

 1. Upload `ow-forms` to `/wp-content/plugins/`.
 2. Activate the plugin through the Plugins menu.
 3. Navigate to `OW Forms > Forms` to create your first form.

## FAQ

### Can I migrate from Contact Form 7?

Yes — OW Forms ships with a one-click Contact Form 7 importer that converts every
CF7 form to an OW Forms schema and rewrites all `[contact-form-7]` shortcodes in
your post content.

### Does it integrate with OW Consent?

Yes — form submissions automatically link to OW Consent records when the plugin 
is active, and DSAR erasure requests automatically delete matching submissions by
email hash.

### Which CAPTCHA providers are supported?

Cloudflare Turnstile, Google reCAPTCHA v3, hCaptcha, and Friendly Captcha. Provider
and site/secret keys are configured globally in the Anti-spam settings.

### Where are uploaded files stored?

In `wp-content/uploads/owf-uploads/YYYY/MM/`, protected by a deny-all `.htaccess`.
Files are MIME-validated against a configurable extension allowlist and hash-checked(
SHA-256) on storage.

### Is there a REST API?

Yes — under the `owfo/v1` namespace. Public submission endpoint is nonce-protected;
admin endpoints require `manage_options` capability.

### What happens if I run `wp config shuffle-salts`?

Nothing breaks. OW Forms hashes submission emails with a dedicated plugin-owned 
salt stored in the `owfo_dsar_salt` option (generated once at activation, never 
regenerated). It does NOT depend on `wp_salt()` / the AUTH_KEY constants, so DSAR
erasure requests continue to match historical submissions after `shuffle-salts`.
If you want to force-rotate the OW Forms salt (which would invalidate every existing
email hash and break future DSAR matching), delete the `owfo_dsar_salt` option manually
via WP-CLI — the next submission will bootstrap a fresh one.

## Reviews

There are no reviews for this plugin.

## Contributors & Developers

“OW Forms” is open source software. The following people have contributed to this
plugin.

Contributors

 *   [ OptionWeb ](https://profiles.wordpress.org/optionweb/)

[Translate “OW Forms” into your language.](https://translate.wordpress.org/projects/wp-plugins/ow-forms)

### Interested in development?

[Browse the code](https://plugins.trac.wordpress.org/browser/ow-forms/), check out
the [SVN repository](https://plugins.svn.wordpress.org/ow-forms/), or subscribe 
to the [development log](https://plugins.trac.wordpress.org/log/ow-forms/) by [RSS](https://plugins.trac.wordpress.org/log/ow-forms/?limit=100&mode=stop_on_copy&format=rss).

## Changelog

#### 1.1.0

 * Compatibility: declared `Tested up to: 7.0` (the current WordPress release). 
   1.0.9 shipped with `6.8`, which Plugin Check flagged as outdated (`6.8 < 7.0`).
 * Readme: shortened the 1.0.9 upgrade notice to stay under the 300-character Plugin
   Check limit. No behavioural code changes since 1.0.9.

#### 1.0.9

 * GDPR (critical): decoupled `email_hash()` from `wp_salt()`. The previous implementation
   used `wp_salt()` as the hashing factor, so any admin running `wp config shuffle-
   salts` (a routine WordPress security hygiene step) would have silently invalidated
   every email hash already stored in `wp_owfo_submissions` — every subsequent DSAR
   erasure request would then have failed to match the historical rows, leaving 
   PII the visitor explicitly asked to delete sitting in the database with no error
   trail. The plugin now uses a dedicated, plugin-owned salt persisted in the `owfo_dsar_salt`
   option (generated once at activation, never regenerated, autoload OFF). Existing
   installs receive the salt on first call via lazy bootstrap, but no existing hash
   needs to be re-computed — only newly-written submissions use the new salt, and
   DSAR matching keeps working on rows written under either salt provided neither
   is rotated. Recommended for ALL sites.
 * Fixed: `Tested up to` corrected to 6.8 (was incorrectly set to 7.0, a WordPress
   version that does not exist yet — would have been flagged by Plugin Check as 
   an invalid version reference).
 * Fixed: admin settings save now routes `from_email` and `default_recipient_email`
   through `sanitize_email()` instead of the generic `sanitize_text_field()`, catching
   malformed inputs at save time instead of silently storing strings that `wp_mail()`
   would later reject.
 * Fixed: `route_handle_submission` REST endpoint now returns a 404 when called 
   against a submission id that does not exist, instead of silently returning `{
   ok: true}` after a no-op `wpdb->update`.
 * Fixed: anti-spam link-density scan now also detects bare `www.example.com` URLs(
   no protocol prefix), which spambots commonly use to slip past the previous `https?://`
   regex.
 * Compliance: shipped the non-minified `friendly-challenge-0.9.18.module.js` next
   to the existing `.min.js`, per WP.org Plugin Check requirements (vendored minified
   JS must ship with the human-readable source alongside).
 * Compliance: added `.distignore` at the plugin root so the WP.org SVN-deploy pipeline
   excludes dev-only files (node_modules, tests, build configs) from the published
   ZIP.
 * Compliance: created the empty `languages/` directory at the plugin root so the`
   make pot` build step has a known output location and translators can drop their`.
   po` files in a predictable place.

#### 1.0.8

 * Compliance: bumped `Tested up to` from 6.9 to 7.0 to satisfy the Plugin Check`
   outdated_tested_upto_header` rule (the header must point to the current WordPress
   release for the plugin to surface in directory searches). [Note: 7.0 is not a
   valid WordPress version — corrected to 6.8 in 1.0.9.]

#### 1.0.7

 * Fixed (regression): the legacy `[owf_form]` shortcode rewrite in post content
   now actually runs on sites that transited through 1.0.5. The 1.0.6 release introduced
   the SQL `REPLACE` but gated it behind the existing `owfo_migrated_owf_prefix`
   flag — which any 1.0.5 install already had set to `'1'`, so the rewrite was skipped
   on the largest existing fleet. The step is now gated by its own independent flag`
   owfo_migrated_shortcode_content` so it runs exactly once per install regardless
   of the version transit path.
 * Fixed: the shortcode-content `REPLACE` now excludes `post_type IN ('revision','
   auto-draft')` and `post_status IN ('inherit', 'auto-draft')`. Rewriting historical
   revisions would have silently re-authored users’ version history.
 * Fixed: hCaptcha invisible-flow second-submit deadlock. The `callback` registered
   on `hcaptcha.render()` only captures the FIRST submit’s `resolve` — every subsequent
   submit hung forever (button locked, spinner stuck). The render callback now dispatches
   through `holder._owfoHcaptchaResolve`, which is updated on every submit before`
   execute()` is called.
 * Bumped `Requires at least` from 6.0 to 6.3 to match the `apiVersion: 3` declared
   in `blocks/form/block.json` (block.json apiVersion 3 was introduced in WP 6.3).

#### 1.0.6

 * Fixed (intent, but see 1.0.7 for the actually-working version): wired the in-
   place migration of legacy `[owf_form id="..."]` shortcodes in post content. The
   migration was correctly added to `migrate_from_owf_prefix()` but shared the `
   owfo_migrated_owf_prefix` idempotency flag with the four pre-existing migration
   steps, which meant sites that had already run 1.0.5 skipped the new step entirely.
   Fix landed in 1.0.7.
 * Compliance: renamed the four captcha script handles from `owf-captcha-*` (3-char
   prefix) to `owfo-captcha-*` (4-char prefix). Aligns with the WordPress.org plugin
   guideline that the prefix rule covers script/style handles, not only PHP identifiers.
 * Compliance: the Gutenberg block now ships a real `block.json` manifest under `
   blocks/form/` (api-version 3) so Plugin Check stops emitting `block_no_block_json`
   and the block is discoverable by the editor inserter metadata API.
 * Fixed (partial — see 1.0.7 for the hCaptcha second-submit fix): front-end captcha
   token retrieval now actually supports hCaptcha (invisible flow with `render` 
   + `execute`) and Friendly Captcha (proof-of-work widget with `doneCallback` polling).
   Previous versions silently shipped empty tokens for both providers, which the
   server rejected with score +100 — all hCaptcha / Friendly Captcha submissions
   were therefore dropped client-side without any error message.
 * Removed: `signature` is no longer listed as a supported field type. It was advertised
   in 1.0.x but `render_field()` and `sanitize_value()` only ever fell back to `
   <input type="text">`. The field count in the description is now 16 (was 17). 
   A real canvas-based signature widget will land in a future release.

#### 1.0.5

 * Addressed the second-round feedback from the WordPress.org plugin review team.
 * Removed the legacy `[owf_form]` back-compat shortcode — the < 4-character prefix
   didn’t meet the WordPress.org plugin guidelines. Existing posts had already been
   migrated in place to `[owfo_form]` by the 1.0.3 upgrade routine, so the removal
   only affects content that was never opened for editing after that upgrade.
 * Fixed a broken Terms of Use URL pointing to Friendly Captcha in the External 
   Services section (`/legal/terms-of-service/`  `/legal/terms/`).

#### 1.0.4

 * Added an `uninstall.php` handler so all plugin data (custom tables, options, 
   form posts) is cleaned up on plugin deletion.
 * Added a `LICENSE.txt` file at the plugin root pointing to the GNU GPL v2 text.
 * Hardened the anti-spam time-trap with a server-anchored HMAC. The previous design’s
   client-set timestamp was trivially forgeable; the new check binds the gate to
   a signed render timestamp.
 * Captcha vendor scripts (Turnstile / reCAPTCHA / hCaptcha / Friendly Captcha) 
   now load only on pages that actually render a form, instead of every page of 
   the site once a provider is configured.
 * Added a composite index `(form_id, status, id)` on the submissions table — eliminates
   filesort on the admin list filter under high row counts. Existing installs pick
   the index up automatically on upgrade.
 * Settings option is now autoloaded, replacing the per-request `SELECT` it triggered
   on cache-cold pages.
 * Shared budget between the retention purge and the orphan-files sweep so a single
   cron tick never exceeds a known total of disk + DB ops. Filterable via `owfo_purge_budget_per_tick`.
 * Internal: spam reject threshold is now a named constant (`OWFO_Spam::REJECT_THRESHOLD`)
   filterable via `owfo_spam_reject_threshold`; routing parameters are stripped 
   from the REST submit payload before validation; baseline check on the uploads
   directory is memoised per request; OW Shield IP-reputation integration explicitly
   documented in the external-services section.

#### 1.0.3

 * Addressed feedback from the WordPress.org plugin review team.
 * Renamed internal prefix from `owf_` to `owfo_` to satisfy the 4+ character minimum
   required by WordPress.org. Existing installations migrate automatically on activation;
   the legacy `[owf_form]` shortcode continues to work for backward compatibility.
 * CSS and JavaScript are now loaded via `wp_enqueue_style()` / `wp_enqueue_script()`
   instead of inline `<style>` / `<script>` blocks. Assets only load on pages that
   actually render a form.
 * File uploads now use the WordPress core `wp_handle_upload()` API instead of `
   move_uploaded_file()`.
 * Form schemas saved through the admin UI are recursively sanitized (every string
   leaf passes through `sanitize_text_field()`).
 * Documented every third-party CAPTCHA provider (Turnstile, reCAPTCHA, hCaptcha,
   Friendly Captcha) in the new `== External services ==` section with what data
   is sent, when, and links to each vendor’s terms and privacy policy.

#### 1.0.2

 * WordPress.org Plugin Directory compliance pass (18/18 rules).
 * i18n source language switched to English; French shipped as a translation file
   under `languages/ow-forms-fr_FR.po`. `languages/ow-forms.pot` template included
   for community translators.
 * Conversion tracking is now opt-in (default OFF) — gtag events fire only after
   explicit admin opt-in.
 * Friendly Captcha widget is now self-hosted under `assets/js/vendor/` instead 
   of loaded from an external CDN.
 * Removed plugin “Powered by” link from the admin header.
 * Hardened SQL preparation, input sanitization, output escaping, and nonce verification
   across all admin and REST surfaces.

#### 1.0.1

 * PHPCS / Plugin Check sweep — SQL prepare, input sanitization, nonce verification,
   file system operations.

#### 1.0.0

 * Initial public release.

## Meta

 *  Version **1.1.0**
 *  Last updated **14 hours ago**
 *  Active installations **Fewer than 10**
 *  WordPress version ** 6.3 or higher **
 *  Tested up to **7.0**
 *  PHP version ** 7.4 or higher **
 * Tags
 * [anti-spam](https://wordpress.org/plugins/tags/anti-spam/)[contact form](https://wordpress.org/plugins/tags/contact-form/)
   [form builder](https://wordpress.org/plugins/tags/form-builder/)[forms](https://wordpress.org/plugins/tags/forms/)
   [GDPR](https://wordpress.org/plugins/tags/gdpr/)
 *  [Advanced View](https://wordpress.org/plugins/ow-forms/advanced/)

## Ratings

No reviews have been submitted yet.

[Your review](https://wordpress.org/support/plugin/ow-forms/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/ow-forms/reviews/)

## Contributors

 *   [ OptionWeb ](https://profiles.wordpress.org/optionweb/)

## Support

Got something to say? Need help?

 [View support forum](https://wordpress.org/support/plugin/ow-forms/)