Five months of beta cooking, condensed into one release: payments on submission, headless / cross-origin REST, six new payment-ready templates, a full admin redesign, and a bootstrap hardening that protects the site during plugin upgrades.
Read full notes31 changes
New submission statuses (pending_payment, paid, payment_failed, refunded), atomic CAS on the paid-state transition so concurrent webhook retries can't double-fire the action loop, return-URL signing with 2-hour expiry to stop replay.
Templates registry gained settings and messages callbacks alongside markup. Every starting point — payment and non-payment — now ships with a context-appropriate success message ("Redirecting to PayPal…", "Booking received…") instead of the generic "We will be in touch soon."
Payments on submission: Five providers, all bundled, all webhook-verified.
Stripe Checkout — hosted Checkout Sessions, test + live keys side-by-side
PayPal — Orders API, fixed or donor-driven amounts via [field] references
Razorpay — UPI / cards / wallets via Razorpay Checkout
Polar.sh — Standard Webhooks signature verification
FluentCart — hosted-checkout handoff. Free + Pro, one-time + subscriptions. Address fields prefilled into FluentCart's checkout (and its tax engine). Order paid → submission paid via fluent_cart/order_paid_done; refunds round-trip.
Headless / cross-origin REST: External sites — Astro, Next.js, Vue, Svelte, plain HTML — can now render and submit Core Forms over REST. Same validation, captcha, action loop and payment redirect machinery runs server-side; the headless site just submits JSON.
GET /wp-json/core-forms/v1/forms/{id} — schema + rendered HTML
POST /wp-json/core-forms/v1/forms/{id}/submit — runs the full pipeline
GET /wp-json/core-forms/v1/embed.js — drop-in vanilla JS widget
Single API key per site (Settings → Headless), per-form opt-in toggle
Snippets in three flavours: widget, native fetch, cURL — each pre-filled with your actual submit URL + active key
New "Keeping the API key private" guidance card with copy-paste server-side proxy templates for Cloudflare Workers / Pages Functions, Next.js App Router, and Astro server endpoints
Six new payment-ready starting points: Each ships with a provider preselected so the form lands one configuration step away from working:
Admin redesign
Per-form Settings, Messages, Payment, Headless tabs converted to native <details>/<summary> accordions with state badges (rate-limit count, schedule "window set", honeypot on/off, FluentCart variation price/type/subscription summary, custom CSS/JS indicators, headless On/Off, configured/not-configured per gateway).
Per-form Submissions list rebuilt: Inbox / Spam / All view tabs with live counts (no more bouncing to global Spam to triage one form), redesigned table with status badges (New / Read / Replied / Archived / Paid / Pending payment / Refunded / Payment failed / Spam), row stripes for new/spam, per-row actions, relative dates with absolute on hover, varied empty states per view.
All Submissions page rebuilt for WordPress 7.0: toolbar split into a filter card (form picker + date range + Filter + Clear) and a search card. Consistent control heights so taller WP 7.0 native dates don't stagger the row. Side-fix: filter inputs are now in their own GET form so form_id / date_from / date_to actually land in the URL — previous version had them inside the bulk-actions POST form so filtering silently did nothing.
WordPress Screen Options dropdown hidden across all Core Forms admin screens.
Persistent "Akismet spam protection is active" banner removed from form-edit pages — status info doesn't belong as a banner on screens unrelated to it.
New cf_get_form_submissions / cf_count_form_submissionsis_spam argument; new bulk_mark_spam per-form action.
Bootstrap hardening
vendor/autoload.php require now guarded with file_exists() so a mid-extraction race during a WordPress in-place plugin upgrade can't fatal the site. The upgrader replaces the plugin directory non-atomically; a hard require in that window kills every PHP request including wp-login.php. Now falls through cleanly and surfaces an admin notice on the next page load if vendor/ is genuinely missing.
Modernisation
Minimum requirements: PHP 8.1, WordPress 6.4
Schema\Field and Schema\FormSchema properties typed, declare(strict_types=1)
Fullscreen multi-step forms expose aria-current="step" + a polite live region for step changes
New filters + actions: cf_payments_orchestrator, cf_payment_completed, cf_form_default_settings, cf_form_templates. Full upgrade guide at docs/getting-started/upgrade-to-4.1.md.
Upgrading: Drop-in compatible from 4.0.x. The vendor-autoload guard means in-place WP upgrades from 4.0.x → 4.1.0 won't fatal even on slow filesystems. Database migrations run automatically on activation / via upgrader_process_complete.
Dashboard navigation, dashboard chrome, submissions polish, and updated documentation links.
Read full notes10 changes
Stat tiles recoloured to the same restrained palette (32×32 icon chip, 18px/600 number, 12px label).
.cf-btn family tightened to native WordPress scale: 7×14 padding, 13px/500, no brand shadow, no lift transform. .cf-btn--secondary uses the standard WP secondary palette so buttons sit comfortably next to native admin chrome.
Extensible via the cf_action_value_labels filter. Applied in the per-form submissions table and the All Submissions cards.
Strip action from new submissions — action is now in the default cf_ignored_field_names, so future submissions never store the AJAX router key. Existing rows still resolve through the friendly-label map.
Hide column — the Data Management extension grows a non-destructive Hide Column toggle alongside Rename Column and Delete Column. Hidden columns are persisted per-form in _cf_hidden_columns post meta and merged with WordPress's get_hidden_columns(). Rename and Delete handlers keep that meta in sync.
Navigation
New shared views/admin-subnav.php — a tab bar (Forms · Add New · Submissions · Settings · Spam) included from every Core Forms dashboard page, with dashicons and an active-tab underline.
Old breadcrumb markup hidden via CSS so legacy includes degrade silently.
Page chrome — Form Theme Customizer card style: .cf-page-hero rebuilt as a clean white card matching the Form Theme Customizer: - 1px solid #dcdcde, 8px radius, subtle 0 1px 2px rgba(0,0,0,.04) shadow. - No gradients, no eyebrow pill, no chrome competing with the content. - Heading scales back to 18px / 600 / #1d2327; sub-text 13px / #50575e.
Submissions: Friendly action labels — new cf_friendly_action_label() helper maps stored WordPress AJAX action keys to human-readable labels: - cf_form_submit → Form Submission - cf_save_draft → Form Draft Saved
Documentation links: All in-app docs links now point to gauravtiwari.org/course/core-forms-training/ (the previous /core-forms/ subdirectory was defunct). The /product/core-forms/ landing page is reserved for marketing CTAs only.
Upgrade notes
No data or schema migrations.
Pure UI / chrome refresh plus opt-in column hiding — fully backwards compatible.
Existing submissions that already contain the action field stay intact and now render as friendly labels.
Visual refresh — the admin dashboard and the default front-end form theme now share the design language of core-forms.com, with no webfonts loaded anywhere.
Read full notes13 changes
Visual refresh — the admin dashboard and the default front-end form theme now share the design language of core-forms.com, with no webfonts loaded anywhere.
New components: - .cf-page-hero — gradient page header with eyebrow pill, heading, sub-text, CTA row - .cf-btn family — primary / secondary / ghost in sm / lg sizes, with the marketing-site shadow + lift-on-hover - .cf-stat — KPI tile with brand-tinted icon chip
WordPress chrome inside Core Forms pages picks up the new look: - .wp-list-table, .form-table inputs, .button-primary, .tablenav, .subsubsub, .notice - Brand-blue 4-step focus ring, 8px corner radii, layered shadow scale
Admin design system: New assets/css/design-system.css declares the brand / ink / surface / radius / shadow tokens lifted directly from the marketing site, scoped to Core Forms admin pages so other plugins are untouched.
Page redesigns
Forms overview opens with the hero plus four KPI stat cards (active forms, total submissions, submissions today, caught as spam) before the forms list.
Settings gets the same hero treatment with a Documentation CTA.
Default front-end form theme: Rewrote form-theme.css against the same tokens: - Brand-blue submit buttons with lift-on-hover and the marketing-site shadow (0 4px 12px rgba(47,99,245,.25)) - 8px input radii, hover state on inputs, brand-blue focus border with 4-step focus ring - Soft-tint success / error / warning messages with proper border colors - Secondary buttons for multi-step \"back\" - Dashed brand-tinted drop-zone styling for <input type=\"file\"> - Headings get proper letter-spacing and weight scale
No webfonts
The admin design system uses the WordPress system stack (-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, …).
The front-end form theme sets --cf-font: inherit, so each form picks up the host theme's font.
No fonts.googleapis.com requests anywhere.
Upgrade notes
No data or schema migrations.
Pure CSS / template chrome refresh — fully backwards compatible.
Custom form theme tokens (cf_form_theme_tokens option) keep working unchanged.
Submission source - [CF_REFERRER_URL], [CF_REFERRER_HOST], [CF_REFERRER_PATH] - [CF_POST_ID], [CF_POST_TITLE], [CF_POST_URL] (resolved via url_to_postid() on the referrer)
Logged-in user - [CF_USER_ID], [CF_USER_LOGIN], [CF_USER_EMAIL], [CF_USER_DISPLAY_NAME]
Submission & timing - [CF_SUBMISSION_ID], [CF_DATE], [CF_TIME] (formatted with the site's date/time format)
Site - [CF_SITE_NAME], [CF_SITE_URL], [CF_ADMIN_EMAIL]
Click any [TOKEN] to insert it at the cursor of the most recently focused input or textarea inside the Actions tab. Brief green pulse confirms the insert. Works on the per-action help text codes too.
Actions tab — clean card redesign: Every configured action is now a single, unified .cf-action-card: - Icon sits inside the header where it belongs (no more orphan icon stranded to the left of the panel). - Header is a real button with aria-expanded; click to toggle, chevron rotates. - Remove action with confirmation; first card opens by default if there's only one. - Replaces the old dual chrome (PHP ::before blue title bar + JS-wrapped .cf-accordion) with a single source of truth rendered directly by PHP. - Works uniformly across all 28 action types (email, twilio_sms, slack, mailchimp, webhook, notion, airtable, autoresponder, hubspot, etc.).
New template variables for actions: cf_replace_data_variables() now resolves:
Click-to-insert in the variables reference: The Actions tab → "Available Variables" panel is now four columns (Form Fields, Submission Source, User & Session, Form & Site) with a tooltip on every token.
Per-action help lines updated: Email, Emailit and Autoresponder now document the most useful new tokens ([CF_REFERRER_URL], [CF_POST_TITLE], [CF_USER_EMAIL] / [CF_SITE_NAME]).
Upgrade notes
No data or schema migrations.
Pure UI / template-variable additions — fully backwards-compatible.
If a third-party extension still emits the legacy .cf-accordion markup around an action, it will keep rendering as before (no-op transitional CSS rule kept).
Stylesheet bug fix. The Gutenberg block no longer auto-loads form-theme.css regardless of settings. The block now respects the global "Default form theme" toggle and the per-form override, matching the shortcode behavior. (Cause: style field in block.json was force-enqueueing the theme stylesheet on any page that used the block.)
Block inspector overhaul. New panels in the block sidebar:
Form — pick a form, jump to its admin editor.
Header — toggle to show the form title as a heading, choose H1–H6.
Stylesheets — per-block overrides ("use form/global setting", "force load", "force disable") for both form-theme.css and forms.css.
Stable version. Bumped from 4.0.0-b9 → 4.0.0 across the plugin header, block.json, package.json, and readme.txt.
Upgrade notes
No schema or data migrations.
If you previously relied on the block always loading form-theme.css, make sure your global "Default form theme" setting is enabled, or use the new per-block "Force load" override.
The max-width block attribute is validated against a strict CSS-length regex (px, em, rem, %, ch, vw, vh); other values are ignored.
Added: Character range (unicode-range) support per font in the Fonts module — limit which characters trigger a font download for faster page loads
Read full notes15 changes
What's Changed
Added Character range (unicode-range) support per font in the Fonts module — limit which characters trigger a font download for faster page loads
Added Quick-pick presets in the admin UI for common subsets (Latin, Latin Extended, Greek, Cyrillic, Vietnamese, Punctuation/Symbols)
Addedunicode-range is also emitted into the theme.json fontFace data layer so it propagates to the block editor
Security Login Security no longer trusts X-Forwarded-For / Client-IP headers by default — these were spoofable on direct connections, allowing IP-based lockouts to be evaded or weaponized. Sites behind a trusted reverse proxy or CDN can opt in via the new "Trust Proxy Headers" setting.
Security Login Security now validates client IPs through FILTER_VALIDATE_IP when proxy headers are in use, dropping malformed values rather than hashing them into transient keys.
Fixed Block Cleanup XPath query now safely escapes class names via a proper XPath 1.0 string-literal builder (addcslashes was the wrong escape function and silently failed on classes containing quotes).
Fixed Snippets kses_with_styles() placeholder collision — <style> extraction now uses a per-call random token so a snippet body containing the literal placeholder string can no longer corrupt the output.
Fixed Fonts module admin badge now reflects the Style field (free-text input) instead of looking for a <select> that doesn't exist.
Fixed Fonts module options static cache is invalidated automatically on update_option_functionalities_fonts, preventing stale font lists when the option is updated mid-request.
Fixed Task Manager AJAX handlers (Export, Delete, etc.) now register whenever in admin, so existing projects remain manageable even when the module is toggled off.
Fixed Task Manager card layout — widget badge now sits above the action row, so Open/Export/Delete align consistently across cards.
Fixed Help & Support buttons now have higher CSS specificity to defeat WP 7.0's button reset.
System prompt no longer restricts the assistant to "context only" knowledge. The LLM can now draw on general knowledge to explain, clarify, or summarize when retrieval is thin.
Every chat request injects the current page (URL, title, up to 4,000 chars of post content via url_to_postid()) into the system prompt so "explain this", "summarize this article", and similar queries work without vector-store hits.
Threads now capture the originating page URL (origin_url) when a conversation begins. Frontend widget sends window.location.href with the first chat request; admin Conversations tab displays it as a clickable link in the detail panel; CSV…
Read full notes3 changes
Added
Threads now capture the originating page URL (origin_url) when a conversation begins. Frontend widget sends window.location.href with the first chat request; admin Conversations tab displays it as a clickable link in the detail panel; CSV export includes it as a new column.
New origin_url VARCHAR(500) column on wp_alpha_chat_threads. Schema version bumped to 1.4.0 — dbDelta adds the column automatically on existing installs.
Removed the hard "no retrieval → fallback" gate in ChatService. The LLM is now always called and instructed to handle conversational messages (greetings, thanks, goodbyes, small talk) naturally, reserving the configured fallback message…
Read full notes4 changes
Changed
Removed the hard "no retrieval → fallback" gate in ChatService. The LLM is now always called and instructed to handle conversational messages (greetings, thanks, goodbyes, small talk) naturally, reserving the configured fallback message verbatim only for genuine unanswerable factual questions.
Fixed
"Thanks", "hi", "bye", and similar conversational messages no longer return the "Sorry, I couldn't find an answer" fallback.
Frontend widget bundles React directly instead of relying on WordPress core's wp-element / wp-dom-ready script handles. The widget no longer enqueues react, react-dom, react-jsx-runtime, wp-element, wp-i18n, wp-hooks, wp-dom-ready, or…
Read full notes4 changes
Changed
Frontend widget bundles React directly instead of relying on WordPress core's wp-element / wp-dom-ready script handles. The widget no longer enqueues react, react-dom, react-jsx-runtime, wp-element, wp-i18n, wp-hooks, wp-dom-ready, or wp-escape-html on the frontend.
Performance
Frontend widget loads as a single ~48 KiB gzipped script instead of seven separate WordPress core script requests.
Indexer::index_post now stores a SHA-256 content hash + embedding model per post and skips re-embedding when nothing has changed. Makes "Reindex all" idempotent and cheap.
Read full notes11 changes
Added
Indexer::index_post now stores a SHA-256 content hash + embedding model per post and skips re-embedding when nothing has changed. Makes "Reindex all" idempotent and cheap.
New GET /knowledge-base/queue endpoint returning pending / in_progress / complete / failed counts for the alpha-chat Action Scheduler group.
New POST /knowledge-base/queue endpoint runs one Action Scheduler batch synchronously (useful when DISABLE_WP_CRON is set).
Dashboard shows live indexing queue counts with auto-refresh every 5s while work is in flight, plus a one-click "Process now" button.
Knowledge Base toolbar gains a "Process queue now" button.
Fixed
Chat panel close button was invisible on mobile — SVG had no explicit size inside the shadow DOM's all: initial root. Added a global svg rule + sized close icon; close is now a circular button in the header top-right.
Re-queued bulk jobs no longer re-embed already-indexed content (hash guard).
Changed
Removed :host reset for all SVGs globally, ensuring any icon placed in the widget renders at its CSS size.