Skip to content

Commit

Permalink
Section styles: improve performance and conceptual consistency.
Browse files Browse the repository at this point in the history
These changes involve:

- Move shared variation definitions from styles.blocks.variations to styles.variations
- Remove blockTypes from styles.variations.
- Do not register shared variations from theme style variation or primary theme.json files.
- Move the merging of theme.json data into the WP_Theme_JSON_Resolver and WP_Theme_JSON classes.

These changes improve performance and are more future-proof API wise.
See conversation at WordPress/gutenberg#62686

Props aaronrobertshaw, oandregal, andrewserong, joemcgill, talldanwp, andrewserong, ramonopoly, richtabor, youknowriad.

See #61312, #61451.

Built from https://develop.svn.wordpress.org/trunk@58466


git-svn-id: http://core.svn.wordpress.org/trunk@57915 1a063a9b-81f0-0310-95a4-ce76da25c4cd
  • Loading branch information
oandregal committed Jun 24, 2024
1 parent 7ef5f94 commit 6476fd9
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 239 deletions.
209 changes: 8 additions & 201 deletions wp-includes/block-supports/block-style-variations.php
Original file line number Diff line number Diff line change
Expand Up @@ -212,176 +212,6 @@ function wp_render_block_style_variation_class_name( $block_content, $block ) {
return $tags->get_updated_html();
}

/**
* Collects block style variation data for merging with theme.json data.
*
* @since 6.6.0
* @access private
*
* @param array $variations Shared block style variations.
*
* @return array Block variations data to be merged under `styles.blocks`.
*/
function wp_resolve_block_style_variations( $variations ) {
$variations_data = array();

if ( empty( $variations ) ) {
return $variations_data;
}

$have_named_variations = ! wp_is_numeric_array( $variations );

foreach ( $variations as $key => $variation ) {
$supported_blocks = $variation['blockTypes'] ?? array();

/*
* Standalone theme.json partial files for block style variations
* will have their styles under a top-level property by the same name.
* Variations defined within an existing theme.json or theme style
* variation will themselves already be the required styles data.
*/
$variation_data = $variation['styles'] ?? $variation;

if ( empty( $variation_data ) ) {
continue;
}

/*
* Block style variations read in via standalone theme.json partials
* need to have their name set to the kebab case version of their title.
*/
$variation_name = $have_named_variations ? $key : ( $variation['slug'] ?? _wp_to_kebab_case( $variation['title'] ) );

foreach ( $supported_blocks as $block_type ) {
// Add block style variation data under current block type.
$path = array( $block_type, 'variations', $variation_name );
_wp_array_set( $variations_data, $path, $variation_data );
}
}

return $variations_data;
}

/**
* Merges variations data with existing theme.json data ensuring that the
* current theme.json data values take precedence.
*
* @since 6.6.0
* @access private
*
* @param array $variations_data Block style variations data keyed by block type.
* @param WP_Theme_JSON_Data $theme_json Current theme.json data.
* @param string $origin Origin for the theme.json data.
*
* @return WP_Theme_JSON The merged theme.json data.
*/
function wp_merge_block_style_variations_data( $variations_data, $theme_json, $origin = 'theme' ) {
if ( empty( $variations_data ) ) {
return $theme_json;
}

$variations_theme_json_data = array(
'version' => WP_Theme_JSON::LATEST_SCHEMA,
'styles' => array( 'blocks' => $variations_data ),
);

$variations_theme_json = new WP_Theme_JSON_Data( $variations_theme_json_data, $origin );

/*
* Merge the current theme.json data over shared variation data so that
* any explicit per block variation values take precedence.
*/
return $variations_theme_json->update_with( $theme_json->get_data() );
}

/**
* Merges any shared block style variation definitions from a theme style
* variation into their appropriate block type within theme json styles. Any
* custom user selections already made will take precedence over the shared
* style variation value.
*
* @since 6.6.0
* @access private
*
* @param WP_Theme_JSON_Data $theme_json Current theme.json data.
*
* @return WP_Theme_JSON_Data
*/
function wp_resolve_block_style_variations_from_theme_style_variation( $theme_json ) {
$theme_json_data = $theme_json->get_data();
$shared_variations = $theme_json_data['styles']['blocks']['variations'] ?? array();
$variations_data = wp_resolve_block_style_variations( $shared_variations );

return wp_merge_block_style_variations_data( $variations_data, $theme_json, 'user' );
}

/**
* Merges block style variation data sourced from standalone partial
* theme.json files.
*
* @since 6.6.0
* @access private
*
* @param WP_Theme_JSON_Data $theme_json Current theme.json data.
*
* @return WP_Theme_JSON_Data
*/
function wp_resolve_block_style_variations_from_theme_json_partials( $theme_json ) {
$block_style_variations = WP_Theme_JSON_Resolver::get_style_variations( 'block' );
$variations_data = wp_resolve_block_style_variations( $block_style_variations );

return wp_merge_block_style_variations_data( $variations_data, $theme_json );
}

/**
* Merges shared block style variations registered within the
* `styles.blocks.variations` property of the primary theme.json file.
*
* @since 6.6.0
* @access private
*
* @param WP_Theme_JSON_Data $theme_json Current theme.json data.
*
* @return WP_Theme_JSON_Data
*/
function wp_resolve_block_style_variations_from_primary_theme_json( $theme_json ) {
$theme_json_data = $theme_json->get_data();
$block_style_variations = $theme_json_data['styles']['blocks']['variations'] ?? array();
$variations_data = wp_resolve_block_style_variations( $block_style_variations );

return wp_merge_block_style_variations_data( $variations_data, $theme_json );
}

/**
* Merges block style variations registered via the block styles registry with a
* style object, under their appropriate block types within theme.json styles.
* Any variation values defined within the theme.json specific to a block type
* will take precedence over these shared definitions.
*
* @since 6.6.0
* @access private
*
* @param WP_Theme_JSON_Data $theme_json Current theme.json data.
*
* @return WP_Theme_JSON_Data
*/
function wp_resolve_block_style_variations_from_styles_registry( $theme_json ) {
$registry = WP_Block_Styles_Registry::get_instance();
$styles = $registry->get_all_registered();
$variations_data = array();

foreach ( $styles as $block_type => $variations ) {
foreach ( $variations as $variation_name => $variation ) {
if ( ! empty( $variation['style_data'] ) ) {
$path = array( $block_type, 'variations', $variation_name );
_wp_array_set( $variations_data, $path, $variation['style_data'] );
}
}
}

return wp_merge_block_style_variations_data( $variations_data, $theme_json );
}

/**
* Enqueues styles for block style variations.
*
Expand All @@ -399,53 +229,30 @@ function wp_enqueue_block_style_variation_styles() {
add_filter( 'render_block', 'wp_render_block_style_variation_class_name', 10, 2 );
add_action( 'wp_enqueue_scripts', 'wp_enqueue_block_style_variation_styles', 1 );

// Resolve block style variations from all their potential sources. The order here is deliberate.
add_filter( 'wp_theme_json_data_theme', 'wp_resolve_block_style_variations_from_primary_theme_json', 10, 1 );
add_filter( 'wp_theme_json_data_theme', 'wp_resolve_block_style_variations_from_theme_json_partials', 10, 1 );
add_filter( 'wp_theme_json_data_theme', 'wp_resolve_block_style_variations_from_styles_registry', 10, 1 );

add_filter( 'wp_theme_json_data_user', 'wp_resolve_block_style_variations_from_theme_style_variation', 10, 1 );

/**
* Registers any block style variations contained within the provided
* theme.json data.
* Registers block style variations read in from theme.json partials.
*
* @since 6.6.0
* @access private
*
* @param array $variations Shared block style variations.
*/
function wp_register_block_style_variations_from_theme_json_data( $variations ) {
function wp_register_block_style_variations_from_theme_json_partials( $variations ) {
if ( empty( $variations ) ) {
return $variations;
return;
}

$registry = WP_Block_Styles_Registry::get_instance();
$have_named_variations = ! wp_is_numeric_array( $variations );

foreach ( $variations as $key => $variation ) {
$supported_blocks = $variation['blockTypes'] ?? array();
$registry = WP_Block_Styles_Registry::get_instance();

/*
* Standalone theme.json partial files for block style variations
* will have their styles under a top-level property by the same name.
* Variations defined within an existing theme.json or theme style
* variation will themselves already be the required styles data.
*/
$variation_data = $variation['styles'] ?? $variation;

if ( empty( $variation_data ) ) {
foreach ( $variations as $variation ) {
if ( empty( $variation['blockTypes'] ) || empty( $variation['styles'] ) ) {
continue;
}

/*
* Block style variations read in via standalone theme.json partials
* need to have their name set to the kebab case version of their title.
*/
$variation_name = $have_named_variations ? $key : ( $variation['slug'] ?? _wp_to_kebab_case( $variation['title'] ) );
$variation_name = $variation['slug'] ?? _wp_to_kebab_case( $variation['title'] );
$variation_label = $variation['title'] ?? $variation_name;

foreach ( $supported_blocks as $block_type ) {
foreach ( $variation['blockTypes'] as $block_type ) {
$registered_styles = $registry->get_registered_styles_for_block( $block_type );

// Register block style variation if it hasn't already been registered.
Expand Down
116 changes: 104 additions & 12 deletions wp-includes/class-wp-theme-json-resolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ protected static function has_same_registered_blocks( $origin ) {
* @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.6.0 Add support for 'default-font-sizes' and 'default-spacing-sizes' theme supports.
* Register the block style variations coming from the partials and the theme.json.
* Added registration and merging of block style variations from partial theme.json files and the block styles registry.
*
* @param array $deprecated Deprecated. Not used.
* @param array $options {
Expand All @@ -258,13 +258,29 @@ public static function get_theme_data( $deprecated = array(), $options = array()
$theme_json_data = array( 'version' => WP_Theme_JSON::LATEST_SCHEMA );
}

// Register variations defined by the theme.
$variations = $theme_json_data['styles']['blocks']['variations'] ?? array();
wp_register_block_style_variations_from_theme_json_data( $variations );

// Register variations defined by theme partials (theme.json files in the styles directory).
/*
* Register variations defined by theme partials (theme.json files in the styles directory).
* This is required so the variations pass sanitization of theme.json data.
*/
$variations = static::get_style_variations( 'block' );
wp_register_block_style_variations_from_theme_json_data( $variations );
wp_register_block_style_variations_from_theme_json_partials( $variations );

/*
* Source variations from the block registry and block style variation files. Then, merge them into the existing theme.json data.
*
* In case the same style properties are defined in several sources, this is how we should resolve the values,
* from higher to lower priority:
*
* - styles.blocks.blockType.variations from theme.json
* - styles.variations from theme.json
* - variations from block style variation files
* - variations from block styles registry
*
* See test_add_registered_block_styles_to_theme_data and test_unwraps_block_style_variations.
*
*/
$theme_json_data = static::inject_variations_from_block_style_variation_files( $theme_json_data, $variations );
$theme_json_data = static::inject_variations_from_block_styles_registry( $theme_json_data );

/**
* Filters the data provided by the theme for global styles and settings.
Expand Down Expand Up @@ -579,10 +595,6 @@ public static function get_user_data() {
unset( $decoded_data['isGlobalStylesUserThemeJSON'] );
$config = $decoded_data;
}

// Register variations defined by the user.
$variations = $config['styles']['blocks']['variations'] ?? array();
wp_register_block_style_variations_from_theme_json_data( $variations );
}

/** This filter is documented in wp-includes/class-wp-theme-json-resolver.php */
Expand Down Expand Up @@ -885,7 +897,7 @@ public static function get_resolved_theme_uris( $theme_json ) {
*
* @since 6.6.0
*
* @param WP_Theme_JSON $theme_json A theme json instance.
* @param WP_Theme_JSON $theme_json A theme json instance.
* @return WP_Theme_JSON Theme merged with resolved paths, if any found.
*/
public static function resolve_theme_file_uris( $theme_json ) {
Expand All @@ -907,4 +919,84 @@ public static function resolve_theme_file_uris( $theme_json ) {

return $theme_json;
}

/**
* Adds variations sourced from block style variations files to the supplied theme.json data.
*
* @since 6.6.0
*
* @param array $data Array following the theme.json specification.
* @param array $variations Shared block style variations.
* @return array Theme json data including shared block style variation definitions.
*/
private static function inject_variations_from_block_style_variation_files( $data, $variations ) {
if ( empty( $variations ) ) {
return $data;
}

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

$variation_name = $variation['slug'] ?? _wp_to_kebab_case( $variation['title'] );

foreach ( $variation['blockTypes'] as $block_type ) {
// First, override partial styles with any top-level styles.
$top_level_data = $data['styles']['variations'][ $variation_name ] ?? array();
if ( ! empty( $top_level_data ) ) {
$variation['styles'] = array_replace_recursive( $variation['styles'], $top_level_data );
}

// Then, override styles so far with any block-level styles.
$block_level_data = $data['styles']['blocks'][ $block_type ]['variations'][ $variation_name ] ?? array();
if ( ! empty( $block_level_data ) ) {
$variation['styles'] = array_replace_recursive( $variation['styles'], $block_level_data );
}

$path = array( 'styles', 'blocks', $block_type, 'variations', $variation_name );
_wp_array_set( $data, $path, $variation['styles'] );
}
}

return $data;
}

/**
* Adds variations sourced from the block styles registry to the supplied theme.json data.
*
* @since 6.6.0
*
* @param array $data Array following the theme.json specification.
* @return array Theme json data including shared block style variation definitions.
*/
private static function inject_variations_from_block_styles_registry( $data ) {
$registry = WP_Block_Styles_Registry::get_instance();
$styles = $registry->get_all_registered();

foreach ( $styles as $block_type => $variations ) {
foreach ( $variations as $variation_name => $variation ) {
if ( empty( $variation['style_data'] ) ) {
continue;
}

// First, override registry styles with any top-level styles.
$top_level_data = $data['styles']['variations'][ $variation_name ] ?? array();
if ( ! empty( $top_level_data ) ) {
$variation['style_data'] = array_replace_recursive( $variation['style_data'], $top_level_data );
}

// Then, override styles so far with any block-level styles.
$block_level_data = $data['styles']['blocks'][ $block_type ]['variations'][ $variation_name ] ?? array();
if ( ! empty( $block_level_data ) ) {
$variation['style_data'] = array_replace_recursive( $variation['style_data'], $block_level_data );
}

$path = array( 'styles', 'blocks', $block_type, 'variations', $variation_name );
_wp_array_set( $data, $path, $variation['style_data'] );
}
}

return $data;
}
}
Loading

0 comments on commit 6476fd9

Please sign in to comment.