Block Hooks: Move ignoredHookedBlocks metadata injection logic.

As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.

In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)

Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).

Props tomjcafferkey, bernhard-reiter.
Fixes #60759.
Built from https://develop.svn.wordpress.org/trunk@58291


git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Bernhard Reiter 2024-06-03 12:05:15 +00:00
parent 68e3310c02
commit b62b7a599e
4 changed files with 119 additions and 10 deletions

View File

@ -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;
}

View File

@ -1003,14 +1003,124 @@ function set_ignored_hooked_blocks_metadata( &$parsed_anchor_block, $relative_po
}
/**
* Runs the hooked blocks algorithm on the given content.
*
* @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, '<!--' );
return substr( $serialized_block, $start, $end - $start );
}
/**
* Updates the wp_postmeta with the list of ignored hooked blocks where the inner blocks are stored as post content.
* Currently only supports `wp_navigation` post types.
*
* @since 6.6.0
* @access private
*
* @param stdClass $post Post object.
* @return stdClass The updated post object.
*/
function update_ignored_hooked_blocks_postmeta( $post ) {
/*
* In this scenario the user has likely tried to create a navigation via the REST API.
* In which case we won't have a post ID to work with and store meta against.
*/
if ( empty( $post->ID ) ) {
return $post;
}
/**
* Skip meta generation when consumers intentionally update specific Navigation fields
* and omit the content update.
*/
if ( ! isset( $post->post_content ) ) {
return $post;
}
/**
* Skip meta generation when the post content is not a navigation block.
*/
if ( ! isset( $post->post_type ) || 'wp_navigation' !== $post->post_type ) {
return $post;
}
$attributes = array();
$ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true );
if ( ! empty( $ignored_hooked_blocks ) ) {
$ignored_hooked_blocks = json_decode( $ignored_hooked_blocks, true );
$attributes['metadata'] = array(
'ignoredHookedBlocks' => $ignored_hooked_blocks,
);
}
$markup = get_comment_delimited_block_content(
'core/navigation',
$attributes,
$post->post_content
);
$serialized_block = apply_block_hooks_to_content( $markup, get_post( $post->ID ), 'set_ignored_hooked_blocks_metadata' );
$root_block = parse_blocks( $serialized_block )[0];
$ignored_hooked_blocks = isset( $root_block['attrs']['metadata']['ignoredHookedBlocks'] )
? $root_block['attrs']['metadata']['ignoredHookedBlocks']
: array();
if ( ! empty( $ignored_hooked_blocks ) ) {
$existing_ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true );
if ( ! empty( $existing_ignored_hooked_blocks ) ) {
$existing_ignored_hooked_blocks = json_decode( $existing_ignored_hooked_blocks, true );
$ignored_hooked_blocks = array_unique( array_merge( $ignored_hooked_blocks, $existing_ignored_hooked_blocks ) );
}
update_post_meta( $post->ID, '_wp_ignored_hooked_blocks', json_encode( $ignored_hooked_blocks ) );
}
$post->post_content = remove_serialized_parent_block( $serialized_block );
return $post;
}
/*
* 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.
*
* This function is meant for internal use only.
*
* @since 6.6.0
* @access private
*
* @param array $parsed_anchor_block The anchor block, in parsed block array format.
* @param string $relative_position The relative position of the hooked blocks.
* Can be one of 'before', 'after', 'first_child', or 'last_child'.
@ -1019,7 +1129,7 @@ function set_ignored_hooked_blocks_metadata( &$parsed_anchor_block, $relative_po
* @return string
*/
function insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata( &$parsed_anchor_block, $relative_position, $hooked_blocks, $context ) {
$markup = insert_hooked_blocks( $parsed_anchor_block, $relative_position, $hooked_blocks, $context );
$markup = insert_hooked_blocks( $parsed_anchor_block, $relative_position, $hooked_blocks, $context );
$markup .= set_ignored_hooked_blocks_metadata( $parsed_anchor_block, $relative_position, $hooked_blocks, $context );
return $markup;

View File

@ -757,4 +757,7 @@ add_action( 'init', '_wp_register_default_font_collections' );
add_filter( 'rest_pre_insert_wp_template', 'inject_ignored_hooked_blocks_metadata_attributes' );
add_filter( 'rest_pre_insert_wp_template_part', 'inject_ignored_hooked_blocks_metadata_attributes' );
// Update ignoredHookedBlocks postmeta for wp_navigation post type.
add_filter( 'rest_pre_insert_wp_navigation', 'update_ignored_hooked_blocks_postmeta' );
unset( $filter, $action );

View File

@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
$wp_version = '6.6-alpha-58290';
$wp_version = '6.6-alpha-58291';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.