HTML API: Fix void tag nesting with next_token

When `next_token()` was introduced, it introduced a regression in the HTML
Processor whereby void tags remain on the stack of open elements when they
shouldn't. This led to invalid values returned from `get_breadcrumbs()`.

The reason was that calling `next_token()` works through a different code path
than the HTML Processor runs everything else. To solve this, its sub-classed
`next_token()` called `step( self::REPROCESS_CURRENT_TOKEN )` so that the proper
HTML accounting takes place.

Unfortunately that same reprocessing code path skipped the step whereby void
and self-closing elements are popped from the stack of open elements.

In this patch, that step is run with a third mode for `step()`, which is the
new `self::PROCESS_CURRENT_TOKEN`. This mode acts as if `self::PROCESS_NEXT_NODE`
were called, except it doesn't advance the parser.

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

Follow-up to [57348]

Props dmsnell, jonsurrell
Fixes #60382



git-svn-id: https://develop.svn.wordpress.org/trunk@57507 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Dennis Snell
2024-02-01 00:41:40 +00:00
parent 4a2aa99d51
commit cdb218b200
2 changed files with 66 additions and 2 deletions

View File

@@ -188,6 +188,59 @@ class Tests_HtmlApi_WpHtmlProcessor extends WP_UnitTestCase {
);
}
/**
* Ensure non-nesting tags do not nest when processing tokens.
*
* @ticket 60382
*
* @dataProvider data_void_tags
*
* @param string $tag_name Name of void tag under test.
*/
public function test_cannot_nest_void_tags_next_token( $tag_name ) {
$processor = WP_HTML_Processor::create_fragment( "<{$tag_name}><div>" );
/*
* This HTML represents the same as the following HTML,
* assuming that it were provided `<img>` as the tag:
*
* <html>
* <body>
* <img>
* <div></div>
* </body>
* </html>
*/
$found_tag = $processor->next_token();
if ( WP_HTML_Processor::ERROR_UNSUPPORTED === $processor->get_last_error() ) {
$this->markTestSkipped( "Tag {$tag_name} is not supported." );
}
$this->assertTrue(
$found_tag,
"Could not find first {$tag_name}."
);
$this->assertSame(
array( 'HTML', 'BODY', $tag_name ),
$processor->get_breadcrumbs(),
'Found incorrect nesting of first element.'
);
$this->assertTrue(
$processor->next_token(),
'Should have found the DIV as the second tag.'
);
$this->assertSame(
array( 'HTML', 'BODY', 'DIV' ),
$processor->get_breadcrumbs(),
"DIV should have been a sibling of the {$tag_name}."
);
}
/**
* Data provider.
*