diff --git a/src/wp-admin/includes/post.php b/src/wp-admin/includes/post.php index 824b969450759..e86cdce43e035 100644 --- a/src/wp-admin/includes/post.php +++ b/src/wp-admin/includes/post.php @@ -2178,6 +2178,7 @@ function taxonomy_meta_box_sanitize_cb_input( $taxonomy, $terms ) { * of a block relevant for client registration. * * @since 5.0.0 + * @since 6.3.0 Added `selectors` field. * * @return array An associative array of registered block data. */ @@ -2192,6 +2193,7 @@ function get_block_editor_server_block_settings() { 'attributes' => 'attributes', 'provides_context' => 'providesContext', 'uses_context' => 'usesContext', + 'selectors' => 'selectors', 'supports' => 'supports', 'category' => 'category', 'styles' => 'styles', diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index 8a20f29e3bd19..49f18ca46f8f5 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -300,6 +300,7 @@ function get_block_metadata_i18n_schema() { * @since 5.7.0 Added support for `textdomain` field and i18n handling for all translatable fields. * @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. * * @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. @@ -382,6 +383,7 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) { 'attributes' => 'attributes', 'providesContext' => 'provides_context', 'usesContext' => 'uses_context', + 'selectors' => 'selectors', 'supports' => 'supports', 'styles' => 'styles', 'variations' => 'variations', diff --git a/src/wp-includes/class-wp-block-type.php b/src/wp-includes/class-wp-block-type.php index 3b3787740a1d3..1fb8894164a7b 100644 --- a/src/wp-includes/class-wp-block-type.php +++ b/src/wp-includes/class-wp-block-type.php @@ -117,6 +117,14 @@ class WP_Block_Type { */ public $variations = array(); + /** + * Custom CSS selectors for theme.json style generation. + * + * @since 6.3.0 + * @var array + */ + public $selectors = array(); + /** * Supported features. * @@ -245,6 +253,7 @@ class WP_Block_Type { * @since 6.1.0 Added the `editor_script_handles`, `script_handles`, `view_script_handles, * `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. * * @see register_block_type() * @@ -268,6 +277,7 @@ class WP_Block_Type { * @type string|null $textdomain The translation textdomain. * @type array[] $styles Alternative block styles. * @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 $example Structured data for the block preview. * @type callable|null $render_callback Block type render callback. 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 e1f34baef6df0..26bd0e05449e6 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 @@ -237,6 +237,7 @@ public function get_item( $request ) { * * @since 5.5.0 * @since 5.9.0 Renamed `$block_type` to `$item` to match parent class for PHP 8 named parameter support. + * @since 6.3.0 Added `selectors` field. * * @param WP_Block_Type $item Block type data. * @param WP_REST_Request $request Full details about the request. @@ -278,6 +279,7 @@ public function prepare_item_for_response( $item, $request ) { 'ancestor', 'provides_context', 'uses_context', + 'selectors', 'supports', 'styles', 'textdomain', @@ -379,6 +381,7 @@ protected function prepare_links( $block_type ) { * Retrieves the block type' schema, conforming to JSON Schema. * * @since 5.5.0 + * @since 6.3.0 Added `selectors` field. * * @return array Item schema data. */ @@ -518,6 +521,14 @@ public function get_item_schema() { 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), + 'selectors' => array( + 'description' => __( 'Custom CSS selectors.' ), + 'type' => 'object', + 'default' => array(), + 'properties' => array(), + 'context' => array( 'embed', 'view', 'edit' ), + 'readonly' => true, + ), 'supports' => array( 'description' => __( 'Block supports.' ), 'type' => 'object', diff --git a/tests/phpunit/data/blocks/notice/block.json b/tests/phpunit/data/blocks/notice/block.json index 9d2fadfb5dc86..c3a3b4dde9513 100644 --- a/tests/phpunit/data/blocks/notice/block.json +++ b/tests/phpunit/data/blocks/notice/block.json @@ -27,6 +27,9 @@ "type": "string" } }, + "selectors": { + "root": ".wp-block-notice" + }, "supports": { "align": true, "lightBlockWrapper": true diff --git a/tests/phpunit/tests/admin/includesPost.php b/tests/phpunit/tests/admin/includesPost.php index 799d927dfa909..07660e6f30539 100644 --- a/tests/phpunit/tests/admin/includesPost.php +++ b/tests/phpunit/tests/admin/includesPost.php @@ -826,6 +826,7 @@ public function test_get_block_editor_server_block_settings() { 'category' => 'common', 'render_callback' => 'foo', 'ancestor' => array( 'core/test-ancestor' ), + 'selectors' => array( 'root' => '.wp-block-test' ), ); register_block_type( $name, $settings ); @@ -845,6 +846,7 @@ public function test_get_block_editor_server_block_settings() { 'lock' => array( 'type' => 'object' ), ), 'usesContext' => array(), + 'selectors' => array( 'root' => '.wp-block-test' ), 'category' => 'common', 'styles' => array(), 'ancestor' => array( 'core/test-ancestor' ), diff --git a/tests/phpunit/tests/blocks/register.php b/tests/phpunit/tests/blocks/register.php index e1cd22db45d44..ac9ba7ada3362 100644 --- a/tests/phpunit/tests/blocks/register.php +++ b/tests/phpunit/tests/blocks/register.php @@ -483,6 +483,7 @@ public function test_metadata_not_found_in_the_current_directory() { * * @ticket 50263 * @ticket 50328 + * @ticket 57585 */ public function test_block_registers_with_metadata_fixture() { $result = register_block_type_from_metadata( @@ -515,6 +516,12 @@ public function test_block_registers_with_metadata_fixture() { $result->provides_context ); $this->assertSameSets( array( 'groupId' ), $result->uses_context ); + // @ticket 57585 + $this->assertSame( + array( 'root' => '.wp-block-notice' ), + $result->selectors, + 'Block type should contain selectors from metadata.' + ); $this->assertSame( array( 'align' => true, 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 4dc177722e494..b19321e224bb9 100644 --- a/tests/phpunit/tests/rest-api/rest-block-type-controller.php +++ b/tests/phpunit/tests/rest-api/rest-block-type-controller.php @@ -196,6 +196,7 @@ public function test_get_block_invalid_name() { /** * @ticket 47620 + * @ticket 57585 */ public function test_get_item_invalid() { $block_type = 'fake/invalid'; @@ -216,6 +217,7 @@ public function test_get_item_invalid() { 'example' => 'invalid_example', 'parent' => 'invalid_parent', 'ancestor' => 'invalid_ancestor', + 'selectors' => 'invalid_selectors', 'supports' => 'invalid_supports', 'styles' => array(), 'render_callback' => 'invalid_callback', @@ -247,6 +249,7 @@ public function test_get_item_invalid() { $this->assertSameSets( array( 'invalid_keywords' ), $data['keywords'] ); $this->assertSameSets( array( 'invalid_parent' ), $data['parent'] ); $this->assertSameSets( array( 'invalid_ancestor' ), $data['ancestor'] ); + $this->assertSameSets( array(), $data['selectors'], 'invalid selectors defaults to empty array' ); $this->assertSameSets( array(), $data['supports'] ); $this->assertSameSets( array(), $data['styles'] ); $this->assertNull( $data['example'] ); @@ -265,6 +268,7 @@ public function test_get_item_invalid() { /** * @ticket 47620 + * @ticket 57585 */ public function test_get_item_defaults() { $block_type = 'fake/false'; @@ -284,6 +288,7 @@ public function test_get_item_defaults() { 'keywords' => false, 'parent' => false, 'ancestor' => false, + 'selectors' => false, 'supports' => false, 'styles' => false, 'render_callback' => false, @@ -316,6 +321,7 @@ public function test_get_item_defaults() { $this->assertSameSets( array(), $data['keywords'] ); $this->assertSameSets( array(), $data['parent'] ); $this->assertSameSets( array(), $data['ancestor'] ); + $this->assertSameSets( array(), $data['selectors'], 'selectors defaults to empty array' ); $this->assertSameSets( array(), $data['supports'] ); $this->assertSameSets( array(), $data['styles'] ); $this->assertNull( $data['example'] ); @@ -534,6 +540,7 @@ public function test_get_variation() { /** * @ticket 47620 + * @ticket 57585 */ public function test_get_item_schema() { wp_set_current_user( self::$admin_id ); @@ -541,7 +548,7 @@ public function test_get_item_schema() { $response = rest_get_server()->dispatch( $request ); $data = $response->get_data(); $properties = $data['schema']['properties']; - $this->assertCount( 28, $properties ); + $this->assertCount( 29, $properties ); $this->assertArrayHasKey( 'api_version', $properties ); $this->assertArrayHasKey( 'title', $properties ); $this->assertArrayHasKey( 'icon', $properties ); @@ -551,6 +558,7 @@ public function test_get_item_schema() { $this->assertArrayHasKey( 'textdomain', $properties ); $this->assertArrayHasKey( 'name', $properties ); $this->assertArrayHasKey( 'attributes', $properties ); + $this->assertArrayHasKey( 'selectors', $properties, 'schema must contain selectors' ); $this->assertArrayHasKey( 'supports', $properties ); $this->assertArrayHasKey( 'category', $properties ); $this->assertArrayHasKey( 'is_dynamic', $properties );