diff --git a/backport-changelog/6.7/6668.md b/backport-changelog/6.7/6668.md new file mode 100644 index 0000000000000..7653dd8d8294e --- /dev/null +++ b/backport-changelog/6.7/6668.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/6668 + +* https://github.com/WordPress/gutenberg/pull/62092 diff --git a/docs/reference-guides/block-api/block-metadata.md b/docs/reference-guides/block-api/block-metadata.md index 1b0925513b3a8..8dea562a45757 100644 --- a/docs/reference-guides/block-api/block-metadata.md +++ b/docs/reference-guides/block-api/block-metadata.md @@ -427,7 +427,7 @@ See the [Example documentation](/docs/reference-guides/block-api/block-registrat ### Variations -- Type: `object[]` +- Type: `object[]|WPDefinedPath` ([learn more](#wpdefinedpath)) - Optional - Localized: Yes (`title`, `description`, and `keywords` of each variation only) - Property: `variations` @@ -454,6 +454,48 @@ Block Variations is the API that allows a block to have similar versions of it, _Note: In JavaScript you can provide a function for the `isActive` property, and a React element for the `icon`. In the `block.json` file both only support strings_ +Starting with version 6.7, it is possible to specify a PHP file in `block.json` that generates the list of block variations on the server side: + +```json +{ "variations": "file:./variations.php" } +``` + +That PHP file is expected to `return` an array that contains the block variations. Strings found in the variations returned from the PHP file will not be localized automatically; instead, use the `__()` function as usual. + +For example: + +```php + true, + 'name' => 'wordpress', + 'title' => 'WordPress', + 'icon' => 'wordpress', + 'attributes' => array( + 'service' => 'wordpress', + ), + 'isActive' => array( 'service' ) + ), + array( + 'name' => 'mail', + 'title' => __( 'Mail' ), + 'keywords' => array( + __( 'email' ), + __( 'e-mail' ) + ), + 'icon' => 'mail', + 'attributes' => array( + 'service' => 'mail', + ), + 'isActive' => array( 'mail' ) + ), +); + +``` + See [the variations documentation](/docs/reference-guides/block-api/block-variations.md) for more details. ### Block Hooks diff --git a/lib/compat/wordpress-6.7/blocks.php b/lib/compat/wordpress-6.7/blocks.php new file mode 100644 index 0000000000000..18d21621be719 --- /dev/null +++ b/lib/compat/wordpress-6.7/blocks.php @@ -0,0 +1,45 @@ + null, ...bootstrappedBlockType, ...blockSettings, + // blockType.variations can be defined as a filePath. variations: mergeBlockVariations( - bootstrappedBlockType?.variations, - blockSettings?.variations + Array.isArray( bootstrappedBlockType?.variations ) + ? bootstrappedBlockType.variations + : [], + Array.isArray( blockSettings?.variations ) + ? blockSettings.variations + : [] ), }; diff --git a/phpunit/blocks/block-json-variations-filename-test.php b/phpunit/blocks/block-json-variations-filename-test.php new file mode 100644 index 0000000000000..3cbbb05aa59b0 --- /dev/null +++ b/phpunit/blocks/block-json-variations-filename-test.php @@ -0,0 +1,48 @@ +is_registered( 'my-plugin/notice' ) ) { + $registry->unregister( 'my-plugin/notice' ); + } + + parent::tear_down(); + } + + /** + * Tests registering a block with variations from a PHP file. + * + * @covers ::register_block_type_from_metadata + */ + public function test_register_block_type_from_metadata_with_variations_php_file() { + $filter_metadata_registration = static function ( $metadata ) { + $metadata['variations'] = 'file:./variations.php'; + return $metadata; + }; + + add_filter( 'block_type_metadata', $filter_metadata_registration, 10, 2 ); + $result = register_block_type_from_metadata( GUTENBERG_DIR_TESTFIXTURES ); + remove_filter( 'block_type_metadata', $filter_metadata_registration ); + + $this->assertInstanceOf( 'WP_Block_Type', $result, 'The block was not registered' ); + + $expected_variations = require GUTENBERG_DIR_TESTFIXTURES . '/variations.php'; + $this->assertSame( $expected_variations, $result->variations, "Block variations haven't been set correctly." ); + } +} diff --git a/phpunit/fixtures/variations.php b/phpunit/fixtures/variations.php new file mode 100644 index 0000000000000..bed66d9544176 --- /dev/null +++ b/phpunit/fixtures/variations.php @@ -0,0 +1,10 @@ + 'warning', + 'title' => 'warning', + 'description' => 'Shows warning.', + 'keywords' => array( 'warning' ), + ), +); diff --git a/schemas/json/block.json b/schemas/json/block.json index 0c036a6e05ffe..6a27447f7b496 100644 --- a/schemas/json/block.json +++ b/schemas/json/block.json @@ -897,91 +897,100 @@ ] }, "variations": { - "type": "array", "description": "Block Variations is the API that allows a block to have similar versions of it, but all these versions share some common functionality.", - "items": { - "type": "object", - "required": [ "name", "title" ], - "additionalProperties": false, - "properties": { - "name": { - "type": "string", - "description": "The unique and machine-readable name." - }, - "title": { - "type": "string", - "description": "A human-readable variation title." - }, - "description": { - "type": "string", - "description": "A detailed variation description." - }, - "category": { - "description": "A category classification, used in search interfaces to arrange block types by category.", - "anyOf": [ - { - "type": "string" + "oneOf": [ + { + "type": "string", + "description": "The path to a PHP file that returns an array of block variations." + }, + { + "type": "array", + "description": "An array of block variations.", + "items": { + "type": "object", + "required": [ "name", "title" ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The unique and machine-readable name." }, - { - "enum": [ - "text", - "media", - "design", - "widgets", - "theme", - "embed" + "title": { + "type": "string", + "description": "A human-readable variation title." + }, + "description": { + "type": "string", + "description": "A detailed variation description." + }, + "category": { + "description": "A category classification, used in search interfaces to arrange block types by category.", + "anyOf": [ + { + "type": "string" + }, + { + "enum": [ + "text", + "media", + "design", + "widgets", + "theme", + "embed" + ] + } ] + }, + "icon": { + "description": "An icon helping to visualize the variation. It can have the same shape as the block type.", + "type": "string" + }, + "isDefault": { + "type": "boolean", + "default": false, + "description": "Indicates whether the current variation is the default one." + }, + "attributes": { + "type": "object", + "description": "Values that override block attributes." + }, + "innerBlocks": { + "type": "array", + "items": { + "type": "array" + }, + "description": "Initial configuration of nested blocks." + }, + "example": { + "type": "object", + "description": "Example provides structured data for the block preview. You can set to undefined to disable the preview shown for the block type." + }, + "scope": { + "type": "array", + "description": "The list of scopes where the variation is applicable.", + "items": { + "enum": [ "inserter", "block", "transform" ] + }, + "default": [ "inserter", "block" ] + }, + "keywords": { + "type": "array", + "description": "An array of terms (which can be translated) that help users discover the variation while searching.", + "items": { + "type": "string" + } + }, + "isActive": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The list of attributes that should be compared. Each attributes will be matched and the variation will be active if all of them are matching." } - ] - }, - "icon": { - "description": "An icon helping to visualize the variation. It can have the same shape as the block type.", - "type": "string" - }, - "isDefault": { - "type": "boolean", - "default": false, - "description": "Indicates whether the current variation is the default one." - }, - "attributes": { - "type": "object", - "description": "Values that override block attributes." - }, - "innerBlocks": { - "type": "array", - "items": { - "type": "array" - }, - "description": "Initial configuration of nested blocks." - }, - "example": { - "type": "object", - "description": "Example provides structured data for the block preview. You can set to undefined to disable the preview shown for the block type." - }, - "scope": { - "type": "array", - "description": "The list of scopes where the variation is applicable.", - "items": { - "enum": [ "inserter", "block", "transform" ] - }, - "default": [ "inserter", "block" ] - }, - "keywords": { - "type": "array", - "description": "An array of terms (which can be translated) that help users discover the variation while searching.", - "items": { - "type": "string" } - }, - "isActive": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The list of attributes that should be compared. Each attributes will be matched and the variation will be active if all of them are matching." } } - } + ] }, "render": { "type": "string",