Changelogs

Follow the improvements and fixes in each product release.

Core Forms

Core Forms is a WordPress form plugin built for performance and simplicity. It creates contact forms, registration forms, and surveys with minimal overhead and clean code output. This…

Explore Product

Release History

Permalink

4.4.0

Core Forms 4.4.0 includes the complete feature set originally planned for roadmap versions 4.4 and 4.5.

Added

  • Added inline Stripe Payment Element checkout with server-owned product pricing, idempotent PaymentIntent creation, and signed webhook confirmation.
  • Added first-class Razorpay hosted checkout with payment-link, captured-payment, failure, cancellation, and refund handling.
  • Added one-click importers for Ninja Forms and Formidable Forms alongside the existing CF7, Gravity Forms, WPForms, and Fluent Forms migration tools.
  • Added WP-CLI commands for form import/export/listing, submission maintenance, product and plan administration, license reporting, order reporting, and expiry maintenance.
  • Added native actions for WooCommerce, Easy Digital Downloads, SureCart, WP Simple Pay, MemberPress, LearnDash, Paid Memberships Pro, Groundhogg, Jetpack CRM, WP-CRM System, and SureContact.
  • Added AutomatorWP, Uncanny Automator, and OttoKit triggers and actions with form and submission payloads.
  • Added signed inbound WhatsApp webhooks for Meta Cloud API and Twilio, including reply correlation and delivery-state history in submission conversations.
  • Added a multi-product licensing and lightweight ecommerce system with products, plans, orders, subscriptions, customer accounts, activation limits, refunds, renewals, and audited signed downloads.
  • Added a dedicated customer dashboard for orders, masked/revealable keys, product downloads, activated sites, and subscription controls.
  • Added free, Stripe, Razorpay, and renewal license-form templates with complete payment and fulfillment actions.
  • Added a default Sample Product with free, USD annual, and INR annual plans on new and upgraded sites.
  • Added native Bricks and Elementor integrations plus a per-form WCAG 2.2 audit and conservative one-click repairs.

Changed

  • The form editor now renders only the active tab instead of executing every tab’s PHP, JavaScript, analytics, and REST requests on every page load.
  • The visual builder now boots from server-rendered form and schema data, removing its two blocking initial REST requests.
  • Builder saves now persist markup and schema atomically through one endpoint with a bounded timeout and a standard form-post fallback.
  • Tab-specific saves merge with existing form settings, preserving payment and action configuration when saving Fields, Messages, or other individual tabs.
  • Licensing actions are always visible under a dedicated Commerce & Licensing category instead of disappearing when the public activation API is disabled.
  • Product and plan slugs are generated automatically, normalized, and made unique; manually entered slugs remain supported.
  • Plan prices are entered in customer-facing major units such as 49.00 instead of minor units such as 4900.
  • Product packages use the WordPress Media Library picker and uploader instead of requiring an attachment ID.
  • The licensing backend now includes catalog statistics, quick-start guidance, direct Add plan/Add package links, and file names instead of raw attachment IDs.
  • The existing core-forms.com CF Licenser client, option keys, 32-character key format, six-hour heartbeat, and update hooks remain separate from and compatible with the new merchant licensing subsystem.

Fixed

  • Fixed the Fields builder remaining on an indefinite loading spinner when either initial REST request stalled.
  • Fixed inactive Analytics requests and form-builder assets loading on unrelated form tabs.
  • Fixed paid plans being fulfillable from a non-payment form or before verified payment confirmation.
  • Fixed payment fulfillment accepting a mismatched paid amount or currency when validation is enabled.
  • Fixed free plans being incorrectly coupled to a payment requirement.
  • Fixed action-variable references showing a permanent Loading message when the Fields builder was not present.
  • Fixed stale admin asset caches by versioning the main admin stylesheet and licensing script from their file modification times while keeping the plugin version at 4.4.0.

Security

  • License fulfillment is idempotent per submission and product selection, preventing duplicate orders or keys during webhook retries.
  • Signed package links expire, verify the stored SHA-256 digest before streaming, and record downloads in an audit table.
  • Verified refunds disable issued licenses and cancel related subscriptions.
  • Inbound messaging and payment webhooks require provider signatures before they can change submission, payment, or fulfillment state.
Permalink

4.3.8

Core Forms 4.3.8

New – Field names accept uppercase. The builder’s Name field no longer force-lowercases input (HTML `name`/`id` are case-sensitive). Illegal characters are still sanitized. – Textarea options: Rows (height), Resize behaviour (default / vertical / horizontal / both / none), and a live character counter that shows “used / limit” when a Max length is set. An explicit Rows value now wins over the 5-line default height. – Phone (tel) value limits: new Min length, Max length, and Pattern controls to constrain accepted values.

