Block Hooks: Respect `"multiple": false` in hooked blocks.
If a prospective hooked block has its `multiple` block-supports field set to `false` (thus allowing only one instance of the block to be present), ensure that: 1. Only one instance of the block will be inserted if it's not yet present in the current context. 2. The block will not be inserted at all if an instance of it is already present in the current context. As always in Block Hooks parlance, "context" denotes the containing template, template part, pattern, or navigation post that a hooked block is supposed to be inserted into. The markup of a webpage that uses a Block Theme typically comprises a number of such contexts -- one template and any number of template parts, patterns, and navigation posts. Note that the limitation imposed by this changeset only applies on a per-context basis, so it's still possible that the resulting page contains more than one instance of a hooked block with `"multiple": false` set, as each context could contribute up to one such instance. Props bernhard-reiter, jonsurrell, gziolo. Fixes #61902. Built from https://develop.svn.wordpress.org/trunk@59124 git-svn-id: http://core.svn.wordpress.org/trunk@58520 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
6cf0577be8
commit
1b6e00c306
|
@ -1056,9 +1056,77 @@ function apply_block_hooks_to_content( $content, $context, $callback = 'insert_h
|
|||
$after_block_visitor = make_after_block_visitor( $hooked_blocks, $context, $callback );
|
||||
}
|
||||
|
||||
$blocks = parse_blocks( $content );
|
||||
$block_allows_multiple_instances = array();
|
||||
/*
|
||||
* Remove hooked blocks from `$hooked_block_types` if they have `multiple` set to false and
|
||||
* are already present in `$content`.
|
||||
*/
|
||||
foreach ( $hooked_blocks as $anchor_block_type => $relative_positions ) {
|
||||
foreach ( $relative_positions as $relative_position => $hooked_block_types ) {
|
||||
foreach ( $hooked_block_types as $index => $hooked_block_type ) {
|
||||
$hooked_block_type_definition =
|
||||
WP_Block_Type_Registry::get_instance()->get_registered( $hooked_block_type );
|
||||
|
||||
return traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
|
||||
$block_allows_multiple_instances[ $hooked_block_type ] =
|
||||
block_has_support( $hooked_block_type_definition, 'multiple', true );
|
||||
|
||||
if (
|
||||
! $block_allows_multiple_instances[ $hooked_block_type ] &&
|
||||
has_block( $hooked_block_type, $content )
|
||||
) {
|
||||
unset( $hooked_blocks[ $anchor_block_type ][ $relative_position ][ $index ] );
|
||||
}
|
||||
}
|
||||
if ( empty( $hooked_blocks[ $anchor_block_type ][ $relative_position ] ) ) {
|
||||
unset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] );
|
||||
}
|
||||
}
|
||||
if ( empty( $hooked_blocks[ $anchor_block_type ] ) ) {
|
||||
unset( $hooked_blocks[ $anchor_block_type ] );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We also need to cover the case where the hooked block is not present in
|
||||
* `$content` at first and we're allowed to insert it once -- but not again.
|
||||
*/
|
||||
$suppress_single_instance_blocks = static function ( $hooked_block_types ) use ( &$block_allows_multiple_instances, $content ) {
|
||||
static $single_instance_blocks_present_in_content = array();
|
||||
foreach ( $hooked_block_types as $index => $hooked_block_type ) {
|
||||
if ( ! isset( $block_allows_multiple_instances[ $hooked_block_type ] ) ) {
|
||||
$hooked_block_type_definition =
|
||||
WP_Block_Type_Registry::get_instance()->get_registered( $hooked_block_type );
|
||||
|
||||
$block_allows_multiple_instances[ $hooked_block_type ] =
|
||||
block_has_support( $hooked_block_type_definition, 'multiple', true );
|
||||
}
|
||||
|
||||
if ( $block_allows_multiple_instances[ $hooked_block_type ] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The block doesn't allow multiple instances, so we need to check if it's already present.
|
||||
if (
|
||||
in_array( $hooked_block_type, $single_instance_blocks_present_in_content, true ) ||
|
||||
has_block( $hooked_block_type, $content )
|
||||
) {
|
||||
unset( $hooked_block_types[ $index ] );
|
||||
} else {
|
||||
// We can insert the block once, but need to remember not to insert it again.
|
||||
$single_instance_blocks_present_in_content[] = $hooked_block_type;
|
||||
}
|
||||
}
|
||||
return $hooked_block_types;
|
||||
};
|
||||
add_filter( 'hooked_block_types', $suppress_single_instance_blocks, PHP_INT_MAX );
|
||||
$content = traverse_and_serialize_blocks(
|
||||
parse_blocks( $content ),
|
||||
$before_block_visitor,
|
||||
$after_block_visitor
|
||||
);
|
||||
remove_filter( 'hooked_block_types', $suppress_single_instance_blocks, PHP_INT_MAX );
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
*
|
||||
* @global string $wp_version
|
||||
*/
|
||||
$wp_version = '6.7-alpha-59123';
|
||||
$wp_version = '6.7-alpha-59124';
|
||||
|
||||
/**
|
||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||
|
|
Loading…
Reference in New Issue