=== MevvForms ===
Contributors: mevvsoft
Tags: forms, contact form, entries, wpforms migration, kvkk
Requires at least: 6.6
Tested up to: 7.1
Requires PHP: 8.1
Stable tag: 1.7.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Accessible forms with conditional logic, spam protection and entry management. No transaction fees, no telemetry.

== Description ==

MevvForms stores form definitions and entries on your WordPress installation. The Free package does not send telemetry or licence requests.

Everything below is in the Free package.

**Building forms**

* Drag-and-drop builder with a full keyboard equivalent, so the form can be built without a mouse.
* Around thirty field types: text, email, phone, URL, number, date, time, dropdown, radio, checkbox, rating, slider, colour, file upload, name, address, ranking, page break and more.
* Column layouts that keep the reading order identical to the field order, so a screen reader and a sighted visitor get the same form.
* Twenty ready templates across contact, sales, HR, events, feedback, support, registration and education.
* Autosave, revisions and restore.
* Shortcode and a Gutenberg block with a live preview.

**Conditional logic**

* Show or hide fields on the value of other fields, with nested AND/OR groups and fourteen operators.
* Conditions are re-evaluated on the server, so a field hidden in the browser cannot be submitted around.
* Works with JavaScript turned off.

**Entries**

* Entry list with search, filters, read state, starring, trash and bulk actions.
* Entry detail with the submitted values, the source page and any uploaded files.
* CSV export that opens correctly in Excel, with spreadsheet formula injection neutralised.

**Notifications**

* Multiple notifications per form, each with its own recipients, subject, body and condition.
* Route to different addresses on a field value; autoresponder to the person who filled the form.
* A delivery log that shows what was sent, what failed and why, with a resend control.

**Spam protection**

* Honeypot and timing checks that cost the visitor nothing and break no assistive technology.
* reCAPTCHA v2 and v3, hCaptcha, Cloudflare Turnstile and Akismet, all optional.
* Keyword, IP address and email address blocklists.
* A submission judged as spam is kept and marked, never silently deleted.

**Access control**

* Open and close a form on a schedule, cap the number of submissions, require a login or a role, or protect it with a password.
* Enforced on the server: a closed form refuses a direct submission.

**Uploads**

* Files are stored outside the web root in an unguessable directory, checked by content rather than by extension, and served only through expiring links bound to the person who requested them.

**Privacy and retention**

* Registered with the WordPress personal data export and erase tools.
* Retention periods per form, with the number of affected entries shown before anything is deleted.

**Migration**

* Import forms from Contact Form 7, WPForms, Gravity Forms, Fluent Forms, Formidable Forms, Ninja Forms and SureForms.
* Migration only reads the other plugin; nothing in it is changed or deleted.
* Anything that cannot be carried over is listed with the reason instead of being dropped quietly.
* Old shortcodes on existing pages keep working after the switch.

**No transaction fees.** Several form plugins take a percentage of what you collect on their entry paid tier. MevvForms does not, on any tier. Rates change, so check the current pricing page of whatever you are comparing against.

== Installation ==

Upload the mevvforms directory, activate the plugin, and open MevvForms in WordPress administration.

== External services ==

This plugin connects to the following external services. Every one of them is
off until you switch it on and enter your own account credentials. With no
provider configured, MevvForms makes no outgoing request at all.

**Google reCAPTCHA** — spam protection on your forms. Active only when you
select reCAPTCHA and enter your own site key and secret key.
Data sent: from the visitor's browser, whatever the reCAPTCHA script itself
collects when it loads on a page containing your form; from your server, your
secret key and the challenge token the visitor's browser produced. The
visitor's IP address is not sent unless the `mevvforms_spam_send_remote_ip`
filter is set to true on your site.
When: the script loads on any page that renders a form; the token is verified
when that form is submitted.
Terms: https://policies.google.com/terms · Privacy: https://policies.google.com/privacy

