Make WordPress Core

Changeset 62219 for trunk


Ignore:
Timestamp:
04/08/2026 12:24:47 PM (4 months ago)
Author:
jonsurrell
Message:

Block Hooks: Set ignored blocks meta in REST API response.

Set _wp_ignored_hooked_blocks post meta in the REST API response sent from post-like endpoints that support Block Hooks (see rest_block_hooks_post_types filter).

Previously, it was enough to set that post meta on write (i.e. save to DB). However, due to the way real-time collaboration syncs posts and reconciles them with content received from the server side, this information is now vital on the client side to ensure hooked blocks aren't duplicated.

Developed in https://github.com/WordPress/wordpress-develop/pull/11410.

Props bernhard-reiter, czarate, ingeniumed.
Fixes #65008.

Location:
trunk
Files:
2 edited

Legend:

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

    r62039 r62219  
    11971197 *
    11981198 * @since 6.8.0
     1199 * @since 7.0.0 Added the `$ignored_hooked_blocks_at_root` parameter.
    11991200 * @access private
    12001201 *
     
    12061207 *                               the markup for a given list of blocks that are hooked to it.
    12071208 *                               Default: 'insert_hooked_blocks'.
     1209 * @param array|null   $ignored_hooked_blocks_at_root A reference to an array that will be populated
     1210 *                               with the ignored hooked blocks at the root level.
     1211 *                               Default: `null`.
    12081212 * @return string The serialized markup.
    12091213 */
    1210 function apply_block_hooks_to_content_from_post_object( $content, $post = null, $callback = 'insert_hooked_blocks' ) {
     1214function apply_block_hooks_to_content_from_post_object(
     1215        $content,
     1216        $post = null,
     1217        $callback = 'insert_hooked_blocks',
     1218        &$ignored_hooked_blocks_at_root = null
     1219) {
    12111220        // Default to the current post if no context is provided.
    12121221        if ( null === $post ) {
     
    12881297        remove_filter( 'hooked_block_types', $suppress_blocks_from_insertion_before_and_after_wrapper_block, PHP_INT_MAX );
    12891298
     1299        if ( null !== $ignored_hooked_blocks_at_root ) {
     1300                // Check wrapper block's metadata for ignored hooked blocks at the root level, and populate the reference parameter if needed.
     1301                $wrapper_block_markup = extract_serialized_parent_block( $content );
     1302                $wrapper_block        = parse_blocks( $wrapper_block_markup )[0];
     1303
     1304                if ( ! empty( $wrapper_block['attrs']['metadata']['ignoredHookedBlocks'] ) ) {
     1305                        $ignored_hooked_blocks_at_root = $wrapper_block['attrs']['metadata']['ignoredHookedBlocks'];
     1306                }
     1307        }
     1308
    12901309        // Finally, we need to remove the temporary wrapper block.
    12911310        $content = remove_serialized_parent_block( $content );
     
    14501469 * @since 6.6.0
    14511470 * @since 6.8.0 Support non-`wp_navigation` post types.
     1471 * @since 7.0.0 Set `_wp_ignored_hooked_blocks` meta in the response for blocks hooked at the root level.
    14521472 *
    14531473 * @param WP_REST_Response $response The response object.
     
    14601480        }
    14611481
     1482        $ignored_hooked_blocks_at_root    = array();
    14621483        $response->data['content']['raw'] = apply_block_hooks_to_content_from_post_object(
    14631484                $response->data['content']['raw'],
    14641485                $post,
    1465                 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata'
     1486                'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata',
     1487                $ignored_hooked_blocks_at_root
    14661488        );
     1489
     1490        if ( ! empty( $ignored_hooked_blocks_at_root ) ) {
     1491                $response->data['meta']['_wp_ignored_hooked_blocks'] = wp_json_encode( $ignored_hooked_blocks_at_root );
     1492        }
    14671493
    14681494        // If the rendered content was previously empty, we leave it like that.
  • trunk/tests/phpunit/tests/blocks/applyBlockHooksToContentFromPostObject.php

    r60173 r62219  
    132132
    133133        /**
    134          * @ticket 62716
     134         * @ticket 65008
     135         */
     136        public function test_apply_block_hooks_to_content_from_post_object_sets_ignored_hooked_blocks() {
     137                $ignored_hooked_blocks_at_root = array();
     138
     139                $expected = '<!-- wp:tests/hooked-block-first-child /-->' .
     140                        '<!-- wp:heading {"level":1,"metadata":{"ignoredHookedBlocks":["tests/hooked-block"]}} -->' .
     141                        '<h1>Hello World!</h1>' .
     142                        '<!-- /wp:heading -->' .
     143                        '<!-- wp:tests/hooked-block /-->';
     144                $actual   = apply_block_hooks_to_content_from_post_object(
     145                        self::$post->post_content,
     146                        self::$post,
     147                        'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata',
     148                        $ignored_hooked_blocks_at_root
     149                );
     150                $this->assertSame( $expected, $actual, "Markup wasn't updated correctly." );
     151                $this->assertSame(
     152                        array( 'tests/hooked-block-first-child' ),
     153                        $ignored_hooked_blocks_at_root,
     154                        "Hooked block added at 'first_child' position wasn't added to ignoredHookedBlocks metadata."
     155                );
     156        }
     157
     158        /**
     159         * @ticket 62716
     160         * @ticket 65008
    135161         */
    136162        public function test_apply_block_hooks_to_content_from_post_object_respects_ignored_hooked_blocks_post_meta() {
    137                 $expected = self::$post_with_ignored_hooked_block->post_content . '<!-- wp:tests/hooked-block /-->';
     163                $ignored_hooked_blocks_at_root = array();
     164
     165                $expected = '<!-- wp:heading {"level":1,"metadata":{"ignoredHookedBlocks":["tests/hooked-block"]}} -->' .
     166                        '<h1>Hello World!</h1>' .
     167                        '<!-- /wp:heading -->' .
     168                        '<!-- wp:tests/hooked-block /-->';
    138169                $actual   = apply_block_hooks_to_content_from_post_object(
    139170                        self::$post_with_ignored_hooked_block->post_content,
    140171                        self::$post_with_ignored_hooked_block,
    141                         'insert_hooked_blocks'
     172                        'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata',
     173                        $ignored_hooked_blocks_at_root
    142174                );
    143175                $this->assertSame( $expected, $actual );
     176                $this->assertSame(
     177                        array( 'tests/hooked-block-first-child' ),
     178                        $ignored_hooked_blocks_at_root,
     179                        "Pre-existing ignored hooked block at root level wasn't reflected in metadata."
     180                );
    144181        }
    145182
    146183        /**
    147184         * @ticket 63287
     185         * @ticket 65008
    148186         */
    149187        public function test_apply_block_hooks_to_content_from_post_object_does_not_insert_hooked_block_before_container_block() {
     
    156194                };
    157195
     196                $ignored_hooked_blocks_at_root = array();
     197
    158198                $expected = '<!-- wp:tests/hooked-block-first-child /-->' .
    159                         self::$post->post_content .
     199                        '<!-- wp:heading {"level":1,"metadata":{"ignoredHookedBlocks":["tests/hooked-block"]}} -->' .
     200                        '<h1>Hello World!</h1>' .
     201                        '<!-- /wp:heading -->' .
    160202                        '<!-- wp:tests/hooked-block /-->';
    161203
     
    164206                        self::$post->post_content,
    165207                        self::$post,
    166                         'insert_hooked_blocks'
     208                        'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata',
     209                        $ignored_hooked_blocks_at_root
    167210                );
    168211                remove_filter( 'hooked_block_types', $filter, 10 );
    169212
    170                 $this->assertSame( $expected, $actual );
    171         }
    172 
    173         /**
    174          * @ticket 62716
     213                $this->assertSame( $expected, $actual, "Hooked block added before 'core/post-content' block shouldn't be inserted." );
     214                $this->assertSame(
     215                        array( 'tests/hooked-block-first-child' ),
     216                        $ignored_hooked_blocks_at_root,
     217                        "ignoredHookedBlocks metadata wasn't set correctly."
     218                );
     219        }
     220
     221        /**
     222         * @ticket 62716
     223         * @ticket 65008
    175224         */
    176225        public function test_apply_block_hooks_to_content_from_post_object_inserts_hooked_block_if_content_contains_no_blocks() {
     226                $ignored_hooked_blocks_at_root = array();
     227
    177228                $expected = '<!-- wp:tests/hooked-block-first-child /-->' . self::$post_with_non_block_content->post_content;
    178229                $actual   = apply_block_hooks_to_content_from_post_object(
    179230                        self::$post_with_non_block_content->post_content,
    180231                        self::$post_with_non_block_content,
    181                         'insert_hooked_blocks'
    182                 );
    183                 $this->assertSame( $expected, $actual );
     232                        'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata',
     233                        $ignored_hooked_blocks_at_root
     234                );
     235                $this->assertSame( $expected, $actual, "Markup wasn't updated correctly." );
     236                $this->assertSame(
     237                        array( 'tests/hooked-block-first-child' ),
     238                        $ignored_hooked_blocks_at_root,
     239                        "Hooked block added at 'first_child' position wasn't added to ignoredHookedBlocks metadata."
     240                );
    184241        }
    185242}
Note: See TracChangeset for help on using the changeset viewer.