From 780f0ad261a99ce718601416986849bda363c48a Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Fri, 28 Jun 2024 13:04:53 +0200 Subject: [PATCH 1/7] Add mixed casing add_tag uniqueness test --- tests/phpunit/tests/html-api/wpHtmlTagProcessor.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index fad1000dd763c..e73a384bb0afb 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -2559,6 +2559,7 @@ public function test_updating_specific_attributes_in_malformed_html() { /** * @ticket 56299 + * @ticket TBD * * @covers WP_HTML_Tag_Processor::add_class * @covers WP_HTML_Tag_Processor::set_attribute @@ -2618,6 +2619,14 @@ public static function data_updating_attributes() { 'input' => ' a HTML Tag]]>test', 'expected' => ' a HTML Tag]]>test', ), + 'tags already with added class names' => array( + 'input' => '
', + 'expected' => '
', + ), + 'tags already with added class names mixed casing' => array( + 'input' => '
', + 'expected' => '
', + ), ); } From 3a0dc8e31de12f4154e18bae786dc0a99b10b68b Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Fri, 28 Jun 2024 14:07:56 +0200 Subject: [PATCH 2/7] Revert "Add mixed casing add_tag uniqueness test" This reverts commit 780f0ad261a99ce718601416986849bda363c48a. --- tests/phpunit/tests/html-api/wpHtmlTagProcessor.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index e73a384bb0afb..fad1000dd763c 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -2559,7 +2559,6 @@ public function test_updating_specific_attributes_in_malformed_html() { /** * @ticket 56299 - * @ticket TBD * * @covers WP_HTML_Tag_Processor::add_class * @covers WP_HTML_Tag_Processor::set_attribute @@ -2619,14 +2618,6 @@ public static function data_updating_attributes() { 'input' => ' a HTML Tag]]>test', 'expected' => ' a HTML Tag]]>test', ), - 'tags already with added class names' => array( - 'input' => '
', - 'expected' => '
', - ), - 'tags already with added class names mixed casing' => array( - 'input' => '
', - 'expected' => '
', - ), ); } From d2073114ec33fd9aae7d2d6baa0f262fb281c261 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Fri, 28 Jun 2024 14:16:32 +0200 Subject: [PATCH 3/7] Add mixed-casing add_ remove_class tests --- .../tests/html-api/wpHtmlTagProcessor.php | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index fad1000dd763c..9b32639e3c515 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -2875,4 +2875,38 @@ public function insert_after( $new_html ) { 'Should have properly applied the update from in front of the cursor.' ); } + + /** + * @ticket TBD + * + * @covers ::add_class + */ + public function test_add_class_does_not_duplicate_case_insensitive_classes() { + $processor = new WP_HTML_Tag_Processor( '
' ); + $processor->next_tag(); + $processor->add_class( 'upper' ); + $processor->add_class( 'LOWER' ); + $this->assertSame( + '
', + $processor->get_updated_html(), + '::add_class added case-insensitive duplicate class names.' + ); + } + + /** + * @ticket TBD + * + * @covers ::remove_class + */ + public function test_remove_class_removes_case_insensitive_matches() { + $processor = new WP_HTML_Tag_Processor( '
' ); + $processor->next_tag(); + $processor->remove_class( 'remove-a' ); + $processor->remove_class( 'REMOVE-B' ); + $this->assertSame( + '
', + $processor->get_updated_html(), + '::remove_class did not remove case-insensitive class name matches.' + ); + } } From 072e88148d8f4e58f0500d95a20a08ef2d7b6f12 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Fri, 28 Jun 2024 14:59:57 +0200 Subject: [PATCH 4/7] Fix tests --- .../html-api/class-wp-html-tag-processor.php | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 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 8fc75938c9384..5ecb756709d9b 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 @@ -679,12 +679,14 @@ class WP_HTML_Tag_Processor { * // Add the `wp-block-group` class, remove the `wp-group` class. * $classname_updates = array( * // Indexed by a comparable class name. - * 'wp-block-group' => WP_HTML_Tag_Processor::ADD_CLASS, - * 'wp-group' => WP_HTML_Tag_Processor::REMOVE_CLASS + * 'wp-block-group' => [ WP_HTML_Tag_Processor::ADD_CLASS, 'wp-block-group'], + * 'wp-group' => [ WP_HTML_Tag_Processor::REMOVE_CLASS ], * ); * * @since 6.2.0 - * @var bool[] + * @since 6.7.0 Changed the structure of values to an array + * + * @var array[] */ private $classname_updates = array(); @@ -2203,13 +2205,13 @@ private function class_name_updates_to_attributes_updates() { // If this class is marked for removal, start processing the next one. $remove_class = ( - isset( $this->classname_updates[ $name ] ) && - self::REMOVE_CLASS === $this->classname_updates[ $name ] + isset( $this->classname_updates[ strtolower( $name ) ] ) && + self::REMOVE_CLASS === $this->classname_updates[ strtolower( $name ) ][0] ); // If a class has already been seen then skip it; it should not be added twice. if ( ! $remove_class ) { - $this->classname_updates[ $name ] = self::SKIP_CLASS; + $this->classname_updates[ strtolower( $name ) ] = array( self::SKIP_CLASS ); } if ( $remove_class ) { @@ -2234,12 +2236,12 @@ private function class_name_updates_to_attributes_updates() { } // Add new classes by appending those which haven't already been seen. - foreach ( $this->classname_updates as $name => $operation ) { - if ( self::ADD_CLASS === $operation ) { + foreach ( $this->classname_updates as $operation ) { + if ( self::ADD_CLASS === $operation[0] ) { $modified = true; $class .= strlen( $class ) > 0 ? ' ' : ''; - $class .= $name; + $class .= $operation[1]; } } @@ -3126,7 +3128,10 @@ public function remove_attribute( $name ) { /** * Adds a new class name to the currently matched tag. * + * Adds unique CSS class names. Case insensitive duplicate classes will not be added. + * * @since 6.2.0 + * @since 6.7.0 Class name matching for uniqueness is case-insensitive. * * @param string $class_name The class name to add. * @return bool Whether the class was set to be added. @@ -3139,7 +3144,7 @@ public function add_class( $class_name ) { return false; } - $this->classname_updates[ $class_name ] = self::ADD_CLASS; + $this->classname_updates[ strtolower( $class_name ) ] = array( self::ADD_CLASS, $class_name ); return true; } @@ -3147,7 +3152,10 @@ public function add_class( $class_name ) { /** * Removes a class name from the currently matched tag. * + * Remove matching CSS class names. Case-insensitive matching class names will be removed. + * * @since 6.2.0 + * @since 6.7.0 Class name matching for removal is case-insensitive. * * @param string $class_name The class name to remove. * @return bool Whether the class was set to be removed. @@ -3161,7 +3169,7 @@ public function remove_class( $class_name ) { } if ( null !== $this->tag_name_starts_at ) { - $this->classname_updates[ $class_name ] = self::REMOVE_CLASS; + $this->classname_updates[ strtolower( $class_name ) ] = array( self::REMOVE_CLASS ); } return true; From c0b70815900b4b9aa8c6ec301b651ef85b3a4930 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Fri, 28 Jun 2024 15:00:35 +0200 Subject: [PATCH 5/7] Update ticket ref --- tests/phpunit/tests/html-api/wpHtmlTagProcessor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index 9b32639e3c515..ed2715e6abb6e 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -2877,7 +2877,7 @@ public function insert_after( $new_html ) { } /** - * @ticket TBD + * @ticket 61531 * * @covers ::add_class */ @@ -2894,7 +2894,7 @@ public function test_add_class_does_not_duplicate_case_insensitive_classes() { } /** - * @ticket TBD + * @ticket 61531 * * @covers ::remove_class */ From dc1514fd74400b1f4ceba1a000f65be49626da01 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Fri, 28 Jun 2024 15:02:11 +0200 Subject: [PATCH 6/7] Fix test exposing new subtle bug --- tests/phpunit/tests/html-api/wpHtmlTagProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index ed2715e6abb6e..d3dc9364e0559 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -2899,7 +2899,7 @@ public function test_add_class_does_not_duplicate_case_insensitive_classes() { * @covers ::remove_class */ public function test_remove_class_removes_case_insensitive_matches() { - $processor = new WP_HTML_Tag_Processor( '
' ); + $processor = new WP_HTML_Tag_Processor( '
' ); $processor->next_tag(); $processor->remove_class( 'remove-a' ); $processor->remove_class( 'REMOVE-B' ); From 8fdd8453604e6711d916deb02f646f2075eca923 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Fri, 28 Jun 2024 15:09:42 +0200 Subject: [PATCH 7/7] Add mixed casing add_class test --- .../tests/html-api/wpHtmlTagProcessor.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index d3dc9364e0559..c040f61ea0449 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -2893,6 +2893,22 @@ public function test_add_class_does_not_duplicate_case_insensitive_classes() { ); } + /** + * @ticket 61531 + * + * @covers ::add_class + */ + public function test_add_class_respects_provided_casing() { + $processor = new WP_HTML_Tag_Processor( '
' ); + $processor->next_tag(); + $processor->add_class( 'mIxEd-CaSiNg' ); + $this->assertSame( + '
', + $processor->get_updated_html(), + '::add_class did not respect the provided class name casing.' + ); + } + /** * @ticket 61531 *