From 79f57654bbaa84bf1b48bba8c8c2112297c10fe4 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Thu, 1 Feb 2024 12:18:34 +1000 Subject: [PATCH] Try allowing theme style variations to define block style variations --- lib/block-supports/variations.php | 44 ++++++++++++++++++ lib/class-wp-theme-json-gutenberg.php | 8 ++-- .../global-styles/global-styles-provider.js | 45 ++++++++++++++++++- .../push-changes-to-global-styles/index.js | 2 +- 4 files changed, 93 insertions(+), 6 deletions(-) diff --git a/lib/block-supports/variations.php b/lib/block-supports/variations.php index 47f1de0c09fd43..c066ecffd0f668 100644 --- a/lib/block-supports/variations.php +++ b/lib/block-supports/variations.php @@ -118,9 +118,53 @@ function gutenberg_render_variation_support_styles( $pre_render, $block ) { wp_enqueue_style( 'variation-styles' ); } +/** + * Merges any shared block style variation definitions into their appropriate + * block type within theme json styles. Any custom user selections already made + * will take precedence over the shared style variation value. + * + * @param WP_Theme_JSON_Data_Gutenberg $theme_json Current theme.json data. + * + * @return WP_Theme_JSON_Data_Gutenberg + */ +function gutenberg_resolve_shared_block_style_variations( $theme_json ) { + // Return early if no shared block style variations. + // TODO: Should the theme with the theme style variation still have to register these block style variations so that they show for selection by the user? + $theme_json_data = $theme_json->get_data(); + $shared_variations = $theme_json_data['styles']['blocks']['variations'] ?? array(); + + if ( empty( $shared_variations ) ) { + return $theme_json; + } + + $variations_data = array( 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA ); + + foreach ( $shared_variations as $variation_name => $variation ) { + $supported_blocks = $variation['supportedBlockTypes'] ?? null; + + if ( ! $supported_blocks ) { + continue; + } + + // TODO: Can we support deregistering block style variations for a + // theme style variation by setting it false/empty or something? + + foreach ( $supported_blocks as $block_name ) { + $path = array( 'styles', 'blocks', $block_name, 'variations', $variation_name ); + _wp_array_set( $variations_data, $path, $variation ); + } + } + + // Merge the current theme.json data over shared variation data so that + // any previous user selections in global styles are maintained. + $variations_theme_json = new WP_Theme_JSON_Data_Gutenberg( $variations_data, 'user' ); + + return $variations_theme_json->update_with( $theme_json_data ); +} // Register the block support. WP_Block_Supports::get_instance()->register( 'variation', array() ); add_filter( 'pre_render_block', 'gutenberg_render_variation_support_styles', 10, 2 ); add_filter( 'render_block', 'gutenberg_render_variation_support', 10, 2 ); +add_filter( 'wp_theme_json_data_user', 'gutenberg_resolve_shared_block_style_variations', 10, 1 ); diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 17e50012d7b61c..76279f93518ea8 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -876,12 +876,12 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n // entries for each individual block. This is compounded when multiple // variations need to added to the schema. Would multiple passes for // validation offer any improvements? - $unique_variations = array_unique( + $unique_variations = array_unique( call_user_func_array( 'array_merge', array_values( $valid_variations ) ) ); - $shared_variation_styles = $block_style_variation_styles; - $shared_variation_styles['block_types'] = null; - $schema_shared_style_variations = array_fill_keys( $unique_variations, $shared_variation_styles ); + $shared_variation_styles = $block_style_variation_styles; + $shared_variation_styles['supportedBlockTypes'] = null; + $schema_shared_style_variations = array_fill_keys( $unique_variations, $shared_variation_styles ); // Allow refs only within the individual block type variations properties. // Assigning it before `$schema_shared_style_variations` would mean diff --git a/packages/edit-site/src/components/global-styles/global-styles-provider.js b/packages/edit-site/src/components/global-styles/global-styles-provider.js index 1e2d43e267a2dd..a7e71ee027f8cc 100644 --- a/packages/edit-site/src/components/global-styles/global-styles-provider.js +++ b/packages/edit-site/src/components/global-styles/global-styles-provider.js @@ -16,6 +16,8 @@ import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; * Internal dependencies */ import { unlock } from '../../lock-unlock'; +//TODO: If this these updates actually stick around. Move this to utils. +import { setNestedValue } from '../../hooks/push-changes-to-global-styles'; const { GlobalStylesContext, cleanEmptyObject } = unlock( blockEditorPrivateApis @@ -30,6 +32,37 @@ export function mergeBaseAndUserConfigs( base, user ) { } ); } +function resolveBlockStyleVariations( userConfig ) { + const sharedVariations = userConfig.styles?.blocks?.variations; + + if ( ! sharedVariations ) { + return userConfig; + } + + const variationsConfig = JSON.parse( JSON.stringify( userConfig ) ); + + Object.entries( sharedVariations ).forEach( + ( [ variationName, variation ] ) => { + if ( ! variation?.supportedBlockTypes ) { + return; + } + + variation.supportedBlockTypes.forEach( ( blockName ) => { + const path = [ + 'styles', + 'blocks', + blockName, + 'variations', + variationName, + ]; + setNestedValue( variationsConfig, path, variation ); + } ); + } + ); + + return deepmerge( variationsConfig, userConfig ); +} + function useGlobalStylesUserConfig() { const { globalStylesId, isReady, settings, styles } = useSelect( ( select ) => { @@ -122,11 +155,21 @@ function useGlobalStylesContext() { const [ isUserConfigReady, userConfig, setUserConfig ] = useGlobalStylesUserConfig(); const [ isBaseConfigReady, baseConfig ] = useGlobalStylesBaseConfig(); + const mergedConfig = useMemo( () => { if ( ! baseConfig || ! userConfig ) { return {}; } - return mergeBaseAndUserConfigs( baseConfig, userConfig ); + // TODO: Where is the right place to resolve shared block style + // variations within the site editor when they are in a theme + // style variation's data that simply gets applied to the "user" + // origin styles? + const configWithResolvedVariations = + resolveBlockStyleVariations( userConfig ); + return mergeBaseAndUserConfigs( + baseConfig, + configWithResolvedVariations + ); }, [ userConfig, baseConfig ] ); const context = useMemo( () => { return { diff --git a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js index 4844ec6d03eb5e..73b764b00a2f3e 100644 --- a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js +++ b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js @@ -253,7 +253,7 @@ function useChangesToPush( name, attributes, userConfig ) { * @param {Array} path Path of the property to set. * @param {*} value Value to set. */ -function setNestedValue( object, path, value ) { +export function setNestedValue( object, path, value ) { if ( ! object || typeof object !== 'object' ) { return object; }