Opened 3 hours ago
Last modified 3 hours ago
#65958 new defect (bug)
Reordering a meta box destroys any TinyMCE editor inside it
| Reported by: | sanket.parmar | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Awaiting Review |
| Component: | Administration | Version: | 7.1 |
| Severity: | major | Keywords: | has-patch |
| Cc: | Focuses: |
Description
Pressing a meta box's Move up / Move down arrow destroys any TinyMCE editor rendered inside that box with wp_editor(). The editor goes blank on screen, its content becomes unreachable, and switching Visual/Text afterwards throws an uncaught TypeError.
This is core-only. It needs no plugins and does not depend on the block editor.
Cause
postboxes.handleOrderBetweenSortables() relocates the box across containers with detach() + appendTo()/prependTo() — see wp-admin/js/postbox.js lines 181–189. Re-inserting a subtree that contains an <iframe> makes the browser give that iframe a brand-new, empty document. TinyMCE keeps a reference to the discarded one, so editor.getDoc() and iframe.contentDocument are no longer the same object, and every subsequent operation acts on a document that is not on screen.
handleOrder() also reorders within a single container using .before() and .after() (lines 129 and 143). That is the same re-insertion, so it should break the same way — I have not tested that path.
Note the guard at line 173:
// Return if there's only one visible sortables area, e.g. in the block editor page.
On a current block editor screen there are three visible sortables areas (normal-sortables, advanced-sortables, side-sortables), so the guard does not fire and a lone meta box hops containers on the first arrow press.
Steps to reproduce
- Drop this in
wp-content/mu-plugins/:
<?php add_action( 'add_meta_boxes', function () { add_meta_box( 'my-custom-metabox', 'Custom Meta', 'demo_metabox_cb' ); } ); function demo_metabox_cb( $post ) { wp_editor( get_post_meta( $post->ID, 'my-custom-meta', true ), 'my-custom-meta' ); }
- Open Posts → Add New, expand the Meta Boxes panel, and type some text into the Custom Meta editor on the Visual tab.
- Press the meta box's Move down arrow.
- The editor is now blank.
- Click Text, then Visual.
Expected
Reordering a meta box leaves the editors inside it working, with their content intact.
Actual
The editor is blank from step 3 on, and step 5 throws:
Uncaught TypeError: Cannot read properties of null (reading 'setBaseAndExtent')
at Object.select (tinymce.min.js:2:293163)
at _ (editor.min.js?ver=7.1:2:5063)
at n (editor.min.js?ver=7.1:2:1731)
Measured either side of step 3 with:
const ed = tinymce.get( 'my-custom-meta' ); const ifr = document.getElementById( 'my-custom-meta_ifr' ); ( { parent: document.getElementById( 'my-custom-metabox' ).parentElement.id, sameDoc: ed.getDoc() === ifr.contentDocument, iframeBody: ifr.contentDocument.body.innerHTML, content: ed.getContent(), } )
| ' | Before | After |
| postbox parent | normal-sortables | advanced-sortables
|
getDoc() === contentDocument | true | false
|
| iframe body | <p>…</p> | ""
|
getContent() | <p>…</p> | <p>…</p> (stranded)
|
Environment
WordPress 7.1, Chrome 151, macOS. Reproduced both with the block editor and with Classic Editor 1.7.0 and classic-editor-replace = classic, i.e. with the block editor entirely out of the page.
Related
Very likely the underlying cause of the setBaseAndExtent reports on #62450. That ticket is framed as a Firefox-only failure to initialise on the Visual tab, but the comments that reopened it describe this exact symptom — content disappearing on Visual/Text switching with can't access property "setBaseAndExtent", n is null — from users of ACF/SCF/JetEngine WYSIWYG fields, which render wp_editor() inside meta boxes and relocate their wrappers in the DOM.
I have not shown that this explains the original Firefox initialise-on-Visual report, and I have only tested Chrome, so I am filing separately rather than assuming they are one bug.
Originally surfaced from Gutenberg #74627.
Change History (2)
This ticket was mentioned in PR #13262 on WordPress/wordpress-develop by @sanket.parmar.
3 hours ago
#1
- Keywords has-patch added
#2
@
3 hours ago
Patch: https://github.com/WordPress/wordpress-develop/pull/13262
The iframe reset can't be prevented once the box is re-inserted, so the editors are re-hydrated around the move instead, and postbox.js stays editor-agnostic.
The move handlers (handleOrder and handleOrderBetweenSortables) now fire the existing postbox-moved event on the arrow paths too. A new listener in wp-admin/js/editor.js responds: for each wp_editor() in the moved box it saves the content, removes the stale TinyMCE instance, and re-initialises it from tinyMCEPreInit in the same mode. Code-mode editors just get the stale instance dropped so the next Visual switch re-initialises cleanly.
This covers the Move up / Move down arrows (both within an area and across areas) and the existing cross-area drag, which already fires postbox-moved.
Verified on a wp_editor() meta box: after reordering, the editor keeps its content and the Visual/Code switch no longer throws.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
## Trac ticket
https://core.trac.wordpress.org/ticket/65958
## What
Moving a meta box re-inserts its DOM subtree; when the box holds a
wp_editor()TinyMCE editor, the re-inserted iframe is reset and TinyMCE keeps a stale reference, so the editor goes blank and the next Visual/Code switch throws.postbox.jsnow fires the existingpostbox-movedevent on the Move up/down paths (it already fires on cross-area drag). A listener ineditor.jsre-initialises each editor in the moved box — save content, remove the stale instance, re-init in the same mode — keepingpostbox.jseditor-agnostic.## Test
grunt jshint:core— 98 files lint freewp_editor()meta box, type in Visual, Move up/down: editor keeps its content,getDoc() === iframe.contentDocumentstays true, no console errorsetBaseAndExtentTypeError## Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 4.8
Used for: root-cause analysis, implementation, and local verification