Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTML API: Fix - avoid calling subclass method while internally scanning in Tag Processor #5475

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions src/wp-includes/html-api/class-wp-html-tag-processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -2270,6 +2270,7 @@ public function __toString() {
*
* @since 6.2.0
* @since 6.2.1 Shifts the internal cursor corresponding to the applied updates.
* @since 6.5.0 No longer calls subclass method `next_tag()` after updating HTML.
*
* @return string The processed HTML.
*/
Expand Down Expand Up @@ -2303,24 +2304,23 @@ public function get_updated_html() {
* Rewind before the tag name starts so that it's as if the cursor didn't
* move; a call to `next_tag()` will reparse the recently-updated attributes
* and additional calls to modify the attributes will apply at this same
* location.
* location, but in order to avoid issues with subclasses that might add
* behaviors to `next_tag()`, the internal methods should be called here
* instead. It's important to note that in this specific place there will
* be no change because the processor was already at a tag when this was
* called and it's rewinding only to the beginning of this very tag before
* reprocessing it and its attributes.
*
* <p>Previous HTML<em>More HTML</em></p>
* ^ | back up by the length of the tag name plus the opening <
* \<-/ back up by strlen("em") + 1 ==> 3
* ↑ │ back up by the length of the tag name plus the opening <
* └←─┘ back up by strlen("em") + 1 ==> 3
*/

// Store existing state so it can be restored after reparsing.
$previous_parsed_byte_count = $this->bytes_already_parsed;
$previous_query = $this->last_query;

// Reparse attributes.
$this->bytes_already_parsed = $before_current_tag;
$this->next_tag();

// Restore previous state.
$this->bytes_already_parsed = $previous_parsed_byte_count;
$this->parse_query( $previous_query );
$this->parse_next_tag();
// Reparse the attributes.
while ( $this->parse_next_attribute() ) {
continue;
}

return $this->html;
}
Expand Down
43 changes: 43 additions & 0 deletions tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,49 @@ public function test_finds_correct_tag_given_breadcrumbs( $html, $breadcrumbs, $
$this->assertTrue( $p->get_attribute( 'target' ), "Found {$p->get_tag()} element didn't contain the necessary 'target' attribute." );
}

/**
* Ensures that updates to a tag's attributes doesn't shift
* the current position into the input HTML document.
*
* @ticket 59607
*/
public function test_remains_stable_when_editing_attributes() {
$p = WP_HTML_Processor::create_fragment( '<div><button>First<button><b here>Second' );
$p->next_tag( array( 'breadcrumbs' => array( 'BUTTON', 'B' ) ) );

$this->assertSame(
array( 'HTML', 'BODY', 'DIV', 'BUTTON', 'B' ),
$p->get_breadcrumbs(),
'Found the wrong nested structure at the matched tag.'
);

$p->set_attribute( 'a-name', 'a-value' );

$this->assertTrue(
$p->get_attribute( 'here' ),
'Should have found the B tag but could not find expected "here" attribute.'
);

$this->assertSame(
array( 'HTML', 'BODY', 'DIV', 'BUTTON', 'B' ),
$p->get_breadcrumbs(),
'Found the wrong nested structure at the matched tag.'
);

$p->get_updated_html();

$this->assertTrue(
$p->get_attribute( 'here' ),
'Should have stayed at the B tag but could not find expected "here" attribute.'
);

$this->assertSame(
array( 'HTML', 'BODY', 'DIV', 'BUTTON', 'B' ),
$p->get_breadcrumbs(),
'Found the wrong nested structure at the matched tag after updating attributes.'
);
}

/**
* @ticket 58517
*
Expand Down