=== EffortLess Multisite Form Creator ===
Contributors: domclic
Tags: form, contact form, gutenberg, ajax, multisite
Requires at least: 5.8
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 7.5.80
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Donate link: https://id7.dev/donate/

AJAX-powered Gutenberg contact forms. Display inline or as popups. Supports multisite, SMTP, captcha, file uploads, and CPT submission storage.

== Description ==

**EffortLess Multisite Form Creator** lets you build forms in the block editor, as a "Form" post whose content is your form's HTML. Each form is placed on a page with a shortcode or the ELMFC Form block, inline or as a popup. Submissions are sent by AJAX, emailed to the addresses you choose, and can optionally be stored as posts of a custom post type.

= Key Features =

* **Gutenberg-Ready** - Build forms directly in the block editor with HTML
* **AJAX Submission** - No page refresh needed
* **Popup or Inline** - Display forms as popups or embedded in your content. A popup is an accessible dialog: the keyboard focus moves into it and stays there, Escape closes it, and the focus returns to the button that opened it
* **Theme Styling by Default** - Forms take your theme's appearance; optional built-in form styles can be enabled in Forms > Settings
* **Fieldset Support** - Full support for fieldset and legend elements, with optional styling
* **Flexible Width Options** - Container width (default), narrow, default, or wide layouts
* **Email Notifications** - Send to the site admin and/or a chosen user; optionally a copy to the submitter
* **SMTP Support** - Optional SMTP configuration for reliable email delivery
* **Per-Form Customization** - Each form can have unique messages and settings
* **Theme Button Support** - Uses your theme's button styles by default (optional custom styling)
* **Fully Translatable** - All messages configurable per form (no hardcoded text)
* **Multisite Compatible** - Forms can be rendered and submitted across the sites of a multisite network
* **Responsive Design** - Mobile-friendly popups and forms with optimized spacing
* **Cloudflare Turnstile** - Optional spam protection without a puzzle for most visitors, per form, instead of the math captcha
* **Webhook with Retries** - Each submission can be sent to a webhook (e.g. Zapier); failed deliveries are retried for about 2.5 hours, and the result is shown on the stored submission
* **Simple Math Captcha** - Optional spam protection; the question is loaded when the form is shown, so it keeps working on cached pages, and forms sent less than 3 seconds after loading are rejected
* **Enhanced Radio & Checkbox** - Card-style radio buttons and highlighted terms checkbox
* **Ready-made Forms** - Contact, newsletter, quote request and call-back request patterns to start from
* **Save Submissions** - Optional storage as custom post type with custom slug; new submissions highlighted, search, date filter, CSV export and a reply-by-email button
* **Configurable Retention** - Optionally auto-delete stored submissions after a set number of days
* **Privacy Tools Integration** - Submissions are included in WordPress's built-in personal data export/erase tools
* **Page Builder Compatible** - Works with Elementor, Beaver Builder, Divi, and Gutenberg blocks
* **No Dependencies** - The front-end script uses no library (no jQuery) and loads deferred, so it does not delay the page

= Use Cases =

* Contact forms
* Support request forms
* Quote request forms
* Newsletter signup forms (with consent & storage)
* Subscription forms with plan selection
* Feedback forms
* Registration forms

= Form Width Options =

Choose how your inline forms should display:

* **Container Width (Default)** - Uses 100% of the parent container width
* **Narrow** - Maximum 450px width, centered
* **Default** - Maximum 720px width, centered  
* **Wide** - Maximum 1080px width, centered

= Email Configuration =

* Send to site admin email
* Send to specific WordPress user
* Send a copy to the form submitter (off by default; requires an email field)
* Optional SMTP configuration for better deliverability
* Customizable email subjects and messages per form

= Styling Features =

By default the plugin styles only the popup, the form width setting and the hiding of multi-step pages; everything else follows your theme. When "Load the plugin's form styles" is enabled in Forms > Settings, it also provides:

* Card-style radio button options with hover effects
* Highlighted terms and conditions checkbox container
* Proper fieldset and legend styling with nested support
* Consistent spacing throughout forms
* Custom or theme button styling options
* Visual width preview in admin settings

== Installation ==

1. Upload the plugin files to `/wp-content/plugins/effortless-multisite-form-creator/`
2. Activate the plugin through the 'Plugins' menu in WordPress
3. Go to Forms > Add New Form
4. Build your form using HTML in the Gutenberg editor
5. Configure settings in the sidebar meta boxes
6. Use shortcode `[elmfc id="123"]` or `[elmfc name="your-form-slug"]`
7. Add `popup="true"` to display as popup: `[elmfc id="123" popup="true"]`

== Frequently Asked Questions ==

= How do I create a form? =

1. Go to Forms > Add New Form
2. Add your form HTML in the editor (use fieldset, input, textarea, select, etc.)
3. Configure email settings, captcha, and appearance in the sidebar
4. Publish and copy the shortcode

= Who can create and edit forms? =

