Make WordPress Core

Changeset 61530


Ignore:
Timestamp:
01/26/2026 04:28:52 PM (6 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.