diff --git a/.changeset/silver-cups-explode.md b/.changeset/silver-cups-explode.md new file mode 100644 index 00000000..a23860d9 --- /dev/null +++ b/.changeset/silver-cups-explode.md @@ -0,0 +1,5 @@ +--- +"@wpengine/wp-graphql-content-blocks": minor +--- + +feat: add support for resolving Template Part blocks diff --git a/includes/Data/ContentBlocksResolver.php b/includes/Data/ContentBlocksResolver.php index fbf07786..dcf6c43c 100644 --- a/includes/Data/ContentBlocksResolver.php +++ b/includes/Data/ContentBlocksResolver.php @@ -148,7 +148,7 @@ private static function handle_do_block( array $block ): ?array { $block['clientId'] = uniqid(); // @todo apply more hydrations. - + $block = self::populate_template_part_inner_blocks( $block ); $block = self::populate_reusable_blocks( $block ); $block = self::populate_pattern_inner_blocks( $block ); @@ -183,6 +183,36 @@ private static function is_block_empty( array $block ): bool { return empty( trim( $stripped ?? '' ) ); } + /** + * Populates the innerBlocks of a template part block with the blocks from the template part. + * + * @param array $block The block to populate. + * + * @return array The populated block. + */ + private static function populate_template_part_inner_blocks( array $block ): array { + // Bail if not WP 5.8 or later. + if ( ! function_exists( 'get_block_templates' ) ) { + return $block; + } + + if ( 'core/template-part' !== $block['blockName'] || ! isset( $block['attrs']['slug'] ) ) { + return $block; + } + + $matching_templates = get_block_templates( [ 'slug__in' => [ $block['attrs']['slug'] ] ], 'wp_template_part' ); + + $template_blocks = ! empty( $matching_templates[0]->content ) ? self::parse_blocks( $matching_templates[0]->content ) : null; + + if ( empty( $template_blocks ) ) { + return $block; + } + + $block['innerBlocks'] = $template_blocks; + + return $block; + } + /** * Populates reusable blocks with the blocks from the reusable ref ID. * diff --git a/tests/unit/ContentBlocksResolverTest.php b/tests/unit/ContentBlocksResolverTest.php index ad509119..dea2faae 100644 --- a/tests/unit/ContentBlocksResolverTest.php +++ b/tests/unit/ContentBlocksResolverTest.php @@ -413,4 +413,58 @@ public function test_resolve_content_blocks_resolves_pattern_inner_blocks() { // Cleanup: Unregistering the pattern. unregister_block_pattern( $pattern_name ); } + + /** + * Tests that template part inner blocks are resolved correctly. + */ + public function test_resolve_content_blocks_resolves_template_part_inner_blocks() { + // Skip if template part functionality is not supported + if ( ! function_exists( 'get_block_templates' ) ) { + $this->markTestSkipped( 'Template part functionality not supported in this WordPress version.' ); + } + + // Mock the get_block_templates function to control the output. + $mock_template = (object) [ + 'content' => '', + ]; + + add_filter( + 'get_block_templates', + function () use ( $mock_template ) { + return [ $mock_template ]; + } + ); + + // Update post content to include template part block + $post_content = ' + + '; + + wp_update_post( + [ + 'ID' => $this->post_id, + 'post_content' => $post_content, + ] + ); + + $post_model = new Post( get_post( $this->post_id ) ); + + // Resolve blocks as nested + $resolved_blocks = $this->instance->resolve_content_blocks( $post_model, [ 'flat' => false ] ); + + // Assertions + $this->assertCount( 1, $resolved_blocks, 'There should be only one top-level block (template-part).' ); + $this->assertEquals( 'core/template-part', $resolved_blocks[0]['blockName'] ); + $this->assertCount( 2, $resolved_blocks[0]['innerBlocks'], 'There should be two inner blocks in the template part.' ); + $this->assertEquals( 'core/paragraph', $resolved_blocks[0]['innerBlocks'][0]['blockName'] ); + $this->assertEquals( 'core/heading', $resolved_blocks[0]['innerBlocks'][1]['blockName'] ); + + // Resolve blocks as flat + $resolved_flat_blocks = $this->instance->resolve_content_blocks( $post_model, [ 'flat' => true ] ); + + $this->assertCount( 3, $resolved_flat_blocks, 'There should be three blocks when flattened.' ); + $this->assertEquals( 'core/template-part', $resolved_flat_blocks[0]['blockName'] ); + $this->assertEquals( 'core/paragraph', $resolved_flat_blocks[1]['blockName'] ); + $this->assertEquals( 'core/heading', $resolved_flat_blocks[2]['blockName'] ); + } }