Fixed – The builder’s HTML generator silently dropped textarea min/max-length and conditional-logic attributes on save, so those validations were lost. The textarea output now matches the server-side renderer.

Permalink

4.3.7

Bug-fix release.

Fixed: critical error after plugin, theme, or core updates and rollbacks.

The upgrader_process_complete migration callback was registered under the plugin namespace (Core_Forms\_cf_on_upgrader_complete), but that function is defined in the global namespace, so it was an invalid callback that triggered a fatal TypeError whenever WordPress finished an update or rollback. It surfaced as “There has been a critical error on this website” on the update/rollback screen. The callback is now registered with the correct name, so updates complete cleanly.

PHPStan had originally flagged this; the error had been suppressed in phpstan-baseline.neon rather than fixed. That stale baseline entry is now removed.

Permalink

4.3.6

Accessibility floor for every Core Form (and Core Poll) input.

This release is about making the default Core Form accessible by default — not “accessible if the author remembers to opt in.” Whether you load only the skeleton (forms.css), only the themed stylesheet (form-theme.css), or both, the floor holds.

What’s in

  • 44 × 44 CSS px touch target on every form control. WCAG 2.5.5 AAA target size. Applied to every text-type input, select, textarea, and button in both stylesheets so the rule survives whether the theme is loaded, disabled, or partially overridden.
  • Windows High Contrast Mode-safe keyboard focus. The themed :focus-visible state used to be outline: none + coloured box-shadow — HCM strips the box-shadow and the ring vanishes. Now :focus-visible pairs the box-shadow with a transparent 2px outline; HCM forces the transparent outline to the system focus colour, so keyboard users on HCM still see a ring.
  • Accessibility baseline in forms.css. Authors who disable the form theme used to drop back to a bare browser stylesheet. The skeleton now ships a tiny accessibility section at the top — 44px target, currentColor focus outline, prefers-reduced-motion transition kill-switch — so disabling the theme doesn’t disable accessibility.
  • Textareas are 5 lines tall by default. Browsers ship rows="2" which is comically short for paragraph answers. Both stylesheets now set min-height: calc(5lh + 22px) (with a 140px px fallback for older browsers) — textareas grow with the host theme’s line-height instead of being pinned to a px value.

Asset loading

  • Form and poll stylesheets now print at the bottom of <head>. Enqueue priority bumped from 20 → 99 so wp_enqueue_style calls land after the host theme’s. WordPress prints in enqueue order → Core Forms styles cascade over theme styles cleanly, no !important, no specificity arms race.
  • Poll CSS is back in <head>. poll-frontend.css used to enqueue inside render_poll_shortcode() during the_content — after wp_head had already printed — so it landed in the footer. PollFrontend::maybe_enqueue_detected_poll_assets() now pre-scans for core-forms/poll blocks and [cf_poll] shortcodes at wp_enqueue_scripts priority 99 and pre-enqueues the stylesheet. Lands in <head> on poll pages, omitted entirely everywhere else.

Upgrading

Just update. If a textarea on a live form previously sat awkwardly between 2 and 4 lines, it’ll now be a comfortable 5; everything else is non-visual or strictly additive.

🤖 Generated with Claude Code

Permalink

4.3.5

Hotfix release — restores the Gutenberg block editor experience.

Root cause

If you’ve been running 4.3.3 or 4.3.4 and noticed the Core Forms block in the editor showing a generic blue “CF” square icon and a single dropdown — no live preview, no inspector panels — this release fixes it.

src/admin/class-admin.php was still enqueuing a legacy assets/js/gutenberg-block.js (a pre-4.0 hand-written registerBlockType call) on enqueue_block_editor_assets. That script registered core-forms/form first, so every modern block-form.js bundle — with ServerSideRender, inspector controls, and the correct form icon — was shipping in every zip but never actually loading in the editor.

The legacy wp_enqueue_script() call also passed no version argument, which is why network-tab diagnostics showed gutenberg-block.js?ver=7.0 (the WP core version) instead of the plugin version. Thanks to the user who reported this from their network tab — that’s what pinpointed it.

