Make WordPress Core

Changeset 58614

Timestamp:
07/02/2024 10:01:17 AM (5 weeks ago)
Author:
Bernhard Reiter
Message:

Block Hooks: Allow child insertion into Template Part block.

The Block Hooks mechanism was previously extended to allow insertion of a block as a Navigation block's first or last child. This was implemented by storing the ignoredHookedBlocks array in the corresponding wp_navigation post's post meta (instead of a metadata attribute on the anchor block).

This changeset extends that mechanism to Template Part blocks, by storing said metadata in the corresponding wp_template_part post's post meta, thus allowing extenders to use Block Hooks to insert a block as a Template Part block's first or last child, respectively.

Props tomjcafferkey, bernhard-reiter.
Fixes #60854.

Location:
trunk
Files:
5 edited

Legend:

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

    r58409 r58614  
    607607    }
    608608
     609
     610
    609611    $before_block_visitor = '_inject_theme_attribute_in_template_part_block';
    610612    $after_block_visitor  = null;
    611     $hooked_blocks        = get_hooked_blocks();
    612     if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) {
     613
     614    if ( ) {
    613615        $before_block_visitor = make_before_block_visitor( $hooked_blocks, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' );
    614616        $after_block_visitor  = make_after_block_visitor( $hooked_blocks, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' );
    615617    }
    616     $blocks            = parse_blocks( $template->content );
    617     $template->content = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
     618
     619    if ( 'wp_template_part' === $template->type && $has_hooked_blocks ) {
     620        /**
     621         * In order for hooked blocks to be inserted at positions first_child and last_child in a template part,
     622         * we need to wrap its content a mock template part block and traverse it.
     623         */
     624        $content           = get_comment_delimited_block_content(
     625            'core/template-part',
     626            array(),
     627            $template->content
     628        );
     629        $content           = traverse_and_serialize_blocks( parse_blocks( $content ), $before_block_visitor, $after_block_visitor );
     630        $template->content = remove_serialized_parent_block( $content );
     631    } else {
     632        $template->content = traverse_and_serialize_blocks(
     633            parse_blocks( $template->content ),
     634            $before_block_visitor,
     635            $after_block_visitor
     636        );
     637    }
    618638
    619639    return $template;
     
    9991019        $before_block_visitor = make_before_block_visitor( $hooked_blocks, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' );
    10001020        $after_block_visitor  = make_after_block_visitor( $hooked_blocks, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' );
    1001         $blocks               = parse_blocks( $template->content );
    1002         $template->content    = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
     1021        if ( 'wp_template_part' === $template->type ) {
     1022            $existing_ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true );
     1023            $attributes                     = ! empty( $existing_ignored_hooked_blocks ) ? array( 'metadata' => array( 'ignoredHookedBlocks' => json_decode( $existing_ignored_hooked_blocks, true ) ) ) : array();
     1024
     1025            /**
     1026             * In order for hooked blocks to be inserted at positions first_child and last_child in a template part,
     1027             * we need to wrap its content a mock template part block and traverse it.
     1028             */
     1029            $content           = get_comment_delimited_block_content(
     1030                'core/template-part',
     1031                $attributes,
     1032                $template->content
     1033            );
     1034            $content           = traverse_and_serialize_blocks( parse_blocks( $content ), $before_block_visitor, $after_block_visitor );
     1035            $template->content = remove_serialized_parent_block( $content );
     1036        } else {
     1037            $template->content = traverse_and_serialize_blocks(
     1038                parse_blocks( $template->content ),
     1039                $before_block_visitor,
     1040                $after_block_visitor
     1041            );
     1042        }
    10031043    }
    10041044
     
    16121652    }
    16131653
    1614     $changes->post_content = apply_block_hooks_to_content( $changes->post_content, $template, 'set_ignored_hooked_blocks_metadata' );
     1654    if ( 'wp_template_part' === $post->post_type ) {
     1655        $attributes                     = array();
     1656        $existing_ignored_hooked_blocks = isset( $post->ID ) ? get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true ) : '';
     1657
     1658        if ( ! empty( $existing_ignored_hooked_blocks ) ) {
     1659            $attributes['metadata'] = array(
     1660                'ignoredHookedBlocks' => json_decode( $existing_ignored_hooked_blocks, true ),
     1661            );
     1662        }
     1663
     1664        $content = get_comment_delimited_block_content(
     1665            'core/template-part',
     1666            $attributes,
     1667            $changes->post_content
     1668        );
     1669        $content = apply_block_hooks_to_content( $content, $template, 'set_ignored_hooked_blocks_metadata' );
     1670        $changes->post_content = remove_serialized_parent_block( $content );
     1671
     1672        $wrapper_block_markup  = extract_serialized_parent_block( $content );
     1673        $wrapper_block         = parse_blocks( $wrapper_block_markup )[0];
     1674        $ignored_hooked_blocks = $wrapper_block['attrs']['metadata']['ignoredHookedBlocks'] ?? array();
     1675        if ( ! empty( $ignored_hooked_blocks ) ) {
     1676            if ( ! isset( $changes->meta_input ) ) {
     1677                $changes->meta_input = array();
     1678            }
     1679            $changes->meta_input['_wp_ignored_hooked_blocks'] = wp_json_encode( $ignored_hooked_blocks );
     1680        }
     1681    } else {
     1682        $changes->post_content = apply_block_hooks_to_content( $changes->post_content, $template, 'set_ignored_hooked_blocks_metadata' );
     1683    }
    16151684
    16161685    return $changes;
  • trunk/src/wp-includes/blocks.php

    r58578 r58614  
    10471047
    10481048/**
     1049
     1050
     1051
     1052
     1053
     1054
     1055
     1056
     1057
     1058
     1059
     1060
     1061
     1062
     1063
     1064
     1065
    10491066 * Updates the wp_postmeta with the list of ignored hooked blocks where the inner blocks are stored as post content.
    10501067 * Currently only supports `wp_navigation` post types.
  • trunk/tests/phpunit/tests/block-templates/buildBlockTemplateResultFromFile.php

    r57266 r58614  
    88 */
    99class Tests_Block_Templates_BuildBlockTemplateResultFromFile extends WP_Block_Templates_UnitTestCase {
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
    1024
    1125    /**
     
    179193        $this->assertEmpty( $template->post_types );
    180194    }
     195
     196
     197
     198
     199
     200
     201
     202
     203
     204
     205
     206
     207
     208
     209
     210
     211
     212
     213
     214
     215
     216
     217
     218
     219
     220
     221
     222
     223
     224
     225
     226
     227
     228
     229
     230
     231
     232
     233
     234
     235
     236
     237
     238
     239
     240
     241
     242
     243
     244
     245
     246
     247
     248
     249
     250
     251
     252
     253
     254
     255
     256
     257
     258
     259
     260
     261
     262
     263
     264
     265
     266
     267
     268
    181269}
  • trunk/tests/phpunit/tests/block-templates/buildBlockTemplateResultFromPost.php

    r57627 r58614  
    112112    }
    113113
     114
     115
     116
     117
     118
     119
     120
     121
     122
     123
     124
     125
     126
     127
     128
     129
     130
     131
     132
     133
     134
     135
     136
     137
     138
     139
     140
     141
     142
     143
     144
     145
     146
     147
     148
     149
     150
     151
     152
     153
     154
     155
     156
     157
    114158    /**
    115159     * @ticket 59646
  • trunk/tests/phpunit/tests/block-templates/injectIgnoredHookedBlocksMetadataAttributes.php

    r58042 r58614  
    1818            unregister_block_type( 'tests/hooked-block' );
    1919        }
     20
    2021
    2122        parent::tear_down();
     
    3940        inject_ignored_hooked_blocks_metadata_attributes( $changes );
    4041
    41         $args              = $action->get_args();
    42         $anchor_block_type = end( $args )[2];
    43         $context           = end( $args )[3];
    44 
    45         $this->assertSame( 'tests/anchor-block', $anchor_block_type );
    46 
    47         $this->assertInstanceOf( 'WP_Block_Template', $context );
    48 
     42        $args               = $action->get_args();
     43        $relative_positions = array_column( $args, 1 );
     44        $anchor_block_types = array_column( $args, 2 );
     45        $contexts           = array_column( $args, 3 );
     46
     47        $this->assertSame(
     48            array(
     49                'before',
     50                'after',
     51            ),
     52            $relative_positions,
     53            'The relative positions passed to the hooked_block_types filter are incorrect.'
     54        );
     55
     56        $this->assertSame(
     57            array(
     58                'tests/anchor-block',
     59                'tests/anchor-block',
     60            ),
     61            $anchor_block_types,
     62            'The anchor block types passed to the hooked_block_types filter are incorrect.'
     63        );
     64
     65        $context = $contexts[0];
     66        $this->assertSame(
     67            array_fill( 0, count( $contexts ), $context ),
     68            $contexts,
     69            'The context passed to the hooked_block_types filter should be the same for all calls.'
     70        );
    4971        $this->assertSame(
    5072            $changes->post_type,
     
    7092    /**
    7193     * @ticket 60754
     94
    7295     */
    7396    public function test_hooked_block_types_filter_with_newly_created_template_part() {
     
    86109        inject_ignored_hooked_blocks_metadata_attributes( $changes );
    87110
    88         $args              = $action->get_args();
    89         $anchor_block_type = end( $args )[2];
    90         $context           = end( $args )[3];
    91 
    92         $this->assertSame( 'tests/anchor-block', $anchor_block_type );
    93 
    94         $this->assertInstanceOf( 'WP_Block_Template', $context );
    95 
     111        $args               = $action->get_args();
     112        $relative_positions = array_column( $args, 1 );
     113        $anchor_block_types = array_column( $args, 2 );
     114        $contexts           = array_column( $args, 3 );
     115
     116        $this->assertSame(
     117            array(
     118                'before',
     119                'after',
     120                'first_child',
     121                'before',
     122                'after',
     123                'last_child',
     124            ),
     125            $relative_positions,
     126            'The relative positions passed to the hooked_block_types filter are incorrect.'
     127        );
     128
     129        $this->assertSame(
     130            array(
     131                'core/template-part',
     132                'core/template-part',
     133                'core/template-part',
     134                'tests/anchor-block',
     135                'tests/anchor-block',
     136                'core/template-part',
     137            ),
     138            $anchor_block_types,
     139            'The anchor block types passed to the hooked_block_types filter are incorrect.'
     140        );
     141
     142        $context = $contexts[0];
     143        $this->assertSame(
     144            array_fill( 0, count( $contexts ), $context ),
     145            $contexts,
     146            'The context passed to the hooked_block_types filter should be the same for all calls.'
     147        );
     148        $this->assertInstanceOf(
     149            'WP_Block_Template',
     150            $context,
     151            'The context passed to the hooked_block_types filter is not an instance of WP_Block_Template.'
     152        );
    96153        $this->assertSame(
    97154            $changes->post_type,
     
    141198        inject_ignored_hooked_blocks_metadata_attributes( $changes );
    142199
    143         $args              = $action->get_args();
    144         $anchor_block_type = end( $args )[2];
    145         $context           = end( $args )[3];
    146 
    147         $this->assertSame( 'tests/anchor-block', $anchor_block_type );
    148 
    149         $this->assertInstanceOf( 'WP_Block_Template', $context );
    150 
     200        $args               = $action->get_args();
     201        $relative_positions = array_column( $args, 1 );
     202        $anchor_block_types = array_column( $args, 2 );
     203        $contexts           = array_column( $args, 3 );
     204
     205        $this->assertSame(
     206            array(
     207                'before',
     208                'after',
     209            ),
     210            $relative_positions,
     211            'The relative positions passed to the hooked_block_types filter are incorrect.'
     212        );
     213
     214        $this->assertSame(
     215            array(
     216                'tests/anchor-block',
     217                'tests/anchor-block',
     218            ),
     219            $anchor_block_types,
     220            'The anchor block types passed to the hooked_block_types filter are incorrect.'
     221        );
     222
     223        $context = $contexts[0];
     224        $this->assertSame(
     225            array_fill( 0, count( $contexts ), $context ),
     226            $contexts,
     227            'The context passed to the hooked_block_types filter should be the same for all calls.'
     228        );
    151229        $this->assertSame(
    152230            $changes->post_name,
     
    182260    /**
    183261     * @ticket 60754
     262
    184263     */
    185264    public function test_hooked_block_types_filter_with_existing_template_part_file() {
     
    202281        inject_ignored_hooked_blocks_metadata_attributes( $changes );
    203282
    204         $args              = $action->get_args();
    205         $anchor_block_type = end( $args )[2];
    206         $context           = end( $args )[3];
    207 
    208         $this->assertSame( 'tests/anchor-block', $anchor_block_type );
    209 
    210         $this->assertInstanceOf( 'WP_Block_Template', $context );
    211 
     283        $args               = $action->get_args();
     284        $relative_positions = array_column( $args, 1 );
     285        $anchor_block_types = array_column( $args, 2 );
     286        $contexts           = array_column( $args, 3 );
     287
     288        $this->assertSame(
     289            array(
     290                'before',
     291                'after',
     292                'first_child',
     293                'before',
     294                'after',
     295                'last_child',
     296            ),
     297            $relative_positions,
     298            'The relative positions passed to the hooked_block_types filter are incorrect.'
     299        );
     300
     301        $this->assertSame(
     302            array(
     303                'core/template-part',
     304                'core/template-part',
     305                'core/template-part',
     306                'tests/anchor-block',
     307                'tests/anchor-block',
     308                'core/template-part',
     309            ),
     310            $anchor_block_types,
     311            'The anchor block types passed to the hooked_block_types filter are incorrect.'
     312        );
     313
     314        $context = $contexts[0];
     315        $this->assertSame(
     316            array_fill( 0, count( $contexts ), $context ),
     317            $contexts,
     318            'The context passed to the hooked_block_types filter should be the same for all calls.'
     319        );
     320        $this->assertInstanceOf(
     321            'WP_Block_Template',
     322            $context,
     323            'The context passed to the hooked_block_types filter is not an instance of WP_Block_Template.'
     324        );
    212325        $this->assertSame(
    213326            $changes->post_name,
     
    260373        inject_ignored_hooked_blocks_metadata_attributes( $changes );
    261374
    262         $args              = $action->get_args();
    263         $anchor_block_type = end( $args )[2];
    264         $context           = end( $args )[3];
    265 
    266         $this->assertSame( 'tests/anchor-block', $anchor_block_type );
    267 
    268         $this->assertInstanceOf( 'WP_Block_Template', $context );
    269 
     375        $args               = $action->get_args();
     376        $relative_positions = array_column( $args, 1 );
     377        $anchor_block_types = array_column( $args, 2 );
     378        $contexts           = array_column( $args, 3 );
     379
     380        $this->assertSame(
     381            array(
     382                'before',
     383                'after',
     384            ),
     385            $relative_positions,
     386            'The relative positions passed to the hooked_block_types filter are incorrect.'
     387        );
     388
     389        $this->assertSame(
     390            array(
     391                'tests/anchor-block',
     392                'tests/anchor-block',
     393            ),
     394            $anchor_block_types,
     395            'The anchor block types passed to the hooked_block_types filter are incorrect.'
     396        );
     397
     398        $context = $contexts[0];
     399        $this->assertSame(
     400            array_fill( 0, count( $contexts ), $context ),
     401            $contexts,
     402            'The context passed to the hooked_block_types filter should be the same for all calls.'
     403        );
    270404        $this->assertSame(
    271405            $changes->post_name,
     
    303437    /**
    304438     * @ticket 60754
     439
    305440     */
    306441    public function test_hooked_block_types_filter_with_existing_template_part_post() {
     
    319454        inject_ignored_hooked_blocks_metadata_attributes( $changes );
    320455
    321         $args              = $action->get_args();
    322         $anchor_block_type = end( $args )[2];
    323         $context           = end( $args )[3];
    324 
    325         $this->assertSame( 'tests/anchor-block', $anchor_block_type );
    326 
    327         $this->assertInstanceOf( 'WP_Block_Template', $context );
    328 
     456        $args               = $action->get_args();
     457        $relative_positions = array_column( $args, 1 );
     458        $anchor_block_types = array_column( $args, 2 );
     459        $contexts           = array_column( $args, 3 );
     460
     461        $this->assertSame(
     462            array(
     463                'before',
     464                'after',
     465                'first_child',
     466                'before',
     467                'after',
     468                'last_child',
     469            ),
     470            $relative_positions,
     471            'The relative positions passed to the hooked_block_types filter are incorrect.'
     472        );
     473
     474        $this->assertSame(
     475            array(
     476                'core/template-part',
     477                'core/template-part',
     478                'core/template-part',
     479                'tests/anchor-block',
     480                'tests/anchor-block',
     481                'core/template-part',
     482            ),
     483            $anchor_block_types,
     484            'The anchor block types passed to the hooked_block_types filter are incorrect.'
     485        );
     486
     487        $context = $contexts[0];
     488        $this->assertSame(
     489            array_fill( 0, count( $contexts ), $context ),
     490            $contexts,
     491            'The context passed to the hooked_block_types filter should be the same for all calls.'
     492        );
     493        $this->assertInstanceOf(
     494            'WP_Block_Template',
     495            $context,
     496            'The context passed to the hooked_block_types filter is not an instance of WP_Block_Template.'
     497        );
    329498        $this->assertSame(
    330499            $changes->post_name,
     
    420589        );
    421590    }
     591
     592
     593
     594
     595
     596
     597
     598
     599
     600
     601
     602
     603
     604
     605
     606
     607
     608
     609
     610
     611
     612
     613
     614
     615
     616
     617
     618
     619
     620
     621
     622
     623
    422624}
Note: See TracChangeset for help on using the changeset viewer.