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 3cdbd91480ca0..31c4bc8a10654 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 @@ -2342,10 +2342,12 @@ private function class_name_updates_to_attributes_updates(): void { } if ( false === $existing_class && isset( $this->attributes['class'] ) ) { - $existing_class = substr( - $this->html, - $this->attributes['class']->value_starts_at, - $this->attributes['class']->value_length + $existing_class = WP_HTML_Decoder::decode_attribute( + substr( + $this->html, + $this->attributes['class']->value_starts_at, + $this->attributes['class']->value_length + ) ); } diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index b6ec3affb2788..22ace3890f469 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -2887,11 +2887,11 @@ public static function data_updating_attributes_in_malformed_html() { ), 'HTML tag opening inside attribute value' => array( 'input' => '
This <is> a <strong is="true">thing.
test', - 'expected' => '
This <is> a <strong is="true">thing.
test', + 'expected' => '
This <is> a <strong is="true">thing.
test', ), 'HTML tag brackets in attribute values and data markup' => array( 'input' => '
This <is> a <strong is="true">thing.
test', - 'expected' => '
This <is> a <strong is="true">thing.
test', + 'expected' => '
This <is> a <strong is="true">thing.
test', ), 'Single and double quotes in attribute value' => array( 'input' => '

test', @@ -3028,6 +3028,50 @@ public static function data_updating_attributes_in_malformed_html() { ); } + /** + * @ticket 64340 + */ + public function test_class_changes_produce_correct_html() { + $processor = new WP_HTML_Tag_Processor( '

' ); + $processor->next_tag(); + + $processor->add_class( '"' ); + $processor->get_updated_html(); + + $processor->add_class( 'OK' ); + $processor->get_updated_html(); + + $this->assertTrue( $processor->has_class( '&' ), 'Missing expected "&" class.' ); + $this->assertTrue( $processor->has_class( '"' ), 'Missing expected \'"\' class.' ); + $this->assertTrue( $processor->has_class( 'OK' ), 'Missing expected "OK" class.' ); + + $expected = '
'; + $this->assertEqualHTML( + $expected, + $processor->get_updated_html(), + '', + 'HTML was not correctly updated after adding classes.' + ); + + $processor->remove_class( '&' ); + $processor->get_updated_html(); + + $processor->remove_class( '"' ); + $processor->get_updated_html(); + + $this->assertFalse( $processor->has_class( '&' ) ); + $this->assertFalse( $processor->has_class( '"' ) ); + $this->assertTrue( $processor->has_class( 'OK' ) ); + + $expected = '
'; + $this->assertEqualHTML( + $expected, + $processor->get_updated_html(), + '', + 'HTML was not correctly updated after removing classes.' + ); + } + /** * @covers WP_HTML_Tag_Processor::next_tag */