AdvancedCustomFields / AdvancedCustomFields/acf
Flexible Content + Tab field: collapsing a newly-added (unsaved) layout throws in _acf-field-tab.js and aborts field init (ACF PRO 6.8.3 / WP 7.0)
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 945
- Forks
- 197
- PR merge metrics
- No merged PRs in 30d
Description
Describe the bug
On WordPress 7.0 + ACF PRO 6.8.3, collapsing a Flexible Content layout that was added in the current (unsaved) editing session throws two uncaught TypeErrors from the core tab-field JS (assets/src/js/_acf-field-tab.js). The first one aborts acf.getFields()'s init loop, so every field rendered after the tab group never initializes, in our case the WYSIWYG sub-fields inside the Flexible Content layouts. The layout can no longer be expanded and its editors are gone until the page is reloaded.
This only affects layouts added client-side in the current session. Collapsing layouts that were rendered server-side (after Save + reload) works perfectly. A field group needs at least one top-level Tab field plus a Flexible Content field to reproduce.
To Reproduce
- Create a field group with a
Tabfield ("Tab A"), a secondTabfield ("Tab B"), and aFlexible Contentfield with one layout containing a singlewysiwygsub-field (minimal JSON below). - Add a new post for the assigned post type.
- In the Flexible Content field, click Add Row and pick the layout.
- Click the new layout's handle to collapse it.
- Open the browser console.
Expected behavior
The layout collapses/expands and the fields inside it (including the WYSIWYG) keep working, exactly as they do for saved / server-rendered layouts.
Screenshots or Video
Both errors fire on the single collapse click:
Uncaught TypeError: Cannot read properties of undefined (reading 'addTab')
at TabField.initialize (acf-input.js)
at acf.newField -> acf.getField -> acf.getFields -> doAction()
Uncaught TypeError: Cannot read properties of undefined (reading 'get')
at render -> getTabs().map() (the tab-fields manager)
at doAction('append' | 'show' | 'refresh')
Code
Minimal repro field group:
{
"key": "group_repro_tab_fc",
"title": "Repro - tabs + flexible content",
"fields": [
{ "key": "field_repro_tab_a", "label": "Tab A", "name": "", "type": "tab", "placement": "top" },
{ "key": "field_repro_text_a", "label": "Text A", "name": "text_a", "type": "text" },
{ "key": "field_repro_tab_b", "label": "Tab B", "name": "", "type": "tab", "placement": "top" },
{ "key": "field_repro_fc", "label": "Blocks", "name": "blocks", "type": "flexible_content", "button_label": "Add Row",
"layouts": {
"layout_repro_text": {
"key": "layout_repro_text", "name": "text", "label": "Text", "display": "block",
"sub_fields": [
{ "key": "field_repro_body", "label": "Body", "name": "body", "type": "wysiwyg", "tabs": "all", "toolbar": "basic", "media_upload": 0 }
]
}
}
}
],
"location": [[{ "param": "post_type", "operator": "==", "value": "post" }]]
}
Version Information:
- WordPress 7.0
- PHP 8.4
- ACF PRO 6.8.3
- Chrome 148 (macOS). Reproduces with a stock theme; our theme JS does not touch ACF or TinyMCE.
Additional context - root cause (pinpointed to assets/src/js/_acf-field-tab.js)
After the collapse, a .acf-tab-wrap element stays in the DOM but loses its group instance: $wrap.data('acf') is now undefined. Two paths then dereference it.
TabField.initialize()runs again (collapse ->doAction->acf.getFields()->acf.newField->initialize). With a preceding wrap present it takes the "reuse" branch:
// L84-L91
if ( ! $tabs.length || settings.endpoint ) {
this.tabs = new Tabs( settings );
} else {
this.tabs = $tabs.data( 'acf' ); // L87 -> undefined (orphaned wrap)
}
this.tab = this.tabs.addTab( $tab, this ); // L91 -> throws: undefined.addTab
The throw is uncaught, so the enclosing getFields().map() loop aborts and no field after the tab group initializes. This is what kills the WYSIWYG editors.
- The tab-fields manager re-renders on
append/show/refreshand maps over every wrap in the document:
// L525-L534
getTabs: function () {
return acf.getInstances( this.findTabs() ); // L526 -> array containing undefined
},
render: function ( $el ) {
this.getTabs().map( function ( tabs ) {
if ( ! tabs.get( 'initialized' ) ) { // L531 -> throws: undefined.get
tabs.initializeTabs();
}
} );
},
Important: I tried defensively guarding both sites (try/catch around initialize, and filtering falsy values out of getInstances). That silences both console errors, but it does not restore the editors or the collapse/expand behaviour, the form state is already corrupted by then. So the underlying issue is that the PRO Flexible Content collapse / re-render leaves a .acf-tab-wrap without its data('acf') group (it should keep it bound, or re-bind on re-render). L87/L91 and L526/L531 are only where it surfaces; null-guarding them would mask the symptom, not fix it.
Possibly related: #986 (Flexible Content expand/collapse state).
Notes:
- The console line that often co-occurs,
Failed to load plugin url: .../wp-includes/js/tinymce/langs/<locale>.js, is unrelated and cosmetic: ACF already printstinymce.ScriptLoader.markDone(...)for that URL. The editor breakage is the tab crash above, not the TinyMCE language file. - Also reproduces with the post type's
editorsupport removed and a non-enadmin locale, but neither is required for the crash.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with assets/src/js/_acf-field-tab.js, especially TabField.initialize() and the tab-fields manager's getTabs() and render() paths, then reproduce the issue with the supplied minimal field-group JSON. Trace the Flexible Content collapse and re-render lifecycle to determine why the tab wrapper loses its group instance. Done means a newly added layout collapses and expands without either TypeError, and its WYSIWYG fields still initialize and work.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 58/100