Skip to content

Commit bc07e58

Browse files
committed
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: #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. git-svn-id: https://develop.svn.wordpress.org/branches/6.9@61530 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 14a0f45 commit bc07e58

File tree

2 files changed

+137
-0
lines changed

2 files changed

+137
-0
lines changed

src/wp-includes/class-wp-block-processor.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,6 +1295,17 @@ public function extract_full_block_and_advance(): ?array {
12951295
$block['innerBlocks'][] = $inner_block;
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

13001311
return $block;

tests/phpunit/tests/block-processor/wpBlockProcessor.php

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,6 +1296,132 @@ public function test_scans_directly_to_requested_block_type( string $html, strin
12961296
);
12971297
}
12981298

1299+
/**
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 -->
1362+
HTML
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 -->
1375+
HTML
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 -->
1393+
HTML
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 -->
1406+
HTML
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 -->
1420+
HTML
1421+
,
1422+
);
1423+
}
1424+
12991425
/**
13001426
* Data provider.
13011427
*

0 commit comments

Comments
 (0)