Gatilab Products

Changelogs

Improvements, fixes, and the details behind each release.

Core Forms

Build forms, collect submissions, and connect the actions your site needs.

View Product
Stable

Core Forms 4.1.0

Read release notes

Core Forms 4.1.0 — stable

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.

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.

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.

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:

| Template | Provider | Pricing | |---|---|---| | One-time payment | Stripe | Fixed $19 | | Donation | PayPal | Donor-entered via [AMOUNT] | | INR payment | Razorpay | Fixed ₹999 | | FluentCart product | FluentCart | Variation-driven, with address fieldset | | Subscription | FluentCart Pro | Variation-driven, recurring | | Event ticket | Stripe | Tier select drives [TIER] |

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."

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_submissions is_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)
  • CI matrix runs PHP 8.1 / 8.2 / 8.3
  • prefers-reduced-motion respected throughout; logical-property RTL fixes
  • 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.

Beta

Core Forms 4.1.0-beta7

Read release notes

Headless tab — API key security guidance

A new "Keeping the API key private" accordion on every form's Headless tab walks through the three patterns that actually keep the site-wide API key out of the browser bundle.

Threat-model framing comes first — honest, not moralizing. The key only authorises form submissions on headless-enabled forms; the worst case is spam on those forms (no account access, no billing, no data exfil). But spam is annoying, so:

Server-side proxy templates — copy-paste, with the form's actual submit URL pre-filled: - Cloudflare Pages Functions / Workers (wrangler secret put) - Next.js App Router route handler (process.env, never NEXT_PUBLIC_*) - Astro server endpoint (import.meta.env, never PUBLIC_*)

Captcha note: Turnstile / reCAPTCHA on the WP install verifies on every submission through the same pipeline — headless or not. Links straight to the global settings.

Defense-in-depth checklist at the proxy: Origin allowlist, body size cap, User-Agent sanity, and an explicit "don't add a honeypot at the proxy" warning (browser autofill on field names like url / company / phone silently drops real submissions — the plugin has its own honeypot upstream).

"If you must put the key in client code" — pragmatic close: not the end of the world, rotate when abused, watch the per-form Spam tab.

Beta

Core Forms 4.1.0-beta6

Read release notes

Submissions page rebuilt for WP 7.0

WP 7.0's taller native form controls (especially date inputs) caused the old toolbar to wrap onto four lines — bulk actions, then the form filter, then dates, then pagination, each on its own row. New layout:

  • Filter card (top): form-picker + date range + Filter button + Clear link, in one row
  • Search card (right of the same row): search input + Search button
  • Bulk-actions row (under): bulk action select + Apply on the left, item count + pagination on the right
  • Cards grid below

Consistent min-height: 36px across selects, date inputs, and buttons so the taller WP 7.0 dates don't stagger the row vertically. Stacks under 900px viewport.

Bonus fix

The previous markup had the filter inputs nested inside the bulk-actions POST form, so the "Filter" button never actually wrote form_id / date_from / date_to to the URL — and the listing reads $_GET. Filtering now uses an independent GET form, so query-string state survives the round trip.

AllSubmissionsTable::extra_tablenav is now a no-op for the same reason (the WP_List_Table hook fires inside the wrong form).

Beta

Core Forms 4.1.0-beta5

Read release notes

