Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block Hooks: Introduce a new hooked_block_{$block_type} filter #5835

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a36ac67
Block Hooks: Extract `insert_hooked_blocks()` function
ockham Jan 3, 2024
5350ae2
Introduce hooked_block filter
ockham Jan 3, 2024
e63213c
get_hooked_block_markup: Change argument order
ockham Jan 3, 2024
a891d3c
Fix get_hooked_block_markup tests
ockham Jan 3, 2024
fabd9c2
Make block type name part of filter name
ockham Jan 3, 2024
afd95d0
Set attrs to empty array
ockham Jan 3, 2024
f797f8a
Allow passing inner blocks
ockham Jan 10, 2024
01f30ab
Use correct block type in ignoredHookedBlocks
ockham Jan 10, 2024
962eaf5
Update comment
ockham Jan 11, 2024
1a214a7
Mark insert_hooked_blocks as private
ockham Jan 11, 2024
8b08619
Slight rewording of a comment
ockham Jan 11, 2024
0658500
Clarify PHPDoc
ockham Jan 11, 2024
45ff3da
Fix tests
ockham Jan 11, 2024
520f67e
Cover new hooked_block_type arg in tests
ockham Jan 11, 2024
df3dc99
Add ticket references to tests
ockham Jan 11, 2024
7b9d6f2
Another ticket reference
ockham Jan 11, 2024
c962fc2
Add assertion to insert_hooked_blocks test
ockham Jan 11, 2024
cf1297d
insert_hooked_blocks Test: Turn vars into class consts
ockham Jan 16, 2024
311c2e6
Add more test coverage
ockham Jan 16, 2024
ace54d4
Add ticket references to 59572
ockham Jan 16, 2024
e3df476
Amend PHPDoc
ockham Jan 25, 2024
275a96a
Change variable names to emphasize parsed block array format
ockham Jan 25, 2024
e21c8e9
Remove unnecessary test mocks
ockham Jan 25, 2024
c2912f8
Ooops
ockham Jan 25, 2024
13f1c5d
Add test coverage for filter
ockham Jan 25, 2024
b9f71ad
Add test to cover wrapping block
ockham Jan 25, 2024
30c2e97
Add assertion messages
ockham Jan 25, 2024
5015617
More assertion messages
ockham Jan 25, 2024
3092b85
Coding standards
ockham Jan 25, 2024
47e80e1
More coding standards
ockham Jan 25, 2024
9cac78c
Tweak PHPDoc
ockham Jan 25, 2024
7fdf956
More PHPDoc tweaking
ockham Jan 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 78 additions & 63 deletions src/wp-includes/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -758,22 +758,28 @@ function get_hooked_blocks() {
}

