diff --git a/src/wp-includes/class-wp-block-processor.php b/src/wp-includes/class-wp-block-processor.php index 7c22dc1ea87cd..b97d21633adff 100644 --- a/src/wp-includes/class-wp-block-processor.php +++ b/src/wp-includes/class-wp-block-processor.php @@ -831,6 +831,11 @@ public function next_token(): bool { $this->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..7bc507c705245 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. + * + * @ticket 66138 + * + * @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 ): void { + $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(): array { + return array( + // Documents ending in a partial delimiter with no earlier delimiter. + 'Ends in <' => array( 'text<', array(), WP_Block_Processor::INCOMPLETE_INPUT ), + 'Ends in array( 'text array( 'text 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 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.