diff --git a/src/wp-includes/block-template-utils.php b/src/wp-includes/block-template-utils.php index 29007811727f6..05012fbf2235f 100644 --- a/src/wp-includes/block-template-utils.php +++ b/src/wp-includes/block-template-utils.php @@ -615,17 +615,7 @@ function _build_block_template_result_from_file( $template_file, $template_type $template->area = $template_file['area']; } - $hooked_blocks = get_hooked_blocks(); - $has_hooked_blocks = ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ); - $before_block_visitor = '_inject_theme_attribute_in_template_part_block'; - $after_block_visitor = null; - - if ( $has_hooked_blocks ) { - $before_block_visitor = make_before_block_visitor( $hooked_blocks, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' ); - $after_block_visitor = make_after_block_visitor( $hooked_blocks, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' ); - } - - if ( 'wp_template_part' === $template->type && $has_hooked_blocks ) { + if ( 'wp_template_part' === $template->type ) { /* * In order for hooked blocks to be inserted at positions first_child and last_child in a template part, * we need to wrap its content a mock template part block and traverse it. @@ -635,13 +625,17 @@ function _build_block_template_result_from_file( $template_file, $template_type array(), $template->content ); - $content = traverse_and_serialize_blocks( parse_blocks( $content ), $before_block_visitor, $after_block_visitor ); + $content = apply_block_hooks_to_content( + $content, + $template, + 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' + ); $template->content = remove_serialized_parent_block( $content ); } else { - $template->content = traverse_and_serialize_blocks( - parse_blocks( $template->content ), - $before_block_visitor, - $after_block_visitor + $template->content = apply_block_hooks_to_content( + $template->content, + $template, + 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' ); } @@ -1036,32 +1030,31 @@ function _build_block_template_result_from_post( $post ) { } } - $hooked_blocks = get_hooked_blocks(); - if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) { - $before_block_visitor = make_before_block_visitor( $hooked_blocks, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' ); - $after_block_visitor = make_after_block_visitor( $hooked_blocks, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' ); - if ( 'wp_template_part' === $template->type ) { - $existing_ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true ); - $attributes = ! empty( $existing_ignored_hooked_blocks ) ? array( 'metadata' => array( 'ignoredHookedBlocks' => json_decode( $existing_ignored_hooked_blocks, true ) ) ) : array(); + if ( 'wp_template_part' === $template->type ) { + $existing_ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true ); + $attributes = ! empty( $existing_ignored_hooked_blocks ) ? array( 'metadata' => array( 'ignoredHookedBlocks' => json_decode( $existing_ignored_hooked_blocks, true ) ) ) : array(); - /* - * In order for hooked blocks to be inserted at positions first_child and last_child in a template part, - * we need to wrap its content a mock template part block and traverse it. - */ - $content = get_comment_delimited_block_content( - 'core/template-part', - $attributes, - $template->content - ); - $content = traverse_and_serialize_blocks( parse_blocks( $content ), $before_block_visitor, $after_block_visitor ); - $template->content = remove_serialized_parent_block( $content ); - } else { - $template->content = traverse_and_serialize_blocks( - parse_blocks( $template->content ), - $before_block_visitor, - $after_block_visitor - ); - } + /* + * In order for hooked blocks to be inserted at positions first_child and last_child in a template part, + * we need to wrap its content a mock template part block and traverse it. + */ + $content = get_comment_delimited_block_content( + 'core/template-part', + $attributes, + $template->content + ); + $content = apply_block_hooks_to_content( + $content, + $template, + 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' + ); + $template->content = remove_serialized_parent_block( $content ); + } else { + $template->content = apply_block_hooks_to_content( + $template->content, + $template, + 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' + ); } return $template; diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index a53092e04e4d7..a479992faa4ca 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -1035,6 +1035,7 @@ function set_ignored_hooked_blocks_metadata( &$parsed_anchor_block, $relative_po * Runs the hooked blocks algorithm on the given content. * * @since 6.6.0 + * @since 6.7.0 Injects the `theme` attribute into Template Part blocks, even if no hooked blocks are registered. * @access private * * @param string $content Serialized content. @@ -1047,15 +1048,16 @@ function set_ignored_hooked_blocks_metadata( &$parsed_anchor_block, $relative_po */ function apply_block_hooks_to_content( $content, $context, $callback = 'insert_hooked_blocks' ) { $hooked_blocks = get_hooked_blocks(); - if ( empty( $hooked_blocks ) && ! has_filter( 'hooked_block_types' ) ) { - return $content; + + $before_block_visitor = '_inject_theme_attribute_in_template_part_block'; + $after_block_visitor = null; + if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) { + $before_block_visitor = make_before_block_visitor( $hooked_blocks, $context, $callback ); + $after_block_visitor = make_after_block_visitor( $hooked_blocks, $context, $callback ); } $blocks = parse_blocks( $content ); - $before_block_visitor = make_before_block_visitor( $hooked_blocks, $context, $callback ); - $after_block_visitor = make_after_block_visitor( $hooked_blocks, $context, $callback ); - return traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor ); } diff --git a/src/wp-includes/class-wp-block-patterns-registry.php b/src/wp-includes/class-wp-block-patterns-registry.php index 6317bc81e51b1..3b5f053bfd8bf 100644 --- a/src/wp-includes/class-wp-block-patterns-registry.php +++ b/src/wp-includes/class-wp-block-patterns-registry.php @@ -158,31 +158,6 @@ public function unregister( $pattern_name ) { return true; } - /** - * Prepares the content of a block pattern. If hooked blocks are registered, they get injected into the pattern, - * when they met the defined criteria. - * - * @since 6.4.0 - * - * @param array $pattern Registered pattern properties. - * @param array $hooked_blocks The list of hooked blocks. - * @return string The content of the block pattern. - */ - private function prepare_content( $pattern, $hooked_blocks ) { - $content = $pattern['content']; - - $before_block_visitor = '_inject_theme_attribute_in_template_part_block'; - $after_block_visitor = null; - if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) { - $before_block_visitor = make_before_block_visitor( $hooked_blocks, $pattern, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' ); - $after_block_visitor = make_after_block_visitor( $hooked_blocks, $pattern, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' ); - } - $blocks = parse_blocks( $content ); - $content = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor ); - - return $content; - } - /** * Retrieves the content of a registered block pattern. * @@ -221,8 +196,12 @@ public function get_registered( $pattern_name ) { } $pattern = $this->registered_patterns[ $pattern_name ]; - $pattern['content'] = $this->get_content( $pattern_name ); - $pattern['content'] = $this->prepare_content( $pattern, get_hooked_blocks() ); + $content = $this->get_content( $pattern_name ); + $pattern['content'] = apply_block_hooks_to_content( + $content, + $pattern, + 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' + ); return $pattern; } @@ -243,8 +222,12 @@ public function get_all_registered( $outside_init_only = false ) { $hooked_blocks = get_hooked_blocks(); foreach ( $patterns as $index => $pattern ) { - $pattern['content'] = $this->get_content( $pattern['name'], $outside_init_only ); - $patterns[ $index ]['content'] = $this->prepare_content( $pattern, $hooked_blocks ); + $content = $this->get_content( $pattern['name'], $outside_init_only ); + $patterns[ $index ]['content'] = apply_block_hooks_to_content( + $content, + $pattern, + 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' + ); } return array_values( $patterns ); diff --git a/tests/phpunit/tests/blocks/applyBlockHooksToContent.php b/tests/phpunit/tests/blocks/applyBlockHooksToContent.php new file mode 100644 index 0000000000000..61f594d011de1 --- /dev/null +++ b/tests/phpunit/tests/blocks/applyBlockHooksToContent.php @@ -0,0 +1,70 @@ + array( + 'tests/anchor-block' => 'after', + ), + ) + ); + } + + /** + * Tear down. + * + * @ticket 61902. + */ + public static function wpTearDownAfterClass() { + $registry = WP_Block_Type_Registry::get_instance(); + + $registry->unregister( 'tests/hooked-block' ); + } + + /** + * @ticket 61902 + */ + public function test_apply_block_hooks_to_content_sets_theme_attribute_on_template_part_block() { + $context = new WP_Block_Template(); + $context->content = ''; + + $actual = apply_block_hooks_to_content( $context->content, $context, 'insert_hooked_blocks' ); + $this->assertSame( + sprintf( '', get_stylesheet() ), + $actual + ); + } + + /** + * @ticket 61902 + */ + public function test_apply_block_hooks_to_content_inserts_hooked_block() { + $context = new WP_Block_Template(); + $context->content = ''; + + $actual = apply_block_hooks_to_content( $context->content, $context, 'insert_hooked_blocks' ); + $this->assertSame( + '', + $actual + ); + } +}