=== Ananyoo Accessible Forms – Contact Form & Entry Storage ===
Contributors: anblik
Donate link: https://ananyoo.com
Tags: accessible forms, contact form, wcag, accessibility, a11y
Requires at least: 6.5
Tested up to: 7.0
Requires PHP: 7.4
Stable tag: 1.9.3
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Accessible, WCAG 2.2 AA contact forms: labelled fields, focus-managed error summary, accessible anti-spam and stored entries.

== Description ==

**Ananyoo Accessible Forms** builds contact and lead forms that conform to **WCAG 2.2 Level AA** out of the box. Instead of bolting accessibility on afterwards, every form is generated with correct semantics from the start: a real `<label>` for every control, `fieldset`/`legend` for grouped inputs, an error summary that takes focus, inline errors tied to their field with `aria-describedby` and `aria-invalid`, and a status region that announces success.

Developed by Shivaji Mitra (M/S. Anblik).

**Live demo:** [Try the accessible forms demo »](https://showcase.ananyoo.com/accessible-forms/)

= Why this plugin? =

Most popular form plugins can be made accessible, but they do not start that way — you have to know exactly which settings to change and which markup to fix. This plugin makes the accessible result the default, so a form added by a non-expert is still usable by keyboard and screen-reader visitors, on the smallest phone, in high-contrast mode.

= Key features =

* **Accessible by construction** — label per field, fieldset/legend for radio and checkbox groups, required state exposed to assistive tech.
* **Error summary with managed focus** — on a failed submit, an `role="alert"` summary lists each problem as a link to the field, and focus moves to it (WCAG 2.2 SC 3.3.1, 2.4.3).
* **Values kept on error** — visitors never retype a whole form because one field failed (SC 3.3.7 Redundant Entry).
* **Accessible anti-spam, no puzzles** — an invisible honeypot plus a submission-time trap stop bots without a CAPTCHA, satisfying SC 3.3.8 Accessible Authentication. Optional Akismet and Cloudflare Turnstile support adds more protection when you want it.
* **Multi-step forms** — split a long form into short, numbered steps with a "Step break". Each step is announced, focus is managed, and the form still works as one page without JavaScript.
* **File uploads, off by default** — add a File upload field, but nothing can be uploaded until you switch uploads on. Per-field size and allowed-type limits, with strict server-side checks on size, extension and real content.
* **Live accessibility health check** — a panel beside the builder reviews the form as you edit and flags issues (missing labels, empty steps, choice fields without options, and more) with a symbol and a word, never colour alone.
* **Reusable forms** — each form is stored once and can be placed on many pages by ID.
* **Stored entries** — every submission is saved so nothing is lost if an email fails. List, search, trash and restore using the native WordPress screens.
* **Spam quarantine** — suspected spam is moved to a recoverable Spam view, not deleted, so false positives can be restored.
* **Block and shortcode** — insert the Accessible Form block, or use `[ananyoo_form id="123"]` anywhere, just like a classic contact form.
* **Any-SMTP delivery** — notifications are sent through `wp_mail()`, so any SMTP plugin you already use handles deliverability.
* **3 px focus ring, 44 × 44 targets** — meets WCAG 2.2 SC 2.4.11/2.4.13 and 2.5.8 by default (both adjustable).
* **Reflows cleanly at 320 px**, **respects prefers-reduced-motion**, and supports **Windows High Contrast / forced-colors**.
* **Works without JavaScript** — the server validates and re-renders; JavaScript only enhances focus handling and adds an early client-side check.
* **Clean uninstall option** — off by default (your data is kept). Turn it on to remove every form, entry and setting when the plugin is deleted.

= Links =

* [Plugin home & documentation](https://ananyoo.com/ananyoo-accessible-forms-plugin/)
* [Live demo](https://showcase.ananyoo.com/accessible-forms/)
* [More accessibility plugins from Ananyoo](https://ananyoo.com/wordpress-accessibility-plugins/) — further WordPress accessibility plugins are in active development.
* [Support & contact](https://ananyoo.com/contact-us/)

= Privacy =

This plugin stores the entries you receive in your own WordPress database and sends notification emails through your site's own mail system (the standard `wp_mail()` function). Out of the box it sends your data to no third-party service and adds no tracking or front-end links of its own.

Two optional extras change this, and both are your choice:

* **Akismet** (off until you switch it on). When enabled, the submitted values, along with the sender's IP address and browser user agent, are sent to Akismet to be checked for spam. This uses the Akismet plugin's own connection and API key, under [Automattic's privacy policy](https://automattic.com/privacy/). Please mention this in your own privacy policy before switching it on.
* **Cloudflare Turnstile**. The separate companion plugin you choose handles that request under its own terms.

== Installation ==

1. Upload the plugin to the `/wp-content/plugins/` directory, or install it from the Plugins screen.
2. Activate it. Four ready-to-use example forms are created automatically: an enquiry form (showing every field type), a newsletter sign-up, a quick feedback form, and an advanced contact form that showcases every feature.
3. Go to **Ananyoo Accessible Forms** to edit fields, or create a new form.
4. Copy the form's shortcode (e.g. `[ananyoo_form id="123"]`) into any page or post, or add the **Accessible Form** block and choose your form.
5. Set the notification email (and optional email logo) under **Ananyoo Accessible Forms → Settings**. Emails send out of the box; for the best inbox delivery we recommend — but do not require — a free SMTP plugin such as WP Mail SMTP or FluentSMTP.

== Frequently Asked Questions ==

= Do I need a CAPTCHA? =

No. The built-in honeypot and submission-time trap stop most bots without asking visitors to solve a puzzle, which keeps the form accessible. The plugin deliberately does not bundle a CAPTCHA, and never uses image-puzzle CAPTCHAs, which create barriers for many disabled visitors.

If your forms attract heavy, targeted spam and you want an extra layer, the most accessible choice is **Cloudflare Turnstile** — in its "Managed" / interaction-only mode it verifies most visitors invisibly, with no puzzle to solve. Add it with a dedicated Turnstile plugin (for example, "Simple CAPTCHA Alternative with Cloudflare Turnstile"). See the next question for connecting it to these forms.

= How do I add Cloudflare Turnstile (or another CAPTCHA) to these forms? =

The easiest way is automatic. Install the free "Simple CAPTCHA with Cloudflare Turnstile" plugin (by RelyWP) and add your Turnstile keys. These forms then detect it and show the Turnstile challenge by themselves — no code, no shortcode. A failed or missing challenge is reported through the same accessible error summary as any other field, with the visitor's answers kept. You can switch this off under Ananyoo Accessible Forms → Settings.

Importantly, this plugin still loads no third-party script itself; the companion plugin renders and enqueues the Turnstile widget. So this plugin makes no external requests on its own.

Prefer a different CAPTCHA, or want full control? Two hooks are also available:

* `do_action( 'ananyoo_aaf_before_submit', $form_id, $uid, $errors )` — fires just before the submit button, inside the form. Use it to output a verification widget.
* `apply_filters( 'ananyoo_aaf_validation_errors', $errors, $raw, $fields, $form_id )` — return a non-empty `name => message` array to reject a submission. The message then appears in the accessible error summary and beside the form.

Developers can also disable the built-in Turnstile integration with the `ananyoo_aaf_use_turnstile` filter (return `false`).

= How do I add Akismet spam filtering to these forms? =

Install the Akismet plugin, add your API key under Settings → Akismet Anti-spam, then tick "Add Akismet spam filtering when the Akismet plugin is active" under Accessible Forms → Settings. It stays off until you tick it.

= Do I need an SMTP plugin for the emails to arrive? =

Not to make it *work*, but it is strongly recommended for *deliverability*. This plugin sends every email through WordPress's own `wp_mail()`, so notifications and confirmations send with no extra setup. However, default server mail is often marked as spam. For emails to land reliably in the inbox we recommend a free SMTP plugin such as **WP Mail SMTP** or **FluentSMTP**. It is optional — nothing here requires it — and the plugin shows a gentle, dismissible tip on its Settings screen if none is detected. Because delivery goes through `wp_mail()`, whichever SMTP plugin you already use handles it automatically.

= Do I need Cloudflare Turnstile or another CAPTCHA? =

No — and that is deliberate. Accessible anti-spam is built in (an invisible honeypot plus a submission-time trap, satisfying SC 3.3.8 Accessible Authentication), with optional Akismet, so most sites need no CAPTCHA at all and visitors never face a puzzle. Cloudflare Turnstile is offered only as an *optional extra layer* for sites hit by heavy, targeted spam; in its invisible "Managed" mode it verifies most people with no interaction. It is never required, and leaving it off keeps the form as accessible as possible.

Akismet adds nothing to the form itself, so there is no puzzle and nothing changes for keyboard or screen-reader users. A submission Akismet thinks is spam is saved quietly under Entries with the Spam status — the visitor is never blocked and never shown an error. This is deliberate: if Akismet guesses wrong, a real person still gets through, and you simply find their message in the Spam view. If Akismet cannot be reached, the entry is saved as normal.

Please note that when this is on, the submitted values are sent to Akismet, an outside service, to be checked. Please make sure your privacy policy says so.

Developers can disable the integration with the `ananyoo_aaf_use_akismet` filter (return `false`), or adjust what is sent with the `ananyoo_aaf_akismet_request` filter.

= How do I let visitors upload a file, and is it safe? =

Add a **File upload** field to your form in the builder. On its own that changes nothing on the front end yet: file uploads are **off for the whole site by default**, on purpose. Until you switch them on under **Settings → File uploads**, the field shows as disabled with a short note, and nothing can be uploaded — so a form is never an open door for unwanted files until you decide to accept them.

When you are ready, tick "Allow visitors to upload files". Each File upload field has its own **maximum size** (2 MB by default) and its own **list of allowed file types** (PDF, DOC, DOCX, JPG, PNG, GIF, WEBP to begin with — change these on the field). Every uploaded file is checked on the server for size, extension and its real content type before it is saved, files are kept in a separate uploads folder, and each one appears as a link on the stored entry.

= How do I make a long form into steps? =

In the form builder, add a **Step break** where you want one step to end and the next to begin. The form is then shown one step at a time, with a numbered progress indicator, Previous/Next buttons, a spoken "Step X of N", and focus moved to each step as it opens. "Next" checks only the current step. If a visitor has JavaScript turned off, the whole form still appears and works as a single page, so nobody is ever locked out.

= Does the plugin make external requests or track anything? =

No. By itself the plugin makes no external/HTTP requests and includes no analytics or tracking. Two optional extras are the exception, and only if you switch them on: the Akismet check sends the submission to Akismet for a verdict (through the Akismet plugin's own connection and key), and a third-party CAPTCHA plugin such as Cloudflare Turnstile handles its own requests. Both are covered by their own privacy terms.

= Are submissions stored if the email fails? =

Yes. Every valid submission is saved as an entry before the email is sent, so a mail problem never loses a message.

= Will deleting the plugin remove my data? =

Only if you choose to. The clean-uninstall option is off by default, so your forms and entries are kept. Enable it under Settings if you want everything removed on delete.

== Screenshots ==

1. The accessible form on the front end: real visible labels, helpful hint text and large, easy-to-tap fields, with each behaviour mapped to its WCAG 2.2 AA success criterion.
2. Accessible validation: an error summary that takes focus, plus inline messages tied to each field and announced to screen readers, never by colour alone.
3. The accessible success state after a valid submission: a clear confirmation announced through a polite live region (SC 4.1.3), with focus moved to it so keyboard users are never left guessing.
4. Every submission is saved as a native WordPress entry. The list shows the sender, subject, form, date and IP, with Quick View, View and Trash actions.
5. A stored entry opened in the admin: every submitted field and value in a semantic table, with checkbox answers shown as Yes or No and the received time and IP set apart below.
6. Quick View opens any entry in an accessible modal dialog without leaving the list: focus moves into the dialog, Escape closes it, and focus returns to the link afterwards.
7. Build a form visually with the Accessible Form block, or drop its shortcode anywhere; both render the identical accessible markup.

== Changelog ==

= 1.9.3 =
* Coding standards: the form-preview page now prints the plugin's registered stylesheet and script through the standard enqueue API instead of hand-written tags, and the uploads folder guard file is written with the WordPress filesystem API. Clears the remaining Plugin Check notices. No change to behaviour.

= 1.9.2 =
* Coding standards: added the required "translators:" comments beside three placeholder strings in the file-upload messages, so the plugin passes Plugin Check / WordPress i18n sniffs cleanly. No change to behaviour.

= 1.9.1 =
* Improved: the bundled "Advanced Contact Form" now includes a live example of both new features — a "Step break" that splits it into two steps (your details, then your enquiry), and an optional File upload field for a document. As uploads are off by default, that field is shown disabled until you turn uploads on, demonstrating the safe default.
* On sites already carrying the earlier Advanced Contact Form, it is refreshed to this new example automatically — but only if you have not edited it. A form you have customised is never overwritten.

= 1.9.0 =
* New: File upload field — add a file question to any form. It is safe by design: uploads are OFF for the whole site by default, so even a form that has a File upload field cannot receive anything until you switch uploads on under Settings → File uploads. Until then the field shows as disabled with a clear note. Each File upload field has its own maximum size (2 MB by default) and its own list of allowed file types (PDF, DOC, DOCX, JPG, PNG, GIF, WEBP to start). Every file is checked on the server for size, extension and real content type before it is saved; files are kept in a separate uploads folder and shown as a link on the entry. Accessible messages explain a file that is too large or of the wrong type.
* New: Multi-step forms — add a "Step break" between fields to split a long form into short, numbered steps. With JavaScript on, visitors see one step at a time with a progress indicator, Previous/Next buttons, a spoken "Step X of N", and focus moved to each step as it opens; "Next" checks just that step. With JavaScript off, the whole form still shows and works as one page. If a problem is found on submit, the form opens the step that needs fixing.
* New: In-builder accessibility health check — a live panel beside the form builder that reviews how the form is set up as you edit: missing labels, duplicate labels, choice fields with no options, empty steps, a long single-page form that could be split, a File upload field while uploads are off, and more. Each result is shown with a symbol and a word (Good / Check / Fix) — never colour alone.
* Improved: the field builder now shows only the settings that apply to the chosen type (options for choice fields, character limit for text, size and type for File upload), keeping each field row tidy.

= 1.8.3 =
* New: an "Advanced Contact Form" now ships as a ready-to-use example, showing every field type and feature together — text, email, phone, website, number, dropdown, radio, checkboxes, a message box with a character counter, and a consent checkbox — with autocomplete, help text, required-field handling and a visitor confirmation already set up.
* Fix: existing sites that installed an earlier version now receive this Advanced Contact Form automatically on the next admin page load — it appears at the end of your Forms list. Fresh installs continue to get all four example forms on activation. No existing form, entry or setting is touched.

= 1.8.2 =
* New: full colour control for the email template — set a background and text colour for the Header, Body and Footer bands under Settings → Email.
* New: a live WCAG contrast checker beside each colour pair. As you pick colours it shows the ratio and whether it passes (4.5:1 "Good", 3–4.5:1 "OK for large text only", below 3:1 "too low"), with a word and a tick/cross — never colour alone.
* The email body, headings, table and footer now follow your chosen colours, keeping the accessible structure (data table with row headers, alt-text logo, plain-text alternative) intact.

= 1.8.1 =
* New: a gentle, dismissible tip on the Settings screen recommending an SMTP plugin for inbox delivery — shown only when no known SMTP plugin is detected. It is a suggestion, not a requirement.
* Docs: clarified that an SMTP plugin is recommended (not required) for deliverability, and that Cloudflare Turnstile / any CAPTCHA is entirely optional — the built-in accessible anti-spam means most sites need no CAPTCHA at all.

= 1.8.0 =
* New: accessible HTML email template for both the admin notification and a new visitor confirmation (autoresponder). Emails use a real data table with a caption and row headers (so screen readers announce each value with its label), a logo with alt text, an <html lang> document, a strong-contrast header, and a matching plain-text version for text-only mail clients.
* New: a shared email design under Settings → Email — upload a logo (with alt text), set the header background colour and a footer line, and turn the visitor confirmation on or off.
* New: per-form confirmation wording — set the subject, intro and closing message on each form. The visitor's copy includes the details they submitted.
* New: "Preview email" links on each form (admin notification and visitor confirmation) that open the rendered email with sample data.
* No breaking changes; existing forms, entries and settings are unaffected. If you prefer the old plain-text admin email, turn the autoresponder off and note the admin email is now HTML with a plain-text alternative attached.

= 1.7.0 =
* New: a "Preview" link for every form — in the forms list (row actions) and as a "Preview form" button on the edit screen. It opens a standalone, interactive preview in a new tab showing exactly how the form looks and behaves (client-side validation and the character counter run); submitting is disabled there, so no entry is stored. The preview is limited to users who can edit the form and is protected by a nonce.
* New: a fourth ready-made example form, "Advanced Contact Form", is installed on a fresh activation. It showcases every field type, required states, help text, automatic autocomplete purpose, a character-limited message with the live counter, and a consent line with a Privacy Policy link. Sites that already had forms receive it once automatically on update.
* No breaking changes; all existing forms, entries and settings are unaffected.

= 1.6.0 =
* New: an optional character limit per short-text or long-text field. When set, it shows a live "used / limit" counter, enforces the limit with the native maxlength attribute, and announces only at ~90% and 100% through a polite live region so screen-reader speech is never saturated (WCAG 4.1.3). The limit is also heard on focus (WCAG 3.3.2).
* New: keyboard "Move up" and "Move down" buttons for every field in the form builder, alongside the existing add/remove. Reordering announces the new position and keeps focus on the button you pressed; at the top or bottom nothing moves and focus is kept (WCAG 2.1.1, 2.4.3).
* Improved: front-end styles now use CSS logical properties, so forms mirror correctly for right-to-left languages (WCAG 1.3.2).
* No breaking changes; all existing forms, entries and settings are unaffected.

= 1.5.0 =
* New: fields now get an automatic `autocomplete` token based on their purpose — email, telephone, name, address, postcode, country and more (WCAG 1.3.5 Identify Input Purpose), so browsers and assistive tech autofill correctly. Any token you set in the editor always wins.
* New: telephone, number, email and URL fields get the right on-screen keyboard on mobile via `inputmode`.
* New: an up-front "Fields marked with an asterisk (*) are required" note appears on any form that has a required field, so the meaning of the marker is available to everyone (WCAG 3.3.2). The per-field asterisk stays hidden from screen readers, which continue to hear the programmatic "required" state.
* No breaking changes; all existing forms, entries and settings are unaffected.

= 1.4.0 =
* New: a Single consent checkbox label can now carry a Privacy Policy link that opens in a new tab. Two ways to add it: write your own link inline as `[the words to link](https://example.com/privacy/)`, or simply include the word "Privacy" (or "Privacy Policy" / "Privacy Policies") in the label and it is linked automatically to your site's Privacy Policy page. If a label has neither, it is shown exactly as written — no link is invented or appended.
* The link is accessible by construction: a real link with `rel="noopener noreferrer"` and a screen-reader "(opens in a new tab)" hint. The whole label stays escaped, so it is safe by default.
* The automatic link points to your WordPress Privacy Policy page (Settings → Privacy), falling back to a page with the "privacy-policy" slug.
* New filter for developers: `ananyoo_aaf_privacy_policy_url` to set or override the URL used for the automatic Privacy Policy link.
* The field editor explains the option in a hint shown only on the consent field (not above every field), tied to the Label input with aria-describedby and announced when it appears.
* Accessibility (admin): the form builder now wraps each field in a fieldset with a numbered legend that follows the field's label, so screen-reader users can tell rows apart; adding and removing a field moves focus sensibly and is announced via a polite live region, and each "Remove field" button has a context-specific accessible name.
* Accessibility (admin): the Entries "Quick View" and "View" row actions now carry per-entry context for screen readers and advertise the dialog (aria-haspopup); the Quick View dialog seeds an accessible name before loading, announces loading/loaded/error states through a live region, and marks the rest of the page inert while open.
* Accessibility (admin): Settings descriptions and status notes are now linked to their controls with aria-describedby, and the decorative header logo is hidden from assistive tech.
* New: an About tab on the Settings screen (Accessible Forms → Settings → About) holding the WCAG 2.2 AA conformance statement, spam-protection guidance, credit/documentation links and version details; the Dashboard now stays focused on getting started.

= 1.3.1 =
* Fixed: the "Settings" link on the Plugins screen showed "Cannot load ananyoo-accessible-forms." It still pointed at the old settings address from before the 1.2.0 menu change. It now opens the Settings page correctly. Sorry about that.

= 1.3.0 =
* New: optional Akismet spam filtering. Switch it on under Accessible Forms → Settings when the Akismet plugin is active and holds an API key. It is off until you switch it on.
* Suspected spam is kept quietly under Entries with the Spam status, so a wrong guess never blocks a real visitor or shows them an error. If Akismet cannot be reached, the entry is saved as normal.
* Akismet adds nothing to the form, so there is no puzzle and nothing changes for keyboard or screen-reader users.
* Note: when this is on, the submitted values are sent to Akismet, an outside service. Please mention this in your privacy policy. The readme Privacy section explains what is sent.
* New filters for developers: `ananyoo_aaf_use_akismet` and `ananyoo_aaf_akismet_request`.

= 1.2.0 =
* New: the "Accessible Forms" menu now opens on a branded Dashboard (the former Getting Started screen) with the blue header, logo, quick start, WCAG conformance statement and version details. All Forms, Add New Form, Entries and Settings sit neatly below it.
* The Settings screen now carries the same branded header for a consistent look.
* No changes to your forms, entries, stored data or the front end.

= 1.1.2 =
* Shortened the admin sidebar menu label to "Accessible Forms" for a cleaner menu, consistent with the other Ananyoo accessibility plugins. The directory name is unchanged.
* Readme: linked the live demo and added Links and Privacy sections. No functional changes.

= 1.1.1 =
* Coding-standards: unified all custom identifiers under the distinct "ananyoo_aaf" prefix. The two custom post types, the spam post status, the entry-manager capability, the Quick View admin-ajax action and its nonce, and all post-meta keys now use the full prefix, avoiding any short or inconsistent names that could collide with other plugins.

= 1.1.0 =
* Renamed the plugin to "Ananyoo Accessible Forms – Contact Form & Entry Storage" so the name leads with the Ananyoo brand and is distinctive (slug: ananyoo-accessible-forms).
* Coding-standards: the "Add New" rule on the Entries screen is now served from the enqueued admin stylesheet instead of an inline style block.
* Hardening: POST data passed to the ananyoo_aaf_validation_errors filter is now sanitised before any third-party callback receives it.
* Hardening: the sender name shown in the Entries list (via the the_title filter) is now escaped at the source.

= 1.0.9 =
* Notification email subject is now "Form Name: Subject" — the form's title followed by the value of the submission's subject field (for example, "Enquiry Form: General enquiry"), replacing the old "[Site] New form entry: …" line. When a form has no subject field, or it is left blank, the subject is just the form name.
* The three sample forms created on a fresh install are now titled in Title Case — "Enquiry Form" (previously "Enquiry form — every field type"), "Newsletter Sign-up" and "Quick Feedback". Existing forms are unaffected.
* No accessibility, settings or visual changes.

= 1.0.8 =
* Accessibility (WCAG 3.3.1 / 2.4.3): on a failed submission, keyboard focus now moves to the FIRST field with an error — never to the error summary — so the screen reader announces that field's own message (via aria-invalid + aria-describedby) and the visitor lands exactly where they can fix it. On a form with many fields, this avoids making the user step past a long list of errors before reaching the first one. Applies to both the client-side check and the server-rendered result after a no-JavaScript submit.
* The error summary at the top is now a plain, visible overview with jump-links to each field, rather than an assertive alert that takes focus. It still appears only after a failed submission, lists every error, and updates live as fields are corrected — it just no longer competes with, or delays, the announcement of the field that focus lands on.
* No settings or visual-design changes.

= 1.0.7 =
* Accessibility: error-summary links now move keyboard focus to the matching field on every path. The server-rendered summary previously only scrolled (focus moved only on the JS-built summary); a single delegated handler now covers both, and grouped radio/checkbox fields focus their first option.
* Accessibility: the group <fieldset> now carries the field id, so the summary link for a radio/checkbox group resolves correctly (it pointed at a non-existent target before).
* Accessibility: correcting a field now updates the error summary live — the fixed field's line is removed from the summary (and the summary disappears once all errors are resolved), matching the inline message that already cleared.
* No settings, markup-structure or visual changes beyond the fieldset id.

= 1.0.6 =
* Getting Started screen: added a "Managing your entries" section covering the entries list columns, the Quick View / View / Trash actions, and the Yes/No display, so the in-plugin help reflects the current features.

= 1.0.5 =
* Single checkbox / consent values now display as "Yes" (or "No") instead of "1" in the entry view, the Quick View popup and the email notification, so they read clearly.

= 1.0.4 =
* The Sender column now shows the submitter's name computed from the submission data, so existing entries read cleanly too (not only newly titled ones).
* New: a "Quick View" row action opens the entry in an accessible modal dialog without leaving the list. Focus moves into the dialog, Escape closes it, focus is trapped while open and returned to the link afterwards, and it falls back to the full View page when JavaScript is unavailable.

= 1.0.3 =
* Entries list improved: the read-only Edit and Quick Edit row actions are replaced by a clear View action (Trash is kept); the first column now shows the Sender name and links to the entry; and new Subject and IP columns are added, with the form name kept in its own column.
* New submissions are now titled by the sender's name rather than "Form name — value", so the entries list reads more cleanly.

= 1.0.2 =
* Improved: in the single-entry admin view, the "Received ... from IP ..." submission metadata is now shown as a centred band, set apart from the field/value table with space above and below, so it reads clearly as information about the submission rather than a submitted value. (The entry-view styles now load on the entry screen too.)

= 1.0.1 =
* Fixed: the URL/website field rejected valid web addresses. Validation now checks the address format instead of performing a live host lookup, so addresses such as https://www.example.com are accepted.
* Fixed: required and format error messages no longer show a stray full stop when a field label is written as a sentence (for example a consent line), so the wording reads cleanly.

= 1.0.0 =
* Initial release.
* Accessible forms built to WCAG 2.2 AA by construction: a real label per field, fieldset/legend for radio and checkbox groups, and the required state exposed to assistive technology.
* Error handling with managed focus: a `role="alert"` summary that links to each field, plus an inline message under every invalid field tied to it with `aria-describedby` and `aria-invalid`. Focus moves to the single field when there is one error, or to the summary when there are several.
* Specific, action-led messages, including format suggestions for email, web address and number fields (WCAG 2.2 SC 3.3.3).
* On-blur checking that validates a field once the visitor has used it and clears the message live as it is fixed; the form still validates fully on submit and on the server, and works with JavaScript disabled.
* Values kept on error (SC 3.3.7), a 3 px focus ring and 44 x 44 targets by default (both adjustable), clean reflow at 320 px, and reduced-motion and forced-colors support.
* Accessible anti-spam with no puzzles: an invisible honeypot and a submission-time trap, plus a recoverable spam quarantine. Optional, automatic Cloudflare Turnstile when the free "Simple CAPTCHA with Cloudflare Turnstile" plugin is active (this plugin loads no third-party script itself); hooks (`ananyoo_aaf_before_submit`, `ananyoo_aaf_validation_errors`) allow any other CAPTCHA.
* Reusable forms placed by ID via the Accessible Form block or the `[ananyoo_form id="123"]` shortcode; submissions stored as entries; notifications through `wp_mail()` for any-SMTP delivery; and an optional clean uninstall.
* Three ready-to-use example forms created on activation: an enquiry form (every field type), a newsletter sign-up, and a quick feedback form.

== Upgrade Notice ==

= 1.0.0 =
Initial release.
