Make WordPress Core

Changeset 61530


Ignore:
Timestamp:
01/26/2026 04:28:52 PM (2 months ago)
Author:
jonsurrell
Message:

Blocks: Ensure extract_full_block_and_advance() matches parse_blocks()

The behavior of WP_Block_Processor::extract_full_block_and_advance() should produce an identical output to what parse_blocks() would return on the same substring of input.

Unfortunately, when HTML spans followed inner blocks, they were being omitted in the output parse tree. This was due to an omission in the original code which would look for those blocks before advancing again after calling extract_full_block_and_advance() recursively.

This patch adds the missing check and resolves the discrepancy.

Developed in: https://github.com/WordPress/wordpress-develop/pull/10769
Discussed in: https://core.trac.wordpress.org/ticket/64538

Follow-up to [60939].

Reviewed by jonsurrell.
Merges [61509] to the 6.9 branch.

Props dmsnell, jonsurrell, jorbin.
Fixes #64537.

Location:
branches/6.9
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/6.9

  • branches/6.9/src/wp-includes/class-wp-block-processor.php

    r61528 r61530  
    12961296                $block['innerContent'][] = null;
    12971297            }
     1298
     1299            /*
     1300             * Because the parser has advanced past the closing block token, it
     1301             * may be matched on an HTML span. This needs to be processed before
     1302             * moving on to the next token at the start of the next loop iteration.
     1303             */
     1304            if ( $this->is_html() ) {
     1305                $chunk                   = $this->get_html_content();
     1306                $block['innerHTML']     .= $chunk;
     1307                $block['innerContent'][] = $chunk;
     1308            }
    12981309        }
    12991310
  • branches/6.9/tests/phpunit/tests/block-processor/wpBlockProcessor.php

    r61528 r61530  
    12981298
    12991299    /**
     1300     * Ensures that block extraction matches the behavior of the default block parser.
     1301     *
     1302     * @ticket 64537
     1303     *
     1304     * @dataProvider data_various_block_posts
     1305     *
     1306     * @param string $test_document An HTML document to parse as blocks.
     1307     */
     1308    public function test_extracts_equivalent_parses_as_parse_blocks( string $test_document ) {
     1309        $processor = new WP_Block_Processor( $test_document );
     1310        $blocks    = array();
     1311
     1312        while ( $processor->next_block( '*' ) ) {
     1313            $blocks[] = $processor->extract_full_block_and_advance();
     1314        }
     1315
     1316        $this->assertSame(
     1317            parse_blocks( $test_document ),
     1318            $blocks,
     1319            'Failed to properly parse the block structure.'
     1320        );
     1321    }
     1322
     1323    /**
     1324     * Data provider.
     1325     *
     1326     * @return Generator
     1327     */
     1328    public static function data_various_block_posts() {
     1329        yield 'Empty post' => array( '' );
     1330
     1331        yield 'Void block' => array( '<!-- wp:void /-->' );
     1332
     1333        yield 'Empty block' => array( '<!-- wp:empty --><!-- /wp:empty -->' );
     1334
     1335        yield 'Paragraph block' => array( '<!-- wp:paragraph --><p>Test</p><!-- /wp:paragraph -->' );
     1336
     1337        yield 'Paragraph block with attributes' => array(
     1338            '<!-- wp:paragraph {"dropCaps": true} --><p>Test</p><!-- /wp:paragraph -->',
     1339        );
     1340
     1341        yield 'Group with void inner' => array(
     1342            '<!-- wp:group --><!-- wp:void /--><!-- /wp:group -->',
     1343        );
     1344
     1345        /*
     1346         * @todo There is a hidden bug in here, which is possibly a problem in
     1347         *       the default parser. There are HTML spans of newlines between
     1348         *       these block delimiters, and without them, the parse doesn’t
     1349         *       match `parse_blocks()`. However, `parse_blocks()` is inconsistent
     1350         *       in its behavior. Whereas it produces an empty text chunk here,
     1351         *       in the case of a void inner block it produces none. The test is
     1352         *       being adjusted to step around this issue so that it can be resolved
     1353         *       separately, and until it’s clear if there is an implementation issue
     1354         *       with `parse_blocks()` itself.
     1355         */
     1356        yield 'Empty columns' => array(
     1357            <<<HTML
     1358            <!-- wp:columns -->
     1359            <!-- wp:column -->
     1360            <!-- /wp:column -->
     1361            <!-- /wp:columns -->
     1362HTML
     1363            ,
     1364        );
     1365
     1366        yield 'Contentful columns' => array(
     1367            <<<HTML
     1368            <!-- wp:columns -->
     1369            <ul>
     1370            <!-- wp:column -->
     1371            <li>A good point.</li>
     1372            <!-- wp:column /-->
     1373            </ul>
     1374            <!-- /wp:columns -->
     1375HTML
     1376            ,
     1377        );
     1378
     1379        yield 'Group with mixed content' => array(
     1380            <<<HTML
     1381            <!-- wp:group -->
     1382            <div>
     1383            <!-- wp:paragraph --><p>Test</p><!-- /wp:paragraph -->
     1384            This is freeform.
     1385            <!-- wp:void /-->
     1386            End
     1387            <!-- wp:footer -->
     1388            <footer>That&rsquo;s it!</footer>
     1389            <!-- /wp:footer -->
     1390            <!-- wp:another-void /-->
     1391            </div>
     1392            <!-- /wp:group -->
     1393HTML
     1394            ,
     1395        );
     1396
     1397        yield 'Nested blocks' => array(
     1398            <<<HTML
     1399            <!-- wp:a -->
     1400            <div>
     1401            <!-- wp:b -->
     1402            <span><!-- wp:c /--></span>
     1403            <!-- /wp:b -->
     1404            </div>
     1405            <!-- /wp:a -->
     1406HTML
     1407            ,
     1408        );
     1409
     1410        yield 'Attributes on nested blocks' => array(
     1411            <<<HTML
     1412            <!-- wp:b1 -->
     1413            <!-- wp:b2 {} -->
     1414            <!-- wp:b3 {"id":"going"} -->
     1415            <!-- wp:b4 {"id":"down"} -->
     1416            <!-- /wp:b4 -->
     1417            <!-- /wp:b3 -->
     1418            <!-- /wp:b2 -->
     1419            <!-- /wp:b1 -->
     1420HTML
     1421            ,
     1422        );
     1423    }
     1424
     1425    /**
    13001426     * Data provider.
    13011427     *
Note: See TracChangeset for help on using the changeset viewer.