Blocks: Introduce filter to allow easy addition of hooked blocks.

Introduce a `hooked_block_types` filter that allows easier conditional addition (or removal) of hooked blocks for a given anchor block and relative position.

{{{#!php
function insert_shopping_cart_hooked_block( $hooked_blocks, $position, $anchor_block, $context ) {
	if ( 'after' === $position && 'core/navigation' === $anchor_block && /** $context is header template part **/ ) {
		$hooked_blocks[] = 'mycommerce/shopping-cart';
	}
	return $hooked_blocks;
}
add_filter( 'hooked_block_types', 'insert_shopping_cart_hooked_block', 10, 4 );
}}}

Props gziolo, nerrad, dmsnell, ndiego.
Fixes #59424.

git-svn-id: https://develop.svn.wordpress.org/trunk@56673 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Bernie Reiter 2023-09-25 08:42:45 +00:00
parent cc40da134e
commit 75c06d620c
2 changed files with 90 additions and 50 deletions

View File

@ -744,20 +744,25 @@ function get_dynamic_block_names() {
*
* @since 6.4.0
*
* @param string $name Block type name including namespace.
* @param string $name Block type name including namespace.
* @param string $relative_position Optional. Relative position of the hooked block. Default empty string.
* @return array Associative array of `$block_type_name => $position` pairs.
*/
function get_hooked_blocks( $name ) {
function get_hooked_blocks( $name, $relative_position = '' ) {
$block_types = WP_Block_Type_Registry::get_instance()->get_all_registered();
$hooked_blocks = array();
foreach ( $block_types as $block_type ) {
if ( ! property_exists( $block_type, 'block_hooks' ) || ! is_array( $block_type->block_hooks ) ) {
continue;
}
foreach ( $block_type->block_hooks as $anchor_block_type => $relative_position ) {
if ( $anchor_block_type === $name ) {
$hooked_blocks[ $block_type->name ] = $relative_position;
foreach ( $block_type->block_hooks as $anchor_block_type => $position ) {
if ( $anchor_block_type !== $name ) {
continue;
}
if ( $relative_position && $relative_position !== $position ) {
continue;
}
$hooked_blocks[ $block_type->name ] = $position;
}
}
return $hooked_blocks;
@ -797,34 +802,48 @@ function make_before_block_visitor( $context ) {
if ( $parent && ! $prev ) {
// Candidate for first-child insertion.
$hooked_blocks_for_parent = get_hooked_blocks( $parent['blockName'] );
foreach ( $hooked_blocks_for_parent as $hooked_block_type => $relative_position ) {
if ( 'first_child' === $relative_position ) {
$hooked_block_markup = get_comment_delimited_block_content( $hooked_block_type, array(), '' );
/** This filter is documented in wp-includes/blocks.php */
$markup .= apply_filters( 'inject_hooked_block_markup', $hooked_block_markup, $hooked_block_type, $relative_position, $parent, $context );
}
$relative_position = 'first_child';
$anchor_block_type = $parent['blockName'];
$hooked_block_types = array_keys( get_hooked_blocks( $anchor_block_type, $relative_position ) );
/**
* Filters the list of hooked block types for a given anchor block type and relative position.
*
* @since 6.4.0
*
* @param string[] $hooked_block_types The list of hooked block types.
* @param string $relative_position The relative position of the hooked blocks.
* Can be one of 'before', 'after', 'first_child', or 'last_child'.
* @param string $anchor_block_type The anchor block type.
* @param WP_Block_Template|array $context The block template, template part, or pattern that the anchor block belongs to.
*/
$hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context );
foreach ( $hooked_block_types as $hooked_block_type ) {
$hooked_block_markup = get_comment_delimited_block_content( $hooked_block_type, array(), '' );
/** This filter is documented in wp-includes/blocks.php */
$markup .= apply_filters( 'inject_hooked_block_markup', $hooked_block_markup, $hooked_block_type, $relative_position, $parent, $context );
}
}
$hooked_blocks = get_hooked_blocks( $block['blockName'] );
foreach ( $hooked_blocks as $hooked_block_type => $relative_position ) {
if ( 'before' === $relative_position ) {
$hooked_block_markup = get_comment_delimited_block_content( $hooked_block_type, array(), '' );
/**
* Filters the serialized markup of a hooked block.
*
* @since 6.4.0
*
* @param string $hooked_block_markup The serialized markup of the hooked block.
* @param string $hooked_block_type The type of the hooked block.
* @param string $relative_position The relative position of the hooked block.
* Can be one of 'before', 'after', 'first_child', or 'last_child'.
* @param array $block The anchor block.
* @param WP_Block_Template|array $context The block template, template part, or pattern that the anchor block belongs to.
*/
$markup .= apply_filters( 'inject_hooked_block_markup', $hooked_block_markup, $hooked_block_type, $relative_position, $block, $context );
}
$relative_position = 'before';
$anchor_block_type = $block['blockName'];
$hooked_block_types = array_keys( get_hooked_blocks( $anchor_block_type, $relative_position ) );
/** This filter is documented in wp-includes/blocks.php */
$hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context );
foreach ( $hooked_block_types as $hooked_block_type ) {
$hooked_block_markup = get_comment_delimited_block_content( $hooked_block_type, array(), '' );
/**
* Filters the serialized markup of a hooked block.
*
* @since 6.4.0
*
* @param string $hooked_block_markup The serialized markup of the hooked block.
* @param string $hooked_block_type The type of the hooked block.
* @param string $relative_position The relative position of the hooked block.
* Can be one of 'before', 'after', 'first_child', or 'last_child'.
* @param array $block The anchor block.
* @param WP_Block_Template|array $context The block template, template part, or pattern that the anchor block belongs to.
*/
$markup .= apply_filters( 'inject_hooked_block_markup', $hooked_block_markup, $hooked_block_type, $relative_position, $block, $context );
}
return $markup;
@ -860,24 +879,28 @@ function make_after_block_visitor( $context ) {
return function( &$block, $parent = null, $next = null ) use ( $context ) {
$markup = '';
$hooked_blocks = get_hooked_blocks( $block['blockName'] );
foreach ( $hooked_blocks as $hooked_block_type => $relative_position ) {
if ( 'after' === $relative_position ) {
$hooked_block_markup = get_comment_delimited_block_content( $hooked_block_type, array(), '' );
/** This filter is documented in wp-includes/blocks.php */
$markup .= apply_filters( 'inject_hooked_block_markup', $hooked_block_markup, $hooked_block_type, $relative_position, $block, $context );
}
$relative_position = 'after';
$anchor_block_type = $block['blockName'];
$hooked_block_types = array_keys( get_hooked_blocks( $anchor_block_type, $relative_position ) );
/** This filter is documented in wp-includes/blocks.php */
$hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context );
foreach ( $hooked_block_types as $hooked_block_type ) {
$hooked_block_markup = get_comment_delimited_block_content( $hooked_block_type, array(), '' );
/** This filter is documented in wp-includes/blocks.php */
$markup .= apply_filters( 'inject_hooked_block_markup', $hooked_block_markup, $hooked_block_type, $relative_position, $block, $context );
}
if ( $parent && ! $next ) {
// Candidate for last-child insertion.
$hooked_blocks_for_parent = get_hooked_blocks( $parent['blockName'] );
foreach ( $hooked_blocks_for_parent as $hooked_block_type => $relative_position ) {
if ( 'last_child' === $relative_position ) {
$hooked_block_markup = get_comment_delimited_block_content( $hooked_block_type, array(), '' );
/** This filter is documented in wp-includes/blocks.php */
$markup .= apply_filters( 'inject_hooked_block_markup', $hooked_block_markup, $hooked_block_type, $relative_position, $parent, $context );
}
$relative_position = 'last_child';
$anchor_block_type = $parent['blockName'];
$hooked_block_types = array_keys( get_hooked_blocks( $anchor_block_type, $relative_position ) );
/** This filter is documented in wp-includes/blocks.php */
$hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context );
foreach ( $hooked_block_types as $hooked_block_type ) {
$hooked_block_markup = get_comment_delimited_block_content( $hooked_block_type, array(), '' );
/** This filter is documented in wp-includes/blocks.php */
$markup .= apply_filters( 'inject_hooked_block_markup', $hooked_block_markup, $hooked_block_type, $relative_position, $parent, $context );
}
}

View File

@ -49,8 +49,9 @@ class Tests_Blocks_BlockHooks extends WP_UnitTestCase {
'tests/injected-one',
array(
'block_hooks' => array(
'tests/hooked-at-before' => 'before',
'tests/hooked-at-after' => 'after',
'tests/hooked-at-before' => 'before',
'tests/hooked-at-after' => 'after',
'tests/hooked-at-before-and-after' => 'before',
),
)
);
@ -58,10 +59,11 @@ class Tests_Blocks_BlockHooks extends WP_UnitTestCase {
'tests/injected-two',
array(
'block_hooks' => array(
'tests/hooked-at-before' => 'before',
'tests/hooked-at-after' => 'after',
'tests/hooked-at-first-child' => 'first_child',
'tests/hooked-at-last-child' => 'last_child',
'tests/hooked-at-before' => 'before',
'tests/hooked-at-after' => 'after',
'tests/hooked-at-before-and-after' => 'after',
'tests/hooked-at-first-child' => 'first_child',
'tests/hooked-at-last-child' => 'last_child',
),
)
);
@ -96,5 +98,20 @@ class Tests_Blocks_BlockHooks extends WP_UnitTestCase {
get_hooked_blocks( 'tests/hooked-at-last-child' ),
'block hooked at the last child position'
);
$this->assertSame(
array(
'tests/injected-one' => 'before',
'tests/injected-two' => 'after',
),
get_hooked_blocks( 'tests/hooked-at-before-and-after' ),
'block hooked before one block and after another'
);
$this->assertSame(
array(
'tests/injected-one' => 'before',
),
get_hooked_blocks( 'tests/hooked-at-before-and-after', 'before' ),
'block hooked before one block and after another, filtered for before'
);
}
}