**hCaptcha** — spam protection on your forms. Active only when you select
hCaptcha and enter your own site key and secret key.
Data sent: whatever the hCaptcha script collects in the visitor's browser,
plus your secret key and the challenge token from your server. The visitor's
IP address is not sent unless the filter above is set to true.
When: the script loads on any page that renders a form; the token is verified
when that form is submitted.
Terms: https://www.hcaptcha.com/terms · Privacy: https://www.hcaptcha.com/privacy

**Cloudflare Turnstile** — spam protection on your forms. Active only when you
select Turnstile and enter your own site key and secret key. Turnstile's widget
script can only be loaded from Cloudflare's own host; it cannot be self-hosted.
Data sent: whatever the Turnstile script collects in the visitor's browser,
plus your secret key and the challenge token from your server. The visitor's
IP address is not sent unless the filter above is set to true.
When: the script loads on any page that renders a form; the token is verified
when that form is submitted.
Terms: https://www.cloudflare.com/website-terms/ · Privacy: https://www.cloudflare.com/privacypolicy/

**Akismet** — spam checking of submitted content. Active only when you select
Akismet and enter your own API key.
Data sent: your API key, your site address, the visitor's IP address, the
browser user agent string, the referring URL, and the submitted name, e-mail
address and message text. This is a transfer of personal data; tell your
visitors before you enable it.
When: once per form submission, while the submission is being processed.
Terms: https://akismet.com/tos/ · Privacy: https://automattic.com/privacy/

**Stripe** — taking payments from a form. Active only when you add a payment
field and enter your own Stripe secret key.
Data sent: your secret key, the amount in minor units, the currency, the line
item labels and quantities, the recurring interval when the payment is a
subscription, your success and cancel return addresses, and the reference
this plugin generates for the submission. Card details are typed on Stripe's
own hosted page and never reach your site or this plugin.
When: when a visitor submits a form that has a payment field, and again when
Stripe calls your webhook address back with the result.
Terms: https://stripe.com/legal/ssa · Privacy: https://stripe.com/privacy

**An AI provider of your choosing** — form building help and entry summaries.
Off by default. The two providers offered out of the box, Ollama and LM Studio,
run on your own server and send nothing outside it. A request leaves your site
only if you choose the third option, "any OpenAI-compatible endpoint", and type
in that endpoint's own address and your own API key — so the receiving service,
its terms and its privacy policy are the ones you picked.
Data sent: the prompt text, which is the form definition or the entry content
you asked to be worked on, plus your API key in the request header.
When: only when you press an AI button in the administration screen.
Terms and privacy: those of the endpoint you configured.

**Webhook destinations you enter yourself** — sending submissions onward.
No destination is configured out of the box.
Data sent: the submitted field values of that form, its form id and entry id,
and the signature header this plugin generates. Redirects are not followed.
When: when a form with a webhook is submitted.
Terms and privacy: those of the address you entered.

== Privacy ==

The Free package sends no telemetry. Spam protection is the only part of MevvForms that can talk to a third party, and only after you enable it:

* Honeypot, timing check, keyword, address and country rules run entirely on your server. Nothing leaves the site.
* Google reCAPTCHA (v2 and v3): the provider script loads in the visitor browser on pages that contain a form, and the challenge token is verified from your server. Google receives whatever its own script collects, plus the token.
* hCaptcha and Cloudflare Turnstile: same shape as above, with their own provider.
* Akismet: the submitted field values, the visitor IP address, the browser user agent and the referring URL are sent to Automattic for checking. This is a transfer of personal data; tell your visitors before you enable it.
* The visitor IP address is not sent to reCAPTCHA, hCaptcha or Turnstile unless a site filter asks for it.
* Country blocking uses only a country your host or CDN already provides. MevvForms ships no GeoIP database and asks no geolocation service.
* Provider secret keys are stored with the WordPress option API, are never printed back into the administration screen, and never reach the browser.

Form analytics is off by default and collects nothing at all until you switch it on and pick the forms it may measure. While it is off no counter row is written, no script is loaded on your pages, and no public endpoint exists. When you switch it on, this is the complete list of what is stored, and it never leaves your own database:

