Skip to content

blockVersion: 3 data migration re-triggers on expanded-editor mount → phantom dirty state (partial regression from 6.8.0.1 fix) #1012

@eightam

Description

@eightam

Bug: Expanded editor mount triggers flat→nested data migration / phantom dirty state (blockVersion 3)

Environment

ACF PRO 6.8.0.1
WordPress 6.9.4
Block editor Post editor, iframe mode
Theme / setup Sage 11 / Acorn — ACF blocks registered via block.json with "blockVersion": 3

Summary

ACF PRO 6.8.0.1 fixed a phantom dirty-state bug where selecting a blockVersion: 3 block whose saved data attribute is in the v2 flat shape would trigger a re-serialization into the v3 nested shape, causing Gutenberg to mark the post as having unsaved changes.

That fix covers the selection code path only. The same bug still occurs on the expanded editor mount path: clicking the pencil icon in the block toolbar to open the slide-out sidebar causes ACF to migrate data from flat → nested shape. Because this differs from the saved serialization, Gutenberg marks the post dirty with zero user edits.


Steps to reproduce

  1. Register an ACF block with "blockVersion": 3 in block.json.
  2. Create a new page, add the block, fill in a field, and save.
    The DB now contains the flat v2 shape, e.g.:
    "data": { "data_header": "test", "_data_header": "field_xxx", ... }
  3. Reload the editor.
  4. Click the block → no dirty state(6.8.0.1 fix working as expected)
  5. Click the pencil icon in the block toolbar to open the expanded editor → post is immediately marked dirty

Expected behaviour

No changes to block data until the user actually edits a field.


Actual behaviour

The block's data attribute is rewritten from:

"data": { "data_header": "test", "_data_header": "field_xxx", ... }

to:

"data": { "field_parent": { "field_xxx": "test", ... } }

…with no user input. Gutenberg's dirty detection picks this up as an edit.


Diagnosis

The mutation originates inside acf-pro-blocks.min.js — the call that dirties the post resolves to the minified function be in that file, reached via a React setTimeout from the expanded-editor mount effect. It is the same flat→nested migration that 6.8.0.1 suppressed on selection; the expanded-editor mount path was not covered.

Console output (custom wp.data.subscribe listener watching isEditedPostDirty() and diffing getEditedPostContent())
[dirty] clean → dirty
Dirty entity records: [{kind: 'postType', name: 'page', key: 4179}]
Edits on postType/page/4179: {blocks: Array(1), selection: {…}, content: ƒ}

CONTENT string changed.
First diff at char 57
prev: <!-- wp:acf/statistics {"name":"acf/statistics","data":{"data_subheader":"test","_data_subheader":"field_5f2707babe67d",...
curr: <!-- wp:acf/statistics {"name":"acf/statistics","data":{"field_5f1a9980a7f2d":{"field_5f2707babe67d":"test",...

BLOCK attrs changed: true | META unchanged | Only dirty entity: post itself

Suggested fix

Whatever guard blockVersion: 3 introduced in 6.8.0.1 to prevent re-migrating already-loaded data on selection should be applied at the expanded-editor mount path as well – likely the mount effect inside the expanded sidebar component.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions