diff --git a/src/parser/content-parser.php b/src/parser/content-parser.php index c5c4e94..7c8535b 100644 --- a/src/parser/content-parser.php +++ b/src/parser/content-parser.php @@ -683,7 +683,14 @@ protected function source_block_raw( $crawler ) { $attribute_value = null; if ( $crawler->count() > 0 ) { - $attribute_value = trim( $crawler->outerHtml() ); + // $crawler's outerHtml() will only return the HTML of the first node in this raw HTML. + // If the raw HTML contains multiple top-level nodes, we need to use the inner HTML of the wrapping + // 'body' tag. This will also preserve internal whitespace in the HTML. + $body_node = $crawler->closest( 'body' ); + + if ( $body_node && $body_node->count() > 0 ) { + $attribute_value = trim( $body_node->html() ); + } } return $attribute_value; diff --git a/tests/parser/sources/test-source-raw.php b/tests/parser/sources/test-source-raw.php index f6d52b9..59c60f5 100644 --- a/tests/parser/sources/test-source-raw.php +++ b/tests/parser/sources/test-source-raw.php @@ -79,4 +79,61 @@ public function test_parse_raw_source__nested() { $this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) ); $this->assertArraySubset( $expected_blocks, $blocks['blocks'], true ); } + + public function test_parse_raw_source_multiple_top_level_nodes() { + $this->register_block_with_attributes( 'test/html', [ + 'content' => [ + 'type' => 'string', + 'source' => 'raw', + ], + ] ); + + $html = ' + +

Node 1

Node 2

+ '; + + $expected_blocks = [ + [ + 'name' => 'test/html', + 'attributes' => [ + 'content' => '

Node 1

Node 2

', + ], + ], + ]; + + $content_parser = new ContentParser( $this->get_block_registry() ); + $blocks = $content_parser->parse( $html ); + $this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) ); + $this->assertArraySubset( $expected_blocks, $blocks['blocks'], true ); + } + + public function test_parse_raw_source_multiple_top_level_nodes_with_whitespace() { + $this->register_block_with_attributes( 'test/html', [ + 'content' => [ + 'type' => 'string', + 'source' => 'raw', + ], + ] ); + + $html = ' + + This should retain inner +whitespace + '; + + $expected_blocks = [ + [ + 'name' => 'test/html', + 'attributes' => [ + 'content' => "This should retain inner\nwhitespace", + ], + ], + ]; + + $content_parser = new ContentParser( $this->get_block_registry() ); + $blocks = $content_parser->parse( $html ); + $this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) ); + $this->assertArraySubset( $expected_blocks, $blocks['blocks'], true ); + } }