Skip to content

Commit

Permalink
Try allowing theme style variations to define block style variations
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronrobertshaw committed Feb 1, 2024
1 parent cd64ec8 commit 79f5765
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 6 deletions.
44 changes: 44 additions & 0 deletions lib/block-supports/variations.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
8 changes: 4 additions & 4 deletions lib/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 ) => {
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit 79f5765

Please sign in to comment.