diff --git a/src/wp-includes/html-api/class-wp-html-processor.php b/src/wp-includes/html-api/class-wp-html-processor.php index 967d616129647..1828123ff879d 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -1505,6 +1505,7 @@ public function serialize_token(): string { case 'SCRIPT': case 'STYLE': + case 'XMP': break; default: diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php index 5afe37a010a41..d9d7d7c13394a 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php @@ -257,6 +257,22 @@ public function test_style_contents_are_not_escaped() { ); } + /** + * XMP contents are parsed using the generic raw text element parsing algorithm. + * Their contents should not be escaped with HTML character references on normalization. + * + * @ticket 65372 + */ + public function test_xmp_contents_are_not_escaped() { + $normalized = WP_HTML_Processor::normalize( " < > & \" ' \x00 " ); + + $this->assertSame( + " < > & \" ' \u{FFFD} ", + $normalized, + 'Should have preserved text inside an XMP element, except for replacing NULL bytes.' + ); + } + public function test_unexpected_closing_tags_are_removed() { $this->assertSame( WP_HTML_Processor::normalize( 'onetwothree' ), @@ -404,6 +420,7 @@ public static function data_tokens_with_null_bytes() { 'Foreign content text' => array( "one\x00two", "one\u{FFFD}two" ), 'SCRIPT content' => array( "", "" ), 'STYLE content' => array( "", "" ), + 'XMP content' => array( "a\x00b", "a\u{FFFD}b" ), 'Comment text' => array( "", "" ), ); } @@ -629,6 +646,7 @@ public static function data_provider_normalized_fuzzer_cases_that_should_be_idem 'Duplicate ALT boundary' => array( '' ), 'NULL byte in SVG child tag' => array( "" ), 'NULL byte before slash in SVG child tag' => array( "" ), + 'XMP generic raw text' => array( " < > & \" ' \x00 " ), ); }