Administrators (users with the `manage_options` capability; on multisite, each site's administrators and the super admins). A form's settings decide where its submissions go (recipients, SMTP server, webhook URL), so Editors, Authors and Contributors cannot create or edit forms. They can still place a published form on a page with the shortcode or the ELMFC Form block. Developers can grant another capability with the `elmfc_manage_forms_capability` filter.

On multisite, a site administrator who is not a super admin may save form fields (`<input>`, `<select>`, `<textarea>`, `<button>`) in a form; WordPress still removes `<script>`, `<style>` and event attributes for them.

= Where can the webhook send submissions? =

To a public `http` or `https` URL. Addresses on the local or private network (`localhost`, `127.0.0.1`, `10.x`, `192.168.x`, and so on) are refused by WordPress's safe HTTP API and nothing is sent.

= What happens when the webhook is down? =

The submission is sent to the webhook right away (waiting at most 3 seconds). If the webhook cannot be reached or answers with an error (anything other than a 2xx status), it is sent again with WP-Cron after 1 minute, 5 minutes, 30 minutes and 2 hours, using the form's current webhook address and secret. Until then the submission's data is kept in a temporary, non-autoloaded option, deleted when the retry runs. When the form stores its submissions, Forms > All Submissions shows the result on each submission: delivered, waiting for the next attempt, or failed after 5 attempts with the last error. On a site where WP-Cron only runs on page views, a retry happens at the first visit after its time.

= How do I use Cloudflare Turnstile instead of the math captcha? =

1. Create a Turnstile widget in your Cloudflare dashboard and add your site's domains (on a network, every domain the forms are shown on).
2. In Forms > Settings, paste its site key and secret key. On multisite, only network administrators can do this, and the keys are shared by every site.
3. Edit a form and tick "Use Cloudflare Turnstile" in its Security settings. It replaces the math captcha on that form; if the form contains `[elmfc_captcha]`, the widget is shown there.

Most visitors see no puzzle. The form cannot be sent until Turnstile has finished its check, and the server confirms the result with Cloudflare before accepting the submission. If Cloudflare cannot be reached, the submission is refused and the visitor can try again. A popup form loads its widget when it is opened. Clearing the site key in Forms > Settings switches every form back to the math captcha.

= How do I add fieldsets? =

Use standard HTML fieldset and legend tags:
```html
<fieldset>
    <legend>Section Title</legend>
    <label>Field Name</label>
    <input type="text" name="field_name" required>
</fieldset>
```

= How do I write my own label/text around the captcha? =

The "Enable simple captcha" checkbox auto-inserts a boxed question with fixed
label text. If you'd rather write that text yourself — and have it translate
like the rest of your form content instead of through a separate settings
field — place the `[elmfc_captcha]` shortcode directly in the form's HTML
instead. It renders only the question (e.g. "5 + 6 = ?"), the answer input,
and a hidden verification token; everything around it is plain HTML you
control:

```html
<label>Security check: [elmfc_captcha]</label>
```

The shortcode already includes its own answer input and hidden token, so
nothing else is needed — just wrap it in whatever label/wording you want.
When `[elmfc_captcha]` is present in the content, the auto-inserted box is
skipped automatically so you never get two captchas on the same form.

= How do I build a form with a Custom HTML block? =

1. Go to Forms > Add New Form and give the form a title (it is shown above the form).
2. Add a Custom HTML block and write the fields. Every field needs a `name` attribute; that name is the label used in the email and in stored submissions.
3. Add a submit button: `<button type="submit">Send</button>`.
4. Optionally put `[elmfc_captcha]` where the captcha should appear; a form containing the tag always shows and checks the captcha, even with "Enable simple captcha" unticked. Without the tag, and with "Enable simple captcha" ticked, the captcha is placed just before the submit button.
5. Publish, then add the form to a page with `[elmfc id="123"]` or the ELMFC Form block.

Example:

```html
<p><label>Name <input type="text" name="name" required></label></p>
<p><label>Email <input type="email" name="email" required></label></p>
<p><label>Message <textarea name="message" rows="5" required></textarea></label></p>
<p><label>Security check: [elmfc_captcha]</label></p>
<button type="submit">Send</button>
```

Line breaks typed in a textarea are kept in the email and the stored submission.

= Can I put my own CSS and JavaScript in a form? =

Yes. In the same Custom HTML block, add a `<style>` element and a `<script>` element. This works when the form's author has the `unfiltered_html` capability: administrators on a single-site install, and super admins on multisite. For authors without that capability, `<script>` and `<style>` are removed from the form when it is displayed.

= How are forms styled? =

By default, with your theme's styles. The plugin always loads a small stylesheet (`assets/css/elmfc-base.css`) for what cannot work without it: the popup (overlay, box, header, close button), the Narrow/Default/Wide width setting, and the hiding of multi-step pages. Fields, buttons, messages, the CAPTCHA and the form box are left to your theme, and you can style them with a `<style>` element in the form's own Custom HTML block. Buttons use the theme's button style; a form's "Use custom button styling" option (Appearance Settings box) gives that form's buttons the plugin's own button style instead.

To use the plugin's own form styles instead, go to Forms > Settings and enable "Load the plugin's form styles". This loads `assets/css/elmfc.css` on every form of the site. It does not restyle theme buttons. The plugin's JavaScript (AJAX submission, popup, validation, multi-step navigation) works the same either way.

= How do I display the form as a popup? =

Add `popup="true"` to your shortcode:
`[elmfc id="123" popup="true"]`

The popup's captcha and submit token are loaded when the popup is first opened, not when the page loads.

= Is the form title shown? =

A popup shows the form's title in its header. A form placed in the page shows its title above the form only when "Show the title above the form" is ticked in the form's Appearance Settings box (off by default). Either way, screen readers announce the form by its title.

= How do I make the form full width? =

By default, forms use their container's full width. To explicitly control width:

1. Edit your form
2. Go to Appearance Settings sidebar
3. Select "Container" for full width, or choose Narrow/Default/Wide for specific max-widths

= Can I change the button texts and messages of one form? =

Yes. Add hidden fields to the form's HTML; each one overrides the default text for that form only:

* `elmfc_submit_text` - not needed for a `<button>` written in the form: it keeps its own text and icons, which are put back after sending
* `elmfc_sent_text` - button text after a successful submission
* `elmfc_sending_message` - button text while the form is being sent
* `elmfc_success_message` - message shown after a successful submission
* `elmfc_success_title` - title above that message (default "Message sent")
* `elmfc_duplicate_message` - message shown when "Refuse an email address already saved" refuses an address
* `elmfc_error_message` - message shown when the email could not be sent
* `elmfc_validation_message` - message shown when a required field is empty
* `elmfc_captcha_error` - message shown after a wrong captcha answer
* `elmfc_captcha_question` - label of the automatically inserted captcha

```html
<input type="hidden" name="elmfc_submit_text" value="Send Message">
<input type="hidden" name="elmfc_success_message" value="Thanks for contacting us!">
```

The notification email's subject and introduction (`_elmfc_admin_subject`, `_elmfc_admin_message`, `_elmfc_user_subject`, `_elmfc_user_message`) cannot be set by hidden fields, so a visitor cannot change them. Set them through Export / Import Settings on the form. The redirect after submission is set in the Appearance Settings box.

= Which CSS classes give fields the built-in styling? =

These classes are styled only when "Load the plugin's form styles" is enabled in Forms > Settings, except `elmfc-btn` (see below).

* `radio-label` on a `<label>` wrapping a radio button: card-style option.
* `checkbox-label` on a `<label>` wrapping a checkbox, inside a `<div class="terms-container">`: highlighted terms checkbox.
* `elmfc-buttons` on the `<div>` around the buttons; `elmfc-btn` on a button uses the plugin's button style when "Use custom button styling" is ticked in the form's Appearance Settings (this works even with the form styles off), otherwise the theme's button style.
* `elmfc-cancel` on a `type="button"` button: resets the form.
* `<span class="required">*</span>` in a label: required-field marker.

```html
<label class="radio-label"><input type="radio" name="source" value="search" required> <span>Search engine</span></label>
<div class="terms-container">
    <label class="checkbox-label"><input type="checkbox" name="terms" required> <span>I agree to the terms <span class="required">*</span></span></label>
</div>
<div class="elmfc-buttons">
    <button type="submit" class="elmfc-btn">Send Message</button>
    <button type="button" class="elmfc-btn elmfc-cancel">Reset</button>
</div>
```

= How do I accept file uploads? =

1. Edit the form and tick "Allow file uploads" in its settings. Set "Max size (MB)" (per file, 1 to 50, default 5) and "Allowed extensions" (comma-separated, default `jpg,jpeg,png,gif,pdf,doc,docx,xls,xlsx,zip`).
2. Add a file field to the form: `<input type="file" name="attachment">`, or `<input type="file" name="attachments[]" multiple>` for several files.

Accepted files are attached to the admin email and deleted from the server afterwards; the email and the stored submission list their names and sizes. A file that is too large or has another extension is left out. Executable extensions (such as `php`, `exe`, `sh`) are always refused.

= How do I enable SMTP? =

1. Edit your form
2. In Email Settings sidebar, check "Use SMTP"
3. Enter your SMTP host, port, encryption, username, and password
4. Save the form

= Does it work with page builders? =

Yes. The shortcode and the block work in any builder that renders shortcodes or blocks. With "Load the plugin's form styles" enabled, the form styles include width overrides for:
* Elementor
* Beaver Builder
* Divi
* Gutenberg blocks
* Generic row/column layouts

= How do I save form submissions? =

1. Edit your form
2. In Storage Settings sidebar, check "Save submissions to CPT"
3. Enter a CPT slug (e.g., "newsletter", "contact-requests")
4. Submissions will appear as a submenu under Forms

In Forms > All Submissions, each form's list shows new submissions in bold (the Forms menu shows how many are new), can be searched, and can be filtered by date with "From" and "To". "Export CSV" exports the submissions of the selected dates (all of them when no date is set); the bulk action "Export to CSV" exports the ticked ones. Opening a submission marks it as read and shows a "Reply by email" button addressed to the visitor (the form's email field, otherwise the first email address in the submission), with "Re: form title" as subject.

