Make WordPress Core


Ignore:
Timestamp:
01/25/2024 01:46:49 PM (3 years ago)
Author:
Bernhard Reiter
Message:

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

Add a new hooked_block_{$block_type} filter that allows modifying a hooked block (in parsed block format) prior to insertion, while providing read access to its anchor block (in the same format).

This allows block authors to e.g. set a hooked block's attributes, or its inner blocks; the filter can peruse information about the anchor block when doing so. As such, this filter provides a solution to both #59572 and #60126.

The new filter is designed to strike a good balance and separation of concerns with regard to the existing `hooked_block_types` filter, which allows addition or removal of a block to the list of hooked blocks for a given anchor block -- all of which are identified only by their block types. This new filter, on the other hand, only applies to one hooked block at a time, and allows modifying the entire (parsed) hooked block; it also gives (read) access to the parsed anchor block.

Props gziolo, tomjcafferkey, andrewserong, isabel_brison, timbroddin, yansern.
Fixes #59572, #60126.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/blocks.php

    r57157 r57354  
    759759
    760760/**
    761  * Conditionally returns the markup for a given hooked block type.
    762  *
    763  * Accepts two arguments: A reference to an anchor block, and the name of a hooked block type.
     761 * Conditionally returns the markup for a given hooked block.
     762 *
     763 * Accepts three arguments: A hooked block, its type, and a reference to an anchor block.
    764764 * If the anchor block has already been processed, and the given hooked block type is in the list
    765765 * of ignored hooked blocks, an empty string is returned.
    766766 *
     767 * The hooked block type is specified separately as it's possible that a filter might've modified
     768 * the hooked block such that `$hooked_block['blockName']` does no longer reflect the original type.
     769 *
    767770 * This function is meant for internal use only.
    768771 *
     
    770773 * @access private
    771774 *
    772  * @param array   $anchor_block      The anchor block. Passed by reference.
    773  * @param string  $hooked_block_type The name of the hooked block type.
    774  * @return string The markup for the given hooked block type, or an empty string if the block is ignored.
    775  */
    776 function get_hooked_block_markup( &$anchor_block, $hooked_block_type ) {
     775 * @param array  $hooked_block      The hooked block, represented as a parsed block array.
     776 * @param string $hooked_block_type The type of the hooked block. This could be different from
     777 *                                  $hooked_block['blockName'], as a filter might've modified the latter.
     778 * @param array  $anchor_block      The anchor block, represented as a parsed block array.
     779 *                                  Passed by reference.
     780 * @return string The markup for the given hooked block, or an empty string if the block is ignored.
     781 */
     782function get_hooked_block_markup( $hooked_block, $hooked_block_type, &$anchor_block ) {
    777783        if ( ! isset( $anchor_block['attrs']['metadata']['ignoredHookedBlocks'] ) ) {
    778784                $anchor_block['attrs']['metadata']['ignoredHookedBlocks'] = array();
     
    787793        $anchor_block['attrs']['metadata']['ignoredHookedBlocks'][] = $hooked_block_type;
    788794
    789         return get_comment_delimited_block_content( $hooked_block_type, array(), '' );
     795        return serialize_block( $hooked_block );
     796}
     797
     798/**
     799 * Returns the markup for blocks hooked to the given anchor block in a specific relative position.
     800 *
     801 * @since 6.5.0
     802 * @access private
     803 *
     804 * @param array                   $parsed_anchor_block The anchor block, in parsed block array format.
     805 * @param string                  $relative_position   The relative position of the hooked blocks.
     806 *                                                     Can be one of 'before', 'after', 'first_child', or 'last_child'.
     807 * @param array                   $hooked_blocks       An array of hooked block types, grouped by anchor block and relative position.
     808 * @param WP_Block_Template|array $context             The block template, template part, or pattern that the anchor block belongs to.
     809 * @return string
     810 */
     811function insert_hooked_blocks( &$parsed_anchor_block, $relative_position, $hooked_blocks, $context ) {
     812        $anchor_block_type  = $parsed_anchor_block['blockName'];
     813        $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
     814                ? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
     815                : array();
     816
     817        /**
     818         * Filters the list of hooked block types for a given anchor block type and relative position.
     819         *
     820         * @since 6.4.0
     821         *
     822         * @param string[]                $hooked_block_types The list of hooked block types.
     823         * @param string                  $relative_position  The relative position of the hooked blocks.
     824         *                                                    Can be one of 'before', 'after', 'first_child', or 'last_child'.
     825         * @param string                  $anchor_block_type  The anchor block type.
     826         * @param WP_Block_Template|array $context            The block template, template part, or pattern that the anchor block belongs to.
     827         */
     828        $hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context );
     829
     830        $markup = '';
     831        foreach ( $hooked_block_types as $hooked_block_type ) {
     832                $parsed_hooked_block = array(
     833                        'blockName'    => $hooked_block_type,
     834                        'attrs'        => array(),
     835                        'innerBlocks'  => array(),
     836                        'innerContent' => array(),
     837                );
     838
     839                /**
     840                 * Filters the parsed block array for a given hooked block.
     841                 *
     842                 * @since 6.5.0
     843                 *
     844                 * @param array                   $parsed_hooked_block The parsed block array for the given hooked block type.
     845                 * @param string                  $relative_position   The relative position of the hooked block.
     846                 * @param array                   $parsed_anchor_block The anchor block, in parsed block array format.
     847                 * @param WP_Block_Template|array $context             The block template, template part, or pattern that the anchor block belongs to.
     848                 */
     849                $parsed_hooked_block = apply_filters( "hooked_block_{$hooked_block_type}", $parsed_hooked_block, $relative_position, $parsed_anchor_block, $context );
     850
     851                // It's possible that the `hooked_block_{$hooked_block_type}` filter returned a block of a different type,
     852                // so we need to pass the original $hooked_block_type as well.
     853                $markup .= get_hooked_block_markup( $parsed_hooked_block, $hooked_block_type, $parsed_anchor_block );
     854        }
     855
     856        return $markup;
    790857}
    791858
     
    827894                if ( $parent_block && ! $prev ) {
    828895                        // Candidate for first-child insertion.
    829                         $relative_position  = 'first_child';
    830                         $anchor_block_type  = $parent_block['blockName'];
    831                         $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
    832                                 ? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
    833                                 : array();
    834 
    835                         /**
    836                          * Filters the list of hooked block types for a given anchor block type and relative position.
    837                          *
    838                          * @since 6.4.0
    839                          *
    840                          * @param string[]                $hooked_block_types  The list of hooked block types.
    841                          * @param string                  $relative_position   The relative position of the hooked blocks.
    842                          *                                                     Can be one of 'before', 'after', 'first_child', or 'last_child'.
    843                          * @param string                  $anchor_block_type   The anchor block type.
    844                          * @param WP_Block_Template|array $context             The block template, template part, or pattern that the anchor block belongs to.
    845                          */
    846                         $hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context );
    847                         foreach ( $hooked_block_types as $hooked_block_type ) {
    848                                 $markup .= get_hooked_block_markup( $parent_block, $hooked_block_type );
    849                         }
    850                 }
    851 
    852                 $relative_position  = 'before';
    853                 $anchor_block_type  = $block['blockName'];
    854                 $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
    855                         ? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
    856                         : array();
    857 
    858                 /** This filter is documented in wp-includes/blocks.php */
    859                 $hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context );
    860                 foreach ( $hooked_block_types as $hooked_block_type ) {
    861                         $markup .= get_hooked_block_markup( $block, $hooked_block_type );
    862                 }
     896                        $markup .= insert_hooked_blocks( $parent_block, 'first_child', $hooked_blocks, $context );
     897                }
     898
     899                $markup .= insert_hooked_blocks( $block, 'before', $hooked_blocks, $context );
    863900
    864901                return $markup;
     
    896933         */
    897934        return function ( &$block, &$parent_block = null, $next = null ) use ( $hooked_blocks, $context ) {
    898                 $markup = '';
    899 
    900                 $relative_position  = 'after';
    901                 $anchor_block_type  = $block['blockName'];
    902                 $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
    903                                 ? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
    904                                 : array();
    905 
    906                 /** This filter is documented in wp-includes/blocks.php */
    907                 $hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context );
    908                 foreach ( $hooked_block_types as $hooked_block_type ) {
    909                         $markup .= get_hooked_block_markup( $block, $hooked_block_type );
    910                 }
     935                $markup = insert_hooked_blocks( $block, 'after', $hooked_blocks, $context );
    911936
    912937                if ( $parent_block && ! $next ) {
    913938                        // Candidate for last-child insertion.
    914                         $relative_position  = 'last_child';
    915                         $anchor_block_type  = $parent_block['blockName'];
    916                         $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
    917                                 ? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
    918                                 : array();
    919 
    920                         /** This filter is documented in wp-includes/blocks.php */
    921                         $hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context );
    922                         foreach ( $hooked_block_types as $hooked_block_type ) {
    923                                 $markup .= get_hooked_block_markup( $parent_block, $hooked_block_type );
    924                         }
     939                        $markup .= insert_hooked_blocks( $parent_block, 'last_child', $hooked_blocks, $context );
    925940                }
    926941
Note: See TracChangeset for help on using the changeset viewer.