/**
* Conditionally returns the markup for a given hooked block type.
* Conditionally returns the markup for a given hooked block.
*
* Accepts two arguments: A reference to an anchor block, and the name of a hooked block type.
* Accepts three arguments: A hooked block, its type, and a reference to an anchor block.
* If the anchor block has already been processed, and the given hooked block type is in the list
* of ignored hooked blocks, an empty string is returned.
*
* The hooked block type is specified separately as it's possible that a filter might've modified
* the hooked block such that `$hooked_block['blockName']` does no longer reflect the original type.
*
* This function is meant for internal use only.
*
* @since 6.5.0
* @access private
*
* @param array $anchor_block The anchor block. Passed by reference.
* @param string $hooked_block_type The name of the hooked block type.
* @return string The markup for the given hooked block type, or an empty string if the block is ignored.
* @param array $hooked_block The hooked block, represented as a parsed block array.
* @param string $hooked_block_type The type of the hooked block. This could be different from
* $hooked_block['blockName'], as a filter might've modified the latter.
* @param array $anchor_block The anchor block, represented as a parsed block array.
* Passed by reference.
* @return string The markup for the given hooked block, or an empty string if the block is ignored.
*/
function get_hooked_block_markup( &$anchor_block, $hooked_block_type ) {
function get_hooked_block_markup( $hooked_block, $hooked_block_type, &$anchor_block ) {
if ( ! isset( $anchor_block['attrs']['metadata']['ignoredHookedBlocks'] ) ) {
$anchor_block['attrs']['metadata']['ignoredHookedBlocks'] = array();
}
Expand All @@ -786,7 +792,68 @@ function get_hooked_block_markup( &$anchor_block, $hooked_block_type ) {
// However, its presence does not affect the frontend.
$anchor_block['attrs']['metadata']['ignoredHookedBlocks'][] = $hooked_block_type;

return get_comment_delimited_block_content( $hooked_block_type, array(), '' );
return serialize_block( $hooked_block );
}

/**
* Returns the markup for blocks hooked to the given anchor block in a specific relative position.
*
* @since 6.5.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'.
* @param array $hooked_blocks An array of hooked block types, grouped by anchor block and relative position.
* @param WP_Block_Template|array $context The block template, template part, or pattern that the anchor block belongs to.
* @return string
*/
function insert_hooked_blocks( &$parsed_anchor_block, $relative_position, $hooked_blocks, $context ) {
$anchor_block_type = $parsed_anchor_block['blockName'];
$hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
: array();

/**
* 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 );

$markup = '';
foreach ( $hooked_block_types as $hooked_block_type ) {
$parsed_hooked_block = array(
'blockName' => $hooked_block_type,
'attrs' => array(),
'innerBlocks' => array(),
'innerContent' => array(),
);

/**
* Filters the parsed block array for a given hooked block.
*
* @since 6.5.0
*
* @param array $parsed_hooked_block The parsed block array for the given hooked block type.
* @param string $relative_position The relative position of the hooked block.
* @param array $parsed_anchor_block The anchor block, in parsed block array format.
* @param WP_Block_Template|array $context The block template, template part, or pattern that the anchor block belongs to.
*/
$parsed_hooked_block = apply_filters( "hooked_block_{$hooked_block_type}", $parsed_hooked_block, $relative_position, $parsed_anchor_block, $context );

// It's possible that the `hooked_block_{$hooked_block_type}` filter returned a block of a different type,
// so we need to pass the original $hooked_block_type as well.
$markup .= get_hooked_block_markup( $parsed_hooked_block, $hooked_block_type, $parsed_anchor_block );
}

return $markup;
}

/**
Expand Down Expand Up @@ -826,40 +893,10 @@ function make_before_block_visitor( $hooked_blocks, $context ) {

if ( $parent_block && ! $prev ) {
// Candidate for first-child insertion.
$relative_position = 'first_child';
$anchor_block_type = $parent_block['blockName'];
$hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
: array();

/**
* 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 ) {
$markup .= get_hooked_block_markup( $parent_block, $hooked_block_type );
}
$markup .= insert_hooked_blocks( $parent_block, 'first_child', $hooked_blocks, $context );
}

$relative_position = 'before';
$anchor_block_type = $block['blockName'];
$hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
: array();

/** 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 ) {
$markup .= get_hooked_block_markup( $block, $hooked_block_type );
}
$markup .= insert_hooked_blocks( $block, 'before', $hooked_blocks, $context );

return $markup;
};
Expand Down Expand Up @@ -895,33 +932,11 @@ function make_after_block_visitor( $hooked_blocks, $context ) {
* @return string The serialized markup for the given block, with the markup for any hooked blocks appended to it.
*/
return function ( &$block, &$parent_block = null, $next = null ) use ( $hooked_blocks, $context ) {
$markup = '';

$relative_position = 'after';
$anchor_block_type = $block['blockName'];
$hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
: array();

/** 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 ) {
$markup .= get_hooked_block_markup( $block, $hooked_block_type );
}
$markup = insert_hooked_blocks( $block, 'after', $hooked_blocks, $context );

if ( $parent_block && ! $next ) {
// Candidate for last-child insertion.
$relative_position = 'last_child';
$anchor_block_type = $parent_block['blockName'];
$hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
: array();

/** 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 ) {
$markup .= get_hooked_block_markup( $parent_block, $hooked_block_type );
}
$markup .= insert_hooked_blocks( $parent_block, 'last_child', $hooked_blocks, $context );
}

return $markup;
Expand Down
66 changes: 55 additions & 11 deletions tests/phpunit/tests/blocks/getHookedBlockMarkup.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,17 @@
* @group block-hooks
*/
class Tests_Blocks_GetHookedBlockMarkup extends WP_UnitTestCase {
const HOOKED_BLOCK_TYPE = 'tests/hooked-block';
const HOOKED_BLOCK = array(
'blockName' => 'tests/different-hooked-block',
'attrs' => array(),
'innerContent' => array(),
);

/**
* @ticket 59572
* @ticket 60008
* @ticket 60126
*
* @covers ::get_hooked_block_markup
*/
Expand All @@ -21,13 +30,23 @@ public function test_get_hooked_block_markup_adds_metadata() {
'blockName' => 'tests/anchor-block',
);

$actual = get_hooked_block_markup( $anchor_block, 'tests/hooked-block' );
$this->assertSame( array( 'tests/hooked-block' ), $anchor_block['attrs']['metadata']['ignoredHookedBlocks'] );
$this->assertSame( '<!-- wp:tests/hooked-block /-->', $actual );
$actual = get_hooked_block_markup( self::HOOKED_BLOCK, self::HOOKED_BLOCK_TYPE, $anchor_block );
$this->assertSame(
array( self::HOOKED_BLOCK_TYPE ),
$anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
"Hooked block type wasn't added to ignoredHookedBlocks metadata."
);
$this->assertSame(
'<!-- wp:' . self::HOOKED_BLOCK['blockName'] . ' /-->',
$actual,
"Markup for hooked block wasn't generated correctly."
);
}

/**
* @ticket 59572
* @ticket 60008
* @ticket 60126
*
* @covers ::get_hooked_block_markup
*/
Expand All @@ -36,33 +55,58 @@ public function test_get_hooked_block_markup_if_block_is_already_hooked() {
'blockName' => 'tests/anchor-block',
'attrs' => array(
'metadata' => array(
'ignoredHookedBlocks' => array( 'tests/hooked-block' ),
'ignoredHookedBlocks' => array( self::HOOKED_BLOCK_TYPE ),
),
),
);

$actual = get_hooked_block_markup( $anchor_block, 'tests/hooked-block' );
$this->assertSame( array( 'tests/hooked-block' ), $anchor_block['attrs']['metadata']['ignoredHookedBlocks'] );
$this->assertSame( '', $actual );
$actual = get_hooked_block_markup( self::HOOKED_BLOCK, self::HOOKED_BLOCK_TYPE, $anchor_block );
$this->assertSame(
array( self::HOOKED_BLOCK_TYPE ),
$anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
"ignoredHookedBlocks metadata shouldn't have been modified."
);
$this->assertSame(
'',
$actual,
"No markup should've been generated for ignored hooked block."
);
}

/**
* @ticket 59572
* @ticket 60008
* @ticket 60126
*
* @covers ::get_hooked_block_markup
*/
public function test_get_hooked_block_markup_adds_to_ignored_hooked_blocks() {
$other_hooked_block_type = 'tests/other-hooked-block';
$other_hooked_block = array(
'blockName' => $other_hooked_block_type,
'attrs' => array(),
'innerContent' => array(),
);

$anchor_block = array(
'blockName' => 'tests/anchor-block',
'attrs' => array(
'metadata' => array(
'ignoredHookedBlocks' => array( 'tests/hooked-block' ),
'ignoredHookedBlocks' => array( self::HOOKED_BLOCK_TYPE ),
),
),
);

$actual = get_hooked_block_markup( $anchor_block, 'tests/other-hooked-block' );
$this->assertSame( array( 'tests/hooked-block', 'tests/other-hooked-block' ), $anchor_block['attrs']['metadata']['ignoredHookedBlocks'] );
$this->assertSame( '<!-- wp:tests/other-hooked-block /-->', $actual );
$actual = get_hooked_block_markup( $other_hooked_block, $other_hooked_block_type, $anchor_block );
$this->assertSame(
array( self::HOOKED_BLOCK_TYPE, $other_hooked_block_type ),
$anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
"Newly hooked block should've been added to ignoredHookedBlocks metadata while retaining previously ignored one."
);
$this->assertSame(
'<!-- wp:' . $other_hooked_block_type . ' /-->',
$actual,
"Markup for newly hooked block should've been generated."
);
}
}
Loading
Loading