From 3364ae2ff2edb80fb513b7986e6d0ead3ef5e786 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 3 Jun 2024 12:11:09 +0200 Subject: [PATCH] Block Hooks API: Move ignoredHookedBlocks metadata injection logic --- src/wp-includes/block-template-utils.php | 6 +- src/wp-includes/blocks.php | 118 ++++++++++- src/wp-includes/default-filters.php | 3 + .../updateIgnoredHookedBlocksPostMeta.php | 196 ++++++++++++++++++ 4 files changed, 314 insertions(+), 9 deletions(-) create mode 100644 tests/phpunit/tests/blocks/updateIgnoredHookedBlocksPostMeta.php diff --git a/src/wp-includes/block-template-utils.php b/src/wp-includes/block-template-utils.php index 8efb03be1af1..b789ed86b778 100644 --- a/src/wp-includes/block-template-utils.php +++ b/src/wp-includes/block-template-utils.php @@ -1599,11 +1599,7 @@ function inject_ignored_hooked_blocks_metadata_attributes( $changes, $deprecated return $template; } - $before_block_visitor = make_before_block_visitor( $hooked_blocks, $template, 'set_ignored_hooked_blocks_metadata' ); - $after_block_visitor = make_after_block_visitor( $hooked_blocks, $template, 'set_ignored_hooked_blocks_metadata' ); - - $blocks = parse_blocks( $changes->post_content ); - $changes->post_content = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor ); + $changes->post_content = apply_block_hooks_to_content( $changes->post_content, $template, 'set_ignored_hooked_blocks_metadata' ); return $changes; } diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index 6727298d75b9..00391b1bc63c 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -1003,14 +1003,124 @@ function set_ignored_hooked_blocks_metadata( &$parsed_anchor_block, $relative_po } /** - * Returns the markup for blocks hooked to the given anchor block in a specific relative position and then - * adds a list of hooked block types to an anchor block's ignored hooked block types. + * Runs the hooked blocks algorithm on the given content. * - * This function is meant for internal use only. + * @since 6.6.0 + * @access private + * + * @param string $content Serialized content. + * @param WP_Block_Template|WP_Post|array $context A block template, template part, `wp_navigation` post object, + * or pattern that the blocks belong to. + * @param callable $callback A function that will be called for each block to generate + * the markup for a given list of blocks that are hooked to it. + * Default: 'insert_hooked_blocks'. + * @return string The serialized markup. + */ +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; + } + + $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 ); +} + +/** + * Accepts the serialized markup of a block and its inner blocks, and returns serialized markup of the inner blocks. * * @since 6.6.0 * @access private * + * @param string $serialized_block The serialized markup of a block and its inner blocks. + * @return string The serialized markup of the inner blocks. + */ +function remove_serialized_parent_block( $serialized_block ) { + $start = strpos( $serialized_block, '-->' ) + strlen( '-->' ); + $end = strrpos( $serialized_block, ''; + $post = new stdClass(); + $post->ID = self::$navigation_post->ID; + $post->post_content = $original_markup; + $post->post_type = 'wp_navigation'; + + $post = update_ignored_hooked_blocks_postmeta( $post ); + + // We expect the '&' character to be replaced with its unicode representation. + $expected_markup = str_replace( '&', '\u0026', $original_markup ); + + $this->assertSame( + $expected_markup, + $post->post_content, + 'Post content did not match expected markup with entities escaped.' + ); + $this->assertSame( + array( 'tests/my-block' ), + json_decode( get_post_meta( self::$navigation_post->ID, '_wp_ignored_hooked_blocks', true ), true ), + 'Block was not added to ignored hooked blocks metadata.' + ); + } + + /** + * @ticket 60759 + */ + public function test_update_ignored_hooked_blocks_postmeta_dont_modify_no_post_id() { + register_block_type( + 'tests/my-block', + array( + 'block_hooks' => array( + 'core/navigation' => 'last_child', + ), + ) + ); + + $original_markup = ''; + $post = new stdClass(); + $post->post_content = $original_markup; + $post->post_type = 'wp_navigation'; + + $post = update_ignored_hooked_blocks_postmeta( $post ); + + $this->assertSame( + $original_markup, + $post->post_content, + 'Post content did not match the original markup.' + ); + } + + /** + * @ticket 60759 + */ + public function test_update_ignored_hooked_blocks_postmeta_retains_content_if_not_set() { + register_block_type( + 'tests/my-block', + array( + 'block_hooks' => array( + 'core/navigation' => 'last_child', + ), + ) + ); + + $post = new stdClass(); + $post->ID = self::$navigation_post->ID; + $post->post_title = 'Navigation Menu with changes'; + $post->post_type = 'wp_navigation'; + + $post = update_ignored_hooked_blocks_postmeta( $post ); + + $this->assertSame( + 'Navigation Menu with changes', + $post->post_title, + 'Post title was changed.' + ); + + $this->assertFalse( + isset( $post->post_content ), + 'Post content should not be set.' + ); + } + + /** + * @ticket 60759 + */ + public function test_update_ignored_hooked_blocks_postmeta_dont_modify_if_not_navigation() { + register_block_type( + 'tests/my-block', + array( + 'block_hooks' => array( + 'core/navigation' => 'last_child', + ), + ) + ); + + $original_markup = ''; + $post = new stdClass(); + $post->ID = self::$navigation_post->ID; + $post->post_content = $original_markup; + $post->post_type = 'post'; + + $post = update_ignored_hooked_blocks_postmeta( $post ); + + $this->assertSame( + $original_markup, + $post->post_content, + 'Post content did not match the original markup.' + ); + } + + /** + * @ticket 60759 + */ + public function test_update_ignored_hooked_blocks_postmeta_dont_modify_if_no_post_type() { + register_block_type( + 'tests/my-block', + array( + 'block_hooks' => array( + 'core/navigation' => 'last_child', + ), + ) + ); + + $original_markup = ''; + $post = new stdClass(); + $post->ID = self::$navigation_post->ID; + $post->post_content = $original_markup; + + $post = update_ignored_hooked_blocks_postmeta( $post ); + + $this->assertSame( + $original_markup, + $post->post_content, + 'Post content did not match the original markup.' + ); + } +}