From 457f90f18b73bfc4b71b1bd341f15f46aa385787 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Fri, 18 Sep 2026 14:12:57 +0400 Subject: [PATCH 1/2] Blocks: Stop reporting a delimiter for trailing partial comments. When a document ends in `<`, `open_blocks_at[] = $after_prev_delimiter; $this->open_blocks_length[] = 0; $this->was_void = true; + + if ( $backup > 0 ) { + $this->last_error = self::INCOMPLETE_INPUT; + } + return true; } diff --git a/tests/phpunit/tests/block-processor/wpBlockProcessor.php b/tests/phpunit/tests/block-processor/wpBlockProcessor.php index 6f8934e003030..f4b9ba3376f88 100644 --- a/tests/phpunit/tests/block-processor/wpBlockProcessor.php +++ b/tests/phpunit/tests/block-processor/wpBlockProcessor.php @@ -362,6 +362,66 @@ public static function data_incomplete_html_comments_that_are_not_delimiters() { ); } + /** + * Verifies that trailing bytes which could start a block comment delimiter + * are not reported as a delimiter. + * + * @dataProvider data_documents_ending_in_a_partial_delimiter + * + * @covers ::next_token() + * + * @param string $html Input document. + * @param string[] $block_types Printable block type of every delimiter in the document, in order. + * @param string|null $last_error Expected error after scanning the entire document. + */ + public function test_reports_no_delimiter_for_partial_delimiter_at_end_of_document( $html, $block_types, $last_error ) { + $processor = new WP_Block_Processor( $html ); + + $found = array(); + while ( $processor->next_delimiter() ) { + $found[] = $processor->get_printable_block_type(); + } + + $this->assertSame( + $block_types, + $found, + 'Should have found only the delimiters which are in the document.' + ); + + $this->assertSame( + $last_error, + $processor->get_last_error(), + 'Should have reported the expected error after reaching the end of the document.' + ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_documents_ending_in_a_partial_delimiter() { + $incomplete = WP_Block_Processor::INCOMPLETE_INPUT; + + return array( + // Documents ending in a partial delimiter with no earlier delimiter. + 'Ends in <' => array( 'text<', array(), $incomplete ), + 'Ends in array( 'text array( 'text array( 'text<', array( 'core/a' ), $incomplete ), + 'Opener, then ends in array( 'text array( 'text array( 'text array( 'text<', array( 'core/a' ), $incomplete ), + + // Documents which do not end in a partial delimiter. + 'Contains < but ends in text' => array( 'a array( 'text', array( 'core/a' ), null ), + ); + } + /** * Verifies that block delimiters are matched even with malformed * JSON attributes as long as they start and end with curly brackets. From cdd5542ab16f174c9b3f4bdd72a5e78e484ef0a7 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Fri, 18 Sep 2026 15:25:19 +0400 Subject: [PATCH 2/2] Add return types and ticket reference to new block processor test --- .../block-processor/wpBlockProcessor.php | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/phpunit/tests/block-processor/wpBlockProcessor.php b/tests/phpunit/tests/block-processor/wpBlockProcessor.php index f4b9ba3376f88..7bc507c705245 100644 --- a/tests/phpunit/tests/block-processor/wpBlockProcessor.php +++ b/tests/phpunit/tests/block-processor/wpBlockProcessor.php @@ -366,6 +366,8 @@ public static function data_incomplete_html_comments_that_are_not_delimiters() { * Verifies that trailing bytes which could start a block comment delimiter * are not reported as a delimiter. * + * @ticket 66138 + * * @dataProvider data_documents_ending_in_a_partial_delimiter * * @covers ::next_token() @@ -374,7 +376,7 @@ public static function data_incomplete_html_comments_that_are_not_delimiters() { * @param string[] $block_types Printable block type of every delimiter in the document, in order. * @param string|null $last_error Expected error after scanning the entire document. */ - public function test_reports_no_delimiter_for_partial_delimiter_at_end_of_document( $html, $block_types, $last_error ) { + public function test_reports_no_delimiter_for_partial_delimiter_at_end_of_document( $html, $block_types, $last_error ): void { $processor = new WP_Block_Processor( $html ); $found = array(); @@ -398,23 +400,21 @@ public function test_reports_no_delimiter_for_partial_delimiter_at_end_of_docume /** * Data provider. * - * @return array[] + * @return array */ - public static function data_documents_ending_in_a_partial_delimiter() { - $incomplete = WP_Block_Processor::INCOMPLETE_INPUT; - + public static function data_documents_ending_in_a_partial_delimiter(): array { return array( // Documents ending in a partial delimiter with no earlier delimiter. - 'Ends in <' => array( 'text<', array(), $incomplete ), - 'Ends in array( 'text array( 'text array( 'text<', array(), WP_Block_Processor::INCOMPLETE_INPUT ), + 'Ends in array( 'text array( 'text array( 'text<', array( 'core/a' ), $incomplete ), - 'Opener, then ends in array( 'text array( 'text array( 'text array( 'text<', array( 'core/a' ), $incomplete ), + 'Opener, then ends in <' => array( 'text<', array( 'core/a' ), WP_Block_Processor::INCOMPLETE_INPUT ), + 'Opener, then ends in array( 'text array( 'text array( 'text array( 'text<', array( 'core/a' ), WP_Block_Processor::INCOMPLETE_INPUT ), // Documents which do not end in a partial delimiter. 'Contains < but ends in text' => array( 'a