Block Hooks: Allow child insertion into Template Part block.
The Block Hooks mechanism was previously extended to allow insertion of a block as a Navigation block's first or last child. This was implemented by storing the `ignoredHookedBlocks` array in the corresponding `wp_navigation` post's post meta (instead of a metadata attribute on the anchor block). This changeset extends that mechanism to Template Part blocks, by storing said metadata in the corresponding `wp_template_part` post's post meta, thus allowing extenders to use Block Hooks to insert a block as a Template Part block's first or last child, respectively. Props tomjcafferkey, bernhard-reiter. Fixes #60854. Built from https://develop.svn.wordpress.org/trunk@58614 git-svn-id: http://core.svn.wordpress.org/trunk@58047 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
df598e1d98
commit
73b9a4956f
|
@ -606,15 +606,35 @@ function _build_block_template_result_from_file( $template_file, $template_type
|
||||||
$template->area = $template_file['area'];
|
$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';
|
$before_block_visitor = '_inject_theme_attribute_in_template_part_block';
|
||||||
$after_block_visitor = null;
|
$after_block_visitor = null;
|
||||||
$hooked_blocks = get_hooked_blocks();
|
|
||||||
if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) {
|
if ( $has_hooked_blocks ) {
|
||||||
$before_block_visitor = make_before_block_visitor( $hooked_blocks, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' );
|
$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' );
|
$after_block_visitor = make_after_block_visitor( $hooked_blocks, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' );
|
||||||
}
|
}
|
||||||
$blocks = parse_blocks( $template->content );
|
|
||||||
$template->content = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
|
if ( 'wp_template_part' === $template->type && $has_hooked_blocks ) {
|
||||||
|
/**
|
||||||
|
* 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',
|
||||||
|
array(),
|
||||||
|
$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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return $template;
|
return $template;
|
||||||
}
|
}
|
||||||
|
@ -998,8 +1018,28 @@ function _build_block_template_result_from_post( $post ) {
|
||||||
if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) {
|
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' );
|
$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' );
|
$after_block_visitor = make_after_block_visitor( $hooked_blocks, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' );
|
||||||
$blocks = parse_blocks( $template->content );
|
if ( 'wp_template_part' === $template->type ) {
|
||||||
$template->content = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
|
$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
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $template;
|
return $template;
|
||||||
|
@ -1611,7 +1651,36 @@ function inject_ignored_hooked_blocks_metadata_attributes( $changes, $deprecated
|
||||||
return $template;
|
return $template;
|
||||||
}
|
}
|
||||||
|
|
||||||
$changes->post_content = apply_block_hooks_to_content( $changes->post_content, $template, 'set_ignored_hooked_blocks_metadata' );
|
if ( 'wp_template_part' === $post->post_type ) {
|
||||||
|
$attributes = array();
|
||||||
|
$existing_ignored_hooked_blocks = isset( $post->ID ) ? get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true ) : '';
|
||||||
|
|
||||||
|
if ( ! empty( $existing_ignored_hooked_blocks ) ) {
|
||||||
|
$attributes['metadata'] = array(
|
||||||
|
'ignoredHookedBlocks' => json_decode( $existing_ignored_hooked_blocks, true ),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = get_comment_delimited_block_content(
|
||||||
|
'core/template-part',
|
||||||
|
$attributes,
|
||||||
|
$changes->post_content
|
||||||
|
);
|
||||||
|
$content = apply_block_hooks_to_content( $content, $template, 'set_ignored_hooked_blocks_metadata' );
|
||||||
|
$changes->post_content = remove_serialized_parent_block( $content );
|
||||||
|
|
||||||
|
$wrapper_block_markup = extract_serialized_parent_block( $content );
|
||||||
|
$wrapper_block = parse_blocks( $wrapper_block_markup )[0];
|
||||||
|
$ignored_hooked_blocks = $wrapper_block['attrs']['metadata']['ignoredHookedBlocks'] ?? array();
|
||||||
|
if ( ! empty( $ignored_hooked_blocks ) ) {
|
||||||
|
if ( ! isset( $changes->meta_input ) ) {
|
||||||
|
$changes->meta_input = array();
|
||||||
|
}
|
||||||
|
$changes->meta_input['_wp_ignored_hooked_blocks'] = wp_json_encode( $ignored_hooked_blocks );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$changes->post_content = apply_block_hooks_to_content( $changes->post_content, $template, 'set_ignored_hooked_blocks_metadata' );
|
||||||
|
}
|
||||||
|
|
||||||
return $changes;
|
return $changes;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1045,6 +1045,23 @@ function remove_serialized_parent_block( $serialized_block ) {
|
||||||
return substr( $serialized_block, $start, $end - $start );
|
return substr( $serialized_block, $start, $end - $start );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts the serialized markup of a block and its inner blocks, and returns serialized markup of the wrapper block.
|
||||||
|
*
|
||||||
|
* @since 6.7.0
|
||||||
|
* @access private
|
||||||
|
*
|
||||||
|
* @see remove_serialized_parent_block()
|
||||||
|
*
|
||||||
|
* @param string $serialized_block The serialized markup of a block and its inner blocks.
|
||||||
|
* @return string The serialized markup of the wrapper block.
|
||||||
|
*/
|
||||||
|
function extract_serialized_parent_block( $serialized_block ) {
|
||||||
|
$start = strpos( $serialized_block, '-->' ) + strlen( '-->' );
|
||||||
|
$end = strrpos( $serialized_block, '<!--' );
|
||||||
|
return substr( $serialized_block, 0, $start ) . substr( $serialized_block, $end );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the wp_postmeta with the list of ignored hooked blocks where the inner blocks are stored as post content.
|
* 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.
|
* Currently only supports `wp_navigation` post types.
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
* @global string $wp_version
|
* @global string $wp_version
|
||||||
*/
|
*/
|
||||||
$wp_version = '6.7-alpha-58613';
|
$wp_version = '6.7-alpha-58614';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||||
|
|
Loading…
Reference in New Issue