Make WordPress Core


Ignore:
Timestamp:
04/03/2024 03:09:38 PM (13 months ago)
Author:
Bernhard Reiter
Message:

Block Hooks: Pass correct context to filters.

The $context argument passed to filters such as hooked_block_types, hooked_block, and hooked_block_{$hooked_block_type} allows them to conditionally insert a hooked block. If the anchor block is contained in a template or template part, $context will be set to a WP_Block_Template object reflecting that template or part.

The aforementioned filters are applied when hooked block insertion is run upon reading a template (or part) from the DB (and before sending the template/part content with hooked blocks inserted over the REST API to the client), but also upon writing to the DB, as that's when the ignoredHookedBlocks metadata attribute is set.

Prior to this changeset, the $context passed to Block Hooks related filters in the latter case reflected the template/part that was already stored in the database (if any), which is a bug; instead, it needs to reflect the template/part that will result from the incoming POST network request that will trigger a database update.

Those incoming changes are encapsulated in the $changes argument passed to the reset_pre_insert_template and reset_pre_insert_template_part filters, respectively, and thus to the inject_ignored_hooked_blocks_metadata_attributes function that is hooked to them. $changes is of type stdClass and only contains the fields that need to be updated. That means that in order to create a WP_Block_Template object, a two-step process is needed:

  • Emulate what the updated wp_template or wp_template_part post object in the database will look like by merging $changes on top of the existing $post object fetched from the DB, or from the theme's block template (part) file, if any.
  • Create a WP_Block_Template from the resulting object.

To achieve the latter, a new helper method (_build_block_template_object_from_post_object) is extracted from the existing _build_block_template_result_from_post function. (The latter cannot be used directly as it includes a few database calls that will fail if no post object for the template has existed yet in the database.)

While somewhat complicated to implement, the overall change allows for better separation of concerns and isolation of entities. This is visible e.g. in the fact that inject_ignored_hooked_blocks_metadata_attributes no longer requires a $request argument, which is reflected by unit tests no longer needing to create a $request object to pass to it, thus decoupling the function from the templates endpoint controller.

Unit tests for inject_ignored_hooked_blocks_metadata_attributes have been moved to a new, separate file. Test coverage has been added such that now, all three relevant scenarios are covered:

  • The template doesn't exist in the DB, nor is there a block theme template file for it.
  • The template doesn't exist in the DB, but there is a block theme template file for it.
  • The template already exists in the DB.

Those scenarios also correspond to the logical branching inside WP_REST_Templates_Controller::prepare_item_for_database, which is where inject_ignored_hooked_blocks_metadata_attributes gets its data from.

Props tomjcafferkey, bernhard-reiter, gziolo, swissspidy.
Fixes #60754.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/block-template-utils.php

    r57799 r57919  
    404404        $this->assertTrue( $has_html_files, 'contains at least one html file' );
    405405    }
    406 
    407     /**
    408      * @ticket 60671
    409      *
    410      * @covers inject_ignored_hooked_blocks_metadata_attributes
    411      */
    412     public function test_inject_ignored_hooked_blocks_metadata_attributes_into_template() {
    413         global $wp_current_filter;
    414         // Mock currently set filter. The $wp_current_filter global is reset during teardown by
    415         // WP_UnitTestCase_Base::_restore_hooks() in tests/phpunit/includes/abstract-testcase.php.
    416         $wp_current_filter[] = 'rest_pre_insert_wp_template';
    417 
    418         register_block_type(
    419             'tests/hooked-block',
    420             array(
    421                 'block_hooks' => array(
    422                     'tests/anchor-block' => 'after',
    423                 ),
    424             )
    425         );
    426 
    427         $id      = self::TEST_THEME . '//' . 'my_template';
    428         $request = new WP_REST_Request( 'POST', '/wp/v2/templates/' . $id );
    429 
    430         $changes               = new stdClass();
    431         $changes->post_content = '<!-- wp:tests/anchor-block -->Hello<!-- /wp:tests/anchor-block -->';
    432 
    433         $post = inject_ignored_hooked_blocks_metadata_attributes( $changes, $request );
    434         $this->assertSame(
    435             '<!-- wp:tests/anchor-block {"metadata":{"ignoredHookedBlocks":["tests/hooked-block"]}} -->Hello<!-- /wp:tests/anchor-block -->',
    436             $post->post_content,
    437             'The hooked block was not injected into the anchor block\'s ignoredHookedBlocks metadata.'
    438         );
    439     }
    440 
    441     /**
    442      * @ticket 60671
    443      *
    444      * @covers inject_ignored_hooked_blocks_metadata_attributes
    445      */
    446     public function test_inject_ignored_hooked_blocks_metadata_attributes_into_template_part() {
    447         global $wp_current_filter;
    448         // Mock currently set filter. The $wp_current_filter global is reset during teardown by
    449         // WP_UnitTestCase_Base::_restore_hooks() in tests/phpunit/includes/abstract-testcase.php.
    450         $wp_current_filter[] = 'rest_pre_insert_wp_template_part';
    451 
    452         register_block_type(
    453             'tests/hooked-block',
    454             array(
    455                 'block_hooks' => array(
    456                     'tests/anchor-block' => 'after',
    457                 ),
    458             )
    459         );
    460 
    461         $id      = self::TEST_THEME . '//' . 'my_template_part';
    462         $request = new WP_REST_Request( 'POST', '/wp/v2/template-parts/' . $id );
    463 
    464         $changes               = new stdClass();
    465         $changes->post_content = '<!-- wp:tests/anchor-block -->Hello<!-- /wp:tests/anchor-block -->';
    466 
    467         $post = inject_ignored_hooked_blocks_metadata_attributes( $changes, $request );
    468         $this->assertSame(
    469             '<!-- wp:tests/anchor-block {"metadata":{"ignoredHookedBlocks":["tests/hooked-block"]}} -->Hello<!-- /wp:tests/anchor-block -->',
    470             $post->post_content,
    471             'The hooked block was not injected into the anchor block\'s ignoredHookedBlocks metadata.'
    472         );
    473     }
    474406}
Note: See TracChangeset for help on using the changeset viewer.