diff --git a/src/wp-includes/html-api/class-wp-html-decoder.php b/src/wp-includes/html-api/class-wp-html-decoder.php
index d14009d3d9fb8..10dbccf3f6ccd 100644
--- a/src/wp-includes/html-api/class-wp-html-decoder.php
+++ b/src/wp-includes/html-api/class-wp-html-decoder.php
@@ -361,7 +361,7 @@ public static function read_character_reference( $context, $text, $at = 0, &$mat
$name_length = 0;
$replacement = $html5_named_character_references->read_token( $text, $name_at, $name_length );
- if ( false === $replacement ) {
+ if ( null === $replacement ) {
return null;
}
diff --git a/tests/phpunit/tests/html-api/wpHtmlDecoder.php b/tests/phpunit/tests/html-api/wpHtmlDecoder.php
index 97954f4eb3e30..28a0e0a421815 100644
--- a/tests/phpunit/tests/html-api/wpHtmlDecoder.php
+++ b/tests/phpunit/tests/html-api/wpHtmlDecoder.php
@@ -61,6 +61,37 @@ static function ( int $errno, string $errstr ) use ( &$errors ) {
$this->assertSame( "&\x00b", $decoded, 'Should have decoded the text without changing it.' );
}
+ /**
+ * Ensures unmatched named character references leave the by-ref match length unchanged.
+ *
+ * @dataProvider data_unmatched_named_character_references
+ *
+ * @param string $context Decoder context.
+ * @param string $raw_text_node Raw text containing an unmatched named character reference.
+ */
+ public function test_unmatched_named_character_reference_does_not_set_match_byte_length( $context, $raw_text_node ) {
+ $match_byte_length = 'sentinel';
+ $this->assertNull(
+ WP_HTML_Decoder::read_character_reference( $context, $raw_text_node, 0, $match_byte_length ),
+ 'Should not have matched an unmatched named character reference.'
+ );
+ $this->assertSame( 'sentinel', $match_byte_length );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array[].
+ */
+ public static function data_unmatched_named_character_references() {
+ return array(
+ 'text invalid name' => array( 'data', '&bogus;' ),
+ 'text invalid short-name candidate' => array( 'data', '&Fv=q' ),
+ 'attribute invalid name' => array( 'attribute', '&bogus;' ),
+ 'attribute invalid short-name candidate' => array( 'attribute', '&Fv=q' ),
+ );
+ }
+
/**
* Ensures proper detection of attribute prefixes ignoring ASCII case.
*