Skip to content

Commit

Permalink
Merge branch 'html-api/fix-short-funky-comment-detector' into woo-prague
Browse files Browse the repository at this point in the history
  • Loading branch information
dmsnell committed Apr 21, 2024
2 parents 0a9a404 + 0376077 commit c144248
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 22 deletions.
12 changes: 9 additions & 3 deletions src/wp-includes/html-api/class-wp-html-tag-processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -1625,7 +1625,7 @@ private function parse_next_tag() {
* `<!` transitions to markup declaration open state
* https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state
*/
if ( '!' === $html[ $at + 1 ] ) {
if ( ! $this->is_closing_tag && '!' === $html[ $at + 1 ] ) {
/*
* `<!--` transitions to a comment state – apply further comment rules.
* https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state
Expand Down Expand Up @@ -1805,6 +1805,12 @@ private function parse_next_tag() {
* See https://html.spec.whatwg.org/#parse-error-missing-end-tag-name
*/
if ( '>' === $html[ $at + 1 ] ) {
// `<>` is interpreted as plaintext.
if ( ! $this->is_closing_tag ) {
++$at;
continue;
}

$this->parser_state = self::STATE_PRESUMPTUOUS_TAG;
$this->token_length = $at + 2 - $this->token_starts_at;
$this->bytes_already_parsed = $at + 2;
Expand All @@ -1815,7 +1821,7 @@ private function parse_next_tag() {
* `<?` transitions to a bogus comment state – skip to the nearest >
* See https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state
*/
if ( '?' === $html[ $at + 1 ] ) {
if ( ! $this->is_closing_tag && '?' === $html[ $at + 1 ] ) {
$closer_at = strpos( $html, '>', $at + 2 );
if ( false === $closer_at ) {
$this->parser_state = self::STATE_INCOMPLETE_INPUT;
Expand Down Expand Up @@ -1887,7 +1893,7 @@ private function parse_next_tag() {
return false;
}

$closer_at = strpos( $html, '>', $at + 3 );
$closer_at = strpos( $html, '>', $at + 2 );
if ( false === $closer_at ) {
$this->parser_state = self::STATE_INCOMPLETE_INPUT;

Expand Down
51 changes: 51 additions & 0 deletions tests/phpunit/tests/html-api/wpHtmlTagProcessor-token-scanning.php
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,57 @@ public function test_basic_assertion_funky_comment() {
);
}

/**
* Ensures that various funky comments are properly parsed.
*
* @ticket 60170
*
* @since 6.5.6
*
* @covers WP_HTML_Tag_Processor::next_token
*
* @dataProvider data_various_funky_comments
*
* @param string $funky_comment_html HTML containing a funky comment.
* @param string $modifiable_text Expected modifiable text of first funky comment in HTML.
*/
public function test_various_funky_comments( $funky_comment_html, $modifiable_text ) {
$processor = new WP_HTML_Tag_Processor( $funky_comment_html );
while ( '#funky-comment' !== $processor->get_token_type() && $processor->next_token() ) {
continue;
}

$this->assertSame(
'#funky-comment',
$processor->get_token_type(),
'Failed to find the expected funky comment.'
);

$this->assertSame(
$modifiable_text,
$processor->get_modifiable_text(),
'Found the wrong modifiable text span inside a funky comment.'
);
}

/**
* Data provider.
*
* @return array[].
*/
public static function data_various_funky_comments() {
return array(
'Space' => array( '</ >', ' ' ),
'Short-bang' => array( '</!>', '!' ),
'Short-slash' => array( '<//>', '/' ),
'Bit (no attrs)' => array( '<//wp:post-meta>', '/wp:post-meta' ),
'Curly-wrapped' => array( '</{json}>', '{json}' ),
'Before P' => array( '</1><p>', '1' ),
'After P' => array( '<p></__("Read more")></p>', '__("Read more")' ),
'Markup Decl. Like' => array( '</?>', '?' ),
);
}

/**
* Test helper that wraps a string in double quotes.
*
Expand Down
46 changes: 27 additions & 19 deletions tests/phpunit/tests/interactivity-api/wpInteractivityAPI.php
Original file line number Diff line number Diff line change
Expand Up @@ -588,29 +588,37 @@ public function test_process_directives_process_the_directives_in_the_correct_or
* @ticket 60356
*
* @covers ::process_directives
*
* @dataProvider data_html_with_unbalanced_tags
*
* @param string $html HTML containing unbalanced tags and also a directive.
*/
public function test_process_directives_doesnt_change_html_if_contains_unbalanced_tags() {
public function test_process_directives_doesnt_change_html_if_contains_unbalanced_tags( $html ) {
$this->interactivity->state( 'myPlugin', array( 'id' => 'some-id' ) );

$html_samples = array(
'<div data-wp-bind--id="myPlugin::state.id">Inner content</div></div>',
'<div data-wp-bind--id="myPlugin::state.id">Inner content</div><div>',
'<div><div data-wp-bind--id="myPlugin::state.id">Inner content</div>',
'</div><div data-wp-bind--id="myPlugin::state.id">Inner content</div>',
'<div data-wp-bind--id="myPlugin::state.id">Inner<div>content</div>',
'<div data-wp-bind--id="myPlugin::state.id">Inner</div>content</div>',
'<div data-wp-bind--id="myPlugin::state.id"><span>Inner content</div>',
'<div data-wp-bind--id="myPlugin::state.id">Inner content</div></span>',
'<div data-wp-bind--id="myPlugin::state.id"><span>Inner content</div></span>',
'<div data-wp-bind--id="myPlugin::state.id">Inner conntent</ ></div>',
);
$processed_html = $this->interactivity->process_directives( $html );
$p = new WP_HTML_Tag_Processor( $processed_html );
$p->next_tag();
$this->assertNull( $p->get_attribute( 'id' ) );
}

foreach ( $html_samples as $html ) {
$processed_html = $this->interactivity->process_directives( $html );
$p = new WP_HTML_Tag_Processor( $processed_html );
$p->next_tag();
$this->assertNull( $p->get_attribute( 'id' ) );
}
/**
* Data provider.
*
* @return array[].
*/
public static function data_html_with_unbalanced_tags() {
return array(
'DIV closer after' => array( '<div data-wp-bind--id="myPlugin::state.id">Inner content</div></div>' ),
'DIV opener after' => array( '<div data-wp-bind--id="myPlugin::state.id">Inner content</div><div>' ),
'DIV opener before' => array( '<div><div data-wp-bind--id="myPlugin::state.id">Inner content</div>' ),
'DIV closer before' => array( '</div><div data-wp-bind--id="myPlugin::state.id">Inner content</div>' ),
'DIV opener inside' => array( '<div data-wp-bind--id="myPlugin::state.id">Inner<div>content</div>' ),
'DIV closer inside' => array( '<div data-wp-bind--id="myPlugin::state.id">Inner</div>content</div>' ),
'SPAN opener inside' => array( '<div data-wp-bind--id="myPlugin::state.id"><span>Inner content</div>' ),
'SPAN closer after' => array( '<div data-wp-bind--id="myPlugin::state.id">Inner content</div></span>' ),
'SPAN overlapping' => array( '<div data-wp-bind--id="myPlugin::state.id"><span>Inner content</div></span>' ),
);
}

/**
Expand Down

0 comments on commit c144248

Please sign in to comment.