Make WordPress Core

Changeset 56805


Ignore:
Timestamp:
10/09/2023 04:38:25 PM (8 months ago)
Author:
Bernhard Reiter
Message:

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.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/block-template-utils.php

    r56724 r56805  
    550550    }
    551551
    552     $blocks               = parse_blocks( $template_content );
    553     $before_block_visitor = make_before_block_visitor( $template );
    554     $after_block_visitor  = make_after_block_visitor( $template );
    555     $template->content    = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
     552    $before_block_visitor = '_inject_theme_attribute_in_template_part_block';
     553    $after_block_visitor  = null;
     554    $hooked_blocks        = get_hooked_blocks();
     555    if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) {
     556        $before_block_visitor = make_before_block_visitor( $hooked_blocks, $template );
     557        $after_block_visitor  = make_after_block_visitor( $hooked_blocks, $template );
     558    }
     559    $blocks            = parse_blocks( $template_content );
     560    $template->content = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
    556561
    557562    return $template;
  • trunk/src/wp-includes/blocks.php

    r56753 r56805  
    724724
    725725/**
    726  * Retrieves block types hooked into the given block, grouped by their relative position.
     726 * Retrieves block types hooked into the given block, grouped by anchor block type and the relative position.
    727727 *
    728728 * @since 6.4.0
    729729 *
    730  * @param string $name Block type name including namespace.
    731  * @return array[] Array of block types grouped by their relative position.
    732  */
    733 function get_hooked_blocks( $name ) {
     730 * @return array[] Array of block types grouped by anchor block type and the relative position.
     731 */
     732function get_hooked_blocks() {
    734733    $block_types   = WP_Block_Type_Registry::get_instance()->get_all_registered();
    735734    $hooked_blocks = array();
     
    739738        }
    740739        foreach ( $block_type->block_hooks as $anchor_block_type => $relative_position ) {
    741             if ( $anchor_block_type !== $name ) {
    742                 continue;
    743             }
    744             if ( ! isset( $hooked_blocks[ $relative_position ] ) ) {
    745                 $hooked_blocks[ $relative_position ] = array();
    746             }
    747             $hooked_blocks[ $relative_position ][] = $block_type->name;
    748         }
    749     }
     740            if ( ! isset( $hooked_blocks[ $anchor_block_type ] ) ) {
     741                $hooked_blocks[ $anchor_block_type ] = array();
     742            }
     743            if ( ! isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] ) ) {
     744                $hooked_blocks[ $anchor_block_type ][ $relative_position ] = array();
     745            }
     746            $hooked_blocks[ $anchor_block_type ][ $relative_position ][] = $block_type->name;
     747        }
     748    }
     749
    750750    return $hooked_blocks;
    751751}
     
    761761 * @access private
    762762 *
    763  * @param WP_Block_Template|array $context A block template, template part, or pattern that the blocks belong to.
     763 * @param array                   $hooked_blocks An array of blocks hooked to another given block.
     764 * @param WP_Block_Template|array $context       A block template, template part, or pattern that the blocks belong to.
    764765 * @return callable A function that returns the serialized markup for the given block,
    765766 *                  including the markup for any hooked blocks before it.
    766767 */
    767 function make_before_block_visitor( $context ) {
     768function make_before_block_visitor( $hooked_blocks, $context ) {
    768769    /**
    769770     * Injects hooked blocks before the given block, injects the `theme` attribute into Template Part blocks, and returns the serialized markup.
     
    778779     * @return string The serialized markup for the given block, with the markup for any hooked blocks prepended to it.
    779780     */
    780     return function ( &$block, $parent_block = null, $prev = null ) use ( $context ) {
     781    return function ( &$block, $parent_block = null, $prev = null ) use ( $hooked_blocks, $context ) {
    781782        _inject_theme_attribute_in_template_part_block( $block );
    782783
     
    787788            $relative_position  = 'first_child';
    788789            $anchor_block_type  = $parent_block['blockName'];
    789             $hooked_block_types = get_hooked_blocks( $anchor_block_type );
    790             $hooked_block_types = isset( $hooked_block_types[ $relative_position ] )
    791                 ? $hooked_block_types[ $relative_position ]
     790            $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
     791                ? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
    792792                : array();
    793793
     
    811811        $relative_position  = 'before';
    812812        $anchor_block_type  = $block['blockName'];
    813         $hooked_block_types = get_hooked_blocks( $anchor_block_type );
    814         $hooked_block_types = isset( $hooked_block_types[ $relative_position ] )
    815             ? $hooked_block_types[ $relative_position ]
     813        $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
     814            ? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
    816815            : array();
    817816
     
    836835 * @access private
    837836 *
    838  * @param WP_Block_Template|array $context A block template, template part, or pattern that the blocks belong to.
     837 * @param array                   $hooked_blocks An array of blocks hooked to another block.
     838 * @param WP_Block_Template|array $context       A block template, template part, or pattern that the blocks belong to.
    839839 * @return callable A function that returns the serialized markup for the given block,
    840840 *                  including the markup for any hooked blocks after it.
    841841 */
    842 function make_after_block_visitor( $context ) {
     842function make_after_block_visitor( $hooked_blocks, $context ) {
    843843    /**
    844844     * Injects hooked blocks after the given block, and returns the serialized markup.
     
    852852     * @return string The serialized markup for the given block, with the markup for any hooked blocks appended to it.
    853853     */
    854     return function ( &$block, $parent_block = null, $next = null ) use ( $context ) {
     854    return function ( &$block, $parent_block = null, $next = null ) use ( $hooked_blocks, $context ) {
    855855        $markup = '';
    856856
    857857        $relative_position  = 'after';
    858858        $anchor_block_type  = $block['blockName'];
    859         $hooked_block_types = get_hooked_blocks( $anchor_block_type );
    860         $hooked_block_types = isset( $hooked_block_types[ $relative_position ] )
    861             ? $hooked_block_types[ $relative_position ]
    862             : array();
     859        $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
     860                ? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
     861                : array();
    863862
    864863        /** This filter is documented in wp-includes/blocks.php */
     
    872871            $relative_position  = 'last_child';
    873872            $anchor_block_type  = $parent_block['blockName'];
    874             $hooked_block_types = get_hooked_blocks( $anchor_block_type );
    875             $hooked_block_types = isset( $hooked_block_types[ $relative_position ] )
    876                 ? $hooked_block_types[ $relative_position ]
     873            $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
     874                ? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
    877875                : array();
    878876
  • trunk/src/wp-includes/class-wp-block-patterns-registry.php

    r56649 r56805  
    154154
    155155    /**
     156     * Prepares the content of a block pattern. If hooked blocks are registered, they get injected into the pattern,
     157     * when they met the defined criteria.
     158     *
     159     * @since 6.4.0
     160     *
     161     * @param array $pattern       Registered pattern properties.
     162     * @param array $hooked_blocks The list of hooked blocks.
     163     * @return string The content of the block pattern.
     164     */
     165    private function prepare_content( $pattern, $hooked_blocks ) {
     166        $content = $pattern['content'];
     167        if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) {
     168            $blocks               = parse_blocks( $content );
     169            $before_block_visitor = make_before_block_visitor( $hooked_blocks, $pattern );
     170            $after_block_visitor  = make_after_block_visitor( $hooked_blocks, $pattern );
     171            $content              = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
     172        }
     173
     174        return $content;
     175    }
     176
     177    /**
    156178     * Retrieves an array containing the properties of a registered block pattern.
    157179     *
     
    166188        }
    167189
    168         $pattern              = $this->registered_patterns[ $pattern_name ];
    169         $blocks               = parse_blocks( $pattern['content'] );
    170         $before_block_visitor = make_before_block_visitor( $pattern );
    171         $after_block_visitor  = make_after_block_visitor( $pattern );
    172         $pattern['content']   = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
     190        $pattern            = $this->registered_patterns[ $pattern_name ];
     191        $pattern['content'] = $this->prepare_content( $pattern, get_hooked_blocks() );
    173192
    174193        return $pattern;
     
    185204     */
    186205    public function get_all_registered( $outside_init_only = false ) {
    187         $patterns = array_values(
     206        $patterns      = array_values(
    188207            $outside_init_only
    189208                ? $this->registered_patterns_outside_init
    190209                : $this->registered_patterns
    191210        );
    192 
     211        $hooked_blocks = get_hooked_blocks();
    193212        foreach ( $patterns as $index => $pattern ) {
    194             $blocks                        = parse_blocks( $pattern['content'] );
    195             $before_block_visitor          = make_before_block_visitor( $pattern );
    196             $after_block_visitor           = make_after_block_visitor( $pattern );
    197             $patterns[ $index ]['content'] = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
     213            $patterns[ $index ]['content'] = $this->prepare_content( $pattern, $hooked_blocks );
    198214        }
    199215        return $patterns;
  • trunk/tests/phpunit/tests/blocks/getHookedBlocks.php

    r56759 r56805  
    6363     */
    6464    public function test_get_hooked_blocks_no_match_found() {
    65         $result = get_hooked_blocks( 'tests/no-hooked-blocks' );
     65        $result = get_hooked_blocks();
    6666
    6767        $this->assertSame( array(), $result );
     
    9999        $this->assertSame(
    100100            array(
    101                 'before' => array(
    102                     'tests/injected-one',
    103                     'tests/injected-two',
     101                'tests/hooked-at-before'           => array(
     102                    'before' => array(
     103                        'tests/injected-one',
     104                        'tests/injected-two',
     105                    ),
     106                ),
     107                'tests/hooked-at-after'            => array(
     108                    'after' => array(
     109                        'tests/injected-one',
     110                        'tests/injected-two',
     111                    ),
     112                ),
     113                'tests/hooked-at-before-and-after' => array(
     114                    'before' => array(
     115                        'tests/injected-one',
     116                    ),
     117                    'after'  => array(
     118                        'tests/injected-two',
     119                    ),
     120                ),
     121                'tests/hooked-at-first-child'      => array(
     122                    'first_child' => array(
     123                        'tests/injected-two',
     124                    ),
     125                ),
     126                'tests/hooked-at-last-child'       => array(
     127                    'last_child' => array(
     128                        'tests/injected-two',
     129                    ),
    104130                ),
    105131            ),
    106             get_hooked_blocks( 'tests/hooked-at-before' ),
    107             'block hooked at the before position'
    108         );
    109         $this->assertSame(
    110             array(
    111                 'after' => array(
    112                     'tests/injected-one',
    113                     'tests/injected-two',
    114                 ),
    115             ),
    116             get_hooked_blocks( 'tests/hooked-at-after' ),
    117             'block hooked at the after position'
    118         );
    119         $this->assertSame(
    120             array(
    121                 'first_child' => array(
    122                     'tests/injected-two',
    123                 ),
    124             ),
    125             get_hooked_blocks( 'tests/hooked-at-first-child' ),
    126             'block hooked at the first child position'
    127         );
    128         $this->assertSame(
    129             array(
    130                 'last_child' => array(
    131                     'tests/injected-two',
    132                 ),
    133             ),
    134             get_hooked_blocks( 'tests/hooked-at-last-child' ),
    135             'block hooked at the last child position'
    136         );
    137         $this->assertSame(
    138             array(
    139                 'before' => array(
    140                     'tests/injected-one',
    141                 ),
    142                 'after'  => array(
    143                     'tests/injected-two',
    144                 ),
    145             ),
    146             get_hooked_blocks( 'tests/hooked-at-before-and-after' ),
    147             'block hooked before one block and after another'
     132            get_hooked_blocks()
    148133        );
    149134    }
Note: See TracChangeset for help on using the changeset viewer.