= Can a newsletter refuse an address that already subscribed? =

Yes. In the form's Storage Settings (with "Save submissions to CPT" on), tick "Refuse an email address already saved". A submission whose address is already among that form's stored submissions is then refused before anything happens (no email, no storage, no webhook), and the visitor sees "This email address has already been registered." (change it with a hidden field named `elmfc_duplicate_message`). The address is read from the form's email field (Email Settings), or a field named `email`; letter case is ignored. Leave the option unticked on a contact form so a visitor can write again. Note that this tells a visitor whether an address is registered; the form's rate limit still applies.

= Are there ready-made forms? =

Yes. When you edit a form, the block inserter's Patterns tab has a "Forms" category with a contact form, a newsletter sign-up, a quote request and a call-back request; a new form also offers them as starting points. Each is a Custom HTML block with labelled fields and a submit button, in the site's language, without CSS: change the fields and add a `<style>` element as you like.

= How is stored submission data handled for privacy (GDPR)? =

If you enable "Save submissions to CPT" for a form, submitted data (name, email, message, and any other field) is stored in your site's database indefinitely by default. You can set "Auto-delete submissions after (days)" in Storage Settings to have the plugin permanently delete submissions older than that automatically (checked once daily); leave it at 0 to keep them forever.

Stored submissions are also included in WordPress's built-in personal data tools (Tools → Export Personal Data / Erase Personal Data), so you can fulfil a visitor's data request without manually searching the database.

= How are forms translated on a multisite network? =

With the EffortLess Multisite Auto Translate plugin active, a form saved on the network's source site is copied and translated to the other sites like a post:

* The text in the form's Custom HTML blocks is translated, and nothing else changes. With EffortLess Multisite Auto Translate 3.3.8 or later, only the visible text and the `placeholder`, `title`, `alt`, `aria-label` and button-label attributes are sent for translation; field names, IDs, classes, types, inline styles and hidden values stay exactly as on the source. The form fields are kept when the translated copy is saved.
* CSS and JavaScript written in the form's Custom HTML block (`<style>`, `<script>`) are kept on every site with EffortLess Multisite Auto Translate 3.3.11 or later, which saves the translated copy as the source form's author. This requires that author, and the user who last saved the source form, to be allowed unfiltered HTML (a super admin on multisite). Otherwise WordPress removes the code from the copy, as it would on that author's own save. Edit the code on the source site; a translated copy should not be edited by a user without that capability, because WordPress would then remove its code on save.
* The form keeps the same slug on every site, so `[elmfc name="..."]` works everywhere. On a page that uses the ELMFC Form block, the block is pointed at the translated form of that site.
* Per-form texts that you set (button labels, messages, email subjects) are translated; the plugin's default texts follow each site's language.
* Form statistics are not copied.

