From 3186d24108c1d0db74fda3bee892c6ae45b0751d Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 7 Sep 2023 18:50:03 +0200 Subject: [PATCH 01/12] Add block_hooks property --- src/wp-includes/blocks.php | 1 + src/wp-includes/class-wp-block-type.php | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index 7795a6969b113..22eb273ed0254 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -432,6 +432,7 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) { 'usesContext' => 'uses_context', 'selectors' => 'selectors', 'supports' => 'supports', + 'blockHooks' => 'block_hooks', 'styles' => 'styles', 'variations' => 'variations', 'example' => 'example', diff --git a/src/wp-includes/class-wp-block-type.php b/src/wp-includes/class-wp-block-type.php index e28bacd3b211c..ff7521a131dc6 100644 --- a/src/wp-includes/class-wp-block-type.php +++ b/src/wp-includes/class-wp-block-type.php @@ -213,6 +213,18 @@ class WP_Block_Type { */ public $style_handles = array(); + /** + * Block hooks for this block type. + * + * A block hook is specified by a block type and a relative position. + * The hooked block will be automatically inserted in the given position + * next to the "anchor" block whenever the latter is encountered. + * + * @since 6.4.0 + * @var array|null + */ + public $block_hooks = array(); + /** * Deprecated block type properties for script and style handles. * @@ -254,6 +266,7 @@ class WP_Block_Type { * `editor_style_handles`, and `style_handles` properties. * Deprecated the `editor_script`, `script`, `view_script`, `editor_style`, and `style` properties. * @since 6.3.0 Added the `selectors` property. + * @since 6.4.0 Added the `block_hooks` property. * * @see register_block_type() * @@ -279,6 +292,7 @@ class WP_Block_Type { * @type array[] $variations Block variations. * @type array $selectors Custom CSS selectors for theme.json style generation. * @type array|null $supports Supported features. + * @type array|null $block_hooks Block hooks. * @type array|null $example Structured data for the block preview. * @type callable|null $render_callback Block type render callback. * @type array|null $attributes Block type attributes property schemas. From 27fcdc51954ae79172facf3bb840d6bd035efe81 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 11 Sep 2023 15:09:28 +0200 Subject: [PATCH 02/12] Map camelCased position string to snake_case --- src/wp-includes/blocks.php | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index 22eb273ed0254..e28dec563d537 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -432,7 +432,6 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) { 'usesContext' => 'uses_context', 'selectors' => 'selectors', 'supports' => 'supports', - 'blockHooks' => 'block_hooks', 'styles' => 'styles', 'variations' => 'variations', 'example' => 'example', @@ -514,6 +513,39 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) { } } + if ( ! empty( $metadata['blockHooks'] ) ) { + /** + * Map camelCased position string (from block.json) to snake_cased block type position. + * + * @var array + */ + $position_mappings = array( + 'before' => 'before', + 'after' => 'after', + 'firstChild' => 'first_child', + 'lastChild' => 'last_child', + ); + + $settings['block_hooks'] = array(); + foreach ( $metadata['blockHooks'] as $anchor_block_name => $position ) { + // Avoid infinite recursion (hooking to itself). + if ( $metadata['name'] === $anchor_block_name ) { + _doing_it_wrong( + __METHOD__, + __( 'Cannot hook block to itself.', 'gutenberg' ), + '6.4.0' + ); + continue; + } + + if ( ! isset( $position_mappings[ $position ] ) ) { + continue; + } + + $settings['block_hooks'][ $anchor_block_name ] = $position_mappings[ $position ]; + } + } + if ( ! empty( $metadata['render'] ) ) { $template_path = wp_normalize_path( realpath( From 42166c89c94d40bd8a4ede79b9ee5862988e1a2d Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 13 Sep 2023 17:36:17 +0200 Subject: [PATCH 03/12] Move block_hooks field under provides_context --- src/wp-includes/class-wp-block-type.php | 26 ++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/wp-includes/class-wp-block-type.php b/src/wp-includes/class-wp-block-type.php index ff7521a131dc6..14620f0177ebc 100644 --- a/src/wp-includes/class-wp-block-type.php +++ b/src/wp-includes/class-wp-block-type.php @@ -173,6 +173,18 @@ class WP_Block_Type { */ public $provides_context = null; + /** + * Block hooks for this block type. + * + * A block hook is specified by a block type and a relative position. + * The hooked block will be automatically inserted in the given position + * next to the "anchor" block whenever the latter is encountered. + * + * @since 6.4.0 + * @var array|null + */ + public $block_hooks = array(); + /** * Block type editor only script handles. * @@ -213,18 +225,6 @@ class WP_Block_Type { */ public $style_handles = array(); - /** - * Block hooks for this block type. - * - * A block hook is specified by a block type and a relative position. - * The hooked block will be automatically inserted in the given position - * next to the "anchor" block whenever the latter is encountered. - * - * @since 6.4.0 - * @var array|null - */ - public $block_hooks = array(); - /** * Deprecated block type properties for script and style handles. * @@ -292,12 +292,12 @@ class WP_Block_Type { * @type array[] $variations Block variations. * @type array $selectors Custom CSS selectors for theme.json style generation. * @type array|null $supports Supported features. - * @type array|null $block_hooks Block hooks. * @type array|null $example Structured data for the block preview. * @type callable|null $render_callback Block type render callback. * @type array|null $attributes Block type attributes property schemas. * @type string[] $uses_context Context values inherited by blocks of this type. * @type string[]|null $provides_context Context provided by blocks of this type. + * @type array|null $block_hooks Block hooks. * @type string[] $editor_script_handles Block type editor only script handles. * @type string[] $script_handles Block type front end and editor script handles. * @type string[] $view_script_handles Block type front end only script handles. From 99ab6c70d4a0c949517734954b0a43db8e620ea8 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 13 Sep 2023 17:37:22 +0200 Subject: [PATCH 04/12] Fix PHPDoc types --- src/wp-includes/class-wp-block-type.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/class-wp-block-type.php b/src/wp-includes/class-wp-block-type.php index 14620f0177ebc..b8ffb92e559b2 100644 --- a/src/wp-includes/class-wp-block-type.php +++ b/src/wp-includes/class-wp-block-type.php @@ -181,7 +181,7 @@ class WP_Block_Type { * next to the "anchor" block whenever the latter is encountered. * * @since 6.4.0 - * @var array|null + * @var array[] */ public $block_hooks = array(); @@ -297,7 +297,7 @@ class WP_Block_Type { * @type array|null $attributes Block type attributes property schemas. * @type string[] $uses_context Context values inherited by blocks of this type. * @type string[]|null $provides_context Context provided by blocks of this type. - * @type array|null $block_hooks Block hooks. + * @type array[] $block_hooks Block hooks. * @type string[] $editor_script_handles Block type editor only script handles. * @type string[] $script_handles Block type front end and editor script handles. * @type string[] $view_script_handles Block type front end only script handles. From 67135e332e35133c1414eceb1278f5cb001ac786 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 13 Sep 2023 17:38:58 +0200 Subject: [PATCH 05/12] Add block_hooks to block types REST API controller --- .../class-wp-rest-block-types-controller.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php index fe86ff669d0bf..0514a0e096384 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php @@ -290,6 +290,7 @@ public function prepare_item_for_response( $item, $request ) { 'editor_style_handles', 'style_handles', 'variations', + 'block_hooks', ), $deprecated_fields ); @@ -705,6 +706,17 @@ public function get_item_schema() { ), 'keywords' => $keywords_definition, 'example' => $example_definition, + 'block_hooks' => array( + 'description' => __( 'Block hooks.' ), + 'type' => 'object', + 'properties' => array(), + 'additionalProperties' => array( + 'type' => 'string', + ), + 'default' => array(), + 'context' => array( 'embed', 'view', 'edit' ), + 'readonly' => true, + ), ), ); From 49bf14e11a4b74eb781f69b003819d298468458d Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 13 Sep 2023 17:46:38 +0200 Subject: [PATCH 06/12] Update REST API field schema --- .../class-wp-rest-block-types-controller.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php index 0514a0e096384..cb3fb2fc3debd 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php @@ -707,15 +707,17 @@ public function get_item_schema() { 'keywords' => $keywords_definition, 'example' => $example_definition, 'block_hooks' => array( - 'description' => __( 'Block hooks.' ), - 'type' => 'object', - 'properties' => array(), - 'additionalProperties' => array( - 'type' => 'string', + 'description' => __( 'This block is automatically inserted near any occurence of the block types used as keys of this map, into a relative position given by the corresponding value.' ), + 'type' => 'object', + 'patternProperties' => array( + '^[a-zA-Z0-9-]+/[a-zA-Z0-9-]+$' => array( + 'type' => 'string', + 'enum' => array( 'before', 'after', 'first_child', 'last_child' ), + ), ), - 'default' => array(), - 'context' => array( 'embed', 'view', 'edit' ), - 'readonly' => true, + 'default' => array(), + 'context' => array( 'embed', 'view', 'edit' ), + 'readonly' => true, ), ), ); From ad879ca909eee627e63bb501ba5ee574eca42a0e Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 14 Sep 2023 11:46:26 +0200 Subject: [PATCH 07/12] Fix (and extend) block type controller test coverage --- .../tests/rest-api/rest-block-type-controller.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/phpunit/tests/rest-api/rest-block-type-controller.php b/tests/phpunit/tests/rest-api/rest-block-type-controller.php index af6fa73a3ad64..51e702730f905 100644 --- a/tests/phpunit/tests/rest-api/rest-block-type-controller.php +++ b/tests/phpunit/tests/rest-api/rest-block-type-controller.php @@ -195,6 +195,7 @@ public function test_get_block_invalid_name() { /** * @ticket 47620 * @ticket 57585 + * @ticket 59346 */ public function test_get_item_invalid() { $block_type = 'fake/invalid'; @@ -205,6 +206,7 @@ public function test_get_item_invalid() { 'attributes' => 'invalid_attributes', 'provides_context' => 'invalid_provides_context', 'uses_context' => 'invalid_uses_context', + 'block_hooks' => 'invalid_block_hooks', 'category' => true, 'editor_script' => true, 'script' => true, @@ -244,6 +246,7 @@ public function test_get_item_invalid() { $data['attributes'] ); $this->assertSameSets( array( 'invalid_uses_context' ), $data['uses_context'] ); + $this->assertSameSets( array(), $data['block_hooks'], 'invalid block_hooks defaults to empty array' ); $this->assertSameSets( array( 'invalid_keywords' ), $data['keywords'] ); $this->assertSameSets( array( 'invalid_parent' ), $data['parent'] ); $this->assertSameSets( array( 'invalid_ancestor' ), $data['ancestor'] ); @@ -266,6 +269,7 @@ public function test_get_item_invalid() { /** * @ticket 47620 * @ticket 57585 + * @ticket 59346 */ public function test_get_item_defaults() { $block_type = 'fake/false'; @@ -276,6 +280,7 @@ public function test_get_item_defaults() { 'attributes' => false, 'provides_context' => false, 'uses_context' => false, + 'block_hooks' => false, 'category' => false, 'editor_script' => false, 'script' => false, @@ -314,6 +319,7 @@ public function test_get_item_defaults() { $data['attributes'] ); $this->assertSameSets( array(), $data['provides_context'] ); + $this->assertSameSets( array(), $data['block_hooks'], 'block_hooks defaults to empty array' ); $this->assertSameSets( array(), $data['uses_context'] ); $this->assertSameSets( array(), $data['keywords'] ); $this->assertSameSets( array(), $data['parent'] ); @@ -538,6 +544,7 @@ public function test_get_variation() { /** * @ticket 47620 * @ticket 57585 + * @ticket 59346 */ public function test_get_item_schema() { wp_set_current_user( self::$admin_id ); @@ -545,7 +552,7 @@ public function test_get_item_schema() { $response = rest_get_server()->dispatch( $request ); $data = $response->get_data(); $properties = $data['schema']['properties']; - $this->assertCount( 29, $properties ); + $this->assertCount( 30, $properties ); $this->assertArrayHasKey( 'api_version', $properties ); $this->assertArrayHasKey( 'title', $properties ); $this->assertArrayHasKey( 'icon', $properties ); @@ -568,6 +575,7 @@ public function test_get_item_schema() { $this->assertArrayHasKey( 'example', $properties ); $this->assertArrayHasKey( 'uses_context', $properties ); $this->assertArrayHasKey( 'provides_context', $properties ); + $this->assertArrayHasKey( 'block_hooks', $properties ); $this->assertArrayHasKey( 'variations', $properties ); $this->assertArrayHasKey( 'ancestor', $properties ); // Deprecated properties. @@ -664,6 +672,7 @@ public function test_prepare_item_limit_fields() { * Util check block type object against. * * @since 5.5.0 + * @since 6.4.0 Added the `block_hooks` extra field. * * @param WP_Block_Type $block_type Sample block type. * @param array $data Data to compare against. @@ -690,6 +699,7 @@ protected function check_block_type_object( $block_type, $data, $links ) { 'parent', 'provides_context', 'uses_context', + 'block_hooks', 'supports', 'styles', 'textdomain', From 8fd46e9fe12ec8b4cbf66f1a590b8f0820338de3 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 14 Sep 2023 12:02:28 +0200 Subject: [PATCH 08/12] Add to get_block_editor_server_block_settings() --- src/wp-admin/includes/post.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wp-admin/includes/post.php b/src/wp-admin/includes/post.php index ed73b8ff5fd14..3709ded67fdd5 100644 --- a/src/wp-admin/includes/post.php +++ b/src/wp-admin/includes/post.php @@ -2207,6 +2207,7 @@ function taxonomy_meta_box_sanitize_cb_input( $taxonomy, $terms ) { * * @since 5.0.0 * @since 6.3.0 Added `selectors` field. + * @since 6.4.0 Added `block_hooks` field. * * @return array An associative array of registered block data. */ @@ -2221,6 +2222,7 @@ function get_block_editor_server_block_settings() { 'attributes' => 'attributes', 'provides_context' => 'providesContext', 'uses_context' => 'usesContext', + 'block_hooks' => 'blockHooks', 'selectors' => 'selectors', 'supports' => 'supports', 'category' => 'category', From e71e581496b6695f55461d0dd0c9dbc68d3c0029 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 14 Sep 2023 12:03:25 +0200 Subject: [PATCH 09/12] Add @since PHPDoc to register_block_type_from_metadata --- src/wp-includes/blocks.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index e28dec563d537..bef59a21dbb8c 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -342,6 +342,7 @@ function get_block_metadata_i18n_schema() { * @since 5.9.0 Added support for `variations` and `viewScript` fields. * @since 6.1.0 Added support for `render` field. * @since 6.3.0 Added `selectors` field. + * @since 6.4.0 Added support for `blockHooks` field. * * @param string $file_or_folder Path to the JSON file with metadata definition for * the block or path to the folder where the `block.json` file is located. From 6de2dc3ea94719fc0d2e6b27310ffd5b92b60e26 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 14 Sep 2023 12:12:23 +0200 Subject: [PATCH 10/12] Verify that block type contains block hooks from metadata --- tests/phpunit/data/blocks/notice/block.json | 3 +++ tests/phpunit/tests/blocks/register.php | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/tests/phpunit/data/blocks/notice/block.json b/tests/phpunit/data/blocks/notice/block.json index c3a3b4dde9513..b6aa36e52e86c 100644 --- a/tests/phpunit/data/blocks/notice/block.json +++ b/tests/phpunit/data/blocks/notice/block.json @@ -30,6 +30,9 @@ "selectors": { "root": ".wp-block-notice" }, + "blockHooks": { + "core/post-content": "before" + }, "supports": { "align": true, "lightBlockWrapper": true diff --git a/tests/phpunit/tests/blocks/register.php b/tests/phpunit/tests/blocks/register.php index eb61f3c307bea..55faf297a5b84 100644 --- a/tests/phpunit/tests/blocks/register.php +++ b/tests/phpunit/tests/blocks/register.php @@ -644,6 +644,12 @@ public function test_block_registers_with_metadata_fixture() { $result->selectors, 'Block type should contain selectors from metadata.' ); + // @ticket 59346 + $this->assertSame( + array( 'core/post-content' => 'before' ), + $result->block_hooks, + 'Block type should contain block hooks from metadata.' + ); $this->assertSame( array( 'align' => true, From f3a04cb121bcd4e4df61aeb08837a3182c54cb28 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 14 Sep 2023 12:21:46 +0200 Subject: [PATCH 11/12] Add test coverage for get_block_editor_server_block_settings --- tests/phpunit/tests/admin/includesPost.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/phpunit/tests/admin/includesPost.php b/tests/phpunit/tests/admin/includesPost.php index 102449cc79899..76746e689ea88 100644 --- a/tests/phpunit/tests/admin/includesPost.php +++ b/tests/phpunit/tests/admin/includesPost.php @@ -918,6 +918,7 @@ public function test_get_block_editor_server_block_settings() { 'render_callback' => 'foo', 'ancestor' => array( 'core/test-ancestor' ), 'selectors' => array( 'root' => '.wp-block-test' ), + 'blockHooks' => array( 'core/post-content' => 'before' ), ); register_block_type( $name, $settings ); @@ -938,6 +939,7 @@ public function test_get_block_editor_server_block_settings() { ), 'usesContext' => array(), 'selectors' => array( 'root' => '.wp-block-test' ), + 'blockHooks' => array( 'core/post-content' => 'before' ), 'category' => 'common', 'styles' => array(), 'ancestor' => array( 'core/test-ancestor' ), From 72de12010b0bd67f814e699705e709f3a125351e Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 14 Sep 2023 14:11:58 +0200 Subject: [PATCH 12/12] Fix unit test --- tests/phpunit/tests/admin/includesPost.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/phpunit/tests/admin/includesPost.php b/tests/phpunit/tests/admin/includesPost.php index 76746e689ea88..f4eaa0f5137eb 100644 --- a/tests/phpunit/tests/admin/includesPost.php +++ b/tests/phpunit/tests/admin/includesPost.php @@ -918,7 +918,7 @@ public function test_get_block_editor_server_block_settings() { 'render_callback' => 'foo', 'ancestor' => array( 'core/test-ancestor' ), 'selectors' => array( 'root' => '.wp-block-test' ), - 'blockHooks' => array( 'core/post-content' => 'before' ), + 'block_hooks' => array( 'core/post-content' => 'before' ), ); register_block_type( $name, $settings ); @@ -938,8 +938,8 @@ public function test_get_block_editor_server_block_settings() { 'lock' => array( 'type' => 'object' ), ), 'usesContext' => array(), - 'selectors' => array( 'root' => '.wp-block-test' ), 'blockHooks' => array( 'core/post-content' => 'before' ), + 'selectors' => array( 'root' => '.wp-block-test' ), 'category' => 'common', 'styles' => array(), 'ancestor' => array( 'core/test-ancestor' ),