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

Theme.json: Allow shared block style variations via separate theme.json files #57787

Closed
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
1 change: 1 addition & 0 deletions lib/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ class WP_Theme_JSON_Gutenberg {
'patterns',
'settings',
'styles',
'supportedBlockTypes',
'templateParts',
'title',
'version',
Expand Down
55 changes: 51 additions & 4 deletions lib/class-wp-theme-json-resolver-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,8 @@ protected static function has_same_registered_blocks( $origin ) {
* @since 5.8.0
* @since 5.9.0 Theme supports have been inlined and the `$theme_support_data` argument removed.
* @since 6.0.0 Added an `$options` parameter to allow the theme data to be returned without theme supports.
* @since 6.5.0 Theme data will now also include block style variations that were registered with a style object.
* @since 6.5.0 Theme data will now also include block style variations that
* were registered with a style object or included via a standalone file.
*
* @param array $deprecated Deprecated. Not used.
* @param array $options {
Expand Down Expand Up @@ -373,9 +374,53 @@ public static function get_theme_data( $deprecated = array(), $options = array()
$with_theme_supports = new WP_Theme_JSON_Gutenberg( $theme_support_data );

if ( $options['with_block_style_variations'] ) {
// Absorb block style variations that were registered with a style object.
$block_style_variations_data = WP_Theme_JSON_Gutenberg::get_from_block_styles_registry();
$with_block_style_variations = new WP_Theme_JSON_Gutenberg( $block_style_variations_data );
$with_theme_supports->merge( $with_block_style_variations );

// Resolve shared block style variations that were bundled in the
// theme via standalone theme.json files.
$shared_block_style_variations = static::get_style_variations( '/block-styles' );
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the moment, the shared block style variations are being looked for in a block-styles directory within the theme. As with theme style variations under styles, this takes into account child theme variations overriding a parent's definition.

Is there a better location to store these block style variations? It seemed keeping them separate from theme style variations made sense to limit further updates to ensure block style variations weren't accidentally included with theme styles.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it needs to be a different directory than the existing styles, but the naming is trickier.

$variations_data = array();
$registry = WP_Block_Styles_Registry::get_instance();

foreach ( $shared_block_style_variations as $variation ) {
if ( empty( $variation['supportedBlockTypes'] ) || empty( $variation['styles'] ) ) {
continue;
}

$variation_slug = _wp_to_kebab_case( $variation['title'] );

// If it proves desirable, block style variations could include
// custom settings which can be included here.
foreach ( $variation['supportedBlockTypes'] as $block_type ) {
// Automatically register the block style variation if it
// hasn't been already.
$registered_styles = $registry->get_registered_styles_for_block( $block_type );
if ( ! array_key_exists( $variation_slug, $registered_styles ) ) {
gutenberg_register_block_style(
$block_type,
array(
'name' => $variation_slug,
'label' => $variation['title'],
)
);
}
Comment on lines +398 to +409
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should block style variations defined within these standalone files be registered for blocks automatically?

Child themes wouldn't be able to deregister block style variations coming from standalone files via unregister_block_style but they could override the variation setting empty styles or supportedBlockTypes properties to avoid the automatic registration and omit that variation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I would prefer that, yes.

  2. This is currently how child themes need to override (remove) theme style variations, so it makes sense.

Yes it is a little limiting, but it is already documented that "The function unregister_block_style only unregisters styles that were registered on the server using register_block_style" so there would be no change.


$path = array( $block_type, 'variations', $variation_slug );
_wp_array_set( $variations_data, $path, $variation['styles'] );
}
}

if ( ! empty( $variations_data ) ) {
$variations_theme_json_data = array(
'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA,
'styles' => array( 'blocks' => $variations_data ),
);
$with_shared_variations = new WP_Theme_JSON_Gutenberg( $variations_theme_json_data );
$with_theme_supports->merge( $with_shared_variations );
}
}

$with_theme_supports->merge( static::$theme );
Expand Down Expand Up @@ -743,14 +788,16 @@ private static function recursively_iterate_json( $dir ) {
* Returns the style variations defined by the theme (parent and child).
*
* @since 6.2.0 Returns parent theme variations if theme is a child.
* @since 6.5.0 Added configurable directory to allow block style variations
* to reside in a different directory to theme style variations.
*
* @return array
*/
public static function get_style_variations() {
public static function get_style_variations( $dir = 'styles' ) {
$variation_files = array();
$variations = array();
$base_directory = get_stylesheet_directory() . '/styles';
$template_directory = get_template_directory() . '/styles';
$base_directory = get_stylesheet_directory() . '/' . $dir;
$template_directory = get_template_directory() . '/' . $dir;
if ( is_dir( $base_directory ) ) {
$variation_files = static::recursively_iterate_json( $base_directory );
}
Expand Down
159 changes: 114 additions & 45 deletions phpunit/class-wp-theme-json-resolver-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,12 @@ public function test_add_theme_supports_are_loaded_for_themes_without_theme_json
$this->assertSame( $color_palette, $settings['color']['palette']['theme'] );
}

/**
* Tests that block style variations registered via either
* `gutenberg_register_block_style` with a style object, or a standalone
* block style variation file within `/block-styles`, are added to the
* theme data.
*/
public function test_add_registered_block_styles_to_theme_data() {
switch_theme( 'block-theme' );

Expand Down Expand Up @@ -267,7 +273,22 @@ public function test_add_registered_block_styles_to_theme_data() {
$group_styles = $theme_json['styles']['blocks']['core/group'] ?? array();
$expected = array(
'variations' => array(
'my-variation' => $variation_styles_data,
'my-variation' => $variation_styles_data,
// The following variations are registered automatically from
// their respective JSON files within the theme's `block-styles`
// directory.
'block-style-variation-a' => array(
'color' => array(
'background' => 'indigo',
'text' => 'plum',
),
),
'block-style-variation-b' => array(
'color' => array(
'background' => 'midnightblue',
'text' => 'lightblue',
),
),
),
);

Expand Down Expand Up @@ -580,54 +601,81 @@ public function data_get_merged_data_returns_origin() {
);
}


/**
* Test that get_style_variations returns all variations, including parent theme variations if the theme is a child,
* and that the child variation overwrites the parent variation of the same name.
* Tests that `get_style_variations` returns all the appropriate variations,
* including parent variations if the theme is a child, and that the child
* variation overwrites the parent variation of the same name.
*
* Note: This covers both theme style variations (`/styles`) and block style
* variations (`/block-styles`).
*
* @covers WP_Theme_JSON_Resolver::get_style_variations
**/
public function test_get_style_variations_returns_all_variations() {
// Switch to a child theme.
switch_theme( 'block-theme-child' );
*
* @dataProvider data_get_style_variations
*
* @param string $theme Name of the theme to use.
* @param string $dir The directory to retrieve variation json files from.
* @param array $expected_variations Collection of expected variations.
*/
public function test_get_style_variations( $theme, $dir, $expected_variations ) {
switch_theme( $theme );
wp_set_current_user( self::$administrator_id );

$actual_settings = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations();
$expected_settings = array(
array(
'version' => 2,
'title' => 'variation-a',
'settings' => array(
'blocks' => array(
'core/paragraph' => array(
'color' => array(
'palette' => array(
'theme' => array(
array(
'slug' => 'dark',
'name' => 'Dark',
'color' => '#010101',
$actual_variations = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations( $dir );

self::recursive_ksort( $actual_variations );
self::recursive_ksort( $expected_variations );

$this->assertSame( $expected_variations, $actual_variations );
}

/**
* Data provider for test_get_style_variations
*
* @return array
*/
public function data_get_style_variations() {
return array(
'theme_style_variations' => array(
'theme' => 'block-theme-child',
'dir' => 'styles',
'expected_variations' => array(
array(
'version' => 2,
'title' => 'variation-a',
'settings' => array(
'blocks' => array(
'core/paragraph' => array(
'color' => array(
'palette' => array(
'theme' => array(
array(
'slug' => 'dark',
'name' => 'Dark',
'color' => '#010101',
),
),
),
),
),
),
),
),
),
),
array(
'version' => 2,
'title' => 'variation-b',
'settings' => array(
'blocks' => array(
'core/post-title' => array(
'color' => array(
'palette' => array(
'theme' => array(
array(
'slug' => 'light',
'name' => 'Light',
'color' => '#f1f1f1',
array(
'version' => 2,
'title' => 'variation-b',
'settings' => array(
'blocks' => array(
'core/post-title' => array(
'color' => array(
'palette' => array(
'theme' => array(
array(
'slug' => 'light',
'name' => 'Light',
'color' => '#f1f1f1',
),
),
),
),
),
Expand All @@ -636,13 +684,34 @@ public function test_get_style_variations_returns_all_variations() {
),
),
),
);
self::recursive_ksort( $actual_settings );
self::recursive_ksort( $expected_settings );

$this->assertSame(
$expected_settings,
$actual_settings
'block_style_variations' => array(
'theme' => 'block-theme-child-with-block-style-variations',
'dir' => 'block-styles',
'expected_variations' => array(
array(
'supportedBlockTypes' => array( 'core/group', 'core/columns', 'core/media-text' ),
'version' => 2,
'title' => 'block-style-variation-a',
'styles' => array(
'color' => array(
'background' => 'darkcyan',
'text' => 'aliceblue',
),
),
),
array(
'supportedBlockTypes' => array( 'core/group', 'core/columns' ),
'version' => 2,
'title' => 'block-style-variation-b',
'styles' => array(
'color' => array(
'background' => 'midnightblue',
'text' => 'lightblue',
),
),
),
),
),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"version": 2,
"supportedBlockTypes": [ "core/group", "core/columns", "core/media-text" ],
"styles": {
"color": {
"background": "darkcyan",
"text": "aliceblue"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
Theme Name: Block Theme Child With Block Style Variations Theme
Theme URI: https://wordpress.org/
Description: For testing purposes only.
Template: block-theme
Version: 1.0.0
Text Domain: block-theme-child-with-block-style-variations
*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"version": 2,
"supportedBlockTypes": [ "core/group", "core/columns" ],
"styles": {
"color": {
"background": "indigo",
"text": "plum"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"version": 2,
"supportedBlockTypes": [ "core/group", "core/columns" ],
"styles": {
"color": {
"background": "midnightblue",
"text": "lightblue"
}
}
}
7 changes: 7 additions & 0 deletions schemas/json/theme.json
Original file line number Diff line number Diff line change
Expand Up @@ -2584,6 +2584,13 @@
"type": "string",
"description": "Description of the global styles variation."
},
"supportedBlockTypes": {
"type": "array",
"description": "List of block types that can use the block style variation this theme.json file represents.",
"items": {
"type": "string"
}
},
"settings": {
"description": "Settings for the block editor and individual blocks. These include things like:\n- Which customization options should be available to the user. \n- The default colors, font sizes... available to the user. \n- CSS custom properties and class names used in styles.\n- And the default layout of the editor (widths and available alignments).",
"type": "object",
Expand Down
Loading