If a site has no translated copy of a form yet, `[elmfc name="..."]` shows the source site's form until the translation exists.

= Can I translate form messages? =

Yes. Each form can override its messages with hidden fields (see "Can I change the button texts and messages of one form?" above).

The plugin's own texts (submit and sending labels, success and error messages, the captcha label and placeholder) follow the site language. The plugin ships translations for German, Spanish, French, Italian, Japanese, Korean, Brazilian Portuguese and Traditional Chinese; they are used until a language pack for that language is available from translate.wordpress.org, which then takes priority. Text you write yourself in the form content, such as field labels or a submit button in a Custom HTML block, is not translated automatically: write it in the site's language.

== External services ==

This plugin can optionally connect to third-party services to reduce spam. Both are off by default: Akismet is used only when it is installed and configured, and Cloudflare Turnstile only on forms that tick "Use Cloudflare Turnstile" after its keys are added in Forms > Settings.

**Akismet**

If the Akismet plugin is installed, active, and configured with an API key on your site, this plugin sends each form submission's author name, email, message text, IP address, user agent, and referrer to Akismet's comment-check endpoint (`https://REST.akismet.com/1.1/comment-check`) to determine whether the submission is spam. This only happens if Akismet is already active on your site; if it is not, no data is sent to Akismet.

