Block Editor: Prevent inner block template from re-inserting when a block is moved via drag and drop - #80679
Block Editor: Prevent inner block template from re-inserting when a block is moved via drag and drop#80679dpmehta wants to merge 3 commits into
Conversation
… re-insertion after remounts.
|
Warning: Type of PR label mismatch To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.
Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task. |
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
What?
Closes #70495
This PR fixes a bug where inner blocks that the user deliberately removed are unexpectedly re-inserted when the parent block (e.g. Details, Quote, Media & Text) is moved via drag and drop. After moving the block, inner blocks reappear as if the user never deleted them.
Why?
useInnerBlockTemplateSyncrelies on auseRef(null)to track whether the template has already been applied. SinceuseRefis tied to the React component instance, it resets tonullevery time the component is destroyed and recreated, which is exactly what happens during a drag-and-drop move.On remount, two conditions happen to be true simultaneously:
currentInnerBlocks.length === 0, because the user already deleted the inner blockshasTemplateChangedistrue, becauseexistingTemplateRef.currentisnullagain after the remountBoth guards pass,
replaceInnerBlocksis called, and the deleted blocks come back. This affects any block that usesuseInnerBlocksPropswith atemplatebut without atemplateLock, confirmed on Details, Quote, and Media & Text blocks.How?
We followed the existing pattern already used by useNestedSettingsUpdate + blockListSettings in the block-editor store: state that must survive React component remounts should live in the Redux store keyed by
clientId, not in auseRef.syncedTemplateClientIdsreducer (aSet<string>) to the block-editor store. It tracks which block clientIds have had their template applied at least once. The key design decision is that the reducer intentionally ignoresMOVE_BLOCKS_TO_POSITION, so the flag survives a drag-and-drop but cleans up onREMOVE_BLOCKS,REPLACE_BLOCKS, andRESET_BLOCKS.markTemplateSyncApplied( clientId )dispatched after the first successful template application.wasTemplateSyncApplied( state, clientId )to read from the Set.useInnerBlockTemplateSyncto read the store flag and skip re-applying the template when the block is unlocked and the flag is already set, preventing the unexpected re-insertion on remount.The fix is scoped only to unlocked templates (
templateLockis not'all'or'contentOnly'), so locked template behaviour is completely unchanged.Testing Instructions
Screenshots or screencast
Before Fix :
Screen.Capture.on.2025-06-20.at.17-21-00.2.mov
After Fix :
after-fix.mov
Use of AI Tools
Claude was used to investigate the issue, figure out existing pattern, implement the fix, and documentation. The changes were reviewed and validated.