Make WordPress Core

Changeset 59523


Ignore:
Timestamp:
12/17/2024 10:35:17 AM (2 months ago)
Author:
Bernhard Reiter
Message:

Block Hooks: Enable for post content.

Block Hooks were previously only applied to layout elements such as templates, template parts, patterns, and navigation menus -- things that are edited in the Site Editor.

This changeset enables Block Hooks in post content. The parity between frontend and editor is preserved: Blocks inserted by Block Hooks are visible both on the frontend and in the editor, and any customizations made by the user are respected on the frontend.

This is possible thanks to setting the metadata.ignoredHookedBlocks attribute on anchor blocks (a technique first introduced in [57594]). For first child and last child insertion into a Post Content block, the corresponding post object's _wp_ignored_hooked_blocks post meta is set.

Props bernhard-reiter, gziolo, jonsurrell, karolmanijak, leewillis77.
Fixes #61074.

Location:
trunk
Files:
3 edited

Legend:

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

    r59482 r59523  
    913913     *                                                            Can be one of 'before', 'after', 'first_child', or 'last_child'.
    914914     * @param string                          $anchor_block_type  The anchor block type.
    915      * @param WP_Block_Template|WP_Post|array $context            The block template, template part, `wp_navigation` post type,
     915     * @param WP_Block_Template|WP_Post|array $context            The block template, template part, post object,
    916916     *                                                            or pattern that the anchor block belongs to.
    917917     */
     
    936936         * @param string                          $relative_position   The relative position of the hooked block.
    937937         * @param array                           $parsed_anchor_block The anchor block, in parsed block array format.
    938          * @param WP_Block_Template|WP_Post|array $context             The block template, template part, `wp_navigation` post type,
     938         * @param WP_Block_Template|WP_Post|array $context             The block template, template part, post object,
    939939         *                                                             or pattern that the anchor block belongs to.
    940940         */
     
    952952         * @param string                          $relative_position   The relative position of the hooked block.
    953953         * @param array                           $parsed_anchor_block The anchor block, in parsed block array format.
    954          * @param WP_Block_Template|WP_Post|array $context             The block template, template part, `wp_navigation` post type,
     954         * @param WP_Block_Template|WP_Post|array $context             The block template, template part, post object,
    955955         *                                                             or pattern that the anchor block belongs to.
    956956         */
     
    10401040 * @since 6.6.0
    10411041 * @since 6.7.0 Injects the `theme` attribute into Template Part blocks, even if no hooked blocks are registered.
     1042 * @since 6.8.0 Have the `$context` parameter default to `null`, in which case `get_post()` will be called to use the current post as context.
    10421043 * @access private
    10431044 *
    1044  * @param string                          $content  Serialized content.
    1045  * @param WP_Block_Template|WP_Post|array $context  A block template, template part, `wp_navigation` post object,
    1046  *                                                  or pattern that the blocks belong to.
    1047  * @param callable                        $callback A function that will be called for each block to generate
    1048  *                                                  the markup for a given list of blocks that are hooked to it.
    1049  *                                                  Default: 'insert_hooked_blocks'.
     1045 * @param string                               $content  Serialized content.
     1046 * @param WP_Block_Template|WP_Post|array|null $context  A block template, template part, post object, or pattern
     1047 *                                                       that the blocks belong to. If set to `null`, `get_post()`
     1048 *                                                       will be called to use the current post as context.
     1049 *                                                       Default: `null`.
     1050 * @param callable                             $callback A function that will be called for each block to generate
     1051 *                                                       the markup for a given list of blocks that are hooked to it.
     1052 *                                                       Default: 'insert_hooked_blocks'.
    10501053 * @return string The serialized markup.
    10511054 */
    1052 function apply_block_hooks_to_content( $content, $context, $callback = 'insert_hooked_blocks' ) {
     1055function apply_block_hooks_to_content( $content, $context = null, $callback = 'insert_hooked_blocks' ) {
     1056    // Default to the current post if no context is provided.
     1057    if ( null === $context ) {
     1058        $context = get_post();
     1059    }
     1060
    10531061    $hooked_blocks = get_hooked_blocks();
    10541062
     
    11661174
    11671175/**
    1168  * Updates the wp_postmeta with the list of ignored hooked blocks where the inner blocks are stored as post content.
    1169  * Currently only supports `wp_navigation` post types.
     1176 * Updates the wp_postmeta with the list of ignored hooked blocks
     1177 * where the inner blocks are stored as post content.
    11701178 *
    11711179 * @since 6.6.0
     1180 * @since 6.8.0 Support non-`wp_navigation` post types.
    11721181 * @access private
    11731182 *
     
    11771186function update_ignored_hooked_blocks_postmeta( $post ) {
    11781187    /*
    1179      * In this scenario the user has likely tried to create a navigation via the REST API.
     1188     * In this scenario the user has likely tried to create a new post object via the REST API.
    11801189     * In which case we won't have a post ID to work with and store meta against.
    11811190     */
     
    11851194
    11861195    /*
    1187      * Skip meta generation when consumers intentionally update specific Navigation fields
     1196     * Skip meta generation when consumers intentionally update specific fields
    11881197     * and omit the content update.
    11891198     */
     
    11931202
    11941203    /*
    1195      * Skip meta generation when the post content is not a navigation block.
     1204     * Skip meta generation if post type is not set.
    11961205     */
    1197     if ( ! isset( $post->post_type ) || 'wp_navigation' !== $post->post_type ) {
     1206    if ( ! isset( $post->post_type ) ) {
    11981207        return $post;
    11991208    }
     
    12091218    }
    12101219
     1220    if ( 'wp_navigation' === $post->post_type ) {
     1221        $wrapper_block_type = 'core/navigation';
     1222    } else {
     1223        $wrapper_block_type = 'core/post-content';
     1224    }
     1225
    12111226    $markup = get_comment_delimited_block_content(
    1212         'core/navigation',
     1227        $wrapper_block_type,
    12131228        $attributes,
    12141229        $post->post_content
     
    12671282
    12681283/**
    1269  * Hooks into the REST API response for the core/navigation block and adds the first and last inner blocks.
     1284 * Hooks into the REST API response for the Posts endpoint and adds the first and last inner blocks.
    12701285 *
    12711286 * @since 6.6.0
     1287 * @since 6.8.0 Support non-`wp_navigation` post types.
    12721288 *
    12731289 * @param WP_REST_Response $response The response object.
     
    12761292 */
    12771293function insert_hooked_blocks_into_rest_response( $response, $post ) {
    1278     if ( ! isset( $response->data['content']['raw'] ) || ! isset( $response->data['content']['rendered'] ) ) {
     1294    if ( empty( $response->data['content']['raw'] ) || empty( $response->data['content']['rendered'] ) ) {
    12791295        return $response;
    12801296    }
     
    12881304        );
    12891305    }
     1306
     1307    if ( 'wp_navigation' === $post->post_type ) {
     1308        $wrapper_block_type = 'core/navigation';
     1309    } else {
     1310        $wrapper_block_type = 'core/post-content';
     1311    }
     1312
    12901313    $content = get_comment_delimited_block_content(
    1291         'core/navigation',
     1314        $wrapper_block_type,
    12921315        $attributes,
    12931316        $response->data['content']['raw']
    12941317    );
    12951318
    1296     $content = apply_block_hooks_to_content( $content, $post );
    1297 
    1298     // Remove mock Navigation block wrapper.
     1319    $content = apply_block_hooks_to_content(
     1320        $content,
     1321        $post,
     1322        'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata'
     1323    );
     1324
     1325    // Remove mock block wrapper.
    12991326    $content = remove_serialized_parent_block( $content );
    13001327
    13011328    $response->data['content']['raw'] = $content;
     1329
     1330    // `apply_block_hooks_to_content` is called above. Ensure it is not called again as a filter.
     1331    $priority = has_filter( 'the_content', 'apply_block_hooks_to_content' );
     1332    if ( false !== $priority ) {
     1333        remove_filter( 'the_content', 'apply_block_hooks_to_content', $priority );
     1334    }
    13021335
    13031336    /** This filter is documented in wp-includes/post-template.php */
    13041337    $response->data['content']['rendered'] = apply_filters( 'the_content', $content );
     1338
     1339    // Restore the filter if it was set initially.
     1340    if ( false !== $priority ) {
     1341        add_filter( 'the_content', 'apply_block_hooks_to_content', $priority );
     1342    }
    13051343
    13061344    return $response;
     
    13211359 *
    13221360 * @param array                           $hooked_blocks An array of blocks hooked to another given block.
    1323  * @param WP_Block_Template|WP_Post|array $context       A block template, template part, `wp_navigation` post object,
     1361 * @param WP_Block_Template|WP_Post|array $context       A block template, template part, post object,
    13241362 *                                                       or pattern that the blocks belong to.
    13251363 * @param callable                        $callback      A function that will be called for each block to generate
     
    13781416 *
    13791417 * @param array                           $hooked_blocks An array of blocks hooked to another block.
    1380  * @param WP_Block_Template|WP_Post|array $context       A block template, template part, `wp_navigation` post object,
     1418 * @param WP_Block_Template|WP_Post|array $context       A block template, template part, post object,
    13811419 *                                                       or pattern that the blocks belong to.
    13821420 * @param callable                        $callback      A function that will be called for each block to generate
  • trunk/src/wp-includes/default-filters.php

    r59415 r59523  
    193193add_filter( 'the_title', 'trim' );
    194194
     195add_filter( 'the_content', 'apply_block_hooks_to_content', 8 ); // BEFORE do_blocks().
    195196add_filter( 'the_content', 'do_blocks', 9 );
    196197add_filter( 'the_content', 'wptexturize' );
     
    761762
    762763// Update ignoredHookedBlocks postmeta for wp_navigation post type.
     764add_filter( 'rest_pre_insert_page', 'update_ignored_hooked_blocks_postmeta' );
     765add_filter( 'rest_pre_insert_post', 'update_ignored_hooked_blocks_postmeta' );
    763766add_filter( 'rest_pre_insert_wp_navigation', 'update_ignored_hooked_blocks_postmeta' );
    764767
    765 // Inject hooked blocks into the wp_navigation post type REST response.
     768// Inject hooked blocks into the Posts endpoint REST response for some given post types.
     769add_filter( 'rest_prepare_page', 'insert_hooked_blocks_into_rest_response', 10, 2 );
     770add_filter( 'rest_prepare_post', 'insert_hooked_blocks_into_rest_response', 10, 2 );
    766771add_filter( 'rest_prepare_wp_navigation', 'insert_hooked_blocks_into_rest_response', 10, 2 );
    767772
  • trunk/tests/phpunit/tests/blocks/applyBlockHooksToContent.php

    r59124 r59523  
    9393
    9494    /**
     95     * @ticket 61074
     96     */
     97    public function test_apply_block_hooks_to_content_with_context_set_to_null() {
     98        $content = '<!-- wp:tests/anchor-block /-->';
     99
     100        /*
     101         * apply_block_hooks_to_content() will fall back to the global $post object (via get_post())
     102         * if the $context parameter is null. However, we'd also like to ensure that the function
     103         * works as expected even when get_post() returns null.
     104         */
     105        $this->assertNull( get_post() );
     106
     107        $actual = apply_block_hooks_to_content( $content, null, 'insert_hooked_blocks' );
     108        $this->assertSame(
     109            '<!-- wp:tests/anchor-block /--><!-- wp:tests/hooked-block /-->',
     110            $actual
     111        );
     112    }
     113
     114    /**
    95115     * @ticket 61902
    96116     */
Note: See TracChangeset for help on using the changeset viewer.