This service is provided by Automattic: [Terms of Service](https://akismet.com/tos/), [Privacy Policy](https://automattic.com/privacy/).

**Cloudflare Turnstile**

On a page showing a form that uses Turnstile, the visitor's browser loads Cloudflare's script from `https://challenges.cloudflare.com/turnstile/v0/api.js`, which checks the browser and produces a token (Cloudflare receives the data its script collects, such as the IP address, browser characteristics and the page address). When the form is submitted, the plugin sends that token, the site's Turnstile secret key and the visitor's IP address to `https://challenges.cloudflare.com/turnstile/v0/siteverify` to confirm it. No form field is sent to Cloudflare.

This service is provided by Cloudflare, Inc.: [Terms of Service](https://www.cloudflare.com/website-terms/), [Privacy Policy](https://www.cloudflare.com/privacypolicy/), [Turnstile Privacy Addendum](https://www.cloudflare.com/turnstile-privacy-policy/).

**Your webhook**

When a form has a webhook address, each submission's fields are sent to that address (a service you choose, such as Zapier), as described in the FAQ.

== Screenshots ==

1. Form builder in Gutenberg editor with fieldset support
2. Popup form
3. Admin settings - Email configuration with SMTP
4. Admin settings - Width options with visual preview
5. Admin settings - Security and appearance options
6. Mobile-responsive form with card-style radio buttons
7. Form with fieldsets and legend styling
8. Submissions stored as custom post type

== Changelog ==

= 7.5.80 =
* Added: "Refuse an email address already saved" in a form's Storage Settings. For a newsletter sign-up, a submission whose email address is already among the form's stored submissions is refused (no email, no storage, no webhook) and the visitor is told the address is already registered (text changeable with the `elmfc_duplicate_message` hidden field). Off by default, so contact forms keep accepting several messages from the same person.

= 7.5.79 =
* Change: the confirmation after a successful send shows a check mark in a green circle, drawn in SVG, so it looks the same in every font and language (the ✓ character looked like a square-root sign in Chinese fonts), with a short drawing animation (none when the visitor prefers reduced motion). In a popup, a "Close" button under the message closes it and has the keyboard focus.
* Fix: the confirmation showed a dark frame on some themes. It was the browser's focus outline on the message area, which the script focuses for screen readers; that area is not a control, so it no longer shows an outline.

= 7.5.78 =
* Change: after a successful submission, the form is replaced by a centred confirmation like EffortLess Simple House Booking's: a large green check mark, a title ("Message sent" by default, or the form's `elmfc_success_title` hidden field) and the success message. It is styled by the always-loaded stylesheet, on a white background so it stays readable on dark themes, and announced by screen readers. The title is translated on other sites by EffortLess Multisite Auto Translate.

= 7.5.77 =
* Fix: the popup's close cross was not centred in its circle (the "×" character sits where the font puts it) and moved off-centre while turning on hover. It is now drawn with CSS, exactly in the middle; the button keeps its "Close" label for screen readers.

= 7.5.76 =
* Added: block patterns for a contact form, a newsletter sign-up, a quote request and a call-back request (Patterns tab, "Forms" category, when editing a form; also offered when a new form is created). Their texts follow the site language.
* Added: a "Reply by email" button on each stored submission, addressed to the visitor, with "Re: form title" as subject.
* Added: a date filter (From / To) on a form's submissions list; "Export CSV" then exports the submissions of those dates. The CSV also has a Webhook column with each submission's delivery result.
* Change: the hooks of EffortLess Multisite Auto Translate are now registered only under their current `elmat_*` names; the `ms_gpt_*` names of versions before its rename are no longer used, nor its old `ms_gpt_source_site` setting.

= 7.5.75 =
* Added: optional Cloudflare Turnstile spam protection. Add its keys in Forms > Settings (on multisite: network administrators only, shared by every site), then tick "Use Cloudflare Turnstile" on a form; it replaces the math captcha there. The token is checked with Cloudflare when the form is submitted. Described under External services.
* Added: a webhook delivery that fails (network error or a non-2xx answer) is retried with WP-Cron after 1 minute, 5 minutes, 30 minutes and 2 hours. The first attempt now waits for the answer (at most 3 seconds) instead of not checking it. A stored submission shows whether its webhook was delivered, is waiting for a retry, or failed.

= 7.5.74 =
* Change: the front-end script no longer needs jQuery and loads with `defer`. On a theme that does not load jQuery itself (such as Twenty Twenty-Five), pages with a form no longer download it.
* Change: a popup form loads its captcha and submit token when it is first opened, instead of on every page view. Its impression is counted at that moment.
* Change: the title above a form placed in the page is shown only when the new "Show the title above the form" setting is ticked (off by default). The popup keeps its title in its header.
* Accessibility: the popup is a dialog (`role="dialog"`, `aria-modal`); the keyboard focus moves into it, stays inside while it is open, and returns to the opening button when it closes. Invalid fields are marked with `aria-invalid` and linked to their error text, messages are announced by screen readers, and the multi-step progress bar reports the current step.
* Change: the multi-step "Previous"/"Next" buttons use the theme's button style, or the plugin's when the form ticks "Use custom button styling".
* Fix: when the server returned an error without a message, nothing was shown; the form's error message is now shown.

= 7.5.73 =
* Change: the popup leaves only a 12px space around the form (was 30px, 25px on tablets and 20px on phones), so the form's own CSS decides its spacing.

= 7.5.72 =
* Change: buttons always keep the theme's button style. The optional form styles no longer repaint theme buttons (they made them grey).
* Change: a form's "Use custom button styling" option works on its own: its button styles are in the always-loaded stylesheet and apply only to forms that tick it, whether or not the form styles are enabled.

= 7.5.71 =
* Change: forms take the theme's appearance by default. The plugin now always loads only a small stylesheet (`elmfc-base.css`) for the popup (overlay, box, header, close button), the Narrow/Default/Wide width setting and the hiding of multi-step pages. The form styles (form box, fields, buttons, messages, CAPTCHA, progress bar) load only when the new "Load the plugin's form styles" option is enabled in Forms > Settings. It replaces "Disable the plugin's built-in CSS"; enable it to keep the previous look.

= 7.5.70 =
* Change: Form Creator no longer rebuilds translated forms. EffortLess Multisite Auto Translate 3.3.11 saves a translated copy as the source form's author when that author may post unfiltered HTML, so WordPress keeps the copy's `<style>`, `<script>` and form fields, the same as for any translated page. The rebuild after each translation, the rebuild when a translated form is shown and the source-code substitution at display time are removed. Requires EffortLess Multisite Auto Translate 3.3.11 or later for translated forms to keep their code.

= 7.5.69 =
* Change: a form translated by EffortLess Multisite Auto Translate is rebuilt from its source form (source markup and code, translated text) and saved with `wp_update_post()` on behalf of the source form's author, instead of being written directly to the database. WordPress applies the same rules as when that person saves the form: the copy is saved only if they may publish unfiltered HTML on the destination site.
* Change: showing a translated form never writes to the database any more. A copy saved before the rebuild existed is shown rebuilt from its source, and is saved at its next translation.

= 7.5.68 =
* Change: Akismet receives the form's real fields. It previously only read fields named `name`, `email` and `message`, so forms with other field names were checked with empty content. The email is the form's configured email field (or the first email address), the author the first field whose name contains "name", and the content every other text field.
* Change: when a submission is stored but its email cannot be sent, the visitor sees the success message instead of an error, so they do not send it again and create a duplicate. The stored submission shows "Failed" and can be resent from Forms > All Submissions.
* Fix: a form placed outside the page content (a template, template part, widget or page builder) now always loads its script and styles. With a block theme such as Twenty Twenty-Five, the styles are in the page head, so the form no longer appears unstyled first.
* Fix: fields written as `disabled` in the form stay disabled after an error, a reset or a show-if rule.
* Fix: the same form shown twice on a page no longer repeats the captcha field's HTML id.
* Fix: the search on a form's submissions screen is kept when moving to another page of results or sorting a column.
* Fix: the "Settings imported" message is shown in the block editor.
* Change: the redirect after submission may point to another domain, for example another site of the network with its own domain. It is read from the form's settings, never from the visitor's request, and must be an http or https address.

= 7.5.67 =
* Fix: a submit button written in the form kept its own text only until the first send. While sending, after an error (for example a wrong captcha answer) and when a popup was closed, it was replaced by the plugin's text ("Submit"), losing any icon or arrow inside it. The button's own markup is now put back.
* Fix: after a wrong captcha answer, the cursor is now placed in the captcha field (it was still disabled when the form tried to focus it).
* Fix: settings import from the "Export / Import Settings" box did nothing in the block editor, because the box's form sat inside the editor's own form. The file is now sent in the background and the editor reloads with the imported settings. The upload settings (allow uploads, maximum size, allowed extensions) are now imported too.
* Fix: fields hidden by a `data-show-if-field` rule were sent with the form (a hidden `<select>` always has a value), and became active again after an error. Disabled fields are no longer sent, and the rules are applied again after an error.
* Security: the submission identifier shown in the admin and the CSV export was the raw value of the email field. It is now used only when it is a valid email address, and the CSV export protects that column against spreadsheet formulas like the other columns.
* Fix: backslashes typed by a visitor were removed from stored submissions.
* Fix: the personal data eraser (Tools > Erase Personal Data) skipped part of the submissions of a person who had more than 50. The personal data export now lists checkbox choices instead of their stored form.
* Fix: bulk "Delete" on the submissions screen acts only on submissions of the form shown.
* Fix: on uninstall, the captcha entries of a single-site install and the folder used for email attachments are removed too.
* Change: the plain-text part of notification emails ("Form", "Submitted from", "Submitted on") follows the site language.
* Change: the page no longer contains the form's email subjects and introductions as hidden fields; they are read from the form's settings when the email is sent. A hidden field written in the form itself (for example `elmfc_sending_message`) now also overrides the texts shown by the form's script.
* Fix: the note shown in the Email Settings box when a site has more than 500 users now points to the CC field.

= 7.5.66 =
* Added: file fields with `multiple` send all the selected files. Previously only one file reached the server, or none when the field name ended with `[]`, without any message.
* Fix: with "Disable the plugin's built-in CSS" enabled, the hidden spam-trap field ("Leave this field empty") was visible in every form. It is now hidden by its own markup. Password managers are also told not to fill it, which would have made a real submission look like spam.
* Fix: a button with the `elmfc-cancel` class resets the form in both button modes. It previously only worked with "custom buttons" enabled.
* Change: a translated form reads its source form once per page view instead of twice.

= 7.5.65 =
* Change: creating, editing and deleting forms requires the `manage_options` capability (administrators) instead of the capabilities used for posts. A form's settings decide where submissions are sent, including the webhook URL and SMTP server, which Authors could previously set. Editors, Authors and Contributors can still place published forms on pages. Developers can change the capability with the `elmfc_manage_forms_capability` filter.
* Change: the webhook is sent with `wp_safe_remote_post()`, which refuses local and private network addresses.
* Change: the form's content is rendered with the block, paragraph and shortcode functions only, instead of the full `the_content` filter, so content that other plugins add to posts (share buttons, related posts, ads) no longer appears inside forms.
* Fix: on multisite, a site administrator who is not a super admin lost every form field when saving a form in the block editor or duplicating it. Form fields are now kept for users who manage forms; `<script>`, `<style>` and event attributes are still removed for them.
* Fix: Duplicate and Copy to site copied the original form's statistics, edit lock and EffortLess Multisite Auto Translate links. A duplicated translated form was then taken for a second translation of the source form. These are no longer copied. Backslashes in the form's content and settings (for example in its JavaScript) are also kept.
* Fix: after a wrong captcha answer, the replacement captcha had no minimum fill time, so a script could send one wrong answer and then the right one at once. The replacement now keeps the time of the first captcha.
* Change: a form's refresh request (security token, captcha and view count when the form is shown) is limited to 60 per form and IP address in 10 minutes. Developers can change it with the `elmfc_refresh_limit` filter.

= 7.5.64 =
* Fix: translated forms whose copy was saved before 7.5.63 kept missing their `<style>`/`<script>`, because EffortLess Multisite Auto Translate only reports a full translation, not a meta-only update of an unchanged form. A translated form whose stored copy differs from its source (apart from the translated text) is now rebuilt from the source once, the next time it is shown, under the same conditions as the rebuild after a translation.

= 7.5.63 =
* Change: a form translated by EffortLess Multisite Auto Translate is now stored identical to its source form except for the translated text, including the `<style>` and `<script>` of its Custom HTML block. Translations are saved in the background, where WordPress's content filter cannot keep that code intact, so right after the save the copy is rebuilt from the source markup with the translated text, the translated `placeholder`, `title`, `alt`, `aria-label` and button labels. Requires the source form's author to be allowed unfiltered HTML. If the copy does not line up piece by piece with the source, it is left as saved and the form still runs the source form's code.
* Change: when a translated form is shown, code identical to its source form's stays where it is in the form; any other `<style>`/`<script>` is removed whole, so code is never printed as text.

= 7.5.62 =
* Fix: opening a popup made the page shift sideways, because hiding the page's overflow removed its scrollbar. On a page that has a scrollbar, the scrollbar now stays visible and the page is held in place while the popup is open, then returned to the same scroll position when it closes. Pages without a scrollbar are unchanged.

= 7.5.61 =
* Change: the popup opens faster and more smoothly. The blur applied to the whole page behind an open popup is removed (it was repainted on every animation frame, which made the popup appear slowly and stutter on phones and image-heavy pages); the dark overlay is unchanged. The open animation is shorter (0.2 s instead of 0.3 s).

= 7.5.60 =
* Change: the Forms list shows only each form's title. In "Extended view" it also printed an excerpt of the form's content (its CSS code and field texts); forms now have no excerpt in the admin, and the Compact/Extended view switch is no longer offered for forms.

= 7.5.59 =
* Change: the Shortcode box and the Slug column of the forms list show a form's non-Latin slug as written (for example `[elmfc name="預約品嚐體驗"]`) instead of WordPress's percent-encoded storage form (`%e9%a0%90...`). Both forms work in the shortcode.

= 7.5.58 =
* Docs: translated forms keep the source form's markup exactly when EffortLess Multisite Auto Translate 3.3.8 or later is used, which translates a form's Custom HTML block text-only. No code change in this plugin; the FAQ explains what is translated.

= 7.5.56 =
* Fix: forms translated by EffortLess Multisite Auto Translate lost their fields. Translations are saved in the background, where WordPress's content filter removes `<input>`, `<select>`, `<textarea>` and `<button>`. While a form translation is being saved, these form tags are now added to the filter's allowed tags (`<script>`, `<style>` and event attributes are still removed).
* Fix: CSS and JavaScript written in a form's Custom HTML block were missing on translated sites, for the same reason. A translated form now runs the `<style>` and `<script>` of its source form, provided the source form's author may publish unfiltered HTML. Keep the code in the native Custom HTML block on the source site.
* Change: a form's Custom HTML block is translated even when it contains `<style>` or `<script>` (reverting the 7.5.55 behaviour): the translated copy's code is not used, so its text can be translated safely.

= 7.5.55 =
* Fix: forms were no longer translated by EffortLess Multisite Auto Translate. That plugin renamed its hooks and settings from `ms_gpt_*` to `elmat_*`, so none of this plugin's translation hooks ran any more: forms were not selected for translation, their HTML was not translated, slugs were not kept and the form block was not pointed at the translated form. The hooks are now registered under both names, and the source site is read from the new setting (with the old one as fallback).
* Change: a form's Custom HTML block that contains `<script>` or `<style>` is copied to other sites without automatic translation, so its code is not altered. Blocks without code are translated as before.

= 7.5.54 =
* Fix: the browser's own validation messages ("Please fill out this field.") follow the browser's language, so they stayed in English on a site in another language. Forms now show the plugin's translated messages for empty required fields, unticked required checkboxes, unselected options and invalid email, web address and number values. A field's own `data-error` message is used when set.

= 7.5.53 =
* Removed: the `bin/smoke-test.php` developer test script is no longer included in the plugin. It was never used by the plugin itself.

= 7.5.52 =
* Fix: searching the submissions list did nothing; the search term was read from the wrong place. Search now also looks inside every submitted field, not only the identifier (email).
* Fix: answers from a group of checkboxes showed as encoded text (`a:2:{…}`) on the submission detail page and in a resent email.
* Fix: "Resend email" added two internal rows ("Elmfc Form", "Elmfc Url") to the email, and sent the copy to the visitor again. It now sends the notifications only, without those rows.
* Fix: line breaks in a submitted message are shown on the submission detail page.
* Fix: the submissions conversion column always showed 0 submissions; the submission counter was never increased.
* Fix: forms in the trash, and draft, pending or scheduled forms, were shown to visitors when a page used their shortcode or block. Visitors now see published forms (and private forms when logged in); drafts are visible only to users who can edit them, for previewing.
* Change: viewing, searching, exporting, resending and deleting stored submissions now requires the `manage_options` capability (administrators) instead of `edit_posts`, because submissions contain visitors' personal data. Developers can change it with the `elmfc_submissions_capability` filter.
* Added: new submissions are marked "New" until opened, the All Submissions menu badge counts new submissions, and the list has "Mark as read" / "Mark as new" bulk actions. Submissions stored before this version are not counted as new.
* Change: CSV export reads submissions 100 at a time, so large exports use less memory.
* Change: the ELMFC Form block is registered from a `block.json` file (block API version 3). Requires WordPress 5.8 or later.
* Change: after a form's emails are sent through its own SMTP server, the shared mailer's keep-alive and timeout settings are restored, so later emails in the same request are not affected.
* Change: the delete confirmations no longer use inline `onclick` attributes, and the admin pages use even side margins.
* Removed: the `[elmfc_submissions]` shortcode, which showed stored submissions on the website. Pages that still contain it display nothing in its place; submissions are under Forms > All Submissions.
* Readme: the "Additional Information" section was moved into the FAQ and corrected (email subjects cannot be set with hidden fields; there is no `popup_width` setting).

= 7.5.51 =
* Fix: the bundled translations were never used, so the plugin's texts (submit and sending labels, success message, captcha label and placeholder) stayed in English on a site set to another language. The bundled translation for the site language is now loaded when no translate.wordpress.org language pack is installed for it; an installed language pack still takes priority.

= 7.5.50 =
* Fix: the ELMFC Form block's labels in the editor ("ELMFC Form", "Select a form", "Open as popup", and so on) used the wrong text domain (`elmfc`), so they could never be translated. They now use the plugin's text domain and are included in the translation template and the bundled translations.
* Added: bundled editor translations for the block in German, Spanish, French, Italian, Japanese, Korean, Brazilian Portuguese and Traditional Chinese, loaded with `wp_set_script_translations()`.

= 7.5.49 =
* Translations: added the "Please take a moment to check your answers, then send the form again." message (shown when a form is sent too quickly) to the translation template and to the bundled German, Spanish, French, Italian, Japanese, Korean, Brazilian Portuguese and Traditional Chinese translations.

= 7.5.48 =
* Fix: after a successful submission the success message could stay hidden. On forms whose submit button sits inside a paragraph or `<div>` (common in a Custom HTML block), hiding the form also hid the message placed next to the button. The message is now moved out of the form fields before they are hidden.

= 7.5.47 =
* Fix: the captcha stayed as "… = ?" when the form contained the `[elmfc_captcha]` tag but "Enable simple captcha" was unticked. A form containing the tag now always shows and checks the captcha. Before 7.5.46 such a form showed a question but did not check the answer.
* Fix: the captcha stayed as "… = ?" on forms that were still drafts. The question is now loaded for every form the shortcode can display.
* Change: when the captcha cannot be loaded, the reason is written to the browser console.

= 7.5.46 =
* Change: the captcha question and the form's security token are now loaded when the form is shown, instead of being written into the page. Forms keep working on pages served from a full-page cache, where they previously failed with "Incorrect captcha" or "Security check failed" after an hour or a day. Rendering a page no longer stores a captcha in the database.
* Change: form views ("impressions") are counted when a browser shows the form, not on every page render, so crawlers and cache warm-ups are no longer counted.
* Added: a form sent less than 3 seconds after its captcha was loaded is rejected with a message asking the visitor to check the answers and send again.
* Change: "Send copy to user" is now off by default for new forms. Anyone can type another person's address into a form, so the copy is only sent when you enable it. Forms that already have the setting saved are unchanged.
* Change: when a form uses its own SMTP server, the admin email and the copies of one submission share one connection, and an unresponsive server is abandoned after 10 seconds instead of 5 minutes.
* Change: SMTP passwords and webhook secrets are encrypted with a key generated for the plugin, instead of one derived from WordPress's security keys, so changing those keys no longer makes the stored passwords unreadable. Existing values are re-encrypted the first time an administrator opens the dashboard of each site.
* Change: the REST route (`/wp-json/elmfc/v1/submit`) now uses the same code as the AJAX submission, so it also runs the Akismet check and accepts file uploads.
* Change: the `[elmfc_submissions]` shortcode is now shown to administrators only (`manage_options`); it previously showed stored submissions to any user who could edit posts, including Contributors.
* Change: stored submissions are no longer registered in the REST API.

= 7.5.45 =
* Fix: when a form has no `[elmfc_captcha]` tag, the captcha is now placed just before the submit button also for a plain `<button type="submit">` or `<input type="submit">` written in a Custom HTML block. Previously it was only placed correctly when the button sat in a Buttons block or an `elmfc-buttons` wrapper, and otherwise ended up after the button.
* Fix: line breaks in multi-line fields (for example a message textarea) are kept in the notification email, the stored submission and the webhook payload. They were previously merged into a single line.
* Fix: the form's CC and BCC addresses are only added to the admin notification, no longer to the copy sent to the person who filled in the form.
* Change: submission storage types are registered from a cached list, removing one database query per storing form on every page load.

= 7.5.44 =
* Fix: the popup overlay's background blur is now applied only while a popup is open. It was always present on the page, which could make scrolling sluggish on some browsers.
* Fix: pages that use the form block now load the plugin's stylesheet in the page head, so the form no longer appears unstyled and then shifts when the page loads.

= 7.5.43 =
* Change: after a successful submission the form fields are hidden and only the success message is shown, in a larger green box with a check mark, and scrolled into view.

= 7.5.42 =
* Added: a Custom HTML block inside a form can now contain its own `<style>` and `<script>` code, when the form's author has the `unfiltered_html` capability (administrators on single-site installs, super admins on multisite). For other authors the previous filtering still applies.

= 7.5.41 =
* Dev: bin/smoke-test.php now escapes its console output, reads the .htaccess file through WP_Filesystem, uses strict comparison, and no longer reuses the names of WordPress globals ($id, $path) for its cleanup loop variables.

= 7.5.40 =
* Added bundled translation files: a template (.pot) and translations for Spanish, Traditional Chinese, Korean, French, Japanese, German, Italian and Brazilian Portuguese.

= 7.5.39 - 2026-10-10 =
* Change: the form submission REST route no longer uses the generic `__return_true` permission callback. A named permission function documents why the route is public and where spam protection (honeypot, math captcha, validation) is applied. No change in behaviour.

= 7.5.38 - 2026-09-12 =
* Fix: the form's outer container (popup and inline display modes alike) had no explicit text color of its own, so fieldset labels, radio options, and the terms-and-conditions checkbox text silently inherited the active theme's body text color — on a theme with light/white body text, they could render nearly invisible against the form's own light backgrounds. The container now sets its own explicit text color instead of relying on the theme.

= 7.5.37 - 2026-09-05 =
* Change: the bundled donate-notice class is renamed from the shared `Effortless_Donate_Notice` to `ELMFC_Donate_Notice`, so the class name carries this plugin's own prefix and cannot collide with another EffortLess plugin loading its own copy.
* Fix: the PHPCS configuration file is no longer included in the released plugin. It is a development-only file and did not belong in a distributed build.

= 7.5.36 - 2026-09-05 =
* Change: tested against WordPress 7.1 and the "Tested up to" header updated to 7.1. No functional changes.
* Change: the donate notice's outbound link no longer includes the site address as a query parameter. It still identifies the plugin and version so support requests can be matched to a release, but not which installation was viewing it.

= 7.5.35 - 2026-08-18 =
* Added: Forms > Settings page with a "Disable the plugin's built-in CSS" option. When enabled, forms render with no plugin styling at all — fields, buttons, the popup, and the CAPTCHA fall back to the active theme's default appearance, for site owners who want to write their own CSS from scratch. Applies site-wide; the plugin's JavaScript (AJAX submission, popup, validation, multi-step navigation) keeps working either way.

== Upgrade Notice ==

= 7.5.14 =
Security release: rate limiter fixed for Redis/Memcached setups, captcha cross-form replay patched, nonce scoped to form_id, email subject injection closed, form_title/URL CPT storage fixed. Strongly recommended.

= 7.5.13 =
Code quality release: shared helpers for reCAPTCHA and rate-limit config, webhook skip-list fix, elmfc_default_texts() memoization, and documentation corrections.

= 7.5.12 =
Security: reCAPTCHA bypass patched — omitting the token no longer skips verification. Rate-limit DB-error bypass fixed. Cross-site redirect URL fixed. Recommended update.

= 7.5.11 =
Security: redirect URL no longer sent as a hidden form field — read server-side from post meta instead.

= 7.5.10 =
Security hardening: REST endpoint now enforces captcha, secrets are encrypted at rest, capability checks tightened. Recommended update.

= 7.5.9 =
Form field labels and HTML content now fully translated. Requires effortless-multisite-auto-translate 3.2.31+.

= 7.5.8 =
Fixes multisite auto-translate integration: forms now translate correctly and the Gutenberg block remaps form IDs across sites.

= 7.5.7 =
Code quality: resolves all remaining PHPCS warnings. No functional changes.

= 7.4.9 =
Adds file upload support, a native Gutenberg block, and fixes required checkbox validation. Cancel button now fully resets the form after submission.

= 7.4.8 =
Security: SMTP passwords are now encrypted at rest. HTML emails, submission detail view, REST API, and settings export/import added.

= 7.4.7 =
Security: proxy IP headers now opt-in. Adds test email button and email delivery log in Submissions table.

= 7.4.6 =
Rate limiter fixes: real IP detection, per-form counters, runs after captcha. Per-form limit now configurable in Security Settings.

= 7.4.5 =
Bug fixes: shortcode copy buttons now work, submission counts batched correctly, rate limiting added (5/IP/10min).

= 7.4.4 =
Bug fixes: redirect URL / CC / BCC no longer appear in emails, duplicate form resets CPT storage, elmfc_before_send cancellation works correctly.

= 7.4.3 =
Adds redirect-after-submit, duplicate form, CC/BCC, developer filters, and form status columns on the list.

= 7.4.2 =
Performance: CSS/JS now loads only on pages with a form shortcode. Adds shortcode sidebar, submission badge, honeypot spam protection, and clean uninstall.

= 7.4.0 =
New dedicated Submissions admin page with full field listing, sortable table, bulk delete, and CSV export.

= 7.3.8 =
Admin refactor: consolidated asset loading, extracted JS/CSS to files, form styles now visible in Gutenberg editor.

= 7.3.7 =
Forms list now shows clickable copy buttons for ID and Slug columns — one click copies the ready-to-paste shortcode.

= 7.3.6 =
Multisite: [elmfc name="slug"] now resolves forms from the main site automatically when copied to destination sites via another plugin.

= 7.3.5 =
Security fix: captcha solution is no longer exposed in page source. Update recommended for all sites using captcha.

= 7.3.3 =
Major update with full container width support, fieldset styling, improved spacing, and enhanced admin interface. Forms now adapt to their container by default with optional width controls.

= 7.3.1 =
CPT submissions now properly organized as submenu under Forms with descriptive titles.

= 7.2.4 =
Full email system with SMTP support. Update recommended for better email deliverability.