FluentCart fixes

  • Address fields collected on the form. FluentCart's checkout requires billing address by default. Beta4's templates didn't collect it, so users hit a half-empty checkout. The FluentCart product + subscription templates now include a billing fieldset (address line 1/2, city, state, postcode, country) named to match FluentCart's checkout schema.
  • Form fields prefill FluentCart checkout. The gateway maps submission data into cart->checkout_data['form_data'] so FluentCart auto-fills its inputs and TaxManager picks up country/state for tax. Two-pass mapping: billing_* / shipping_* keys forward verbatim; common aliases (NAME, EMAIL, COUNTRY, etc.) map to FluentCart equivalents.
  • Test/Live badge now reads FluentCart's own mode. The per-form Payment tab no longer shows the global Core Forms test/live badge for the FluentCart provider (which it doesn't gate). Instead reads FluentCart\Api\CurrencySettings's order_mode and renders "FluentCart: Live" / "FluentCart: Test" with a tooltip linking to the FC store settings.
  • FluentCart hidden when not installed. The gateway only registers when FluentCart's PHP classes exist. The "FluentCart product" and "Subscription" starter templates are filtered out of the Add Form gallery on the same condition.
  • Provider-switch resilience. FluentCart templates ship with a fallback payment_amount + currency so swapping to Stripe/PayPal/Razorpay later doesn't trip the gateway's "amount must be greater than zero" guard.

Per-template submission messages

Templates registry gained a messages callback alongside markup and settings. Every template now ships with a context-appropriate Success message instead of the generic "We will be in touch soon":

  • Payment templates — "Redirecting to PayPal…", "Welcome aboard…", etc. + payment-specific error copy
  • Contact — "Your message is on its way"
  • Newsletter — "You're on the list. Check your inbox"
  • Support — "Support ticket received. We'll reply within one business day"
  • Booking — "Booking received. You'll get a confirmation email"
  • (and so on for the rest)

cf_get_template_messages() helper feeds the preset into cf_message_* post meta on form creation.

Beta

Core Forms 4.1.0-beta4

Read release notes

Payment-ready starting points

Six new templates in the Add Form gallery, each pre-configured with a payment provider so the form lands one step away from collecting money:

| Template | Provider | Pricing | |---|---|---| | One-time payment | Stripe | Fixed $19 | | Donation | PayPal | Donor-entered amount via [AMOUNT] | | INR payment | Razorpay | Fixed ₹999 | | FluentCart product | FluentCart | Variation-driven | | Subscription | FluentCart Pro | Variation-driven, recurring | | Event ticket | Stripe | Tier select drives [TIER] amount |

Templates registry now supports a settings callback alongside markup — new cf_get_template_settings() helper feeds the preset into the new form's _cf_settings meta on creation. Payment-category templates carry a blue "Payment ready" badge instead of the default "Accessible" one.

UI fixes

  • Global Payments settings: gateway accordions collapsed by default, not auto-opened on unconfigured gateways. Less visual noise; expand the one you're configuring.
  • Screen Options hidden: the WordPress Screen Options dropdown is suppressed across all Core Forms admin pages — All Forms, Add New, Settings, Spam, plus the per-form editor and submissions views.
  • Akismet banner removed: dropped the persistent "Akismet spam protection is active" notice on every form edit page. Status info doesn't belong as a banner on screens unrelated to it.
Beta

Core Forms 4.1.0-beta3

Read release notes

FluentCart correlation fixes

Tested live against gauravtiwari.org's FluentCart 1.3.27 — beta2's correlation path was wrong:

  • Cart model uses cart_hash as its primary key, not id. Beta2 referenced $cart->id (always null), so the metadata-fallback path could never run. Removed it.
  • Order → Cart link goes through wp_fct_order_operations.cart_hash, not a direct $order->cart_id (no such column). The order_paid_done listener now walks Order → orderOperation → cart_hash → Cart and reads checkout_data['core_forms']['submission_id'].
  • Variations have no per-row currency; FluentCart is single-currency. Currency is now read from FluentCart\Api\CurrencySettings.
  • Per-form preview chip formats price using FluentCart's currency sign + position, surfaces subscription billing summary, trial days, and physical-fulfillment hints.

Form settings UI redesign

Six sections in the Settings tab now use <details>/<summary> accordions matching the Payment and Headless tabs. Each summary carries useful at-a-glance state:

  • Submissions — "rate limit 60/h" or "not stored" badges
  • After submission — confirmation type badge; redirect URL row only renders when redirect is selected
  • Anti-spam — honeypot on/off badge
  • Save & resume — on/off badge
  • Scheduling — "window set" / "always open" badge
  • Advanced — CSS / JS badges when custom code is present