Changes

  • Removed the enqueue_block_editor_assets listener and enqueue_gutenberg_assets() method from class-admin.php.
  • Deleted the orphan assets/js/gutenberg-block.js.
  • block.json now owns the entire editor lifecycle — register_block_type(__DIR__ . '/block.json') loads assets/js/build/block-form.js with the modern Edit component, and the version: "4.3.5" field cache-busts it against CORE_FORMS_VERSION.
  • Reverted the 4.3.4 form-picker label change back to Title (slug) so forms sharing a base title stay distinguishable in the dropdown.

Upgrading

Just update. Hard-refresh the editor once (Cmd/Ctrl+Shift+R) to clear the cached gutenberg-block.js?ver=7.0 from your browser — after that the modern block editor UI is back.

🤖 Generated with Claude Code

Permalink

4.3.4

Two performance memoisations and three UX improvements layered on top of the 4.3.3 bug fixes. No breaking changes, no migrations.

Performance

  • cf_get_form() is request-scoped memoised. The same form requested multiple times per page (block render, get_html, action loop, analytics tracker) no longer re-fetches the post + meta and rebuilds the settings/messages arrays. Each call returns a clone so future callers can’t poison the cached instance with property mutations. Invalidation: save_post_core-form (always) and *_post_meta hooks gated on get_post_type() so other CPT meta touches don’t trash the cache.
  • cf_count_form_submissions() is request-scoped memoised. The forms list table called this per-row — a 50-form admin issued 50 COUNT(*) queries; now it issues one per (form_id, is_spam) pair and the rest are cache hits. Invalidated on cf_submission_inserted.

UX

  • Block-editor preview skeleton. The Gutenberg block preview shows an animated shimmer skeleton (title bar → input rows → submit button) while ServerSideRender is fetching, instead of a bare spinner. Respects prefers-reduced-motion.
  • Cleaner form picker. The block’s form-picker dropdown shows just the form title instead of \”Title (slug)\” — much cleaner when titles are distinct. The slug is still surfaced via the Edit Form deep link beneath the picker.
  • / keyboard shortcut on the forms list. Press / or s to focus the search box. Standard list-UI shortcut (GitHub, GitLab, Linear, every modern dashboard). Skipped when an input, textarea, or contenteditable already has focus so it never hijacks typing.

4.3.3 fixes are intact

  • The wp_cf_submission_replies table self-heal and the un-spam action-replay parity from 4.3.3 are untouched — verified 10 call sites still wired.

Upgrade notes

  • No data or schema migrations.
  • No breaking API changes.
  • The cache-invalidation hooks are guarded with function_exists('add_action') to match the existing convention in functions.php, so the file remains autoload-safe for standalone test environments.

Verified

  • 151 unit tests pass.
  • PHPStan reports no errors.
  • Production zip ships at 815 KB with no test framework, no PHPStan, no composer.json.
  • block-form.js rebuilt; bundle still contains wp.serverSideRender and the new cf-block-skeleton styles.
Permalink

4.3.3

Bug-fix release.

Fixed: fatal “Table ‘wp_cf_submission_replies’ doesn’t exist” when opening a submission. The reply-history feature queried a table that no installer or migration ever created. The table is now created on activation, on new-blog insert, and on multisite activation, and existing installs are backfilled by a 4.3.3 migration so they self-heal on update.

Fixed: submissions-table “Not Spam” bulk action did not fire form actions. Moving a submission out of spam from the submissions table now replays the form’s success and configured actions (notifications, integrations) that were skipped at submit time, matching the behavior of the spam-page single and bulk paths. The replay is centralised in cf_replay_submission_actions() so the three un-spam paths can’t drift apart.

Permalink

4.3.2

Core Forms 4.3.2

  • Optimized frontend asset loading so forms.js, accessibility.js, analytics.js, and form styles load only when a Core Forms block or shortcode is present.
  • Removed redundant Core Form block viewScript metadata because rendered forms enqueue the runtime directly.
  • Added tests for form asset detection, including a poll-only case.
  • Synced release requirements to WordPress 6.4+ and PHP 8.1+.

Zip SHA-256: 1eb8f317ed899596f1df041fa84e501e72a191c9367b4a9adb4c4487557cc052

Permalink

4.3.0

Stable release. Marks the end of the v4.3 beta cycle (beta1 → beta6).

Polls — full rework

Tabbed editor (Question / Settings / Schedule / Embed / Results), drag-to-reorder options, “Other” write-in toggle, Duplicate row action.

Vote integrity rewrite: every vote stores a voter_hash (poll + IP + UA + cookie + user) and dedupe queries that one column regardless of mode. Cookie set on render with SameSite=Lax; Secure, persists across AJAX. vote_limit=user rejects anonymous voters at submit. Honeypot on by default, per-IP rate limiter (12/minute).

Scheduling (start date + hourly cf_poll_auto_close cron), change-vote window, Gutenberg block (core-forms/poll) with picker + display-mode, opt-in live results (15s, pauses on hidden tab), bar / columns / percent result styles, container-query-driven adaptive layout, REST API (/cf/v1/polls, /polls/{id}/results public, /polls/{id}/analytics auth), per-poll analytics screen + CSV export.

Accessibility: <fieldset><legend>, role="progressbar" with aria-valuenow, role="status" aria-live="polite", focus moves to result heading on submit, prefers-reduced-motion honored. jQuery removed from poll JS.

Schema migration (cf_db_version → 4.3.0) is additive with backfill so historical dedupe keeps working.

Importers — three new sources

  • Gravity Forms — GFAPI-driven, ~14 field types, notifications → Email actions with per-recipient conditions, confirmations → success message / redirect, conditional logic → data-show-if / data-hide-if. Field IDs resolve through a per-form name map so condition references stay valid.
  • WPForms (Lite + Pro) — Decodes the form JSON, maps notifications, optional entry import from wp_wpforms_entries (Pro) into wp_cf_submissions so admin history survives the cutover.
  • Fluent Forms — Reads wp_fluentform_forms + wp_fluentform_form_meta directly (no plugin dependency), maps fields, notifications, webhooks, and conditional logic.

All three plug into the existing Core Forms → Import page via a new cf_import_sources filter + cf_import_render_section action exposed by CF7Migration, with shared helpers in a BaseMigration abstract class.

Send Email — conditional emails (per recipient)

New “Recipient routes” repeater on the Send Email action. Each route has a field + operator + value + recipient address; the first matching route’s recipient overrides the default To. The existing action-level conditions block keeps working — that gates whether the action runs at all; routes only re-target where it sends.

Forms list

Fix for the Duplicate row action: it used to drop the user into the editor for the original form because the URL carries a form_id and the overview page short-circuited into the editor before the list table’s single-row handler could run.

Build & CI

ESLint inheritance cleared (~80 prettier autofixes + targeted eqeqeq / no-unsafe-wp-apis / no-noninteractive-element-interactions fixes); PHPStan baseline regenerated at level 5; PHP 8.1 / 8.2 / 8.3 unit tests green.

Upgrade notes

  • Migration is automatic on next admin pageload (or on plugin update via upgrader_process_complete).
  • New WP-Cron hook cf_poll_auto_close is scheduled hourly; unscheduled on deactivation.
  • New post meta keys for importer provenance: _cf_gf_source_id, _cf_wpforms_source_id, _cf_fluent_source_id — useful for debugging or re-import workflows.
Permalink

4.2.10

Fixes

  • Duplicate row action now duplicates the form. Clicking Duplicate on the forms list used to drop the user into the editor for the original form because the duplicate URL carries a form_id and the overview page short-circuited into the editor before the list table could run its single-row action handler. The overview now processes action=duplicate_single first, clones the form, and redirects back to the list with ?duplicated=1.
Permalink

4.2.9

Container builder polish

  • Add Field popover redesigned. Fixed 360px width with a 4-column icon grid, header bar, and a dedicated close button. Dismisses on outside-click or Escape.
  • Containers default to a single column. New Containers ship as plain wrappers; opt into a grid via the Layout panel when you actually want one.
  • Column changes preview in real time. The canvas duplicates the .cf-row grid rules locally, so editing column counts updates the preview immediately.
  • Better drop-target affordance. Empty containers and group bodies show a dashed outline at rest and a solid blue highlight while dragging.

Also: fixes two pre-existing PHPStan warnings that were blocking the release pipeline.

Permalink

4.2.8

Patch: Container field column controls in the inspector sidebar

Selecting a Container on the Fields tab now reveals a Layout section in the inspector sidebar with the column controls. Three column-count inputs (desktop / tablet / mobile, 1–6 each) plus a free-text gap field. Tablet and mobile inherit from the next breakpoint up when left blank.

  • Settings persist on the field and emit as inline CSS variables (--cf-cols, --cf-cols-t, --cf-cols-m, --cf-gap) on the saved .cf-row wrapper, so the runtime form picks them up via the existing rules in forms.css.
  • The canvas now applies the same CSS variables to the container’s drop area, so the drag-and-drop preview mirrors the runtime grid instead of stacking fields vertically.
  • New Containers ship with cols_desktop: 2, cols_mobile: 1, gap: 1rem by default — a useful starting point you can override per breakpoint.

Full Changelog: