Blocks: Call `get_hooked_blocks` only once per template/part/pattern.

Prior to this changeset, `get_hooked_blocks` was called four times ''for every parsed block'' in each template, template part, and pattern. With this changeset applied, `get_hooked_blocks` is called only once per template, template part, or pattern.

Additionally, `get_hooked_blocks` is called only once when returning the list of all registered patterns. (The latter modification brings the implementation closer to its state prior to Block Hooks.)

Finally, when there are no registered hooked blocks or `hooked_block_types` filters, parsing, hooked block insertion, and re-serializing is skipped altogether.

Props gziolo, flixos90, joemcgill, dmsnell, spacedmonkey, hellofromtonya.
Fixes #59383.
Built from https://develop.svn.wordpress.org/trunk@56805


git-svn-id: http://core.svn.wordpress.org/trunk@56317 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Bernhard Reiter 2023-10-09 16:40:24 +00:00
parent e0596b5835
commit fc229aa436
4 changed files with 63 additions and 44 deletions

View File

@ -549,10 +549,15 @@ function _build_block_template_result_from_file( $template_file, $template_type
$template->area = $template_file['area'];
}
$blocks = parse_blocks( $template_content );
$before_block_visitor = make_before_block_visitor( $template );
$after_block_visitor = make_after_block_visitor( $template );
$template->content = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
$before_block_visitor = '_inject_theme_attribute_in_template_part_block';
$after_block_visitor = null;
$hooked_blocks = get_hooked_blocks();
if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) {
$before_block_visitor = make_before_block_visitor( $hooked_blocks, $template );
$after_block_visitor = make_after_block_visitor( $hooked_blocks, $template );
}
$blocks = parse_blocks( $template_content );
$template->content = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
return $template;
}

View File

@ -723,14 +723,13 @@ function get_dynamic_block_names() {
}
/**
* Retrieves block types hooked into the given block, grouped by their relative position.
* Retrieves block types hooked into the given block, grouped by anchor block type and the relative position.
*
* @since 6.4.0
*
* @param string $name Block type name including namespace.
* @return array[] Array of block types grouped by their relative position.
* @return array[] Array of block types grouped by anchor block type and the relative position.
*/
function get_hooked_blocks( $name ) {
function get_hooked_blocks() {
$block_types = WP_Block_Type_Registry::get_instance()->get_all_registered();
$hooked_blocks = array();
foreach ( $block_types as $block_type ) {
@ -738,15 +737,16 @@ function get_hooked_blocks( $name ) {
continue;
}
foreach ( $block_type->block_hooks as $anchor_block_type => $relative_position ) {
if ( $anchor_block_type !== $name ) {
continue;
if ( ! isset( $hooked_blocks[ $anchor_block_type ] ) ) {
$hooked_blocks[ $anchor_block_type ] = array();
}
if ( ! isset( $hooked_blocks[ $relative_position ] ) ) {
$hooked_blocks[ $relative_position ] = array();
if ( ! isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] ) ) {
$hooked_blocks[ $anchor_block_type ][ $relative_position ] = array();
}
$hooked_blocks[ $relative_position ][] = $block_type->name;
$hooked_blocks[ $anchor_block_type ][ $relative_position ][] = $block_type->name;
}
}
return $hooked_blocks;
}
@ -760,11 +760,12 @@ function get_hooked_blocks( $name ) {
* @since 6.4.0
* @access private
*
* @param WP_Block_Template|array $context A block template, template part, or pattern that the blocks belong to.
* @param array $hooked_blocks An array of blocks hooked to another given block.
* @param WP_Block_Template|array $context A block template, template part, or pattern that the blocks belong to.
* @return callable A function that returns the serialized markup for the given block,
* including the markup for any hooked blocks before it.
*/
function make_before_block_visitor( $context ) {
function make_before_block_visitor( $hooked_blocks, $context ) {
/**
* Injects hooked blocks before the given block, injects the `theme` attribute into Template Part blocks, and returns the serialized markup.
*
@ -777,7 +778,7 @@ function make_before_block_visitor( $context ) {
* @param array $prev The previous sibling block of the given block.
* @return string The serialized markup for the given block, with the markup for any hooked blocks prepended to it.
*/
return function ( &$block, $parent_block = null, $prev = null ) use ( $context ) {
return function ( &$block, $parent_block = null, $prev = null ) use ( $hooked_blocks, $context ) {
_inject_theme_attribute_in_template_part_block( $block );
$markup = '';
@ -786,9 +787,8 @@ function make_before_block_visitor( $context ) {
// Candidate for first-child insertion.
$relative_position = 'first_child';
$anchor_block_type = $parent_block['blockName'];
$hooked_block_types = get_hooked_blocks( $anchor_block_type );
$hooked_block_types = isset( $hooked_block_types[ $relative_position ] )
? $hooked_block_types[ $relative_position ]
$hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
: array();
/**
@ -810,9 +810,8 @@ function make_before_block_visitor( $context ) {
$relative_position = 'before';
$anchor_block_type = $block['blockName'];
$hooked_block_types = get_hooked_blocks( $anchor_block_type );
$hooked_block_types = isset( $hooked_block_types[ $relative_position ] )
? $hooked_block_types[ $relative_position ]
$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 */
@ -835,11 +834,12 @@ function make_before_block_visitor( $context ) {
* @since 6.4.0
* @access private
*
* @param WP_Block_Template|array $context A block template, template part, or pattern that the blocks belong to.
* @param array $hooked_blocks An array of blocks hooked to another block.
* @param WP_Block_Template|array $context A block template, template part, or pattern that the blocks belong to.
* @return callable A function that returns the serialized markup for the given block,
* including the markup for any hooked blocks after it.
*/
function make_after_block_visitor( $context ) {
function make_after_block_visitor( $hooked_blocks, $context ) {
/**
* Injects hooked blocks after the given block, and returns the serialized markup.
*
@ -851,15 +851,14 @@ function make_after_block_visitor( $context ) {
* @param array $next The next sibling block of the given block.
* @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 ( $context ) {
return function ( &$block, $parent_block = null, $next = null ) use ( $hooked_blocks, $context ) {
$markup = '';
$relative_position = 'after';
$anchor_block_type = $block['blockName'];
$hooked_block_types = get_hooked_blocks( $anchor_block_type );
$hooked_block_types = isset( $hooked_block_types[ $relative_position ] )
? $hooked_block_types[ $relative_position ]
: array();
$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 );
@ -871,9 +870,8 @@ function make_after_block_visitor( $context ) {
// Candidate for last-child insertion.
$relative_position = 'last_child';
$anchor_block_type = $parent_block['blockName'];
$hooked_block_types = get_hooked_blocks( $anchor_block_type );
$hooked_block_types = isset( $hooked_block_types[ $relative_position ] )
? $hooked_block_types[ $relative_position ]
$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 */

View File

@ -152,6 +152,28 @@ final class WP_Block_Patterns_Registry {
return true;
}
/**
* Prepares the content of a block pattern. If hooked blocks are registered, they get injected into the pattern,
* when they met the defined criteria.
*
* @since 6.4.0
*
* @param array $pattern Registered pattern properties.
* @param array $hooked_blocks The list of hooked blocks.
* @return string The content of the block pattern.
*/
private function prepare_content( $pattern, $hooked_blocks ) {
$content = $pattern['content'];
if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) {
$blocks = parse_blocks( $content );
$before_block_visitor = make_before_block_visitor( $hooked_blocks, $pattern );
$after_block_visitor = make_after_block_visitor( $hooked_blocks, $pattern );
$content = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
}
return $content;
}
/**
* Retrieves an array containing the properties of a registered block pattern.
*
@ -165,11 +187,8 @@ final class WP_Block_Patterns_Registry {
return null;
}
$pattern = $this->registered_patterns[ $pattern_name ];
$blocks = parse_blocks( $pattern['content'] );
$before_block_visitor = make_before_block_visitor( $pattern );
$after_block_visitor = make_after_block_visitor( $pattern );
$pattern['content'] = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
$pattern = $this->registered_patterns[ $pattern_name ];
$pattern['content'] = $this->prepare_content( $pattern, get_hooked_blocks() );
return $pattern;
}
@ -184,17 +203,14 @@ final class WP_Block_Patterns_Registry {
* and per style.
*/
public function get_all_registered( $outside_init_only = false ) {
$patterns = array_values(
$patterns = array_values(
$outside_init_only
? $this->registered_patterns_outside_init
: $this->registered_patterns
);
$hooked_blocks = get_hooked_blocks();
foreach ( $patterns as $index => $pattern ) {
$blocks = parse_blocks( $pattern['content'] );
$before_block_visitor = make_before_block_visitor( $pattern );
$after_block_visitor = make_after_block_visitor( $pattern );
$patterns[ $index ]['content'] = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
$patterns[ $index ]['content'] = $this->prepare_content( $pattern, $hooked_blocks );
}
return $patterns;
}

View File

@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
$wp_version = '6.4-beta2-56804';
$wp_version = '6.4-beta2-56805';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.