Problem/Motivation

A mapped field whose block has inner blocks is saved with its markup out of order. Every inner block comes out before its parent's markup, and the parent's own markup is left behind as an empty shell. Lists show it most clearly: since lists are stored as core/list with core/list-item inner blocks, a mapped list is saved as orphaned <li>s followed by an empty <ul>, so the front end renders bullets with no list around them.
The cause is MappingFieldsHelper::getInnerHtmlRecursive(), added in #3152047. It walks the block array with a RecursiveIteratorIterator and collects every innerHTML value it meets. In a parsed block, innerBlocks comes before innerHTML, so the children are collected first. The parent's innerHTML also has its inner blocks removed, so all that is left of it is the wrapper.

Steps to reproduce

  1. Add a formatted text field field_summary to a Gutenberg-enabled content type.
  2. Use the rich text mapping from the Field Mapping docs in the content type's template:
    [
      ["core/group", {"mappingFields": [{"field": "field_summary", "property": "value", "text_format": "full_html"}]}]
    ]
  3. Create a node, and add a paragraph and a bulleted list with two items inside the group. Save.
  4. Look at the stored field_summary value.

Expected:

<div class="wp-block-group">
<p>Intro</p>
<ul class="wp-block-list">
<li>One</li>
<li>Two</li>
</ul>
</div>

Actual:

<p>Intro</p>
<li>One</li>
<li>Two</li>
<ul class="wp-block-list">
</ul>
<div class="wp-block-group">
</div>

Both outputs are from running the parser and getInnerHtmlRecursive() on the same block markup. Blank lines are trimmed.
We saw this on a production site after upgrading from 2.14 to 3.0.x: every node saved with a list in a mapped block got the broken markup. The editor still looks correct, because the body is fine; only the mapped field is wrong.

Proposed resolution

Rebuild the markup from innerContent. It holds the block's own markup with a NULL where each inner block sits, in order. That's how WordPress's serialize_block() and render_block() put a block back together. Replace each NULL with the matching inner block, recursively. Blocks without inner blocks give the same result as before.

Remaining tasks

  • Review.
  • Add a test. There is no test coverage for field mapping yet; see #3404460.

User interface changes

None

API changes

None

Data model changes

None. values that were already saved stay broken until the node's body is saved with changes. Sites can rebuild them by running getMappedValuesFromContent() on the body again.

Issue fork gutenberg-3632111

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

doxigo created an issue. See original summary.

doxigo’s picture

Issue summary: View changes

doxigo’s picture

Assigned: Unassigned » doxigo
Issue summary: View changes
Status: Active » Needs review