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
Beta

Core Forms 4.3.0-beta3

Read release notes

Pre-release. Same scope as beta2 + one access fix.

Fix vs beta2

  • Poll analytics page returned "Sorry, you are not allowed". The hidden analytics screen registered under the core-forms parent and then called remove_submenu_page() to hide the menu entry — but removing from \$submenu also strips the slug from WP's URL allowlist, so user_can_access_admin_page() rejected everyone except super-admins. Switched to an empty parent slug; the page now resolves at admin.php?page=cf-poll-analytics&poll=X and honors the per-page edit_posts cap.

Polls rework (carried over)

Tabbed editor, drag-to-reorder, "Other" write-in, vote-integrity rewrite (voter_hash dedupe, cookie-on-render with SameSite=Lax; Secure, user-mode anon rejection, honeypot, per-IP rate limit), hourly auto-close cron, Gutenberg block, REST endpoints, live results, change-vote window, bar/columns/percent styles, analytics screen + CSV export, accessibility pass, jQuery removed, schema migration with backfill.

Install on staging only. Real installs stay on 4.2.10 until stable 4.3.0.

Beta

Core Forms 4.3.0-beta2

Read release notes

Pre-release. Same scope as v4.3.0-beta1 but pinned to the commit where CI is green (ESLint + PHPStan + PHP 8.1/8.2/8.3 unit tests all pass).

What's new vs beta1

  • ESLint clean: ~80 prettier formatting issues autofixed, eqeqeq != null → explicit !== undefined && !== null, @wordpress/no-unsafe-wp-apis and jsx-a11y/no-noninteractive-element-interactions silenced where intentional.

Polls rework (carried over from beta1)

  • Tabbed editor (Question / Settings / Schedule / Embed / Results), drag-to-reorder options, Duplicate row action, "Other" write-in toggle.
  • Vote integrity rewrite: voter_hash dedupe, cookie set on render (and persisted from AJAX), vote_limit=user rejects anon at submit, honeypot, per-IP rate limit, hourly auto-close cron.
  • Gutenberg block core-forms/poll + REST endpoints (/cf/v1/polls/{id}/results public, list/single/analytics auth).
  • Live results polling (opt-in, 15s, pauses while tab hidden), change-vote window, bar/columns/percent result styles.
  • Per-poll analytics screen + CSV export of raw votes.
  • Accessibility: <fieldset><legend>, role="progressbar" + aria-valuenow, aria-live status region, focus management, prefers-reduced-motion.
  • jQuery removed from poll frontend and admin JS.
  • Schema migration (cf_db_version → 4.3.0) with backfill so historical dedupe keeps working.

Install on staging only. Real installs stay on 4.2.10 until stable 4.3.0.

Beta

Core Forms 4.3.0-beta1

Read release notes

Pre-release. Real installs continue to update to 4.2.10 — opt in to this beta only on staging.

Polls rework

Schema migration (cf_db_version → 4.3.0), tabbed editor, Gutenberg block, REST API, analytics screen, CSV export, hourly auto-close cron, accessibility pass, and a full vote-integrity rewrite.

Editor

  • Tabbed editor (Question / Settings / Schedule / Embed / Results) replaces the metabox screen
  • Drag-to-reorder options, Duplicate row action, "Other" write-in toggle, dedicated type selector (single vs. multiple)

Vote integrity

  • Every vote now stores a voter_hash (poll + IP + UA + cookie + user) and dedupe queries against that single column regardless of mode
  • Cookie set on render with SameSite=Lax; Secure; HttpOnly; AJAX requests persist a fresh cookie too (was previously broken because admin-ajax doesn't fire send_headers)
  • vote_limit=user rejects anonymous voters at submit (was silently letting them vote unlimited times)
  • Honeypot field on by default; per-IP rate limit (12 votes/minute) covers both real submits and honeypot trips
  • Hourly cf_poll_auto_close cron flips status to closed once the end time passes

Frontend & block

  • core-forms/poll Gutenberg block (no-build, vanilla JS) — picker dropdown + display-mode (auto / results-only / form-only); server-render shares code with the shortcode
  • Result styles: bar (default), columns, percent-only
  • Optional live results polling (15 s, opt-in per poll; pauses while tab is hidden)
  • Optional change-vote window (per-poll, in minutes) — re-renders the form pre-checked
  • Accessible markup: <fieldset><legend>, role="progressbar" with aria-valuenow, role="status" aria-live="polite", focus moves to result heading on submit, respects prefers-reduced-motion

Results & analytics

  • REST: GET /cf/v1/polls/{id}/results (public), GET /cf/v1/polls and /polls/{id} and /polls/{id}/analytics (auth)
  • Per-poll analytics screen with totals, unique voters, 30-day SVG line chart, option breakdown
  • CSV export of raw votes (option label, value, voter_hash, IP, user, voted_at, referrer)

JS

  • Removed jQuery from the poll frontend and admin scripts

Schema migration

Adds type, starts_at, allow_other, post_close_behavior, redirect_url, enable_live_results, change_vote_window to wp_cf_polls. Adds option_value, voter_hash, referrer to wp_cf_poll_votes plus a (poll_id, voter_hash) composite index. Existing rows are backfilled so historical dedupe keeps working.

Known follow-ups for stable 4.3.0

  • Donut style currently falls back to bar rendering (CSS hook exists)
  • Image-option polls / NPS / rating types are deferred to 4.4.0
Stable

Core Forms 4.2.10

Read release notes

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

Core Forms 4.2.9

Read release notes

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.

Stable

Core Forms 4.2.8

Read release notes

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

Core Forms 4.2.7

Read release notes

Patch: Polls moved under the Core Forms admin menu

"Core Polls" no longer registers its own top-level menu item. Polls now live as two submenu entries (Polls + Add Poll) under the Core Forms menu, so the admin sidebar reads as one product instead of two side-by-side icons.

  • PollAdmin::add_admin_menu() switched from add_menu_page to two add_submenu_page calls under the core-forms parent.
  • admin_menu hooked at priority 20 so Admin::menu() (default priority 10) has already registered the parent slug before Polls tries to attach.
  • New parent_file filter keeps the Core Forms top-level item highlighted (and selects the right submenu sub-item — Polls list vs Add Poll) while editing, creating, or listing polls. Without it, the WP post-type screens would blank out the sidebar's active state.
Stable

Core Forms 4.2.6

Read release notes

Patch: preview button on the per-form template chooser

The Preview button that landed on the Add Form gallery in 4.2.4 now also appears on the template picker that opens inside the per-form Fields tab (the React visual builder).

  • Each non-blank card carries a "Preview" pill in its top-right corner. Hovering or focusing the card reveals it; clicking it opens the same iframe modal the Add Form gallery uses. event.stopPropagation stops it from also firing the parent "select template" click.
  • The preview modal moved from inline page markup into Admin::render_template_preview_modal, hooked on admin_footer for every Core Forms admin screen. Click handling is delegated — any element with data-cf-preview="{slug}" (anywhere on a Core Forms page) fires it. window.CoreFormsAdmin.openTemplatePreview(id, label) is exposed for programmatic triggers.
  • Localized cfFormTemplates entries now carry a preview_url so the React builder (or any other JS) doesn't have to re-derive the admin-ajax URL.
Stable

Core Forms 4.2.5

Read release notes

Patch: template preview + Create Comment surface + default actions

Three fixes / one-line connections that were missing in 4.2.4.

  • Template preview iframe now actually loads. The wp_ajax_cf_template_preview action was being registered on the Admin class constructor, which is gated behind ! DOING_AJAX — so the AJAX handler was never wired during AJAX requests. WP's admin-ajax fell through to its default "0" output and the iframe showed a blank page. Registered the handler in the AJAX branch separately with a lazy-constructed instance.

  • Create Comment action now appears in the Actions tab picker. The action class registered fine via cf_available_form_actions, but the WordPress category in tab-actions.php didn't list create_comment in its types array — so the grouped grid skipped it. Now slotted in next to create_user/create_post with an admin-comments dashicon.

  • Every starter template lands with a default Email action wired. Previously a brand-new form had no actions at all — submissions saved to the inbox but never emailed anyone. process_create_form() now appends a default "Email the admin" action when the template doesn't ship its own. Templates that DO ship actions (product_review → Create Comment, payment templates → providers) keep their wiring untouched.

  • Product review + Lightweight comment templates ship with Create Comment pre-wired. Field mappings — NAME → comment author, EMAIL → author email, REVIEW/COMMENT → content, RATING → rating meta — plus a default Email notification. Open the form, pick a target post on the action, save — done.

Stable

Core Forms 4.2.4

Read release notes

Star ratings, comments, and a much richer admin

This release adds a proper review/comment workflow (star rating field + a Create Comment action that writes to WordPress comments with aggregate rating meta), five new starter templates with a sandboxed preview iframe on the Add Form gallery, a column-layout container with responsive breakpoints, real-time preview sync in code mode, and a bunch of admin clarity fixes.

Star rating + comments

  • New .cf-rating field type — radio-based 1–5 star picker with CSS-mask icons inlined as data URIs (works whether or not the form theme is loaded). Keyboard-reachable with per-star screen-reader labels. Reverse-ordered radios + the adjacent-sibling cascade fill stars to the left of hover/check.
  • New Create Comment / Review action — posts the submission as a WordPress comment against a target post (numeric id, [field] reference, or auto-detected via referer URL). When a rating field is configured, stores the value as comment meta rating and recomputes the target post's cf_rating_average + cf_rating_count post meta — Schema-rich-snippet plugins read these keys by convention. Status flips (pending → approved) trigger a recompute via transition_comment_status.
  • Code-mode toolbar gains Insert star rating + Insert columns row buttons.

Five new starter templates

| Template | Use | |---|---| | Product review | Star rating + headline + comment, paired with the Create Comment action | | Lightweight comment form | AJAX-submitted drop-in for the native WP comment form | | NPS / satisfaction survey | 0–10 scale + reason + optional email | | Bug report | Severity, browser, steps, attachment — two-column layout | | Product waitlist | Email + company + source, two-column layout |

Template preview iframe

Every non-blank template card on the Add Form gallery now has a Preview button that opens a modal iframe loading the markup via wp_ajax_cf_template_preview. Capability-gated to edit_forms, loads the same forms.css + form-theme.css a real form would use, submit-disabled so nothing fires.

Columns layout container (.cf-row)

CSS helper driven by inline CSS variables — --cf-cols, --cf-cols-t, --cf-cols-m, --cf-gap — sets desktop / tablet (≤1024px) / mobile (≤640px) column counts up to 6 each. Variable chaining means setting only the desktop count cascades to tablet and mobile. Code-mode inserter prompts for the three numbers and drops the wrapper in.

Real-time preview sync

Code-mode textarea now pushes its current markup to the preview iframe on every keystroke (180ms debounce) via postMessage. The iframe replaces #cf-preview-root innerHTML in place. Origin- and form-id-scoped so a cross-form iframe can't be poisoned.

Form editor preview honours the global stylesheet toggles

The admin asset enqueue now conditionally loads forms.css and form-theme.css (with cf_form_theme_tokens overrides) when you're on a form-edit screen, so the visual builder canvas and code-mode iframe both render with the same stack the front-end uses. Previously the editor preview was unstyled even with the theme on globally.

Settings clarity

  • Skeleton CSS vs Default form theme — both options renamed with explicit descriptions of what they load. Skeleton (forms.css, ~1.5 KB, structural only — labels, error states, button alignment, the new column-row helper). Theme (form-theme.css, opinionated visual layer — colors, radii, focus rings, typography). Choices are "Load / Skip".
  • After Submission — clearer two-way choice ("Show success message" / "Redirect to a URL"). Contextual help appears with the selection. The redundant "Redirect to a page" option was removed; the URL field already covers that case.
  • Per-form Settings tab now opens with only the first accordion (Submissions) — previously two opened simultaneously.
  • "Add-ons" → "Extras" in Settings + Messages section labels.

Action merge: CreatePost + CreateArticle

The richer CreateArticle (title/content/excerpt mapping, taxonomies, ACF, featured image, author lookup) now claims the canonical create_post slug and the label "Create Post / Article / CPT". Forms saved with the old create_article type are forwarded to the merged handler at runtime — no migration.

Bug fixes / hardening

  • vendor/autoload.php require is now file_exists()-guarded so a partial extraction during an in-place plugin upgrade can't fatal the site. Clear admin notice surfaces on the next page load if vendor/ is genuinely missing.
  • Template preview wp_die() calls now pass HTTP codes via the response arg instead of as the title. Unauthorized hits actually return 403/400/404.
  • CreateComment recompute only fires when a valid in-range rating actually landed as comment meta; out-of-range values skip the recompute.
Stable

Core Forms 4.2.3

Read release notes

Adds a CF_DEMO_MODE wp-config constant guard so the public demo build at core-forms.com/demo can be safely handed out via token-gated R2 — the plugin self-disables anywhere except playground.wordpress.net subdomains. No-op for production sites.

Stable

Core Forms 4.2.2

Read release notes

Patch release. Hot-fix for the headless embed.

What was wrong

The bundled `embed.js` (served from `/wp-json/core-forms/v1/embed.js`) was rendering `result.data.message` directly into the success card. But the form processor returns it as an object — `{ type: 'success', text: '...' }` — not a string. JavaScript stringified the object to literal `[object Object]`, so every successful headless submission ended with that string in the success card. Same shape bug in the error path.

What's fixed

Added a `pickText()` helper that: - Plucks `.text` when the message is an object. - Returns the value when it's already a string (for forward-compat). - Falls back to a sensible default (`Thanks!` / `Submission failed.`) when the field is missing.

Applied to both success and error code paths.

Who's affected

Anyone running the drop-in embed widget (the `