Fatal error at the end of the update to 2.1.8 - updating from 2.1.7 or older showed "Class ACPT\Utils\Http\ACPTApiClient not found" (or "ACPT\Utils\PHP\Session") after "Plugin updated successfully". The update did complete and the site kept working: the old version, still running until the update page finished, couldn't find its files in the new package. Updating from older versions no longer shows the error (Tickets #1444, #1446).
Activating ACPT while ACPT Lite 2.1.0 is active crashed - upgrading from ACPT Lite failed with "Plugin could not be activated because it triggered a fatal error": both plugins declared the same functions, and the import stopped on a Lite field group without a position (e.g. a field group on users). ACPT now activates, imports Lite's post types, taxonomies and field groups, and deactivates Lite.
Fatal error when saving a post - on sites where another plugin loads a newer version of the webmozart/assert library (2.x, PHP 8.2+), saving a post with ACPT fields crashed with "Declaration of ACPT\Utils\PHP\Assert::string must be compatible". ACPT no longer redeclares the library's methods, so it works with both versions (Ticket #1435).
Conflicts with other plugins' PHP libraries - ACPT's PHP libraries (Twig, phpfastcache, webmozart/assert, Symfony YAML and the others) are now bundled under ACPT's own namespace, so another plugin loading a different version of the same library can no longer break ACPT, or be broken by it.
The update was offered again after updating - right after an update, WordPress offered the same version again. ACPT now compares against the installed version, and an up-to-date ACPT shows the auto-updates toggle (Ticket #1439).
"No response from the server" on the license page - when acpt.io's answer wasn't JSON (a firewall's block page, an error page), the license page hid what the site received. It now shows the HTTP status and the page's text (Ticket #1431).
Saving a meta group with a nameless box crashed - the save failed with a server error; the box is now rejected with a message. Empty field type groups are hidden in the WooCommerce product data builder.
Required fields hidden by their conditions blocked the save - a required field hidden by its own or its box's conditions stopped the browser from submitting the form, and was still validated on the server ("Expected a non-empty value."). Hidden fields are no longer required or validated; their value is still saved (Ticket #1437).
Repeater children named "type" or "original_name" - they were saved but missing from get_acpt_field. They are returned again (Ticket #1437).
Length limits counted bytes - Min/Max length on meta and form fields rejected accented text the browser had accepted. Limits now count characters, as the browser does (Ticket #1439).
Date & time values in the canonical format were rejected - the date check was inverted: a Date & time field saved as 2026-10-26 14:30:00 (from code, the REST API or an import) failed validation. It is now accepted, like every other date format the field can store.
Saved ACPT blocks showed as unsupported - "Your site doesn't include support for this block" appeared when the editor parsed the post before ACPT registered its blocks, and on post types registered on init (GeneratePress Elements, most plugin CPTs) the blocks and their styles weren't registered server-side. Both are fixed (Ticket #1441).
Image fields printed the alt text in dynamic block templates - {{ acpt_box_image }} printed the alt text or title, so broke. Image, File and Gallery values now print their URL and still answer .alt, .title, .id and the other attachment properties (Ticket #1436).
Bricks: query filters didn't work on CCT columns - on a post type whose fields come from a CCT, filter elements (Select, Checkbox, Range...) had no options and never narrowed the loop. They now index and filter the CCT column values (Ticket #1434).
WPML / Polylang: media fields showed the same attachment in every language - the generated wpml-config.xml didn't list the attachment ID key of Image, Gallery, File, Video, Audio and Image slider fields. It does now, with the field's own translation settings (Ticket #1432).
Test suite on WordPress 7.2 (no change for users) - two tests expected HTML exactly as WordPress 7.1 sanitized it. The tests now pass on both versions.
Feeds setting for post types - a new "Feeds" toggle (Settings step, on by default) switches off a post type's archive feed. With it off, /{slug}/feed/ is gone, the archive stops advertising the feed and ?post_type=x&feed=rss2 redirects to the archive. Saving a post type now also flushes the rewrite rules with its new settings instead of the previous ones (Ticket #1427).
Segurança
Stored XSS in the CPT admin filters - meta values and terms were printed unescaped in the list-screen filter dropdowns, so a stored value could inject markup (Author → Admin). They are now escaped.
PHP Object Injection in CCT values - a serialized object stored in a CCT column (through the REST API or a public form) was instantiated on every read of the record. CCT values now go through the plugin's object-safe unserializer.
Fields were renamed on save - since 2.1.0 a field sharing its name with a field in another box was renamed to name_1, name_2... on any save of its group, orphaning its stored values. Field names now only need to be unique within their box, and an existing field is never renamed (Tickets #1421, #1422).
Table fields rendered empty - since 2.1.0 Table fields were stored as a PHP array instead of JSON, so they rendered empty in Bricks, the shortcode and the builders, and Bricks' raw tag crashed. They are stored as JSON again, and tables saved by 2.1.0-2.1.6 render without a re-save (Ticket #1428).
Stray backslashes in Table cells - the Table editor saved its own escapes as text ("210 / 297 mm" showed as "210 \/ 297 mm") and typed backslashes were lost. Cells now save as typed, and cells saved with a stray "\/" display without it (Ticket #1428).
Phone field country on user profiles and term screens - a saved country always showed as the US, and picking only a flag in the default-value editor stored a broken value that crashed the field editor. Both are fixed; a number without a country falls back to the field's default country (Ticket #1426).
Dates in a custom format failed validation - a date column with its own format (e.g. "Y") rejected the value from the admin form. Dates, times and date ranges are now parsed with the column's format first (Ticket #1423).
Relationships to another CCT table - a Relationship field pointing to a CCT table printed "Array" (or nothing in Bricks). The related records now resolve, and Bricks renders them by their label column (Ticket #1424).
"Set as post thumbnail" ignored for CCT columns - Image, Gallery and Image slider columns saved in a CCT table now set the featured image when the option is on (Ticket #1425).
Datasets couldn't be edited - since 2.1.2 every "Manage" link opened the datasets list instead of the dataset, so a dataset's items couldn't be changed. The list now lives at #/tools/datasets; old links to #/tools/dataset still work (Ticket #1420).
Updates could keep running the previous release's scripts - the helper scripts loaded by the admin had no version in their URL, so a browser could keep the old ones cached after an update (and downloaded them twice). They now carry the plugin version (Ticket #1413).
The Icon field was blocked by the icon service - each search result was loaded with its own request, so after a few searches the icon service refused them and icons in later Repeater rows showed as broken and couldn't be picked. Results now load with one request per icon set and picking an icon needs no request. Saved values are unchanged (Ticket #1413).
Table data saved from tab views was lost - in meta groups shown as vertical or horizontal tabs, every save created a new record that wasn't linked to the post, so the data looked never saved and Bricks query loops showed nothing. Saves now update the post's record (Ticket #1416).
Failed table saves were silent - when a record failed validation the post saved and the table data was lost without a message. An error notice is now shown, also in the block editor (Ticket #1416).
Empty optional numbers and dates blocked the save - an empty Number, Date, Date & time or Time input failed validation for the whole record; optional columns now save as empty (NULL). Decimal numbers no longer lose their decimals (1.6 was saved as 1) (Ticket #1416).
Bricks: Toggle conditions on the displayed label stopped matching - since 2.1.2 a condition comparing a Toggle field with its label (e.g. == Pravda on a Czech site) hid the element. It matches again (Ticket #1419).
Elementor Pro: a Select field shown as label crashed the editor when empty - building a Loop Grid failed with a TypeError. An empty field now renders nothing and multi-value fields render comma separated (Ticket #1415).
Versão 2.1.5
4 novidades6 correções
Novidade
"Show meta box" taxonomy setting - turn it off to hide a taxonomy's box on the classic post edit screen, e.g. when its terms are assigned through a Term field. The block editor ignores this WordPress setting (Ticket #1402).
Hierarchical terms in Term pickers - in Term and Terms (Multiple) fields, child terms are listed right after their parent and indented by level (Ticket #1400).
The field builder sidebar stays in view - while a long list of fields scrolls, the sidebar sticks below the page header and scrolls on its own (Ticket #1401).
Clear errors when a custom table can't be synced - an index or a foreign key that MySQL would reject (an index on a JSON column, a text index without a length, a foreign key between columns of different types, "SET NULL" on a column that doesn't allow empty values) is now explained in the sync dialog, with how to fix it and a link to the step, before anything runs. The Indexes and Foreign keys steps show the same warnings. If MySQL still refuses a change, the error is explained in plain words…
Correção
Select fields stayed on "Loading..." for non-admin users - Post, Term and User selects loaded their options with a request limited to administrators, so for Editors and other roles they never loaded (Ticket #1412).
Editors couldn't add Repeater rows - the request that adds a row (and the one that generates ID field values) was limited to administrators (Ticket #1408).
Repeater and Flexible Content fields on option pages lost their attributes - values like the link text of a Url field came back empty, and the next save erased them (Tickets #1409, #1410).
LIKE / NOT LIKE conditions crashed the post editor - a condition on a field with no value yet, or with several values (e.g. a Terms field), caused a white screen (Ticket #1399).
Changing a field's type could crash the page - a default value left from the old type (e.g. Phone Number to Text) caused a fatal error where the field was shown (Ticket #1403).
The Icon field showed broken images and couldn't pick icons - the icon search sent a request per keystroke and loaded every result image at once, so the icon service blocked the site. Searches now wait for typing to stop and images load as they scroll into view (Ticket #1409).
Saving from the block editor lost every custom field value - since 2.1.3 the second request the block editor sends to save meta boxes crashed with Call to undefined function check_admin_referer, so the editor said "Updated" while ACPT fields (and other plugins' meta boxes) were not saved (Tickets #1385, #1388, #1390, #1394, #1396, #1397).
The edit screen took 30+ seconds with the ACPT cache off - every repeater row reloaded its parent field and every admin page reloaded each meta box once per field, adding up to over 100,000 database queries on large field groups. Each is now loaded once (Ticket #1387).
Date fields were saved in the display format - since 2.1.0 Date, Date & time, Time and Date range values were stored as shown in the picker (e.g. 08.10.2026) instead of Y-m-d, breaking tools that read the stored value, like Bricks' {cf_...} tags and date ordering in queries. New saves use the canonical format again; existing values are converted the next time the post is saved (Ticket #1389).
Date and Time fields inside a Repeater came back empty - the read used the Repeater's date format instead of the sub-field's own, so e.g. a d/m/Y date was never recognised and dynamic tags (Bricks query loops included) returned nothing (Ticket #1393).
WYSIWYG editors could become blank and not editable in the block editor - the block editor moves the meta boxes around the page (on load, and again e.g. when toggling distraction-free mode), which reset the editors. They now recover automatically, keeping their content (Ticket #1395).
Relationship fields with a maximum number of items didn't load - with the select2 selector, a JavaScript error stopped the selector from initialising (Ticket #1395).
Malformed Repeater or Flexible Content data made a post uneditable - an unexpected value in the stored data (e.g. left by the 2.0.63-2.0.66 block-sort bug) crashed the edit screen. Such entries now show as empty rows that can be removed (Ticket #1397).
Backslashes were removed from Textarea and Text values - every \ was stripped on save, so JSON escapes were lost and JSON values could be stored invalid (Ticket #1380).
Fields inside a Repeater couldn't be deleted from the canvas - the trash icon on a sub-field selected the Repeater instead and the confirmation disappeared (Ticket #1392).
The Repeater/Flexible "Leading field" dropdown was always empty (Ticket #1379).
A field's conditional rendering only listed fields of its own meta box - fields of the other boxes in the same group can now be used too (Ticket #1383).
Records with a Relationship value couldn't be saved from the admin - selecting a related item made the save fail with "Additional object properties are not allowed", listing every column. Relationship values are now accepted, and validation errors show the real problem next to the column (Ticket #1382).
Collapsible sidebar in the field builders - the sidebar of every canvas builder (meta fields, forms, custom table columns, dynamic blocks, option pages, WooCommerce product data) can be hidden to a thin strip, from a toolbar button or by dragging its edge, giving the fields the full width on small screens. The choice is remembered per item, and clicking a field reopens the sidebar with its settings.
Correção
Forms stopped sending email with plugins that replace wp_mail - since 2.1.0 ACPT loaded WordPress' pluggable functions while plugins were still loading, so plugins that override wp_mail (e.g. ActiveCampaign Postmark) could no longer do it and form emails were lost (Ticket #1377).
Updating installed the previous version - after a release WordPress showed the new version but installed the previous zip, served from a cache. The update package URL now includes the version, so every release gets its own download (Tickets #1354, #1370).
The admin crashed when two tables had foreign keys pointing at each other - loading the tables recursed until PHP ran out of memory on every admin page, locking users out of wp-admin. Tables referencing each other, in a pair or a longer chain, now load normally (Ticket #1372).
JSON in a Textarea field still lost characters with "Allow HTML" off - spaces and line breaks at the start and end of every JSON string were removed, so values made only of line breaks (common in Etch and Gutenberg exports) were saved empty. The JSON is now saved exactly as typed (Ticket #1370).
A Relationship value read with get_acpt_field couldn't be saved back - it returns the related posts, users or terms as objects, and passing them to save_acpt_meta_field_value failed with a PHP error, so nothing was saved. Objects are now saved as their IDs, and removing an item with unset works too (Ticket #1371).
HTML and line breaks were stripped from a block's Callback and CSS on save - the Twig template lost every tag and was compressed to one line, and the CSS was flattened. Both are now saved as typed; users without the unfiltered_html capability (e.g. multisite site admins) get post-safe HTML in the Callback and tag-free CSS (Ticket #1378).
Narrow field cards overflowed their border - a field at 50% width, or inside a repeater, pushed its switches and type badge outside the card. Cards now adapt to their real width, hiding the inline switches and then the type badge when there's no room; both stay available in the sidebar (Ticket #1376).
The sidebar width followed the screen as a percentage - a sidebar made wider on a large monitor took more than half of the builder on a laptop. Its width is now kept in pixels and capped to half of the builder when the page loads (found while auditing Ticket #1376).
Box and block header icons could fall outside the box, the toolbar's "Sidebar on the right" button was cut off at 1024px, and field names were truncated after 10 characters even when there was room. Headers keep their icons inside, the toolbar switches to compact icons on narrow builders, and names use the available width with the full name on hover (found while auditing Ticket #1376).
Toggle fields never matched in element conditions on non-English sites - a Toggle was rendered as the translated "True"/"False" (e.g. "Wahr"/"Falsch"), which Bricks conditions don't treat as yes/no, so {acpt_...} == 1 never matched. Toggles now return 1/0 inside element conditions and with the :value argument (Ticket #1375).
Editor fields inside Repeaters lost all formatting on save - since 2.1.0 every sub-field of a Repeater or Flexible Content field was sanitized as plain text, so saving the post stripped the HTML tags and line breaks from Editor sub-fields (and line breaks from Textarea sub-fields). Each sub-field is now sanitized according to its own type; Editor sub-fields keep post-safe HTML (Ticket #1361).
Select dropdowns were clipped below 1200px window width - the responsive meta-field layout set overflow: hidden, which cut off the Selectize popup and made arrow-key navigation look unresponsive. Only horizontal overflow is clipped now (Ticket #1360).
A saved 0 showed as empty in the admin - since 2.1.1 a required Number field accepts and saves 0, but on reload the edit screen showed the input empty (Currency, Weight and Length too), because the escaping helper treated "0" as empty. A stored 0 is now shown, and a 0 min/max on the admin Number field is respected (Ticket #1354).
Blank Number, Currency, Weight and Length fields were saved as 0 - leaving the amount empty stored 0, so the front end showed 0 / 0.00 EUR instead of nothing. A blank amount now stays blank; an explicit 0 is still saved as 0 (found while investigating Ticket #1355).
Time field values came back empty when saved in a format other than the site's time format (e.g. 10:00 on a site using g:i a), which is what the admin time picker saves when the field's display format differs. get_acpt_field, shortcodes and page builder tags returned nothing, including for Time fields inside repeaters. Any supported time format is now accepted (Ticket #1352).
Bulk Edit wiped ACPT fields - WordPress' Bulk Edit panel submitted every ACPT quick-edit input, including the ones left blank, so any bulk edit (even just enabling comments) emptied those fields on every selected post. Blank Bulk Edit inputs now mean "no change", as they do for WordPress' own fields; this also applies to Custom table columns (Ticket #1369).
JSON saved in a Textarea field was altered - %20-style sequences and tags inside JSON strings were stripped, and with "Allow HTML" enabled the JSON was saved with backslash-escaped quotes and &, <, > encoded, so it was no longer valid JSON. JSON is now kept as typed; tags inside it follow the field's "Allow HTML" setting (Ticket #1370).
The unit of a blank Currency, Weight or Length field was replaced - when the amount was empty, the edit screen preselected the field's default unit instead of the saved one, so saving the post again overwrote it (Ticket #1355).
List pagination crashed with "Unexpected Application Error! 404 Not Found" - page 2 and later of the Meta Keys Manager, Datasets and WooCommerce product data lists had no matching route, and the Custom Tables list linked its pages to a non-existent /tables path. All four now paginate (Ticket #1363).
Fatal error with plugins that run the main query early in wp-admin - a custom login URL plugin rendering its 404 page during an admin request triggered Call to undefined function get_current_screen in the admin columns code, white-screening the site (Ticket #1368).
Advanced column settings were lost on save - on a column saved without any advanced settings, later changes to them (width, before/after text, CSS class, min/max, pattern, ...) were silently dropped on every save, because the empty settings were returned as a JSON array instead of an object (found while investigating Ticket #1363).
Tables with UNSIGNED or ZEROFILL columns could not be created or synced - the generated SQL put UNSIGNED/ZEROFILL after NOT NULL (and, when syncing an existing table, after DEFAULT/COMMENT too), e.g. BIGINT NOT NULL UNSIGNED, which MySQL and MariaDB reject as a syntax error. Syncing a column with a text default also produced an unterminated DEFAULT 'value. Both are fixed (Ticket #1367).
A column default of 0 was dropped, and decimal defaults were truncated - 0 was treated as "no default" when creating or syncing a table (so DEFAULT 0 never reached the database), a default like 1.5 was synced as 1, and a DECIMAL default such as 1 kept showing the table as not synced because the server reports it as 1.00 (found while fixing Ticket #1367).
No way to set a Currency column's default currency - the record form always preselected USD. Currency columns now have a "Default currency" setting (Ticket #1362). Saved advanced settings are also shown again when a column is reopened.
Duplicating a column only kept its type - the copy got the column type but none of the settings changed in the sidebar (length, nullable, default value, advanced settings, ...). The duplicate now copies them, with a new name and id; the primary key flag, index/foreign key links and the inverse side of a bidirectional relation are not copied (Ticket #1363).
Text field tags rendered empty in link settings - an ACPT Text field used as the only content of a Bricks link setting (e.g. an Icon element's custom URL) returned nothing, because Text fields weren't registered for Bricks' link context. They now resolve to the bare URL, without the field's before/after text (Ticket #1356).
Date and Time tags printed the "before" text twice and never the "after" text (found while fixing Ticket #1352).
Front-end form Number fields still rejected 0 - with no limits configured they were rendered with min="1" max="100", so the browser refused 0 (and anything above 100) even after the 2.1.1 fix, and a minimum set to 0 was ignored. Number fields now have no limits unless configured, and a 0 limit is respected (Ticket #1354, follow-up of #1338).
Currency, Weight and Length fields rejected 0 - in both front-end forms and the admin, their amount input defaulted to a minimum of 0.01 (Currency) or 1 (admin Weight/Length), and a minimum set to 0 was ignored. They now have no minimum or maximum unless configured, and a 0 limit is respected (Ticket #1354).
Block Bindings: ACPT fields missing from the Site Editor's Attributes panel - the list of bindable fields was computed once and then cached, so switching templates in the Site Editor without a page reload kept the fields of whatever screen it was first computed on (often none, which hides the panel). The list now follows the template being edited. The list could also be computed before ACPT's fields had finished loading and then stay empty for that template even after a reload (more likely on…
WYSIWYG (Editor) fields lost their formatting in ACPT Dynamic Data - lists, bold text and other markup were stripped unless "Enable Raw HTML" was turned on. Editor fields now render their HTML (filtered to post-safe markup) by default, like the [acpt] shortcode and the legacy ACPT Meta Fields module (Ticket #1358).
Address map never loaded when another ACPT script was on the page - seven static scripts overwrote each other's window.onload; they now use addEventListener('load', ...) (Ticket #1344).
Caught errors re-crashed the page when ACPT logging was enabled - the acpt/error logger only accepted \Exception, so an \Error caught by ACPT's own safety nets (Breakdance, field-group visibility, location rules...) threw a new fatal from inside the logger. It now accepts any \Throwable.
PHP 8.4 deprecation notices - OptionPageModel::duplicate and MetaBoxModel::construct implicitly marked a typed parameter as nullable via a null default instead of an explicit ?type, both deprecated as of PHP 8.4.
Correção
Saving a field group failed with "Value key is mandatory" - a field option row without a value (e.g. a stale row reaching an Image field) aborted the whole group save. Such rows are now skipped, and a row with a label but no value falls back to its label (Ticket #1349).
Saving an "All users" / "All comments" location rule fataled - the empty find the UI submits for these rule types is now normalised instead of throwing (Ticket #1339).
Currency / Weight / Length fields fataled the post editor when a default unit was set without a default amount (explode: Argument #2 must be of type string, array given) (Ticket #1346).
Required fields rejected 0 - a required Number field set to 0 failed with "Expected a non-empty value" in the admin and "The field is required" on front-end forms (Ticket #1338).
Field groups did not show on taxonomies registered by other plugins (e.g. WooCommerce Product categories) - they could be selected as a location but never rendered or saved (Ticket #1337).
Link fields without link text returned a plain URL string instead of the {url, label} array 2.0.x returned, so they rendered empty in Elementor Pro, Bricks, Divi, Oxygen, Yoast, WP Grid Builder and Zion, and an Elementor Pro display condition on them fataled (Ticket #1341).
Repeater "Add element" did nothing on option pages - the AJAX row generation fataled with a Strings::toDBFormat TypeError, affecting every repeater on an option page (Ticket #1333).
Form submissions bypassed ACPT permissions - field- and column-level permissions are now enforced on submission, and forms writing CCT records require the table's create/update permission (Ticket #1345).
ACPT blocks rendered empty on the front end - the Basic, Repeater and Relational field blocks and all Dynamic Blocks were registered only in editor contexts, so on the front end WordPress never called their render callback (Ticket #1348).
Basic Fields block showed "Error loading block: [object Object]" in the Site Editor for fields with large settings - the preview request exceeded the server URL limit; it is now sent via POST (Ticket #1322).
SEOPress: pages crashed when an ACPT field rendered empty or 0 - the SEOPress integration returned null from a string-typed method whenever a field value rendered to an empty string or 0, a fatal error on every page where SEOPress builds its dynamic variables (single posts, archives, and the Breakdance builder preview). It now returns an empty string (Ticket #1335).
Breakdance/Oxygen 6 native Repeater Field element could white-screen - ACPTRepeaterField::hasSubFields left an internal value undefined when a repeater's meta group belonged to something other than a post type, taxonomy, or option page, instead of resolving cleanly to "no rows"; ACPTField::getValue and RawValueConverter::convert also only guarded against \Exception, not every PHP error type, and Breakdance's own dynamic-data render chain has no error handling of its own, so any uncaught error…
PUT /acpt/v1/meta/{id} rejected the unchanged output of GET - read-only keys returned by GET are now accepted, missing settings (group display/context/priority, box settings) were added to the schema, and updating a field keeps its position (Ticket #1347).
Custom Content Types - create and manage fully custom MySQL (InnoDB) tables directly from the ACPT admin, each with its own schema, auto-generated record manager, and optional REST API, completely independent from wp_postmeta. Opt-in via ACPT → Settings → Content settings.
Table Groups - link one or more CCT tables to WordPress contexts (post types, taxonomies, users, option pages) via configurable location rules, with four display modes: Standard, Accordion, Vertical Tabs, Horizontal Tabs.
30+ column types - VARCHAR, TEXT, LONGTEXT, BIGINT, DECIMAL, DATE, DATETIME, TIME, TINYINT(1), JSON, BLOB, plus VIRTUAL pseudo-types for Repeater and Flexible block columns. Each maps to a generated admin input and a typed REST property.
Repeater and Flexible block columns - nestable column types stored as JSON.
Relational columns - link a record to another CCT table, a post, a term, a user, or an option page, with optional bidirectional sync.
Foreign keys - database-level FOREIGN KEY constraints with configurable ON DELETE / ON UPDATE (CASCADE, SET NULL, RESTRICT, NO ACTION).
Database indexes - INDEX, UNIQUE, FULLTEXT, SPATIAL on any column or combination.
Custom primary keys - designate any column as the primary key, with optional AUTO_INCREMENT; or use the implicit AUTO_INCREMENT / UUID v4 / ULID id column (Ticket #1166).
Timestamps and soft delete - opt-in created_at / updated_at and a deleted_at soft-delete column, with an All/Trash records view (per-row and bulk Restore / Delete Permanently / Empty Trash).
Schema sync - ACPT creates and migrates the physical table on save; the table list shows a per-row schema-status indicator and a one-click sync.
CCT REST API - per-table CRUD at /wp-json/acpt/v1/{tableName} (opt-in per table), with page, per_page, orderby, order, and per-column filters; file columns accept multipart/form-data.
Table metabox settings - per-table context (normal/side/advanced), priority, hide-title, and hide-toggle controls for the record metabox, matching meta-group box settings.
CCT fallbacks in core functions - get_acpt_fields, acpt_field_has_rows, acpt_field_has_blocks, and is_acpt_field_visible transparently resolve CCT tables/columns, so existing templates work unchanged.
Import / export - Tables and Table Groups can be exported and re-imported alongside CPTs, taxonomies, option pages, meta groups, and forms, preserving repeater/flexible hierarchies and foreign keys regardless of order in the file.
Unified Canvas UI - one drag-and-drop builder across meta fields, forms, CCT table columns, dynamic block controls, option pages, and WooCommerce product data. Built on @dnd-kit and react-resizable-panels.
No-distraction mode, resizable panels, and an advanced-mode toggle, all persisted per entity.
Inline editing - click-to-edit a field's label / name / type directly on the canvas, plus inline switch toggles (Show in archive, Filterable, Quick edit, Required) on each row, with name-uniqueness validation shared between canvas and sidebar.
Keyboard-accessible drag-and-drop with live-region announcements (WCAG 2.1.1 / 4.1.3).
Meta Keys Manager (ACPT → Tools → Meta Keys Manager) - lists every meta key in the database regardless of origin, with Key / Field type / Context / Associated to / Value / Actions columns, search, context filter, sorting, pagination, single-click inline value editing, and bulk Delete / Export CSV / Export JSON.
Message field - static, HTML-formatted informational text (no stored value); available for Meta Fields, Forms, and CCT columns.
Post Format as a meta-group location condition (Ticket #1192).
Box-level conditional visibility - a metabox's visibility can depend on another field's live value ("Other fields" / "Other columns"), matching field-level conditional rendering.
"Fill table" action - write a submission directly into a CCT record (create or update), with a per-column mapping UI.
Record_id attribute on [acpt_form] - bind a form to an existing CCT record for editing.
Submission limits converted to a flexible list layout.
Block Bindings - bindable meta fields (20 types including Text, Textarea, Editor, Number, Email, Image, Url, Select, Date, Color) can be connected to core blocks (Paragraph, Heading, Image, Button, ...) through WordPress's own native Block Bindings UI (WP 6.7+), with an inline-edit affordance for eligible text bindings. ACPT registers acpt/field as a core binding source - there is no custom panel.
Full Abilities API - 57 MCP-exposed, schema-validated operations covering custom post types, taxonomies, meta groups/boxes/fields, field values, option pages, forms, dynamic blocks, and Custom Content Types (tables, table groups, records). All share one AbstractAbility base and register through both WP core's Abilities API and the ACFW (agent-connector-for-wp) integration with audit-log wrapping. Requires WordPress 6.9+ (or the Abilities API feature plugin).
CCT support across Divi, Elementor, Bricks, Breakdance, Yoast, WPML, RankMath, WPGraphQL, WP All Export, WP All Import, GenerateBlocks, WP Grid Builder, SEOPress, and Slim SEO.
FacetWP - new integration indexing ACPT meta fields (including Repeater) for facets.
Divi 5 - Dynamic Tags integration.
Etch - native integration (no external patches required).
Import review step - lists every entity that will be created or updated before committing.
Dynamic Blocks can now be exported and imported.
New Table-field functions: SQRT, ABS, MOD, MEDIAN, COUNT.
New acpt/* action/filter hooks for FacetWP, Elementor Pro, and integration-active checks.
Melhoria
Append_acpt_meta_field_value - append a single Repeater row without resending the others (also the acpt/append-meta-field-value ability).
WPAttachmentFactory - centralised resolution of File / Image / Gallery values (ID, URL, or array) into attachment objects.
CI pipeline (.github/workflows/tests.yml) - ESLint (jsx-a11y), PHPStan level 7, Jest, and a 4-way-sharded PHPUnit matrix on PHP 8.3 / MySQL 8.0.
Boot performance - warm-boot DB queries cut from ~5 to 1 on wp-admin and 0 on the front end: boot-critical options are consistently autoload=true (with a one-time migration), the settings table has its own bootstrap-safe cache, wp_enqueue_media only runs on ACPT's own screens, and the media-library month query is served via WP core's media_library_months_with_files filter. Textdomain loading is deferred to plugins_loaded.
Accessibility (WCAG 2.1 AA) - completed the admin-UI roadmap: keyboard-accessible drag-and-drop with announcements, global focus-visible outlines, accessible Modal / Monaco / Quill editors, corrected colour-contrast tokens (including ::placeholder, Ticket #1210), fixed heading order across wizards and Canvas builders, a WCAG-accessible shared Tooltip and breadcrumb, and numerous screen-reader label fixes (row-action menus, CardRow-wrapped controls, the Permissions matrix). A self-assessed…
PHPStan level 7 - the 227-entry baseline was fully fixed and emptied; src/ stays baseline-free.
Testing - ~2,200 new Jest tests across the whole React admin app (every component, page, and Redux slice) plus further coverage this cycle, fixing dozens of smaller UI bugs along the way. The e2e suite was migrated from Cypress to Playwright (data-cy -> data-testid).
Forms settings UI - General / Email / CSS / Submission Limits tabs and the canvas field-settings sidebar reorganised into grouped, icon-labelled sections, with a syntax-highlighted custom-CSS editor.
Option Pages - first-level pages can be nested under a native WP admin page via a parent_slug.
RTL - consolidated ~25 files' duplicated RTL-detection onto one shared helper and added a dir attribute on the admin app root.
Renamed the "Import data" / "Export data" tools to "Import settings" / "Export settings".
License checks - bounded the boot-time license-validation network call with a 30-minute backoff and shorter timeouts, and honour the dev-mode skip flag.
Release pipeline - release.sh builds with pnpm (matching CI) and fails loudly on any error.
Field / table / column descriptions are sanitised to preserve safe HTML instead of being stripped (rich text is required by the Message field).
Regenerated the hand-maintained assets/static/js/*.min.js for this release.
Segurança
REST API authentication - ACPT_Api_Auth::authenticate only checked that credentials belonged to some valid user, not any capability - any authenticated user (including a Subscriber) could call every "secured" REST v1 route. Now requires manage_options. Reported by Patchstack.
SQL injection - WooCommerce product-data field cleanup concatenated client IDs into a NOT IN (...) clause unescaped; a crafted ID could delete the whole field table. Rebuilt with prepared statements. Reported by Patchstack.
Privilege escalation - a public form submission could set acpt_form_user_id / _post_id / _term_id to update an existing user/post/term with no capability check - an anonymous "create user" form could overwrite an administrator. Added current_user_can checks. Reported by Patchstack. Two follow-up id-extraction bugs in the same code were found and fixed during this release's security regression pass (Tickets #1274 / #1275).
PHP Object Injection - hardened all 30 unserialize / maybe_unserialize call sites to reject embedded objects. Originally reported by Patchstack against 2 of these sites.
Stored XSS - the meta-field sanitizer's allowed-tags list admitted, so wp_kses never stripped it from rich-text output.
13 unsanitised dangerouslySetInnerHTML usages in the admin UI now pass through DOMPurify via a shared DangerousContent component.
REST v1 + Table permissions - the Table Permission System is now enforced on the REST API auth path (Ticket #1206).
Column reorder silently reverting after save (Tickets #1186 / #1187) - the reordered order never reached the save request.
Advanced-mode column drag corrupting the column's database type / repeater nesting (Tickets #1186 / #1195 / #1196) - a reorder in Advanced mode could rewrite a column's DB type to a literal string, or lose repeater nesting.
CCT UI-type to MySQL-type mapper divergence (Tickets #1218 / #1219) - the client and server disagreed on the physical type for several column kinds; the mapping is now server-authoritative. Also fixed column type / UI-type changes being reverted on save.
Options input losing focus after one character (Ticket #1186).
Column sync crash after adopting a table without its real primary key flagged (Ticket #1186); primary-key + nullable column saved without a validation error (Ticket #1197).
Stats panel crash for any table with a Date or Text column (Ticket #1186).
Foreign-key "referenced columns" dropdown empty for tables whose primary key had no UNIQUE index (Ticket #1166); nullable toggle reverting to on after save (Ticket #1166).
Index / foreign-key save & sync - many fixes to index and FK persistence and to the schema-sync executor, including dropping FKs before altering their columns (Tickets #1212 / #1215 / #1216 / #1217 / #1220 / #1221 / #1223), and removing the unsupported SET DEFAULT FK action (Ticket #1222).
Hyphenated table names 404 on the REST API (Ticket #1201).
CCT admin / REST data loss & permission bypass (Tickets #1202 / #1204 / #1205) - partial updates could delete column data, and several endpoints didn't enforce table/group permissions (Ticket #1266).
Incomplete relationship config silently dropped on save (Ticket #1200).
Wizard General tab not reflecting persisted toggle values (Ticket #1224); Indexes-step row delete was a no-op (Ticket #1223); decimal columns rejected fractional values on the record form.
Flexible-Content block reorder on the post-edit screen losing data and fataling the edit screen (Ticket #1241) - four compounding JS bugs; a new reindexFlexibleBlocks routine.
CCT column conditional rendering never evaluated on the record-edit form - a column set to "show only when X" always rendered (Ticket #1307).
CCT column validation rules not enforced server-side and not API-writable; MAX / MIN / REGEX rejected; unguarded hydration could brick a table (Tickets #1238 / #1239 / #1240).
CCT column-level permissions were inert - now enforced via TableColumnModel::userColumnPermissions (Ticket #1242).
Stale sync / cache - assorted CCT sync and cache-staleness gaps closed for stable; the "Flush cache" button now also clears the settings and schema caches (Tickets #1208 / #1213).
Trash / restore counts stale, plus infinite recursion in countRecords on tables without soft delete.
Duplicate success toast after saving a table; "Register table" button label wrong after reload (Ticket #1232).
SaveTableGroupCommand silently ignoring an explicit "unlink all tables" save - submitting a table group with an empty table list left the previous associations in place instead of clearing them.
Meta group editor reliability - a crash when deselecting/deleting a field mid-edit; the wrong field's form state removed in nested repeater/flexible scenarios; location-rule IDs corrupted on every save; two never-wired delete-confirmation modals; several settings-panel bugs.
Colliding auto-generated field names silently breaking saving and disabling the group's Save button (Ticket #1229); the box-name collision guard weakened in the Canvas migration was restored (Tickets #1234 / #1248).
Repeater / Flexible children silently wiped by a partial update that didn't resend children (Tickets #1178 / #1231 / #1233), plus invisible Relationship-field warnings.
Relation fields (Ticket #1178) - a schema mismatch could reject or drop a saved relation; an unconfigured Post relation silently no-op'd.
Get_acpt_fields cross-box field collisions - fields keyed by position within their box, so a later box overwrote an earlier one (Ticket #1174).
getAdvancedOptions index instability - now index-stable via placeholder models; also fixed a restrict_image_extensions key mismatch (Ticket #1235).
"Autoincrement" ID field never got a value outside wp-admin - now generated on save regardless of how the post is created, with a one-time backfill (Ticket #1181). The ID-format contract is enforced in save_acpt_meta_field_value (Ticket #1250).
Site-wide crash from an invalid save-meta-group operator - a belongs rule with an empty operator crashed every later read of that structure; it is now validated on write and tolerated on read (Ticket #1182).
Live conditional rendering - an orphaned Flexible Content reference could fatal the whole live visibility check on every keystroke; also fixed N+1 lookups and duplicate AJAX.
CPT wizard icon field - selecting an icon didn't clear a stale "mandatory" error; Windows menu-icon uploads were broken by a URL-building bug (Tickets #1173 / #1178).
Gallery field losing images on drag-reorder (and Gallery-in-Repeater locating the wrong input); "hide unless this field has a value" never detecting an empty Gallery / Audio (multiple) / Video (multiple) / Image Slider on first render.
Screen-reader label markup leaking into aria-label (Ticket #1178).
FileField fatal on missing advanced options and on a post-less-screen metabox render (Ticket #1211).
An explicit-null required key on a Save*Command (e.g. save_acpt_meta_group(['name' => null])) caused a WSOD - now a graceful validation error (Ticket #1249).
Prefix-overlapping sibling data destroyed - DeleteMetaFieldValueCommand ran an unescaped LIKE ' %' that also matched other fields sharing the prefix; a new keyPredicate scopes the delete (Ticket #1244).
SelectMulti / Checkbox inline value editing now pre-selects and saves a proper array (Ticket #1245); further fixes (Ticket #1246).
An orphaned-role permission row white-screened the entire site, front end included (Ticket #1271).
Custom-role cascade lockout - granting a capability to one custom role could remove it from others, across Table / TableGroup / OptionPage / Taxonomy / MetaField permissions (Ticket #1269).
Field- and column-level permissions were enforced on render only, not on save (Tickets #1242 / #1243).
"Add permission" row rendered every checkbox pre-checked, and toggled state wasn't visible (a CSS sibling selector couldn't reach past the screen-reader span); "Delete all" / single-row Delete never persisted to the server (Tickets #1267 / #1268 / #1270).
TableGroupController never enforced edit/read permissions (Ticket #1266); an OptionPage read-only role could bypass edit via a crafted POST (Ticket #1273).
SavePermissionCommand couldn't clear all permissions - deleteByEntityId ran after the empty-items guard.
Constructing Table permissions threw (create / update missing from $allowedPermissions); a gerPermissionsAsArray typo was fixed; ACPT_Permissions never actually applied saved table/group caps to WP roles.
Crash on first load of the Taxonomy / CPT / Block detail view ("Nothing was returned from render").
CPT / Taxonomy association - a failed association threw a silent JS error instead of showing the toast.
Wizard navigation (Table Group / Taxonomy / CPT / Table) could skip an incomplete step or crash stepping back; wizards mutated shared form state in place, bleeding edits between unrelated fields.
Failed save/action toasts showed a blank message - 58 Redux thunks weren't propagating the failure reason.
Health Check stuck on "running" after a failed request, and checked/created the wrong cache directory.
Export / Import / Settings - stuck loading indicators; Import didn't validate file type/size; Settings' Save button stuck on a stale loading state.
Remount race on the Settings page; added a keepMounted prop (Ticket #1209).
Pagination totals ignored active search / filters across nine list views.
Placeholder / readonly input contrast below WCAG AA (Ticket #1210).
Numerous smaller fixes across form controls, list pages, and shared components, found via the new Jest suite.
Field_key varchar(12) collision - acpt/save-form (and the save_acpt_form_field sibling path) silently collapsed fields whose keys collided after truncation (Ticket #1254).
Front-end form crashes - a Date field with no explicit format fataled the page; front-end.js died on block themes where jQuery loaded after it; the textarea character counter crashed on typing (Tickets #1255 / #1256 / #1261).
Submission 500s - on a null $_FILES entry and on a missing nonce field (Tickets #1257 / #1260).
Saving one form deleted every other form's and every Meta field's validation rules - removeOrphanValidationRules ran WHERE 1=1 (Ticket #1262).
Re-saving a form with a populated fields and no ids deleted every field (Ticket #1263).
The Form Settings editor kept the previous form's key / CSS / meta on an in-app form switch (Ticket #1264).
A non-required field with a format / comparison rule was de-facto mandatory (Ticket #1258); dropped min={0} / max={0} and the redirect timeout had no range validation (Ticket #1265).
Form metadata schema rejected object values, breaking get-form / list-forms for CSS-customised forms (Ticket #1259).
Duplicate / misattributed submission-log rows (a join with no ON clause); a stale Forms list; forms using the "None" action never rendered an opening tag.
CPT "Rewrite" toggle silently disabled when editing a post type whose stored settings predate the rewrite key - saving for any reason persisted rewrite: false and 404'd the CPT (Tickets #1153 / #1160 / #1251). The same bug was fixed for taxonomies (Ticket #1253).
A reserved-slug taxonomy save reported success while persisting nothing (Ticket #1252).
Capabilities_0..3 read unconditionally in TaxonomyController::save - Undefined array key warnings on every taxonomy save without the optional capability selects.
The field group for the product post type leaking onto the WooCommerce attribute edit page.
Elementor (free + Pro) front-end rendering regressions from the PHPStan level-7 pass -: string return-type hints turned echo into return, blank-screening bound fields (Tickets #1286 / #1288 / #1290).
Breakdance / Oxygen 6 - binding a CCT column white-screened the front end (hasParent on null, no try/catch) (Ticket #1284).
Bricks - get_tag_value unguarded $post->ID on term archives (Ticket #1283); a repeater-nested relation to a post type now resolves (Ticket #1228); plus through-relationship tags, query-loop relation fields, and top-level term-archive loop fields.
Divi 5 - CCT columns were unrenderable in dynamic content; Date / Time format override (Tickets #1291 / #1292).
GenerateBlocks - user-context fields in single dynamic tags (Ticket #1294); {acpt.*} record tags were keyed by position, not field name; multi-value media fields (Video / Gallery / Slider / Audio multiple) had no dynamic-tag provider (Ticket #1175).
WP Grid Builder - CCT columns in pickers; a returnValue(array) front-end WSOD guard (Tickets #1295 / #1296).
FacetWP - isActive lost a load-order race and the integration was inert; acpt/ source resolution (Tickets #1297 / #1298).
Slim SEO - an option-page token leak; taxonomy / user variables were never resolved (Tickets #1299 / #1300).
SEOPress - a relational field's array value hit a wp_strip_all_tags TypeError, white-screening the front end; taxonomy / user variables (Tickets #1301 / #1302).
RankMath - a positional-arg %acpt_field(x)% variable fataled the front end (Ticket #1305).
License page unrecoverable after a site migration - an unrecognised stored activation id always rendered the dead "Activate" screen; the error is now surfaced (Ticket #1164). A fatal on every request when license reconciliation can't reach acpt.io from a cloned/staging domain now degrades gracefully.
Logical-operator cleanup (and / or to && / ||) surfaced three real bugs: nested Checkbox field input names, Zion / Yoast staying inactive when only the second plugin variant was installed, and a Divi blog-query check ignoring the property value.
Partial-update data loss across 8 ability families (Table, MetaField, FormField, DynamicBlock, TableGroup, Form, MetaBox, TableRecord) - a payload omitting an optional field silently deleted it; omitting columns on a Table update deleted every column / index / FK definition and the next sync dropped the physical columns. All 8 now merge onto the existing record. OptionPage had the same class of bug on partial save (Ticket #1277).
Save-meta-field never found the field being edited - it matched the wrong data shape, so non-rename edits silently no-op'd and renames created orphan duplicates.
Ability_invalid_output on rest_base - list-* / get-* for any taxonomy / post type with no explicit REST base (e.g. core's post_format); fixed at the read layer so stored data self-heals.
Acpt/save-post-type defaulting capability_type to the post slug - generated meta caps assigned to no role, so the CPT was invisible in wp-admin and rejected every edit. The default is now post (Ticket #1170).
MetaFieldSchema didn't declare label as writable; save_acpt_table could duplicate the ENGINE table option on a partial update.
ACFW boot-order race - its audit-log / MCP decoration silently never applied when both integrations were active; abilities were missing meta.mcp.public, so wordpress/mcp-adapter hosts rejected every call.
Acpt/sync-table and acpt/delete-table* are now flagged destructive (and require DELETE through WP's REST layer).
Inverted import guard - "import into an existing dataset" rejected the only valid case and passed invalid requests to a fatal.
Delete_acpt_option_page($slug, true) never removed the field values (Ticket #1237).
"Delete all" modals (Datasets, Permissions, WooCommerce fields, Meta boxes, Option pages) stuck open after confirming.
XML re-import data loss - an empty value round-tripped as indistinguishable from an empty array and aborted the whole import; .acpt re-import failed on legacy double-escaped / backslash payloads.
Export bugs - CPT / taxonomy lists capped at 20; XML / YAML export of Tables or Forms failed or dropped data; range-selection never worked; bulk CSV export always produced an empty file (a CSVFormatter data-shape mismatch).
Additional axe-core violations fixed in the field / column settings sidebar and across the Canvas builders (nested-interactive select wrappers, focus management), from this release's accessibility regression spot-check (Tickets #1278 / #1279 / #1280 / #1282).
License, plugin-version and ID-field-backfill options queried on every request - These three tracking options were stored with autoload=no, forcing WordPress to issue a dedicated SELECT for each on literally every front-end and admin request instead of folding into its single bulk options query. Now stored autoloaded, with a one-time migration that fixes the flag on sites already storing these from an earlier version.
Settings table queried on every request without ever hitting the plugin's cache - Reading the settings table happens during the plugin's own bootstrap, before its file-based query cache has been initialized, so this specific read could never benefit from it no matter how warm the cache was elsewhere. It now has its own lightweight cache, invalidated whenever a setting is saved.
wp_enqueue_media running on every wp-admin screen - ACPT called WordPress's media-library bootstrap function unconditionally on every admin_enqueue_scripts, triggering a wp_posts query on every wp-admin page for every plugin - not just ACPT's own screens. It's now only called on screens where ACPT actually registered assets.
Media library "date filter" dropdown query re-run on every wp_enqueue_media call - Hooked WordPress core's media_library_months_with_files filter (provided by core specifically to avoid this cost, see core.trac.wordpress.org ticket #31071) to cache the dropdown's month/year data instead of recomputing it with an uncached wp_posts scan every time.
Segurança
REST API authentication - ACPT_Api_Auth::authenticate only verified that Basic Auth credentials or an API key belonged to some valid WordPress user, without checking any capability - any authenticated user (including a Subscriber) could call every "secured" REST v1 route. Now requires manage_options, matching the plugin's own AJAX proxy. Reported by Patchstack.
SQL injection - WooCommerce product-data field cleanup built its DELETE queries by string-concatenating client-supplied IDs into a NOT IN (...) clause with no escaping; a crafted ID could delete every row of the field table, not just orphans. Rebuilt with prepared-statement placeholders. Reported by Patchstack.
Privilege escalation - A public form submission could set a client-controlled acpt_form_user_id/_post_id/_term_id field to update an existing WordPress user/post/term instead of creating a new one, with no ownership or capability check - an anonymous "create new user" form submission could overwrite an administrator account. Added current_user_can checks before any update.
PHP Object Injection - Hardened all 30 unserialize /maybe_unserialize call sites across the plugin (form metadata, relation-field sync, box/field-rename sync, form/block/permission builders, WooCommerce and WP All Import integrations) to reject embedded objects, closing a gadget-chain risk originally reported by Patchstack against 2 of these sites.
Stored XSS - The meta-field sanitizer's allowed-tags list admitted, so wp_kses-based sanitization never actually stripped it from rich-text field output.
Site-wide crash from an invalid save-meta-group operator - A belongs rule with a missing/empty operator could be persisted with an empty value and then crash every subsequent read of that structure (admin, front-end, REST, every Ability) as soon as it was re-hydrated from the database. The operator is now validated and invalid rules are rejected gracefully, both when saving and when reading a pre-existing row (Ticket #1182).
"Autoincrement" ID field never got a value outside wp-admin - An ID-type meta field only ever generated its value inside the wp-admin edit-screen form; a post created via REST, the Abilities API, an import, or wp_insert_post directly permanently had no value for that field. The value is now generated automatically on save regardless of how the post was created, and a one-time migration backfills every already-existing post on update (Ticket #1181).
Get_acpt_fields cross-box field collisions - Fetching every field across a whole meta group (no specific box - the call ACPT's native Etch integration uses for {options.acpt}) could silently drop entire boxes' worth of data: fields were keyed by their position within their own box, which resets to 0 for every box, so a later box's fields overwrote an earlier box's fields at the same position (Ticket #1174).
Gallery field losing images on drag-reorder - Dragging to reorder a Gallery field's images in wp-admin could silently drop entries: the preview only rendered a thumbnail for attachments that still resolved (e.g. not deleted from the media library since being selected), and reordering rebuilt the field's saved value from only the rendered thumbnails, discarding anything without one - occasionally emptying the field entirely. A Gallery field nested inside a Repeater/Flexible block had a second…
Ability_invalid_output on rest_base - list-post-types/list-taxonomies/get-taxonomy could fail output validation for any taxonomy or post type registered without an explicit REST base (e.g. WP core's link_category/post_format), since WP_Taxonomy/WP_Post_Type::$rest_base defaults to the literal boolean false, not string|null as declared. Fixed at the read layer so already-stored data self-heals, not just new syncs.
Acpt/save-post-type defaulting capability_type to the post slug - A settings payload that omitted capability_type explicitly (rather than omitting settings entirely) defaulted it to the post type's own slug, generating meta capabilities never assigned to any role - the resulting CPT was registered but invisible in wp-admin and rejected edits for every role, including administrator. Default is now post, matching WP core (Ticket #1170).
GenerateBlocks Dynamic Data for multi-value media fields - Video (multiple), Gallery, Image Slider, and Audio (multiple) fields had no Dynamic Tag provider and never appeared as usable dynamic data; only their single-value counterparts were supported (Ticket #1175).
Windows image URLs - Image/media field URL-building used DIRECTORY_SEPARATOR (a backslash on Windows) to join URL segments instead of a forward slash, silently breaking meta box saves on Windows hosts (Ticket #1173).
Abilities API architecture - Unified all ~41 abilities under a shared AbstractAbility base class (src/Core/Ability/), registered consistently through both the core WordPress Abilities API and the ACFW (agent-connector-for-wp) integration, with the same exception-handling, permission checks, and audit-log wrapping applied everywhere. Brings along the crash and data-loss fixes below.
Correção
License page stuck unrecoverable after a site migration: when the stored activation id is no longer recognized by the license server (e.g. Activation ID not found), the React app silently discarded the error and always rendered the "Activate your license" screen with a dead (linkless) button, with no way to reach the "Deactivate license" action that would clear the stale local record. The fetch error is now surfaced and routes to the license details screen so it can be deactivated and…
Fatal error on every request when license reconciliation can't reach acpt.io (e.g. cloned/staging domains) - the unguarded API call is now wrapped so a network failure degrades gracefully instead of fataling the whole site (Ticket #1164).
CPT rewrite rules silently disabled when editing existing post types: the "Rewrite" toggle defaulted to unchecked for existing post types whose stored settings lacked an explicit rewrite key, so saving the form for any reason (e.g. just updating the front URL prefix) silently persisted rewrite: false, registering zero rewrite rules and 404ing the CPT - not fixable by flushing permalinks. Also hardens the custom_rewrite/front-URL-prefix priority check so a stale custom_rewrite value can no…
Image/media field values not saving when served from a different host (CDN, offloaded media, image accelerator, etc.) - attachment resolution now falls back to matching on the URL path alone when the host differs from the site's own upload base URL.
Bricks Query Filter showed no checkbox options for POST_TYPE relation fields, and a cold indexer run could produce zero index rows; relational-loop dynamic data tags also resolved against the archive's queried object instead of the loop target.
Site-wide crash (front-end, admin, REST, AJAX) from a missing/empty location-rule operator on save-meta-group - the operator is now validated and invalid rules are rejected gracefully.
Partial updates across 8 ability families (Table, MetaField, FormField, DynamicBlock, TableGroup, Form, MetaBox, TableRecord) were silently deleting data the payload didn't mention - most seriously, omitting columns on a Table update deleted every column/index/foreign-key definition, and the next schema sync then dropped the corresponding database columns. All 8 now merge onto the existing record instead of rebuilding it from scratch.
Save-meta-field matched against the wrong data shape and never actually found the field being edited, so non-rename edits silently no-op'd and renames created orphan duplicates.
ACFW's audit-logging/MCP registration always lost a boot-order race against the core Abilities API integration, so its decoration silently never applied when both were active.
ACPT abilities were missing meta.mcp.public, so the official wordpress/mcp-adapter package (used by ACFW and other MCP host plugins) rejected every call with "not exposed via MCP" even though the ability registered fine.
Integration with the Abilities API, including output-schema fixes for save-post-type and 9 other providers whose output validation was broken.
Append_acpt_meta_field_value function/ability to append a single Repeater row without resending existing ones - new AppendMetaFieldRowCommand, wired into the Abilities API as acpt/append-meta-field-value.
New Table field arithmetic functions: SQRT, ABS, MOD, MEDIAN, COUNT.
New telemetry insight keys (DB engine, multisite, active theme, PHP memory limit, WooCommerce version, feature usage counters) plus a deactivation ping.
Melhoria
Replaced ambiguous has with explicit hasGet /hasPost; all now delegates to requestAll.
Correção
Table field Maths singleton memoization (was comparing flattened data against raw input, so caching never worked); malformed formulas (e.g. =(ROUND("abc",2))) now return a graceful error instead of crashing the live AJAX formula editor.
CodeMirror text overflow in admin meta field editors - long lines/URLs now wrap instead of overflowing the layout.
Etch fatal error when an Image field is nested inside a Repeater (WPAttachment private property access via property_exists ).
Dynamic blocks not appearing/rendering in the FSE site editor.
REST block-renderer live-preview error when inserting a dynamic block in the FSE site editor.
ACPT loop fields empty on Bricks top-level term-archive templates.
Front URL prefix causing 404s on Custom Post Type permalinks (Ticket #1153).
WPML custom field translations getting stuck in one language (Ticket #1118).
Image/Audio/Video/File field values silently not persisting to wp_postmeta via the REST save path: WPAttachment::fromUrl now resolves attachments through query-string, URL-encoding, and -scaled suffix variants instead of only an exact _wp_attached_file match, and ACPT_Api_Rest_Fields::updateCallback now returns a WP_Error when a field fails to save instead of silently discarding the failure.
Added math calculations to Table fields in Bricks builder.
New renderer for relational fields in GenerateBlocks Pro integration.
Gutenberg Gallery Block improvements: Added carousel speed control option.; Added fixed-height option to the mosaic gallery.
Melhoria
Collect all validation errors before persisting meta fields, replacing the previous fail-fast behaviour.
Correção
Correct use of menu_order for custom post type sorting.
Invalidate license on site URL mismatch after domain migration.
Trim slashes from taxonomy rewrite slug to prevent double slashes in rewrite rules.
Added pagination to the post type ↔ taxonomy association pages.
Prevent duplicate rewrite rule when custom_rewrite and front_url_prefix are identical.
Fixed the last carousel slide not being responsive in the Gutenberg Gallery Block.
Correct G:i time format conversion and time picker positioning on first open: Added G (24-hour without leading zero) to convertTimeFormatForJS, mapping to Moment.js H token.; Fixed time picker opening in the wrong position on first render by deferring picker.move with setTimeout(0).; Applies to both Gutenberg and legacy TinyMCE editor contexts.