From 808eef429a966e874c68264a3ac77f997006d19c Mon Sep 17 00:00:00 2001 From: rejaulalomkhan Date: Mon, 2 Nov 2026 10:52:18 +0600 Subject: [PATCH 1/3] Blocks: Treat a null document as empty in WP_Block_Parser::parse(). Since [64870], parse() passes its document to the WP_Block_Processor constructor, which is typed to accept only a string. A null document therefore causes a fatal TypeError in parse_blocks(), do_blocks(), and anything hooked to the_content, where previously the parser returned an empty list of blocks. Follow-up to [64870]. See #66138. --- src/wp-includes/class-wp-block-parser.php | 6 +++--- tests/phpunit/tests/blocks/wpBlockParser.php | 13 +++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/class-wp-block-parser.php b/src/wp-includes/class-wp-block-parser.php index 06342fc5acb64..eaf36dc2903d2 100644 --- a/src/wp-includes/class-wp-block-parser.php +++ b/src/wp-includes/class-wp-block-parser.php @@ -67,16 +67,16 @@ class WP_Block_Parser { * * @since 5.0.0 * - * @param string $document Input document being parsed. + * @param string|null $document Input document being parsed. Null is treated as an empty document. * @return array[] */ public function parse( $document ) { - $this->document = $document; + $this->document = $document ?? ''; $this->offset = 0; $this->output = array(); $this->stack = array(); - $this->block_processor = new WP_Block_Processor( $document ); + $this->block_processor = new WP_Block_Processor( $this->document ); while ( $this->proceed() ) { continue; diff --git a/tests/phpunit/tests/blocks/wpBlockParser.php b/tests/phpunit/tests/blocks/wpBlockParser.php index 07fdb556efcc4..8dae5e9918249 100644 --- a/tests/phpunit/tests/blocks/wpBlockParser.php +++ b/tests/phpunit/tests/blocks/wpBlockParser.php @@ -42,6 +42,19 @@ public function test_parses_basic_empty_block() { ); } + /** + * Ensures that a null document parses as an empty document instead of causing a fatal error. + * + * @ticket 66138 + * + * @covers ::parse + */ + public function test_parses_null_document_as_empty() { + $p = new WP_Block_Parser(); + + $this->assertSame( array(), $p->parse( null ) ); + } + /** * Ensures that implicitly closing a final open block does not repeat content parsed before it. * From 39ccd66409f61b717194b2172edb292860b733b7 Mon Sep 17 00:00:00 2001 From: rejaulalomkhan Date: Thu, 5 Nov 2026 10:25:58 +0600 Subject: [PATCH 2/3] Blocks: Return an empty array for a non-string document in WP_Block_Parser::parse(). --- src/wp-includes/class-wp-block-parser.php | 16 +++++++++--- tests/phpunit/tests/blocks/wpBlockParser.php | 26 +++++++++++++++++--- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/wp-includes/class-wp-block-parser.php b/src/wp-includes/class-wp-block-parser.php index eaf36dc2903d2..fcc67f22f55a4 100644 --- a/src/wp-includes/class-wp-block-parser.php +++ b/src/wp-includes/class-wp-block-parser.php @@ -66,17 +66,27 @@ class WP_Block_Parser { * return an error on invalid inputs. * * @since 5.0.0 + * @since 7.2.0 Returns an empty array and triggers a notice when the document is not a string. * - * @param string|null $document Input document being parsed. Null is treated as an empty document. + * @param string $document Input document being parsed. * @return array[] */ public function parse( $document ) { - $this->document = $document ?? ''; + if ( ! is_string( $document ) ) { + _doing_it_wrong( + __METHOD__, + __( 'The document must be a string.' ), + '7.2.0' + ); + return array(); + } + + $this->document = $document; $this->offset = 0; $this->output = array(); $this->stack = array(); - $this->block_processor = new WP_Block_Processor( $this->document ); + $this->block_processor = new WP_Block_Processor( $document ); while ( $this->proceed() ) { continue; diff --git a/tests/phpunit/tests/blocks/wpBlockParser.php b/tests/phpunit/tests/blocks/wpBlockParser.php index 8dae5e9918249..560353699b071 100644 --- a/tests/phpunit/tests/blocks/wpBlockParser.php +++ b/tests/phpunit/tests/blocks/wpBlockParser.php @@ -43,16 +43,36 @@ public function test_parses_basic_empty_block() { } /** - * Ensures that a null document parses as an empty document instead of causing a fatal error. + * Ensures that a document that is not a string returns an empty array and triggers a notice. * * @ticket 66138 * * @covers ::parse + * + * @dataProvider data_non_string_documents + * + * @expectedIncorrectUsage WP_Block_Parser::parse + * + * @param mixed $document Document that is not a string. */ - public function test_parses_null_document_as_empty() { + public function test_returns_empty_array_for_non_string_document( $document ) { $p = new WP_Block_Parser(); - $this->assertSame( array(), $p->parse( null ) ); + $this->assertSame( array(), $p->parse( $document ) ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_non_string_documents() { + return array( + 'null' => array( null ), + 'false' => array( false ), + 'integer' => array( 123 ), + 'array' => array( array( 'content' ) ), + ); } /** From afa82b15af08eced4704e4e3cac9cf66aaa0ad3f Mon Sep 17 00:00:00 2001 From: rejaulalomkhan Date: Wed, 11 Nov 2026 10:24:00 +0600 Subject: [PATCH 3/3] Blocks: Keep parsing a stringable document in WP_Block_Parser::parse(). A stringable object parses normally on 7.1 and trunk because PHP converts it to a string. Convert it explicitly and trigger a notice, rather than returning an empty array. See #66138. --- src/wp-includes/class-wp-block-parser.php | 12 +++++++- tests/phpunit/tests/blocks/wpBlockParser.php | 29 ++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-block-parser.php b/src/wp-includes/class-wp-block-parser.php index fcc67f22f55a4..13c5ac2029518 100644 --- a/src/wp-includes/class-wp-block-parser.php +++ b/src/wp-includes/class-wp-block-parser.php @@ -66,12 +66,22 @@ class WP_Block_Parser { * return an error on invalid inputs. * * @since 5.0.0 - * @since 7.2.0 Returns an empty array and triggers a notice when the document is not a string. + * @since 7.2.0 Triggers a notice when the document is not a string, and returns + * an empty array unless the document is a stringable object. * * @param string $document Input document being parsed. * @return array[] */ public function parse( $document ) { + if ( is_object( $document ) && method_exists( $document, '__toString' ) ) { + _doing_it_wrong( + __METHOD__, + __( 'Convert the document to a string before calling parse().' ), + '7.2.0' + ); + $document = (string) $document; + } + if ( ! is_string( $document ) ) { _doing_it_wrong( __METHOD__, diff --git a/tests/phpunit/tests/blocks/wpBlockParser.php b/tests/phpunit/tests/blocks/wpBlockParser.php index 560353699b071..37da69265b228 100644 --- a/tests/phpunit/tests/blocks/wpBlockParser.php +++ b/tests/phpunit/tests/blocks/wpBlockParser.php @@ -72,9 +72,38 @@ public static function data_non_string_documents() { 'false' => array( false ), 'integer' => array( 123 ), 'array' => array( array( 'content' ) ), + 'object' => array( new stdClass() ), ); } + /** + * Ensures that a stringable object is parsed as a string and triggers a notice. + * + * @ticket 66138 + * + * @covers ::parse + * + * @expectedIncorrectUsage WP_Block_Parser::parse + */ + public function test_parses_stringable_document_as_string() { + $markup = '

Hello

'; + $document = new class( $markup ) { + private $markup; + + public function __construct( $markup ) { + $this->markup = $markup; + } + + public function __toString() { + return $this->markup; + } + }; + + $p = new WP_Block_Parser(); + + $this->assertSame( $p->parse( $markup ), $p->parse( $document ) ); + } + /** * Ensures that implicitly closing a final open block does not repeat content parsed before it. *