From 2673ae46b78fa6f65a7f695b7d4786a4f16c1724 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 30 Jun 2026 21:22:43 +0200 Subject: [PATCH 1/3] HTML API: Avoid creating self-closing flags when removing attributes --- .../html-api/class-wp-html-tag-processor.php | 49 ++++++- .../tests/html-api/wpHtmlProcessor.php | 94 +++++++++++++ .../tests/html-api/wpHtmlTagProcessor.php | 130 ++++++++++++++++++ 3 files changed, 267 insertions(+), 6 deletions(-) diff --git a/src/wp-includes/html-api/class-wp-html-tag-processor.php b/src/wp-includes/html-api/class-wp-html-tag-processor.php index 3c849047a9a51..73d848d91cde3 100644 --- a/src/wp-includes/html-api/class-wp-html-tag-processor.php +++ b/src/wp-includes/html-api/class-wp-html-tag-processor.php @@ -2576,9 +2576,12 @@ private function apply_attributes_updates( int $shift_this_point ): int { $accumulated_shift_for_given_point += $shift; } - $output_buffer .= substr( $this->html, $bytes_already_copied, $diff->start - $bytes_already_copied ); + if ( $diff->start > $bytes_already_copied ) { + $output_buffer .= substr( $this->html, $bytes_already_copied, $diff->start - $bytes_already_copied ); + } + $output_buffer .= $diff->text; - $bytes_already_copied = $diff->start + $diff->length; + $bytes_already_copied = max( $bytes_already_copied, $diff->start + $diff->length ); } $this->html = $output_buffer . substr( $this->html, $bytes_already_copied ); @@ -4544,17 +4547,27 @@ public function remove_attribute( $name ): bool { * * Result:
*/ - $this->lexical_updates[ $name ] = new WP_HTML_Text_Replacement( + $attribute_removal = $this->get_attribute_removal_span( $this->attributes[ $name ]->start, - $this->attributes[ $name ]->length, + $this->attributes[ $name ]->length + ); + + $this->lexical_updates[ $name ] = new WP_HTML_Text_Replacement( + $attribute_removal->start, + $attribute_removal->length, '' ); // Removes any duplicated attributes if they were also present. foreach ( $this->duplicate_attributes[ $name ] ?? array() as $attribute_token ) { - $this->lexical_updates[] = new WP_HTML_Text_Replacement( + $attribute_removal = $this->get_attribute_removal_span( $attribute_token->start, - $attribute_token->length, + $attribute_token->length + ); + + $this->lexical_updates[] = new WP_HTML_Text_Replacement( + $attribute_removal->start, + $attribute_removal->length, '' ); } @@ -4562,6 +4575,30 @@ public function remove_attribute( $name ): bool { return true; } + /** + * Returns the full span to remove for an attribute. + * + * Slash characters may be used as attribute separators, as in `
`. + * If an attribute following those separators is removed without removing the + * slash, then the remaining slash can become a self-closing flag. + * + * @since 7.1.0 + * + * @param int $start Byte offset where the attribute starts. + * @param int $length Byte length of the attribute. + * @return WP_HTML_Span Full span to remove. + */ + private function get_attribute_removal_span( int $start, int $length ): WP_HTML_Span { + $tag_name_ends_at = $this->tag_name_starts_at + $this->tag_name_length; + + while ( $start > $tag_name_ends_at && '/' === $this->html[ $start - 1 ] ) { + --$start; + ++$length; + } + + return new WP_HTML_Span( $start, $length ); + } + /** * Adds a new class name to the currently matched tag. * diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php index 8cece32438bd3..4836b4ffd807d 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php @@ -606,6 +606,100 @@ public function test_unquoted_slash_attribute_does_not_self_close_foreign_conten ); } + /** + * Ensures that removing an attribute after a slash separator doesn't self-close foreign content. + * + * @covers ::remove_attribute + * + * @dataProvider data_remove_attribute_after_slash_separator_preserves_foreign_content + * + * @param string $html HTML containing a foreign element with an attribute after a slash separator. + * @param string $tag_name Foreign element tag name to modify. + * @param string $updated_html Expected updated HTML. + * @param string $normalized_html Expected normalized HTML after reparsing the updated HTML. + */ + public function test_remove_attribute_after_slash_separator_preserves_foreign_content( $html, $tag_name, $updated_html, $normalized_html ) { + $processor = WP_HTML_Processor::create_fragment( $html ); + + $this->assertTrue( $processor->next_tag( $tag_name ), "Failed to find the {$tag_name} tag: check test setup." ); + $this->assertFalse( $processor->has_self_closing_flag(), 'Test setup should not include a self-closing flag.' ); + $this->assertTrue( $processor->expects_closer(), 'Test setup should expect a closing tag.' ); + + $this->assertTrue( $processor->remove_attribute( 'b' ), 'Could not remove the target attribute.' ); + + $this->assertSame( + $updated_html, + $processor->get_updated_html(), + 'Removing the attribute should not leave a slash that turns into a self-closing flag.' + ); + $this->assertFalse( $processor->has_self_closing_flag(), 'Removing the attribute should not create a self-closing flag.' ); + $this->assertTrue( $processor->expects_closer(), 'Removing the attribute should not stop the element from expecting a closer.' ); + $this->assertSame( + $normalized_html, + WP_HTML_Processor::normalize( $processor->get_updated_html() ), + 'Updated HTML should preserve the foreign element as a non-self-closing element when parsed again.' + ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_remove_attribute_after_slash_separator_preserves_foreign_content() { + return array( + 'SVG G' => array( '', 'G', '', '' ), + 'MathML MI' => array( '', 'MI', '', '' ), + ); + } + + /** + * Ensures that removing an attribute doesn't remove an existing foreign-content self-closing flag. + * + * @covers ::remove_attribute + * + * @dataProvider data_remove_attribute_preserves_foreign_content_self_closing_flag + * + * @param string $html HTML containing a self-closing foreign element with an attribute. + * @param string $tag_name Foreign element tag name to modify. + * @param string $updated_html Expected updated HTML. + * @param string $normalized_html Expected normalized HTML after reparsing the updated HTML. + */ + public function test_remove_attribute_preserves_foreign_content_self_closing_flag( $html, $tag_name, $updated_html, $normalized_html ) { + $processor = WP_HTML_Processor::create_fragment( $html ); + + $this->assertTrue( $processor->next_tag( $tag_name ), "Failed to find the {$tag_name} tag: check test setup." ); + $this->assertTrue( $processor->has_self_closing_flag(), 'Test setup should include a self-closing flag.' ); + $this->assertFalse( $processor->expects_closer(), 'Test setup should not expect a closing tag.' ); + + $this->assertTrue( $processor->remove_attribute( '=' ), 'Could not remove the target attribute.' ); + + $this->assertSame( + $updated_html, + $processor->get_updated_html(), + 'Removing the attribute should preserve the original self-closing flag.' + ); + $this->assertTrue( $processor->has_self_closing_flag(), 'Removing the attribute should preserve the self-closing flag.' ); + $this->assertFalse( $processor->expects_closer(), 'Removing the attribute should not make the element expect a closer.' ); + $this->assertSame( + $normalized_html, + WP_HTML_Processor::normalize( $processor->get_updated_html() ), + 'Updated HTML should preserve the foreign element as a self-closing element when parsed again.' + ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_remove_attribute_preserves_foreign_content_self_closing_flag() { + return array( + 'SVG G' => array( 'text', 'G', 'text', 'text' ), + 'MathML MI' => array( 'text', 'MI', 'text', 'text' ), + ); + } + /** * Ensures that expects_closer works for void-like elements in foreign content. * diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index 88762ddbb60c4..cb33c79991685 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -1107,6 +1107,136 @@ public function test_get_attribute_reflects_removed_attribute_before_it_is_appli ); } + /** + * Ensures that removing an attribute following a slash separator doesn't create a self-closing flag. + * + * @covers WP_HTML_Tag_Processor::remove_attribute + * + * @dataProvider data_remove_attribute_after_slash_separator_does_not_create_self_closing_flag + * + * @param string $html HTML containing an attribute after a slash separator. + * @param string $attribute_to_remove Name of the attribute to remove. + * @param string $expected Expected updated HTML. + */ + public function test_remove_attribute_after_slash_separator_does_not_create_self_closing_flag( $html, $attribute_to_remove, $expected ) { + $processor = new WP_HTML_Tag_Processor( $html ); + $this->assertTrue( $processor->next_tag(), 'Could not find the DIV tag: check test setup.' ); + $this->assertFalse( $processor->has_self_closing_flag(), 'Test setup should not include a self-closing flag.' ); + + $processor->remove_attribute( $attribute_to_remove ); + + $this->assertSame( + $expected, + $processor->get_updated_html(), + 'Removing the attribute should not leave a slash that turns into a self-closing flag.' + ); + $this->assertFalse( $processor->has_self_closing_flag(), 'Removing the attribute should not create a self-closing flag.' ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_remove_attribute_after_slash_separator_does_not_create_self_closing_flag() { + return array( + 'Boolean attribute' => array( '
', 'b', '
' ), + 'Unquoted attribute' => array( '
', 'b', '
' ), + 'Double-quoted attribute' => array( '
', 'b', '
' ), + 'Single-quoted attribute' => array( "
", 'b', '
' ), + 'Equals-sign attribute name' => array( '
', '=', '
' ), + 'Duplicate attribute after separator' => array( '
', 'b', '
' ), + 'Multiple slash separators' => array( '
', 'b', '
' ), + ); + } + + /** + * Ensures that removing attributes before an existing self-closing flag preserves the flag. + * + * @covers WP_HTML_Tag_Processor::remove_attribute + * + * @dataProvider data_remove_attribute_preserves_existing_self_closing_flag + * + * @param string $html HTML containing an attribute before a self-closing flag. + * @param string $attribute_to_remove Name of the attribute to remove. + * @param string $expected Expected updated HTML. + */ + public function test_remove_attribute_preserves_existing_self_closing_flag( $html, $attribute_to_remove, $expected ) { + $processor = new WP_HTML_Tag_Processor( $html ); + $this->assertTrue( $processor->next_tag(), 'Could not find the DIV tag: check test setup.' ); + $this->assertTrue( $processor->has_self_closing_flag(), 'Test setup should include a self-closing flag.' ); + + $processor->remove_attribute( $attribute_to_remove ); + + $this->assertSame( + $expected, + $processor->get_updated_html(), + 'Removing the attribute should preserve the original self-closing flag.' + ); + $this->assertTrue( $processor->has_self_closing_flag(), 'Removing the attribute should preserve the self-closing flag.' ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_remove_attribute_preserves_existing_self_closing_flag() { + return array( + 'Boolean attribute before self-closing flag' => array( '
', 'b', '
' ), + 'Equals-sign attribute before self-closing flag' => array( '
', '=', '
' ), + 'Slash-separated attribute before self-closing flag' => array( '
', 'b', '
' ), + 'Spaced boolean attribute before self-closing flag' => array( '
', 'b', '
' ), + 'Spaced equals-sign attribute before self-closing flag' => array( '
', '=', '
' ), + ); + } + + /** + * Ensures that adding and removing attributes with the same insertion point doesn't reinsert the removed text. + * + * @covers WP_HTML_Tag_Processor::set_attribute + * @covers WP_HTML_Tag_Processor::add_class + * @covers WP_HTML_Tag_Processor::remove_attribute + * + * @dataProvider data_can_add_attribute_while_removing_slash_separated_attribute + * + * @param string $html HTML containing a slash-separated attribute. + * @param string $method Method for adding an attribute before removing another. + * @param string $expected Expected updated HTML. + */ + public function test_can_add_attribute_while_removing_slash_separated_attribute( $html, $method, $expected ) { + $processor = new WP_HTML_Tag_Processor( $html ); + $this->assertTrue( $processor->next_tag(), 'Could not find the DIV tag: check test setup.' ); + + if ( 'set_attribute' === $method ) { + $processor->set_attribute( 'a', 'x' ); + } else { + $processor->add_class( 'x' ); + } + + $processor->remove_attribute( 'b' ); + + $this->assertSame( + $expected, + $processor->get_updated_html(), + 'Adding an attribute while removing another should not reinsert the removed slash-separated attribute.' + ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_can_add_attribute_while_removing_slash_separated_attribute() { + return array( + 'Set attribute, no self-closing flag' => array( '
', 'set_attribute', '
' ), + 'Add class, no self-closing flag' => array( '
', 'add_class', '
' ), + 'Set attribute, self-closing flag' => array( '
', 'set_attribute', '
' ), + 'Add class, self-closing flag' => array( '
', 'add_class', '
' ), + ); + } + /** * @ticket 56299 * From 6e6694f0c74a970f82cbb6818d8bff6dbf8b568c Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 1 Jul 2026 11:22:15 +0200 Subject: [PATCH 2/3] HTML API: Consolidate self-closing attribute removal tests --- .../tests/html-api/wpHtmlProcessor.php | 94 +++++++------------ .../tests/html-api/wpHtmlTagProcessor.php | 85 ++++++----------- 2 files changed, 63 insertions(+), 116 deletions(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php index 4836b4ffd807d..8b002ea4e1fb3 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php @@ -607,84 +607,56 @@ public function test_unquoted_slash_attribute_does_not_self_close_foreign_conten } /** - * Ensures that removing an attribute after a slash separator doesn't self-close foreign content. + * Ensures that removing attributes preserves foreign-content self-closing semantics. * * @covers ::remove_attribute * - * @dataProvider data_remove_attribute_after_slash_separator_preserves_foreign_content + * @dataProvider data_remove_attribute_preserves_foreign_content_self_closing_semantics * - * @param string $html HTML containing a foreign element with an attribute after a slash separator. - * @param string $tag_name Foreign element tag name to modify. - * @param string $updated_html Expected updated HTML. - * @param string $normalized_html Expected normalized HTML after reparsing the updated HTML. + * @param string $html HTML containing a foreign element with an attribute. + * @param string $tag_name Foreign element tag name to modify. + * @param string $attribute_to_remove Name of the attribute to remove. + * @param string $updated_html Expected updated HTML. + * @param string $normalized_html Expected normalized HTML after reparsing the updated HTML. + * @param bool $expected_has_self_closing_flag Expected self-closing flag state. + * @param bool $expected_expects_closer Expected closer expectation. */ - public function test_remove_attribute_after_slash_separator_preserves_foreign_content( $html, $tag_name, $updated_html, $normalized_html ) { + public function test_remove_attribute_preserves_foreign_content_self_closing_semantics( $html, $tag_name, $attribute_to_remove, $updated_html, $normalized_html, $expected_has_self_closing_flag, $expected_expects_closer ) { $processor = WP_HTML_Processor::create_fragment( $html ); $this->assertTrue( $processor->next_tag( $tag_name ), "Failed to find the {$tag_name} tag: check test setup." ); - $this->assertFalse( $processor->has_self_closing_flag(), 'Test setup should not include a self-closing flag.' ); - $this->assertTrue( $processor->expects_closer(), 'Test setup should expect a closing tag.' ); - - $this->assertTrue( $processor->remove_attribute( 'b' ), 'Could not remove the target attribute.' ); - $this->assertSame( - $updated_html, - $processor->get_updated_html(), - 'Removing the attribute should not leave a slash that turns into a self-closing flag.' + $expected_has_self_closing_flag, + $processor->has_self_closing_flag(), + 'Test setup has the wrong self-closing flag state.' ); - $this->assertFalse( $processor->has_self_closing_flag(), 'Removing the attribute should not create a self-closing flag.' ); - $this->assertTrue( $processor->expects_closer(), 'Removing the attribute should not stop the element from expecting a closer.' ); $this->assertSame( - $normalized_html, - WP_HTML_Processor::normalize( $processor->get_updated_html() ), - 'Updated HTML should preserve the foreign element as a non-self-closing element when parsed again.' - ); - } - - /** - * Data provider. - * - * @return array[] - */ - public static function data_remove_attribute_after_slash_separator_preserves_foreign_content() { - return array( - 'SVG G' => array( '', 'G', '', '' ), - 'MathML MI' => array( '', 'MI', '', '' ), + $expected_expects_closer, + $processor->expects_closer(), + 'Test setup has the wrong closer expectation.' ); - } - /** - * Ensures that removing an attribute doesn't remove an existing foreign-content self-closing flag. - * - * @covers ::remove_attribute - * - * @dataProvider data_remove_attribute_preserves_foreign_content_self_closing_flag - * - * @param string $html HTML containing a self-closing foreign element with an attribute. - * @param string $tag_name Foreign element tag name to modify. - * @param string $updated_html Expected updated HTML. - * @param string $normalized_html Expected normalized HTML after reparsing the updated HTML. - */ - public function test_remove_attribute_preserves_foreign_content_self_closing_flag( $html, $tag_name, $updated_html, $normalized_html ) { - $processor = WP_HTML_Processor::create_fragment( $html ); - - $this->assertTrue( $processor->next_tag( $tag_name ), "Failed to find the {$tag_name} tag: check test setup." ); - $this->assertTrue( $processor->has_self_closing_flag(), 'Test setup should include a self-closing flag.' ); - $this->assertFalse( $processor->expects_closer(), 'Test setup should not expect a closing tag.' ); - - $this->assertTrue( $processor->remove_attribute( '=' ), 'Could not remove the target attribute.' ); + $this->assertTrue( $processor->remove_attribute( $attribute_to_remove ), 'Could not remove the target attribute.' ); $this->assertSame( $updated_html, $processor->get_updated_html(), - 'Removing the attribute should preserve the original self-closing flag.' + 'Removing the attribute should preserve foreign-content self-closing semantics.' + ); + $this->assertSame( + $expected_has_self_closing_flag, + $processor->has_self_closing_flag(), + 'Removing the attribute should preserve the self-closing flag state.' + ); + $this->assertSame( + $expected_expects_closer, + $processor->expects_closer(), + 'Removing the attribute should preserve the closer expectation.' ); - $this->assertTrue( $processor->has_self_closing_flag(), 'Removing the attribute should preserve the self-closing flag.' ); - $this->assertFalse( $processor->expects_closer(), 'Removing the attribute should not make the element expect a closer.' ); $this->assertSame( $normalized_html, WP_HTML_Processor::normalize( $processor->get_updated_html() ), - 'Updated HTML should preserve the foreign element as a self-closing element when parsed again.' + 'Updated HTML should preserve foreign-content self-closing semantics when parsed again.' ); } @@ -693,10 +665,12 @@ public function test_remove_attribute_preserves_foreign_content_self_closing_fla * * @return array[] */ - public static function data_remove_attribute_preserves_foreign_content_self_closing_flag() { + public static function data_remove_attribute_preserves_foreign_content_self_closing_semantics() { return array( - 'SVG G' => array( 'text', 'G', 'text', 'text' ), - 'MathML MI' => array( 'text', 'MI', 'text', 'text' ), + 'SVG G without self-closing flag' => array( '', 'G', 'b', '', '', false, true ), + 'MathML MI without self-closing flag' => array( '', 'MI', 'b', '', '', false, true ), + 'SVG G with self-closing flag' => array( 'text', 'G', '=', 'text', 'text', true, false ), + 'MathML MI with self-closing flag' => array( 'text', 'MI', '=', 'text', 'text', true, false ), ); } diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index cb33c79991685..2095454e234e4 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -1108,72 +1108,38 @@ public function test_get_attribute_reflects_removed_attribute_before_it_is_appli } /** - * Ensures that removing an attribute following a slash separator doesn't create a self-closing flag. + * Ensures that removing attributes preserves self-closing flag state. * * @covers WP_HTML_Tag_Processor::remove_attribute * - * @dataProvider data_remove_attribute_after_slash_separator_does_not_create_self_closing_flag + * @dataProvider data_remove_attribute_preserves_self_closing_flag_state * - * @param string $html HTML containing an attribute after a slash separator. - * @param string $attribute_to_remove Name of the attribute to remove. - * @param string $expected Expected updated HTML. + * @param string $html HTML containing an attribute to remove. + * @param string $attribute_to_remove Name of the attribute to remove. + * @param string $expected Expected updated HTML. + * @param bool $expected_has_self_closing_flag Expected self-closing flag state. */ - public function test_remove_attribute_after_slash_separator_does_not_create_self_closing_flag( $html, $attribute_to_remove, $expected ) { + public function test_remove_attribute_preserves_self_closing_flag_state( $html, $attribute_to_remove, $expected, $expected_has_self_closing_flag ) { $processor = new WP_HTML_Tag_Processor( $html ); $this->assertTrue( $processor->next_tag(), 'Could not find the DIV tag: check test setup.' ); - $this->assertFalse( $processor->has_self_closing_flag(), 'Test setup should not include a self-closing flag.' ); - - $processor->remove_attribute( $attribute_to_remove ); - $this->assertSame( - $expected, - $processor->get_updated_html(), - 'Removing the attribute should not leave a slash that turns into a self-closing flag.' - ); - $this->assertFalse( $processor->has_self_closing_flag(), 'Removing the attribute should not create a self-closing flag.' ); - } - - /** - * Data provider. - * - * @return array[] - */ - public static function data_remove_attribute_after_slash_separator_does_not_create_self_closing_flag() { - return array( - 'Boolean attribute' => array( '
', 'b', '
' ), - 'Unquoted attribute' => array( '
', 'b', '
' ), - 'Double-quoted attribute' => array( '
', 'b', '
' ), - 'Single-quoted attribute' => array( "
", 'b', '
' ), - 'Equals-sign attribute name' => array( '
', '=', '
' ), - 'Duplicate attribute after separator' => array( '
', 'b', '
' ), - 'Multiple slash separators' => array( '
', 'b', '
' ), + $expected_has_self_closing_flag, + $processor->has_self_closing_flag(), + 'Test setup has the wrong self-closing flag state.' ); - } - - /** - * Ensures that removing attributes before an existing self-closing flag preserves the flag. - * - * @covers WP_HTML_Tag_Processor::remove_attribute - * - * @dataProvider data_remove_attribute_preserves_existing_self_closing_flag - * - * @param string $html HTML containing an attribute before a self-closing flag. - * @param string $attribute_to_remove Name of the attribute to remove. - * @param string $expected Expected updated HTML. - */ - public function test_remove_attribute_preserves_existing_self_closing_flag( $html, $attribute_to_remove, $expected ) { - $processor = new WP_HTML_Tag_Processor( $html ); - $this->assertTrue( $processor->next_tag(), 'Could not find the DIV tag: check test setup.' ); - $this->assertTrue( $processor->has_self_closing_flag(), 'Test setup should include a self-closing flag.' ); $processor->remove_attribute( $attribute_to_remove ); $this->assertSame( $expected, $processor->get_updated_html(), - 'Removing the attribute should preserve the original self-closing flag.' + 'Removing the attribute should not change the self-closing flag state.' + ); + $this->assertSame( + $expected_has_self_closing_flag, + $processor->has_self_closing_flag(), + 'Removing the attribute should preserve the self-closing flag state.' ); - $this->assertTrue( $processor->has_self_closing_flag(), 'Removing the attribute should preserve the self-closing flag.' ); } /** @@ -1181,13 +1147,20 @@ public function test_remove_attribute_preserves_existing_self_closing_flag( $htm * * @return array[] */ - public static function data_remove_attribute_preserves_existing_self_closing_flag() { + public static function data_remove_attribute_preserves_self_closing_flag_state() { return array( - 'Boolean attribute before self-closing flag' => array( '
', 'b', '
' ), - 'Equals-sign attribute before self-closing flag' => array( '
', '=', '
' ), - 'Slash-separated attribute before self-closing flag' => array( '
', 'b', '
' ), - 'Spaced boolean attribute before self-closing flag' => array( '
', 'b', '
' ), - 'Spaced equals-sign attribute before self-closing flag' => array( '
', '=', '
' ), + 'Boolean attribute after slash separator' => array( '
', 'b', '
', false ), + 'Unquoted attribute after slash separator' => array( '
', 'b', '
', false ), + 'Double-quoted attribute after slash separator' => array( '
', 'b', '
', false ), + 'Single-quoted attribute after slash separator' => array( "
", 'b', '
', false ), + 'Equals-sign attribute after slash separator' => array( '
', '=', '
', false ), + 'Duplicate attribute after slash separator' => array( '
', 'b', '
', false ), + 'Attribute after multiple slash separators' => array( '
', 'b', '
', false ), + 'Boolean attribute before self-closing flag' => array( '
', 'b', '
', true ), + 'Equals-sign attribute before self-closing flag' => array( '
', '=', '
', true ), + 'Slash-separated attribute before self-closing flag' => array( '
', 'b', '
', true ), + 'Spaced boolean attribute before self-closing flag' => array( '
', 'b', '
', true ), + 'Spaced equals-sign attribute before self-closing flag' => array( '
', '=', '
', true ), ); } From c9c17f7fdd999a4143c64c23764642fac0d05307 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 14 Jul 2026 11:28:28 +0200 Subject: [PATCH 3/3] Fix lints --- .../tests/html-api/wpHtmlProcessor.php | 8 ++--- .../tests/html-api/wpHtmlTagProcessor.php | 30 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php index 179a61266df52..6a0bdb11adb5d 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php @@ -669,10 +669,10 @@ public function test_remove_attribute_preserves_foreign_content_self_closing_sem */ public static function data_remove_attribute_preserves_foreign_content_self_closing_semantics() { return array( - 'SVG G without self-closing flag' => array( '', 'G', 'b', '', '', false, true ), - 'MathML MI without self-closing flag' => array( '', 'MI', 'b', '', '', false, true ), - 'SVG G with self-closing flag' => array( 'text', 'G', '=', 'text', 'text', true, false ), - 'MathML MI with self-closing flag' => array( 'text', 'MI', '=', 'text', 'text', true, false ), + 'SVG G without self-closing flag' => array( '', 'G', 'b', '', '', false, true ), + 'MathML MI without self-closing flag' => array( '', 'MI', 'b', '', '', false, true ), + 'SVG G with self-closing flag' => array( 'text', 'G', '=', 'text', 'text', true, false ), + 'MathML MI with self-closing flag' => array( 'text', 'MI', '=', 'text', 'text', true, false ), ); } diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index 38cf53cdb8a5c..549d28d3730b5 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -1150,17 +1150,17 @@ public function test_remove_attribute_preserves_self_closing_flag_state( $html, */ public static function data_remove_attribute_preserves_self_closing_flag_state() { return array( - 'Boolean attribute after slash separator' => array( '
', 'b', '
', false ), - 'Unquoted attribute after slash separator' => array( '
', 'b', '
', false ), - 'Double-quoted attribute after slash separator' => array( '
', 'b', '
', false ), - 'Single-quoted attribute after slash separator' => array( "
", 'b', '
', false ), - 'Equals-sign attribute after slash separator' => array( '
', '=', '
', false ), - 'Duplicate attribute after slash separator' => array( '
', 'b', '
', false ), - 'Attribute after multiple slash separators' => array( '
', 'b', '
', false ), - 'Boolean attribute before self-closing flag' => array( '
', 'b', '
', true ), - 'Equals-sign attribute before self-closing flag' => array( '
', '=', '
', true ), - 'Slash-separated attribute before self-closing flag' => array( '
', 'b', '
', true ), - 'Spaced boolean attribute before self-closing flag' => array( '
', 'b', '
', true ), + 'Boolean attribute after slash separator' => array( '
', 'b', '
', false ), + 'Unquoted attribute after slash separator' => array( '
', 'b', '
', false ), + 'Double-quoted attribute after slash separator' => array( '
', 'b', '
', false ), + 'Single-quoted attribute after slash separator' => array( "
", 'b', '
', false ), + 'Equals-sign attribute after slash separator' => array( '
', '=', '
', false ), + 'Duplicate attribute after slash separator' => array( '
', 'b', '
', false ), + 'Attribute after multiple slash separators' => array( '
', 'b', '
', false ), + 'Boolean attribute before self-closing flag' => array( '
', 'b', '
', true ), + 'Equals-sign attribute before self-closing flag' => array( '
', '=', '
', true ), + 'Slash-separated attribute before self-closing flag' => array( '
', 'b', '
', true ), + 'Spaced boolean attribute before self-closing flag' => array( '
', 'b', '
', true ), 'Spaced equals-sign attribute before self-closing flag' => array( '
', '=', '
', true ), ); } @@ -1204,10 +1204,10 @@ public function test_can_add_attribute_while_removing_slash_separated_attribute( */ public static function data_can_add_attribute_while_removing_slash_separated_attribute() { return array( - 'Set attribute, no self-closing flag' => array( '
', 'set_attribute', '
' ), - 'Add class, no self-closing flag' => array( '
', 'add_class', '
' ), - 'Set attribute, self-closing flag' => array( '
', 'set_attribute', '
' ), - 'Add class, self-closing flag' => array( '
', 'add_class', '
' ), + 'Set attribute, no self-closing flag' => array( '
', 'set_attribute', '
' ), + 'Add class, no self-closing flag' => array( '
', 'add_class', '
' ), + 'Set attribute, self-closing flag' => array( '
', 'set_attribute', '
' ), + 'Add class, self-closing flag' => array( '
', 'add_class', '
' ), ); }