* Two tables of daily counters. `wp_mevvforms_analytics_daily` holds one row per form per day with four numbers: views, starts, submissions and abandonments. `wp_mevvforms_analytics_field` holds one row per form per field per day with five numbers: abandonments at that field, times it was left empty, validation errors, total focus time in milliseconds, and how many visitors focused it.
* Nothing else. There is no column for an IP address, a user id, an email address, a session token, a cookie value, a browser fingerprint, a referring URL or a submitted field value, so no row can be traced back to a visitor.
* No cookie is set, no browser storage is used, and no visitor identifier is created. The browser signal is authenticated with the form's own short-lived signed ticket, which is identical in shape for every visitor of that form.
* The signal is sent to your own site with `navigator.sendBeacon`; no third party is contacted and no external script or chart library is loaded, in the visitor page or in the administration screen.
* Because the counters are aggregates, a WordPress personal data export finds nothing to export. An erase request is answered explicitly with a line saying that MevvForms analytics holds no personal data.
* Counters are deleted by the same retention policy that deletes the form's entries, and in any case after 365 days (filterable with `mevvforms_analytics_max_days`).

== Changelog ==

= 1.7.1 =
* Prepared for submission to the WordPress Plugin Directory. The plugin header now carries its licence, the readme lists every external service the plugin can talk to and exactly what is sent to each, and the packager can build the directory package.
* Every filesystem operation now goes through one gate that asks WP_Filesystem first (`MevvForms_FS`). The private file vault no longer calls `move_uploaded_file()`, `rename()`, `mkdir()` or `chmod()` directly; the upload check that made `move_uploaded_file()` worth having is now written out explicitly as `is_uploaded_file()`.
* Table names in the migration readers and the admin counters are passed as `%i` identifier placeholders instead of being interpolated into the query string. The test doubles model `%i` the way the real `$wpdb->prepare()` does, so this path is covered rather than assumed.
* `parse_url()` and `strip_tags()` replaced with their WordPress equivalents, which behave the same across PHP versions.

= 1.7.0 =
* Uploaded files can now be kept in cloud storage instead of on your server. The rule that makes it safe lives in the free plugin: a file is still received, checked and stored locally first, it is moved on a background pass, and the local copy is deleted only once the remote end has confirmed it. If the upload fails the file stays here, the entry is still saved, and the next pass tries again — nothing is ever lost. Downloads stay behind the same decision they always were, and generated documents are deliberately left on this server so email attachments keep working. The destination itself comes from Pro (or from any plugin that implements `MevvForms_File_Remote_Store`).
* New schema migration (version 10) adding the vault's remote-storage columns. It runs on the normal upgrade path; no reactivation is needed.

= 1.6.1 =
* No free-side change; version kept in step with Pro, which fixes a PayPal refund defect.

= 1.6.0 =
* Free-side maintenance for the Pro additions: no behaviour change in the free plugin. The gateway registry, webhook payload builder, signature, delivery log and job queue are now consumed by two new Pro modules (PayPal and the Zapier/Make REST hooks) through their existing seams.

= 1.5.0 =
* The MevvPos bridge now actually opens. It required methods MevvPos never exposed, so Turkish payment providers were never available; MevvPos 4.7.0 adds the surface and this release connects to it.
* Fixed: a provider that cannot be queried for a payment's status was still marked as confirmable that way. Had the bridge opened, every signed notification would have been dropped and its retry discarded as a duplicate — every payment lost, silently.
* A provider that cannot issue refunds can now still take payments. Requiring refunds outright meant a Turkish merchant got no card payments at all, rather than payments refunded from the bank's own screen.

= 1.4.0 =
* Conditional logic can now be built in the builder, with the keyboard as well as the mouse: fields, notifications, confirmations, the submit button (enabled, visible and its text) and feeds. The source menu leaves out any field that would close a loop.
* Rules are still checked on the server; the editor is built so it cannot produce a tree the server would refuse.