New UI primitives: - Pill-style Yes/No radios with hover/checked state - Number inputs with trailing unit hints (e.g. "submissions / IP / hour") - From → To range pairs for date and time - Day-of-week segmented picker — checked days fill blue - Monospace inset-shadow code textareas for Custom CSS/JS - Tightened form-table spacing inside accordions - Stacks to single column under 1100px viewport

Messages tab redesign

Same accordion pattern. Four core messages grouped under "Submission outcomes" with an explanatory header. Extension-injected <tr> rows get their own accordion when present, otherwise the section is omitted entirely.

Beta

Core Forms 4.1.0-beta2

Read release notes

Headless / REST API

External sites (Astro, Next.js, plain HTML, anywhere) can now render and submit Core Forms over REST.

  • New endpoints under /wp-json/core-forms/v1:
  • GET /forms/{id} — schema (HTML + structured fields)
  • POST /forms/{id}/submit — runs the same validation/captcha/action pipeline as on-site submissions
  • GET /embed.js — drop-in vanilla JS widget
  • Site-wide API key (Settings → Headless) gates submissions; per-form Headless tab toggles exposure on/off and shows copy-paste snippets (widget, native fetch, cURL) pre-filled with the actual key.
  • Reveal/generate/copy controls on the API key field, status banners on the per-form tab.
  • CORS reflected per-origin; captcha is force-recommended since cross-origin submits can't use WP nonces.

FluentCart integration

Hosted-checkout handoff via FluentCart's own checkout — works on free + Pro, one-time + subscriptions.

  • New FluentCart payment gateway slots into the existing payments orchestrator alongside Stripe/PayPal/Razorpay/Polar.
  • Per-form Variation ID picker with live preview (title, price, payment type, link to FluentCart).
  • Listens to fluent_cart/order_paid_done to mark submissions paid and fire the post-payment action loop. order_status_changed_to_refunded syncs refunds back.
  • Pricing/currency come from the FluentCart variation — the form's Pricing fields are bypassed when this provider is selected.
  • Subscription variations work transparently on FluentCart Pro (FluentCart owns the recurring billing).

UI polish

  • Per-form Payment tab sections converted to native <details>/<summary> accordions matching the global Payments gateway list.
  • New Headless tab in the form editor with status banners, monospace code blocks, floating copy buttons, color-coded HTTP method tags.
  • Same-site gateways (FluentCart) skip the irrelevant Webhook URL row in global settings and explain why no credentials are needed.
Beta

Core Forms 4.1.0-beta1

Read release notes

What's Changed

  • Add payment gateway integration (Stripe, PayPal, Razorpay, Polar)

Improvements

  • Convert per-form Payment tab (Provider / Pricing / After payment) to native <details>/<summary> accordions, matching the global Payments gateway list

Fixes

  • Fix undefined $form_id in submissions list tab (use $form->ID)
Stable

Core Forms 4.0.3

Read release notes

Dashboard navigation, dashboard chrome, submissions polish, and updated documentation links.

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.

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.

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

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.

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.
Stable

Core Forms 4.0.2

Read release notes

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.

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.

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

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.
Stable

Core Forms 4.0.1

Read release notes

Polish release on the 4.x line.

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:

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-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.

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.

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).
Stable

Core Forms 4.0.0

Read release notes

First stable release on the 4.x line.

Highlights

  • 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.
  • Layout — alignment toolbar (left/center/right), max-width (px/em/rem/%/ch), HTML anchor id, custom CSS class.
  • 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.

Files changed

block.json, render.php, assets/js/src/blocks/form/edit.js, assets/js/build/block-form.js, core-forms.php, package.json, readme.txt.