Make WordPress Core

Changeset 57627

Timestamp:
02/13/2024 03:10:21 PM (6 months ago)
Author:
Bernhard Reiter
Message:

Block Hooks: Set ignoredHookedBlocks metadata upon saving.

Decouple hooked blocks insertion from setting the metadata.ignoredHookedBlocks attribute on anchor blocks, and perform the latter step upon saving a template or template part to the database. This ensures that anchor blocks that have been newly added to a template (or part) on the client side will also get ignoredHookedBlocks metadata set correctly, thus preserving editor/front-end parity. Hooked block insertion, on the other hand, will continue to happen upon reading a template (or part).

Props gziolo, tomjcafferkey.
Fixes #60506.

Location:
trunk
Files:
1 added
1 deleted
8 edited

Legend:

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

    r57594 r57627  
    14331433    return $template_hierarchy;
    14341434}
     1435
     1436
     1437
     1438
     1439
     1440
     1441
     1442
     1443
     1444
     1445
     1446
     1447
     1448
     1449
     1450
     1451
     1452
     1453
     1454
     1455
     1456
     1457
     1458
     1459
     1460
     1461
     1462
     1463
     1464
     1465
     1466
     1467
     1468
     1469
     1470
  • trunk/src/wp-includes/blocks.php

    r57590 r57627  
    852852
    853853/**
    854  * Conditionally returns the markup for a given hooked block.
    855  *
    856  * Accepts three arguments: A hooked block, its type, and a reference to an anchor block.
    857  * If the anchor block has already been processed, and the given hooked block type is in the list
    858  * of ignored hooked blocks, an empty string is returned.
    859  *
    860  * The hooked block type is specified separately as it's possible that a filter might've modified
    861  * the hooked block such that `$hooked_block['blockName']` does no longer reflect the original type.
    862  *
    863  * This function is meant for internal use only.
    864  *
    865  * @since 6.5.0
    866  * @access private
    867  *
    868  * @param array  $hooked_block      The hooked block, represented as a parsed block array.
    869  * @param string $hooked_block_type The type of the hooked block. This could be different from
    870  *                                  $hooked_block['blockName'], as a filter might've modified the latter.
    871  * @param array  $anchor_block      The anchor block, represented as a parsed block array.
    872  *                                  Passed by reference.
    873  * @return string The markup for the given hooked block, or an empty string if the block is ignored.
    874  */
    875 function get_hooked_block_markup( $hooked_block, $hooked_block_type, &$anchor_block ) {
    876     if ( ! isset( $anchor_block['attrs']['metadata']['ignoredHookedBlocks'] ) ) {
    877         $anchor_block['attrs']['metadata']['ignoredHookedBlocks'] = array();
    878     }
    879 
    880     if ( in_array( $hooked_block_type, $anchor_block['attrs']['metadata']['ignoredHookedBlocks'], true ) ) {
    881         return '';
    882     }
    883 
    884     // The following is only needed for the REST API endpoint.
    885     // However, its presence does not affect the frontend.
    886     $anchor_block['attrs']['metadata']['ignoredHookedBlocks'][] = $hooked_block_type;
    887 
    888     return serialize_block( $hooked_block );
    889 }
    890 
    891 /**
    892854 * Returns the markup for blocks hooked to the given anchor block in a specific relative position.
    893855 *
     
    947909
    948910        // It's possible that the `hooked_block_{$hooked_block_type}` filter returned a block of a different type,
    949         // so we need to pass the original $hooked_block_type as well.
    950         $markup .= get_hooked_block_markup( $parsed_hooked_block, $hooked_block_type, $parsed_anchor_block );
     911        // so we explicitly look for the original `$hooked_block_type` in the `ignoredHookedBlocks` metadata.
     912        if (
     913            ! isset( $parsed_anchor_block['attrs']['metadata']['ignoredHookedBlocks'] ) ||
     914            ! in_array( $hooked_block_type, $parsed_anchor_block['attrs']['metadata']['ignoredHookedBlocks'], true )
     915        ) {
     916            $markup .= serialize_block( $parsed_hooked_block );
     917        }
    951918    }
    952919
    953920    return $markup;
     921
     922
     923
     924
     925
     926
     927
     928
     929
     930
     931
     932
     933
     934
     935
     936
     937
     938
     939
     940
     941
     942
     943
     944
     945
     946
     947
     948
     949
     950
     951
     952
     953
     954
     955
     956
     957
     958
     959
     960
     961
     962
    954963}
    955964
     
    964973 *
    965974 * @since 6.4.0
     975
    966976 * @access private
    967977 *
     
    969979 * @param WP_Block_Template|WP_Post|array $context       A block template, template part, `wp_navigation` post object,
    970980 *                                                       or pattern that the blocks belong to.
     981
     982
     983
    971984 * @return callable A function that returns the serialized markup for the given block,
    972985 *                  including the markup for any hooked blocks before it.
    973986 */
    974 function make_before_block_visitor( $hooked_blocks, $context ) {
     987function make_before_block_visitor( $hooked_blocks, $context ) {
    975988    /**
    976989     * Injects hooked blocks before the given block, injects the `theme` attribute into Template Part blocks, and returns the serialized markup.
     
    985998     * @return string The serialized markup for the given block, with the markup for any hooked blocks prepended to it.
    986999     */
    987     return function ( &$block, &$parent_block = null, $prev = null ) use ( $hooked_blocks, $context ) {
     1000    return function ( &$block, &$parent_block = null, $prev = null ) use ( $hooked_blocks, $context ) {
    9881001        _inject_theme_attribute_in_template_part_block( $block );
    9891002
     
    9921005        if ( $parent_block && ! $prev ) {
    9931006            // Candidate for first-child insertion.
    994             $markup .= insert_hooked_blocks( $parent_block, 'first_child', $hooked_blocks, $context );
    995         }
    996 
    997         $markup .= insert_hooked_blocks( $block, 'before', $hooked_blocks, $context );
     1007            $markup .= call_user_func_array(
     1008                $callback,
     1009                array( &$parent_block, 'first_child', $hooked_blocks, $context )
     1010            );
     1011        }
     1012
     1013        $markup .= call_user_func_array(
     1014            $callback,
     1015            array( &$block, 'before', $hooked_blocks, $context )
     1016        );
    9981017
    9991018        return $markup;
     
    10111030 *
    10121031 * @since 6.4.0
     1032
    10131033 * @access private
    10141034 *
     
    10161036 * @param WP_Block_Template|WP_Post|array $context       A block template, template part, `wp_navigation` post object,
    10171037 *                                                       or pattern that the blocks belong to.
     1038
     1039
     1040
    10181041 * @return callable A function that returns the serialized markup for the given block,
    10191042 *                  including the markup for any hooked blocks after it.
    10201043 */
    1021 function make_after_block_visitor( $hooked_blocks, $context ) {
     1044function make_after_block_visitor( $hooked_blocks, $context ) {
    10221045    /**
    10231046     * Injects hooked blocks after the given block, and returns the serialized markup.
     
    10311054     * @return string The serialized markup for the given block, with the markup for any hooked blocks appended to it.
    10321055     */
    1033     return function ( &$block, &$parent_block = null, $next = null ) use ( $hooked_blocks, $context ) {
    1034         $markup = insert_hooked_blocks( $block, 'after', $hooked_blocks, $context );
     1056    return function ( &$block, &$parent_block = null, $next = null ) use ( $hooked_blocks, $context, $callback ) {
     1057        $markup = call_user_func_array(
     1058            $callback,
     1059            array( &$block, 'after', $hooked_blocks, $context )
     1060        );
    10351061
    10361062        if ( $parent_block && ! $next ) {
    10371063            // Candidate for last-child insertion.
    1038             $markup .= insert_hooked_blocks( $parent_block, 'last_child', $hooked_blocks, $context );
     1064            $markup .= call_user_func_array(
     1065                $callback,
     1066                array( &$parent_block, 'last_child', $hooked_blocks, $context )
     1067            );
    10391068        }
    10401069
  • trunk/src/wp-includes/default-filters.php

    r57558 r57627  
    753753add_action( 'init', '_wp_register_default_font_collections' );
    754754
     755
     756
     757
     758
     759
    755760unset( $filter, $action );
  • trunk/tests/phpunit/tests/block-templates/base.php

    r57594 r57627  
    4040                'post_name'    => 'my_template',
    4141                'post_title'   => 'My Template',
    42                 'post_content' => '<!-- wp:heading {"level":1} --><h1>Template</h1><!-- /wp:heading -->',
     42                'post_content' => '<!-- wp:heading {"level":1} --><h1>Template</h1><!-- /wp:heading -->',
    4343                'post_excerpt' => 'Description of my template',
    4444                'tax_input'    => array(
     
    5858                'post_name'    => 'my_template_part',
    5959                'post_title'   => 'My Template Part',
    60                 'post_content' => '<!-- wp:heading {"level":2} --><h2>Template Part</h2><!-- /wp:heading -->',
     60                'post_content' => '<!-- wp:heading {"level":2} --><h2>Template Part</h2><!-- /wp:heading -->',
    6161                'post_excerpt' => 'Description of my template part',
    6262                'tax_input'    => array(
  • trunk/tests/phpunit/tests/block-templates/buildBlockTemplateResultFromPost.php

    r57594 r57627  
    1919        if ( $registry->is_registered( 'tests/my-block' ) ) {
    2020            $registry->unregister( 'tests/my-block' );
     21
     22
     23
     24
    2125        }
    2226
     
    6872    /**
    6973     * @ticket 59646
     74
    7075     */
    7176    public function test_should_inject_hooked_block_into_template() {
     
    8489        );
    8590        $this->assertStringStartsWith( '<!-- wp:tests/my-block /-->', $template->content );
    86         $this->assertStringContainsString( '"metadata":{"ignoredHookedBlocks":["tests/my-block"]}', $template->content );
    8791    }
    8892
    8993    /**
    9094     * @ticket 59646
     95
    9196     */
    9297    public function test_should_inject_hooked_block_into_template_part() {
    ��  
    105110        );
    106111        $this->assertStringEndsWith( '<!-- wp:tests/my-block /-->', $template_part->content );
    107         $this->assertStringContainsString( '"metadata":{"ignoredHookedBlocks":["tests/my-block"]}', $template_part->content );
     112    }
     113
     114    /**
     115     * @ticket 59646
     116     * @ticket 60506
     117     */
     118    public function test_should_not_inject_ignored_hooked_block_into_template() {
     119        register_block_type(
     120            'tests/ignored',
     121            array(
     122                'block_hooks' => array(
     123                    'core/heading' => 'after',
     124                ),
     125            )
     126        );
     127
     128        $template = _build_block_template_result_from_post(
     129            self::$template_post,
     130            'wp_template'
     131        );
     132        $this->assertStringNotContainsString( '<!-- wp:tests/ignored /-->', $template->content );
     133    }
     134
     135    /**
     136     * @ticket 59646
     137     * @ticket 60506
     138     */
     139    public function test_should_not_inject_ignored_hooked_block_into_template_part() {
     140        register_block_type(
     141            'tests/ignored',
     142            array(
     143                'block_hooks' => array(
     144                    'core/heading' => 'after',
     145                ),
     146            )
     147        );
     148
     149        $template_part = _build_block_template_result_from_post(
     150            self::$template_part_post,
     151            'wp_template_part'
     152        );
     153        $this->assertStringNotContainsString( '<!-- wp:tests/ignored /-->', $template_part->content );
    108154    }
    109155}
  • trunk/tests/phpunit/tests/blocks/getHookedBlocks.php

    r57172 r57627  
    137137     * @ticket 59313
    138138     * @ticket 60008
     139
    139140     *
    140141     * @covers ::get_hooked_blocks
     
    151152        );
    152153        $this->assertStringContainsString(
    153             '<!-- wp:post-content {"layout":{"type":"constrained"},"metadata":{"ignoredHookedBlocks":["tests/hooked-after"]}} /-->'
     154            '<!-- wp:post-content {"layout":{"type":"constrained"}} /-->'
    154155            . '<!-- wp:tests/hooked-after /-->',
    155156            $template->content
     
    168169     * @ticket 59313
    169170     * @ticket 60008
     171
    170172     *
    171173     * @covers ::get_hooked_blocks
     
    179181        $this->assertStringContainsString(
    180182            '<!-- wp:tests/hooked-before /-->'
    181             . '<!-- wp:navigation {"layout":{"type":"flex","setCascadingProperties":true,"justifyContent":"right"},"metadata":{"ignoredHookedBlocks":["tests/hooked-before"]}} /-->',
     183            . '<!-- wp:navigation {"layout":{"type":"flex","setCascadingProperties":true,"justifyContent":"right"}} /-->',
    182184            $template->content
    183185        );
     
    199201     * @ticket 59313
    200202     * @ticket 60008
     203
    201204     *
    202205     * @covers ::get_hooked_blocks
     
    219222        );
    220223        $this->assertStringContainsString(
    221             '<!-- wp:comments {"metadata":{"ignoredHookedBlocks":["tests/hooked-first-child"]}} -->'
     224            '<!-- wp:comments -->'
    222225            . '<div class="wp-block-comments">'
    223226            . '<!-- wp:tests/hooked-first-child /-->',
  • trunk/tests/phpunit/tests/blocks/insertHookedBlocks.php

    r57354 r57627  
    2626     * @ticket 59572
    2727     * @ticket 60126
     28
    2829     *
    2930     * @covers ::insert_hooked_blocks
    3031     */
    31     public function test_insert_hooked_blocks_adds_metadata() {
     32    public function test_insert_hooked_blocks_() {
    3233        $anchor_block = array(
    3334            'blockName' => self::ANCHOR_BLOCK_TYPE,
     
    3536
    3637        $actual = insert_hooked_blocks( $anchor_block, 'after', self::HOOKED_BLOCKS, array() );
    37         $this->assertSame(
    38             array( self::HOOKED_BLOCK_TYPE ),
    39             $anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
    40             "Hooked block type wasn't added to ignoredHookedBlocks metadata."
    41         );
    4238        $this->assertSame(
    4339            '<!-- wp:' . self::HOOKED_BLOCK_TYPE . ' /-->',
     
    5046     * @ticket 59572
    5147     * @ticket 60126
     48
    5249     *
    5350     * @covers ::insert_hooked_blocks
    5451     */
    55     public function test_insert_hooked_blocks_if_block_is_already_hooked() {
     52    public function test_insert_hooked_blocks_if_block_is_ed() {
    5653        $anchor_block = array(
    5754            'blockName' => 'tests/anchor-block',
     
    6562        $actual = insert_hooked_blocks( $anchor_block, 'after', self::HOOKED_BLOCKS, array() );
    6663        $this->assertSame(
    67             array( self::HOOKED_BLOCK_TYPE ),
    68             $anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
    69             "ignoredHookedBlocks metadata shouldn't have been modified."
    70         );
    71         $this->assertSame(
    7264            '',
    7365            $actual,
     
    7971     * @ticket 59572
    8072     * @ticket 60126
     73
    8174     *
    8275     * @covers ::insert_hooked_blocks
    8376     */
    84     public function test_insert_hooked_blocks_adds_to_ignored_hooked_blocks() {
     77    public function test_insert_hooked_blocks_() {
    8578        $anchor_block = array(
    8679            'blockName' => 'tests/anchor-block',
     
    9487        $actual = insert_hooked_blocks( $anchor_block, 'before', self::HOOKED_BLOCKS, array() );
    9588        $this->assertSame(
    96             array( self::HOOKED_BLOCK_TYPE, self::OTHER_HOOKED_BLOCK_TYPE ),
    97             $anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
    98             "Newly hooked block should've been added to ignoredHookedBlocks metadata while retaining previously ignored one."
    99         );
    100         $this->assertSame(
    10189            '<!-- wp:' . self::OTHER_HOOKED_BLOCK_TYPE . ' /-->',
    10290            $actual,
     
    10896     * @ticket 59572
    10997     * @ticket 60126
     98
    11099     *
    111100     * @covers ::insert_hooked_blocks
     
    141130
    142131        $this->assertSame(
    143             array( self::HOOKED_BLOCK_TYPE ),
    144             $anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
    145             "Hooked block type wasn't added to ignoredHookedBlocks metadata."
    146         );
    147         $this->assertSame(
    148132            '<!-- wp:' . self::HOOKED_BLOCK_TYPE . ' {"layout":{"type":"constrained"}} /-->',
    149133            $actual,
     
    155139     * @ticket 59572
    156140     * @ticket 60126
     141
    157142     *
    158143     * @covers ::insert_hooked_blocks
     
    191176
    192177        $this->assertSame(
    193             array( self::HOOKED_BLOCK_TYPE ),
    194             $anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
    195             "Hooked block type wasn't added to ignoredHookedBlocks metadata."
    196         );
    197         $this->assertSame(
    198178            '<!-- wp:group --><div class="wp-block-group"><!-- wp:' . self::HOOKED_BLOCK_TYPE . ' /--></div><!-- /wp:group -->',
    199179            $actual,
  • trunk/tests/phpunit/tests/blocks/wpBlockPatternsRegistry.php

    r57172 r57627  
    345345     * @ticket 59476
    346346     * @ticket 60008
     347
    347348     *
    348349     * @covers WP_Block_Patterns_Registry::register
     
    386387        $this->assertCount( 3, $registered );
    387388        $this->assertStringEndsWith( '<!-- wp:tests/my-block /-->', $registered[1]['content'] );
    388         $this->assertStringContainsString( '"metadata":{"ignoredHookedBlocks":["tests/my-block"]}', $registered[1]['content'] );
    389389        $this->assertStringEndsWith( '<!-- wp:tests/my-block /-->', $registered[2]['content'] );
    390         $this->assertStringContainsString( '"metadata":{"ignoredHookedBlocks":["tests/my-block"]}', $registered[2]['content'] );
    391390    }
    392391
     
    419418     * @ticket 59476
    420419     * @ticket 60008
     420
    421421     *
    422422     * @covers WP_Block_Patterns_Registry::register
     
    447447        $pattern = $this->registry->get_registered( 'test/one' );
    448448        $this->assertStringStartsWith( '<!-- wp:tests/my-block /-->', $pattern['content'] );
    449         $this->assertStringContainsString( '"metadata":{"ignoredHookedBlocks":["tests/my-block"]}', $pattern['content'] );
    450449    }
    451450
Note: See TracChangeset for help on using the changeset viewer.