Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

block.json: Allow passing filename as variations field #62092

Merged
merged 17 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions backport-changelog/6.7/6668.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
https://github.com/WordPress/wordpress-develop/pull/6668

* https://github.com/WordPress/gutenberg/pull/62092
44 changes: 43 additions & 1 deletion docs/reference-guides/block-api/block-metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand All @@ -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
<?php
// Generate variations for a Social Icon kind of block.

return array(
array(
'isDefault' => 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
Expand Down
45 changes: 45 additions & 0 deletions lib/compat/wordpress-6.7/blocks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php
/**
* Temporary compatibility shims for block APIs present in Gutenberg.
*
* @package gutenberg
*/

/**
* Allow passing a PHP file as `variations` field for Core versions < 6.7
*
* @param array $settings Array of determined settings for registering a block type.
* @param array $metadata Metadata provided for registering a block type.
* @return array The block type settings
*/
function gutenberg_filter_block_type_metadata_settings_allow_variations_php_file( $settings, $metadata ) {
// If `variations` is a string, it's the name of a PHP file that
// generates the variations.
if ( ! empty( $settings['variations'] ) && is_string( $settings['variations'] ) ) {
$variations_path = wp_normalize_path(
realpath(
dirname( $metadata['file'] ) . '/' .
remove_block_asset_path_prefix( $settings['variations'] )
)
);
if ( $variations_path ) {
/**
* Generates the list of block variations.
*
* @since 6.7.0
*
* @return string Returns the list of block variations.
*/
$settings['variation_callback'] = static function () use ( $variations_path ) {
$variations = require $variations_path;
return $variations;
};
// The block instance's `variations` field is only allowed to be an array
// (of known block variations). We unset it so that the block instance will
// provide a getter that returns the result of the `variation_callback` instead.
unset( $settings['variations'] );
}
}
return $settings;
}
add_filter( 'block_type_metadata_settings', 'gutenberg_filter_block_type_metadata_settings_allow_variations_php_file', 10, 2 );
3 changes: 3 additions & 0 deletions lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ function gutenberg_is_experiment_enabled( $name ) {
require __DIR__ . '/compat/wordpress-6.6/option.php';
require __DIR__ . '/compat/wordpress-6.6/post.php';

// WordPress 6.7 compat.
require __DIR__ . '/compat/wordpress-6.7/blocks.php';

// Experimental features.
require __DIR__ . '/experimental/block-editor-settings-mobile.php';
require __DIR__ . '/experimental/blocks.php';
Expand Down
9 changes: 7 additions & 2 deletions packages/blocks/src/store/process-block-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,14 @@ export const processBlockType =
save: () => 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
: []
),
};

Expand Down
48 changes: 48 additions & 0 deletions phpunit/blocks/block-json-variations-filename-test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php
/**
* Test for the block.json's variations field being a PHP file.
*
* @package WordPress
* @subpackage Blocks
*/

/**
* Test that block variations can be registered from a PHP file.
*
* @group blocks
*/
class Block_Json_Variations_Filename_Test extends WP_UnitTestCase {
/**
* Tear down each test method.
*/
public function tear_down() {
$registry = WP_Block_Type_Registry::get_instance();

if ( $registry->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." );
}
}
10 changes: 10 additions & 0 deletions phpunit/fixtures/variations.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

return array(
array(
'name' => 'warning',
'title' => 'warning',
'description' => 'Shows warning.',
'keywords' => array( 'warning' ),
),
);
11 changes: 10 additions & 1 deletion schemas/json/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -897,8 +897,15 @@
]
},
"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.",
"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" ],
Expand Down Expand Up @@ -982,6 +989,8 @@
}
}
}
}
]
},
"render": {
"type": "string",
Expand Down
Loading