= 1.3.0 =
* A style tab in the builder: colours, typography and corner radius, with a live responsive preview. Free CSS is still refused — values come from an allowlist, and the font stack from a server constant.
* Conditional feeds and a conditional submit button, resolved on the server for the first frame so the button is right before any script runs.
* Fixed: style tokens were written on the column shell, which does not exist without columns — a chosen accent colour never reached the submit button or the confirmation.
* Fixed: corner radius was read only by the error block, so changing it did nothing.
* Fixed: a cleared style setting came back on the next load.
* Security: the protected user-meta list named `wp_capabilities` literally. On an install with a non-default table prefix the real key was not recognised, so a registration form could have written it. It is now derived from the installation's own prefix.

= 1.2.2 =
* Fixed a serious bug: an uploaded file was never attached to its entry. The admin Attachments list was always empty, the file could not be downloaded, and the orphan collector deleted every submitted file after 24 hours. Files uploaded before this release and already collected cannot be recovered.
* The browser gate now covers analytics, front-end views, the full field matrix (including a signature drawn with real pointer events) and a non-Latin locale.

= 1.2.1 =
* The four new field types are now configurable from the builder: matrix rows and columns, quiz choices and answer key, repeater sub-fields, and the signature size limit.
* A signature now renders as an image in the entry detail screen; it is still never exposed in views, exports or webhooks.
* Fixed: renaming a quiz choice silently invalidated the answer key.

= 1.2.0 =
* Four new field types: signature, repeater, matrix and quiz. Quiz answers are never rendered into the page and the score is derived on the server.
* Outbound webhooks: every submission can be POSTed, HMAC-signed, to any address. Passwords, cards, files and signatures are never included.
* Entry editing with an audit trail, admin notes, and a pending/approved/rejected approval workflow.
* Responsive preview in the builder, a review step and a conversational flow for multi-step forms.
* Eight new templates (28 in total).
* ACF field mapping, email-confirmation activation for registration forms, and all three PDF adapters now covered by tests.
* Nested views no longer issue N+1 queries: a ten-row list with three nesting levels went from 123 queries to 9.

= 1.1.1 =
* Security: the update and licence signature public keys can no longer be swapped by a filter in production. Any other plugin on the same site could previously supply its own key and serve a forged, validly-signed update.

= 1.1.0 =
* The six administration tabs that were placeholders now work: Reports, Integrations, Import/Export, Settings, Roles and Logs.
* Roles screen cannot escalate: a role with administrative capabilities is locked, and nobody can grant a capability they do not hold themselves.
* Logs carry no personal data — no recipient, subject, error text, job payload or user login is read.
* Signed update client for the free edition. An unsigned response is never applied and the package address is accepted only from our own domain.

= 1.0.0 =
* First release. Drag-and-drop builder with a full keyboard equivalent, 34 field types, column layouts that keep the reading order, and twenty ready templates.
* Conditional logic with nested AND/OR groups and fourteen operators, re-evaluated on the server so a field hidden in the browser cannot be submitted around; works with JavaScript off.
* Entry management: search, filters, read state, bulk actions and CSV export that opens correctly in Excel with Turkish characters and neutralises spreadsheet formula injection.
* Notification routing with per-field recipients, autoresponder and a delivery log with resend.
* Access control enforced on the server: schedule, submission cap, login or role, password.
* Secure file uploads stored outside the web root, checked by content rather than by extension, served through expiring links bound to the person who requested them.
* Front-end views in five layouts; the map layout contacts no third party.
* Privacy and retention wired into the WordPress personal data tools, with the affected entry count shown before anything is deleted.
* Analytics that is off by default, sets no cookie and creates no visitor identifier.
* AI form generation against a local Ollama or LM Studio model, or your own key. No quota.
* Import from Contact Form 7, WPForms, Gravity Forms, Fluent Forms, Formidable Forms, Ninja Forms and SureForms; the source plugin is only read, and anything that cannot be carried over is listed with its reason.
* Nineteen locales.

= 0.1.0 =
* Initial F0 core, accessible renderer, local entries, outbox, and WPForms migration.
* Added free spam protection: rotating honeypot, signed timing trap, keyword, address and country rules, reCAPTCHA v2/v3, hCaptcha, Cloudflare Turnstile and Akismet, with flagged submissions stored for review instead of being discarded.
