From 9400453eac40d47d1b85fd05574f380fc4b22368 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 19 Apr 2023 09:25:32 +0000 Subject: [PATCH] HTML API: Ensure attribute updates happen only once for case variants. When setting a new value for an attribute multiple times and providing multiple case variations of the attribute name the Tag Processor has been appending multiple copies of the attribute into the updated HTML. This means that only the first attribute set determines the value in the final output, plus the output will //appear// wrong. In this patch we're adding a test to catch the situation and resolving it by using the appropriate comparable attribute name as a key for storing the updates as we go. Previously we stored updates to the attribute by its given `$name`, but when a new update of the same name with a case variant was queued, it would not override the previously-enqueued value as it out to have. Props dmsnell, zieladam. Fixes #58146. git-svn-id: https://develop.svn.wordpress.org/trunk@55659 602fd350-edb4-49c9-b593-d223f7449a82 --- .../html-api/class-wp-html-tag-processor.php | 5 +++-- .../tests/html-api/wpHtmlTagProcessor.php | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 2 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 ab0b88693a..31352d2e88 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 @@ -1815,6 +1815,7 @@ class WP_HTML_Tag_Processor { * For string attributes, the value is escaped using the `esc_attr` function. * * @since 6.2.0 + * @since 6.2.1 Fix: Only create a single update for multiple calls with case-variant attribute names. * * @param string $name The attribute name to target. * @param string|bool $value The new attribute value. @@ -1907,8 +1908,8 @@ class WP_HTML_Tag_Processor { * * Result:
*/ - $existing_attribute = $this->attributes[ $comparable_name ]; - $this->lexical_updates[ $name ] = new WP_HTML_Text_Replacement( + $existing_attribute = $this->attributes[ $comparable_name ]; + $this->lexical_updates[ $comparable_name ] = new WP_HTML_Text_Replacement( $existing_attribute->start, $existing_attribute->end, $updated_attribute diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index 6b0c263c5d..39d8fd3550 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -962,6 +962,24 @@ class Tests_HtmlApi_wpHtmlTagProcessor extends WP_UnitTestCase { ); } + /** + * Ensures that when setting an attribute multiple times that only + * one update flushes out into the updated HTML. + * + * @ticket 58146 + * + * @covers WP_HTML_Tag_Processor::set_attribute + */ + public function test_set_attribute_with_case_variants_updates_only_the_original_first_copy() { + $p = new WP_HTML_Tag_Processor( '
' ); + $p->next_tag(); + $p->set_attribute( 'DATA-ENABLED', 'canary' ); + $p->set_attribute( 'Data-Enabled', 'canary' ); + $p->set_attribute( 'dATa-EnABled', 'canary' ); + + $this->assertSame( '
', strtolower( $p->get_updated_html() ) ); + } + /** * @ticket 56299 *