Block Themes: Add section styling via extended block style variations
Provide users with the ability to style entire sections of a page without having to tediously reapply the same sets of styles. This is done by extending block style variations to apply to nested blocks. See https://github.com/WordPress/gutenberg/pull/57908. Fixes #61312. Props aaronrobertshaw, talldanwp, ramonopoly, isabel_brison, andrewserong. Built from https://develop.svn.wordpress.org/trunk@58264 git-svn-id: http://core.svn.wordpress.org/trunk@57727 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
bdc9ff5c76
commit
51c676d7ea
|
@ -0,0 +1,424 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Block support to enable per-section styling of block types via
|
||||||
|
* block style variations.
|
||||||
|
*
|
||||||
|
* @package WordPress
|
||||||
|
* @since 6.6.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate block style variation instance name.
|
||||||
|
*
|
||||||
|
* @since 6.6.0
|
||||||
|
* @access private
|
||||||
|
*
|
||||||
|
* @param array $block Block object.
|
||||||
|
* @param string $variation Slug for the block style variation.
|
||||||
|
*
|
||||||
|
* @return string The unique variation name.
|
||||||
|
*/
|
||||||
|
function wp_create_block_style_variation_instance_name( $block, $variation ) {
|
||||||
|
return $variation . '--' . md5( serialize( $block ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the block style variation names within a CSS class string.
|
||||||
|
*
|
||||||
|
* @since 6.6.0
|
||||||
|
*
|
||||||
|
* @param string $class_string CSS class string to look for a variation in.
|
||||||
|
*
|
||||||
|
* @return array|null The block style variation name if found.
|
||||||
|
*/
|
||||||
|
function wp_get_block_style_variation_name_from_class( $class_string ) {
|
||||||
|
if ( ! is_string( $class_string ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
preg_match_all( '/\bis-style-(?!default)(\S+)\b/', $class_string, $matches );
|
||||||
|
return $matches[1] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the block style variation's styles.
|
||||||
|
*
|
||||||
|
* In the case of nested blocks with variations applied, we want the parent
|
||||||
|
* variation's styles to be rendered before their descendants. This solves the
|
||||||
|
* issue of a block type being styled in both the parent and descendant: we want
|
||||||
|
* the descendant style to take priority, and this is done by loading it after,
|
||||||
|
* in the DOM order. This is why the variation stylesheet generation is in a
|
||||||
|
* different filter.
|
||||||
|
*
|
||||||
|
* @since 6.6.0
|
||||||
|
* @access private
|
||||||
|
*
|
||||||
|
* @param array $parsed_block The parsed block.
|
||||||
|
*
|
||||||
|
* @return array The parsed block with block style variation classname added.
|
||||||
|
*/
|
||||||
|
function wp_render_block_style_variation_support_styles( $parsed_block ) {
|
||||||
|
$classes = $parsed_block['attrs']['className'] ?? null;
|
||||||
|
$variations = wp_get_block_style_variation_name_from_class( $classes );
|
||||||
|
|
||||||
|
if ( ! $variations ) {
|
||||||
|
return $parsed_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tree = WP_Theme_JSON_Resolver::get_merged_data();
|
||||||
|
$theme_json = $tree->get_raw_data();
|
||||||
|
|
||||||
|
// Only the first block style variation with data is supported.
|
||||||
|
$variation_data = array();
|
||||||
|
foreach ( $variations as $variation ) {
|
||||||
|
$variation_data = $theme_json['styles']['blocks'][ $parsed_block['blockName'] ]['variations'][ $variation ] ?? array();
|
||||||
|
|
||||||
|
if ( ! empty( $variation_data ) ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( empty( $variation_data ) ) {
|
||||||
|
return $parsed_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
$variation_instance = wp_create_block_style_variation_instance_name( $parsed_block, $variation );
|
||||||
|
$class_name = "is-style-$variation_instance";
|
||||||
|
$updated_class_name = $parsed_block['attrs']['className'] . " $class_name";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Even though block style variations are effectively theme.json partials,
|
||||||
|
* they can't be processed completely as though they are.
|
||||||
|
*
|
||||||
|
* Block styles support custom selectors to direct specific types of styles
|
||||||
|
* to inner elements. For example, borders on Image block's get applied to
|
||||||
|
* the inner `img` element rather than the wrapping `figure`.
|
||||||
|
*
|
||||||
|
* The following relocates the "root" block style variation styles to
|
||||||
|
* under an appropriate blocks property to leverage the preexisting style
|
||||||
|
* generation for simple block style variations. This way they get the
|
||||||
|
* custom selectors they need.
|
||||||
|
*
|
||||||
|
* The inner elements and block styles for the variation itself are
|
||||||
|
* still included at the top level but scoped by the variation's selector
|
||||||
|
* when the stylesheet is generated.
|
||||||
|
*/
|
||||||
|
$elements_data = $variation_data['elements'] ?? array();
|
||||||
|
$blocks_data = $variation_data['blocks'] ?? array();
|
||||||
|
unset( $variation_data['elements'] );
|
||||||
|
unset( $variation_data['blocks'] );
|
||||||
|
|
||||||
|
_wp_array_set(
|
||||||
|
$blocks_data,
|
||||||
|
array( $parsed_block['blockName'], 'variations', $variation_instance ),
|
||||||
|
$variation_data
|
||||||
|
);
|
||||||
|
|
||||||
|
$config = array(
|
||||||
|
'version' => WP_Theme_JSON::LATEST_SCHEMA,
|
||||||
|
'styles' => array(
|
||||||
|
'elements' => $elements_data,
|
||||||
|
'blocks' => $blocks_data,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Turn off filter that excludes block nodes. They are needed here for the variation's inner block types.
|
||||||
|
if ( ! is_admin() ) {
|
||||||
|
remove_filter( 'wp_theme_json_get_style_nodes', 'wp_filter_out_block_nodes' );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temporarily prevent variation instance from being sanitized while processing theme.json.
|
||||||
|
$styles_registry = WP_Block_Styles_Registry::get_instance();
|
||||||
|
$styles_registry->register( $parsed_block['blockName'], array( 'name' => $variation_instance ) );
|
||||||
|
|
||||||
|
$variation_theme_json = new WP_Theme_JSON( $config, 'blocks' );
|
||||||
|
$variation_styles = $variation_theme_json->get_stylesheet(
|
||||||
|
array( 'styles' ),
|
||||||
|
array( 'custom' ),
|
||||||
|
array(
|
||||||
|
'skip_root_layout_styles' => true,
|
||||||
|
'scope' => ".$class_name",
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Clean up temporary block style now instance styles have been processed.
|
||||||
|
$styles_registry->unregister( $parsed_block['blockName'], $variation_instance );
|
||||||
|
|
||||||
|
// Restore filter that excludes block nodes.
|
||||||
|
if ( ! is_admin() ) {
|
||||||
|
add_filter( 'wp_theme_json_get_style_nodes', 'wp_filter_out_block_nodes' );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( empty( $variation_styles ) ) {
|
||||||
|
return $parsed_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_register_style( 'block-style-variation-styles', false, array( 'global-styles', 'wp-block-library' ) );
|
||||||
|
wp_add_inline_style( 'block-style-variation-styles', $variation_styles );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add variation instance class name to block's className string so it can
|
||||||
|
* be enforced in the block markup via render_block filter.
|
||||||
|
*/
|
||||||
|
_wp_array_set( $parsed_block, array( 'attrs', 'className' ), $updated_class_name );
|
||||||
|
|
||||||
|
return $parsed_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure the variation block support class name generated and added to
|
||||||
|
* block attributes in the `render_block_data` filter gets applied to the
|
||||||
|
* block's markup.
|
||||||
|
*
|
||||||
|
* @see wp_render_block_style_variation_support_styles
|
||||||
|
*
|
||||||
|
* @since 6.6.0
|
||||||
|
* @access private
|
||||||
|
*
|
||||||
|
* @param string $block_content Rendered block content.
|
||||||
|
* @param array $block Block object.
|
||||||
|
*
|
||||||
|
* @return string Filtered block content.
|
||||||
|
*/
|
||||||
|
function wp_render_block_style_variation_class_name( $block_content, $block ) {
|
||||||
|
if ( ! $block_content || empty( $block['attrs']['className'] ) ) {
|
||||||
|
return $block_content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Matches a class prefixed by `is-style`, followed by the
|
||||||
|
* variation slug, then `--`, and finally a hash.
|
||||||
|
*
|
||||||
|
* See `wp_create_block_style_variation_instance_name` for class generation.
|
||||||
|
*/
|
||||||
|
preg_match( '/\bis-style-(\S+?--\w+)\b/', $block['attrs']['className'], $matches );
|
||||||
|
|
||||||
|
if ( empty( $matches ) ) {
|
||||||
|
return $block_content;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tags = new WP_HTML_Tag_Processor( $block_content );
|
||||||
|
|
||||||
|
if ( $tags->next_tag() ) {
|
||||||
|
/*
|
||||||
|
* Ensure the variation instance class name set in the
|
||||||
|
* `render_block_data` filter is applied in markup.
|
||||||
|
* See `wp_render_block_style_variation_support_styles`.
|
||||||
|
*/
|
||||||
|
$tags->add_class( $matches[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tags->get_updated_html();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects block style variation data for merging with theme.json data.
|
||||||
|
* As each block style variation is processed it is registered if it hasn't
|
||||||
|
* been already. This registration is required for later sanitization of
|
||||||
|
* 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_and_register_block_style_variations( $variations ) {
|
||||||
|
$variations_data = array();
|
||||||
|
|
||||||
|
if ( empty( $variations ) ) {
|
||||||
|
return $variations_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
$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();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 : _wp_to_kebab_case( $variation['title'] );
|
||||||
|
$variation_label = $variation['title'] ?? $variation_name;
|
||||||
|
|
||||||
|
foreach ( $supported_blocks as $block_type ) {
|
||||||
|
$registered_styles = $registry->get_registered_styles_for_block( $block_type );
|
||||||
|
|
||||||
|
// Register block style variation if it hasn't already been registered.
|
||||||
|
if ( ! array_key_exists( $variation_name, $registered_styles ) ) {
|
||||||
|
register_block_style(
|
||||||
|
$block_type,
|
||||||
|
array(
|
||||||
|
'name' => $variation_name,
|
||||||
|
'label' => $variation_label,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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_and_register_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_and_register_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_and_register_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.
|
||||||
|
*
|
||||||
|
* @since 6.6.0
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function wp_enqueue_block_style_variation_styles() {
|
||||||
|
wp_enqueue_style( 'block-style-variation-styles' );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the block support.
|
||||||
|
WP_Block_Supports::get_instance()->register( 'block-style-variation', array() );
|
||||||
|
|
||||||
|
add_filter( 'render_block_data', 'wp_render_block_style_variation_support_styles', 10, 2 );
|
||||||
|
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 );
|
|
@ -701,16 +701,46 @@ class WP_Theme_JSON_Resolver {
|
||||||
return $nested_json_files;
|
return $nested_json_files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a supplied style variation matches the provided scope.
|
||||||
|
*
|
||||||
|
* For backwards compatibility, if a variation does not define any scope
|
||||||
|
* related property, e.g. `blockTypes`, it is assumed to be a theme style
|
||||||
|
* variation.
|
||||||
|
*
|
||||||
|
* @since 6.6.0
|
||||||
|
*
|
||||||
|
* @param array $variation Theme.json shaped style variation object.
|
||||||
|
* @param string $scope Scope to check e.g. theme, block etc.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
private static function style_variation_has_scope( $variation, $scope ) {
|
||||||
|
if ( 'block' === $scope ) {
|
||||||
|
return isset( $variation['blockTypes'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( 'theme' === $scope ) {
|
||||||
|
return ! isset( $variation['blockTypes'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the style variations defined by the theme.
|
* Returns the style variations defined by the theme.
|
||||||
*
|
*
|
||||||
* @since 6.0.0
|
* @since 6.0.0
|
||||||
* @since 6.2.0 Returns parent theme variations if theme is a child.
|
* @since 6.2.0 Returns parent theme variations if theme is a child.
|
||||||
|
* @since 6.6.0 Added configurable scope parameter to allow filtering
|
||||||
|
* theme.json partial files by the scope to which they
|
||||||
|
* can be applied e.g. theme vs block etc.
|
||||||
|
*
|
||||||
|
* @param string $scope The scope or type of style variation to retrieve e.g. theme, block etc.
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function get_style_variations() {
|
public static function get_style_variations( $scope = 'theme' ) {
|
||||||
$variation_files = array();
|
$variation_files = array();
|
||||||
$variations = array();
|
$variations = array();
|
||||||
$base_directory = get_stylesheet_directory() . '/styles';
|
$base_directory = get_stylesheet_directory() . '/styles';
|
||||||
|
@ -733,7 +763,7 @@ class WP_Theme_JSON_Resolver {
|
||||||
ksort( $variation_files );
|
ksort( $variation_files );
|
||||||
foreach ( $variation_files as $path => $file ) {
|
foreach ( $variation_files as $path => $file ) {
|
||||||
$decoded_file = wp_json_file_decode( $path, array( 'associative' => true ) );
|
$decoded_file = wp_json_file_decode( $path, array( 'associative' => true ) );
|
||||||
if ( is_array( $decoded_file ) ) {
|
if ( is_array( $decoded_file ) && static::style_variation_has_scope( $decoded_file, $scope ) ) {
|
||||||
$translated = static::translate( $decoded_file, wp_get_theme()->get( 'TextDomain' ) );
|
$translated = static::translate( $decoded_file, wp_get_theme()->get( 'TextDomain' ) );
|
||||||
$variation = ( new WP_Theme_JSON( $translated ) )->get_raw_data();
|
$variation = ( new WP_Theme_JSON( $translated ) )->get_raw_data();
|
||||||
if ( empty( $variation['title'] ) ) {
|
if ( empty( $variation['title'] ) ) {
|
||||||
|
|
|
@ -346,9 +346,11 @@ class WP_Theme_JSON {
|
||||||
* @since 5.9.0 Renamed from `ALLOWED_TOP_LEVEL_KEYS` to `VALID_TOP_LEVEL_KEYS`,
|
* @since 5.9.0 Renamed from `ALLOWED_TOP_LEVEL_KEYS` to `VALID_TOP_LEVEL_KEYS`,
|
||||||
* added the `customTemplates` and `templateParts` values.
|
* added the `customTemplates` and `templateParts` values.
|
||||||
* @since 6.3.0 Added the `description` value.
|
* @since 6.3.0 Added the `description` value.
|
||||||
|
* @since 6.6.0 Added `blockTypes` to support block style variation theme.json partials.
|
||||||
* @var string[]
|
* @var string[]
|
||||||
*/
|
*/
|
||||||
const VALID_TOP_LEVEL_KEYS = array(
|
const VALID_TOP_LEVEL_KEYS = array(
|
||||||
|
'blockTypes',
|
||||||
'customTemplates',
|
'customTemplates',
|
||||||
'description',
|
'description',
|
||||||
'patterns',
|
'patterns',
|
||||||
|
@ -823,6 +825,7 @@ class WP_Theme_JSON {
|
||||||
* @since 5.8.0
|
* @since 5.8.0
|
||||||
* @since 5.9.0 Added the `$valid_block_names` and `$valid_element_name` parameters.
|
* @since 5.9.0 Added the `$valid_block_names` and `$valid_element_name` parameters.
|
||||||
* @since 6.3.0 Added the `$valid_variations` parameter.
|
* @since 6.3.0 Added the `$valid_variations` parameter.
|
||||||
|
* @since 6.6.0 Updated schema to allow extended block style variations.
|
||||||
*
|
*
|
||||||
* @param array $input Structure to sanitize.
|
* @param array $input Structure to sanitize.
|
||||||
* @param array $valid_block_names List of valid block names.
|
* @param array $valid_block_names List of valid block names.
|
||||||
|
@ -881,6 +884,27 @@ class WP_Theme_JSON {
|
||||||
|
|
||||||
$schema_styles_blocks = array();
|
$schema_styles_blocks = array();
|
||||||
$schema_settings_blocks = array();
|
$schema_settings_blocks = array();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate a schema for blocks.
|
||||||
|
* - Block styles can contain `elements` & `variations` definitions.
|
||||||
|
* - Variations definitions cannot be nested.
|
||||||
|
* - Variations can contain styles for inner `blocks`.
|
||||||
|
* - Variation inner `blocks` styles can contain `elements`.
|
||||||
|
*
|
||||||
|
* As each variation needs a `blocks` schema but further nested
|
||||||
|
* inner `blocks`, the overall schema will be generated in multiple passes.
|
||||||
|
*/
|
||||||
|
foreach ( $valid_block_names as $block ) {
|
||||||
|
$schema_settings_blocks[ $block ] = static::VALID_SETTINGS;
|
||||||
|
$schema_styles_blocks[ $block ] = $styles_non_top_level;
|
||||||
|
$schema_styles_blocks[ $block ]['elements'] = $schema_styles_elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
$block_style_variation_styles = static::VALID_STYLES;
|
||||||
|
$block_style_variation_styles['blocks'] = $schema_styles_blocks;
|
||||||
|
$block_style_variation_styles['elements'] = $schema_styles_elements;
|
||||||
|
|
||||||
foreach ( $valid_block_names as $block ) {
|
foreach ( $valid_block_names as $block ) {
|
||||||
// Build the schema for each block style variation.
|
// Build the schema for each block style variation.
|
||||||
$style_variation_names = array();
|
$style_variation_names = array();
|
||||||
|
@ -897,12 +921,9 @@ class WP_Theme_JSON {
|
||||||
|
|
||||||
$schema_styles_variations = array();
|
$schema_styles_variations = array();
|
||||||
if ( ! empty( $style_variation_names ) ) {
|
if ( ! empty( $style_variation_names ) ) {
|
||||||
$schema_styles_variations = array_fill_keys( $style_variation_names, $styles_non_top_level );
|
$schema_styles_variations = array_fill_keys( $style_variation_names, $block_style_variation_styles );
|
||||||
}
|
}
|
||||||
|
|
||||||
$schema_settings_blocks[ $block ] = static::VALID_SETTINGS;
|
|
||||||
$schema_styles_blocks[ $block ] = $styles_non_top_level;
|
|
||||||
$schema_styles_blocks[ $block ]['elements'] = $schema_styles_elements;
|
|
||||||
$schema_styles_blocks[ $block ]['variations'] = $schema_styles_variations;
|
$schema_styles_blocks[ $block ]['variations'] = $schema_styles_variations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -913,6 +934,12 @@ class WP_Theme_JSON {
|
||||||
$schema['settings']['blocks'] = $schema_settings_blocks;
|
$schema['settings']['blocks'] = $schema_settings_blocks;
|
||||||
$schema['settings']['typography']['fontFamilies'] = static::schema_in_root_and_per_origin( static::FONT_FAMILY_SCHEMA );
|
$schema['settings']['typography']['fontFamilies'] = static::schema_in_root_and_per_origin( static::FONT_FAMILY_SCHEMA );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shared block style variations can be registered from the theme.json data so we can't
|
||||||
|
* validate them against pre-registered block style variations.
|
||||||
|
*/
|
||||||
|
$schema['styles']['blocks']['variations'] = null;
|
||||||
|
|
||||||
// Remove anything that's not present in the schema.
|
// Remove anything that's not present in the schema.
|
||||||
foreach ( array( 'styles', 'settings' ) as $subtree ) {
|
foreach ( array( 'styles', 'settings' ) as $subtree ) {
|
||||||
if ( ! isset( $input[ $subtree ] ) ) {
|
if ( ! isset( $input[ $subtree ] ) ) {
|
||||||
|
@ -1016,16 +1043,36 @@ class WP_Theme_JSON {
|
||||||
* @since 5.9.0 Added `duotone` key with CSS selector.
|
* @since 5.9.0 Added `duotone` key with CSS selector.
|
||||||
* @since 6.1.0 Added `features` key with block support feature level selectors.
|
* @since 6.1.0 Added `features` key with block support feature level selectors.
|
||||||
* @since 6.3.0 Refactored and stabilized selectors API.
|
* @since 6.3.0 Refactored and stabilized selectors API.
|
||||||
|
* @since 6.6.0 Updated to include block style variations from the block styles registry.
|
||||||
*
|
*
|
||||||
* @return array Block metadata.
|
* @return array Block metadata.
|
||||||
*/
|
*/
|
||||||
protected static function get_blocks_metadata() {
|
protected static function get_blocks_metadata() {
|
||||||
$registry = WP_Block_Type_Registry::get_instance();
|
$registry = WP_Block_Type_Registry::get_instance();
|
||||||
$blocks = $registry->get_all_registered();
|
$blocks = $registry->get_all_registered();
|
||||||
|
$style_registry = WP_Block_Styles_Registry::get_instance();
|
||||||
|
|
||||||
// Is there metadata for all currently registered blocks?
|
// Is there metadata for all currently registered blocks?
|
||||||
$blocks = array_diff_key( $blocks, static::$blocks_metadata );
|
$blocks = array_diff_key( $blocks, static::$blocks_metadata );
|
||||||
if ( empty( $blocks ) ) {
|
if ( empty( $blocks ) ) {
|
||||||
|
/*
|
||||||
|
* New block styles may have been registered within WP_Block_Styles_Registry.
|
||||||
|
* Update block metadata for any new block style variations.
|
||||||
|
*/
|
||||||
|
$registered_styles = $style_registry->get_all_registered();
|
||||||
|
foreach ( static::$blocks_metadata as $block_name => $block_metadata ) {
|
||||||
|
if ( ! empty( $registered_styles[ $block_name ] ) ) {
|
||||||
|
$style_selectors = $block_metadata['styleVariations'] ?? array();
|
||||||
|
|
||||||
|
foreach ( $registered_styles[ $block_name ] as $block_style ) {
|
||||||
|
if ( ! isset( $style_selectors[ $block_style['name'] ] ) ) {
|
||||||
|
$style_selectors[ $block_style['name'] ] = static::get_block_style_variation_selector( $block_style['name'], $block_metadata['selector'] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static::$blocks_metadata[ $block_name ]['styleVariations'] = $style_selectors;
|
||||||
|
}
|
||||||
|
}
|
||||||
return static::$blocks_metadata;
|
return static::$blocks_metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1060,11 +1107,20 @@ class WP_Theme_JSON {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the block has style variations, append their selectors to the block metadata.
|
// If the block has style variations, append their selectors to the block metadata.
|
||||||
|
$style_selectors = array();
|
||||||
if ( ! empty( $block_type->styles ) ) {
|
if ( ! empty( $block_type->styles ) ) {
|
||||||
$style_selectors = array();
|
|
||||||
foreach ( $block_type->styles as $style ) {
|
foreach ( $block_type->styles as $style ) {
|
||||||
$style_selectors[ $style['name'] ] = static::get_block_style_variation_selector( $style['name'], static::$blocks_metadata[ $block_name ]['selector'] );
|
$style_selectors[ $style['name'] ] = static::get_block_style_variation_selector( $style['name'], static::$blocks_metadata[ $block_name ]['selector'] );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block style variations can be registered through the WP_Block_Styles_Registry as well as block.json.
|
||||||
|
$registered_styles = $style_registry->get_registered_styles_for_block( $block_name );
|
||||||
|
foreach ( $registered_styles as $style ) {
|
||||||
|
$style_selectors[ $style['name'] ] = static::get_block_style_variation_selector( $style['name'], static::$blocks_metadata[ $block_name ]['selector'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! empty( $style_selectors ) ) {
|
||||||
static::$blocks_metadata[ $block_name ]['styleVariations'] = $style_selectors;
|
static::$blocks_metadata[ $block_name ]['styleVariations'] = $style_selectors;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1158,6 +1214,7 @@ class WP_Theme_JSON {
|
||||||
* @since 5.8.0
|
* @since 5.8.0
|
||||||
* @since 5.9.0 Removed the `$type` parameter, added the `$types` and `$origins` parameters.
|
* @since 5.9.0 Removed the `$type` parameter, added the `$types` and `$origins` parameters.
|
||||||
* @since 6.3.0 Add fallback layout styles for Post Template when block gap support isn't available.
|
* @since 6.3.0 Add fallback layout styles for Post Template when block gap support isn't available.
|
||||||
|
* @since 6.6.0 Added `skip_root_layout_styles` option to omit layout styles if desired.
|
||||||
*
|
*
|
||||||
* @param string[] $types Types of styles to load. Will load all by default. It accepts:
|
* @param string[] $types Types of styles to load. Will load all by default. It accepts:
|
||||||
* - `variables`: only the CSS Custom Properties for presets & custom ones.
|
* - `variables`: only the CSS Custom Properties for presets & custom ones.
|
||||||
|
@ -1165,9 +1222,10 @@ class WP_Theme_JSON {
|
||||||
* - `presets`: only the classes for the presets.
|
* - `presets`: only the classes for the presets.
|
||||||
* @param string[] $origins A list of origins to include. By default it includes VALID_ORIGINS.
|
* @param string[] $origins A list of origins to include. By default it includes VALID_ORIGINS.
|
||||||
* @param array $options An array of options for now used for internal purposes only (may change without notice).
|
* @param array $options An array of options for now used for internal purposes only (may change without notice).
|
||||||
* The options currently supported are 'scope' that makes sure all style are scoped to a
|
* The options currently supported are:
|
||||||
* given selector, and root_selector which overwrites and forces a given selector to be
|
* - 'scope' that makes sure all style are scoped to a given selector
|
||||||
* used on the root node.
|
* - `root_selector` which overwrites and forces a given selector to be used on the root node
|
||||||
|
* - `skip_root_layout_styles` which omits root layout styles from the generated stylesheet.
|
||||||
* @return string The resulting stylesheet.
|
* @return string The resulting stylesheet.
|
||||||
*/
|
*/
|
||||||
public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' ), $origins = null, $options = array() ) {
|
public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' ), $origins = null, $options = array() ) {
|
||||||
|
@ -1220,7 +1278,7 @@ class WP_Theme_JSON {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( in_array( 'styles', $types, true ) ) {
|
if ( in_array( 'styles', $types, true ) ) {
|
||||||
if ( false !== $root_style_key ) {
|
if ( false !== $root_style_key && empty( $options['skip_root_layout_styles'] ) ) {
|
||||||
$stylesheet .= $this->get_root_layout_rules( $style_nodes[ $root_style_key ]['selector'], $style_nodes[ $root_style_key ] );
|
$stylesheet .= $this->get_root_layout_rules( $style_nodes[ $root_style_key ]['selector'], $style_nodes[ $root_style_key ] );
|
||||||
}
|
}
|
||||||
$stylesheet .= $this->get_block_classes( $style_nodes );
|
$stylesheet .= $this->get_block_classes( $style_nodes );
|
||||||
|
@ -3114,6 +3172,7 @@ class WP_Theme_JSON {
|
||||||
*
|
*
|
||||||
* @since 5.9.0
|
* @since 5.9.0
|
||||||
* @since 6.3.2 Preserves global styles block variations when securing styles.
|
* @since 6.3.2 Preserves global styles block variations when securing styles.
|
||||||
|
* @since 6.6.0 Updated to allow variation element styles.
|
||||||
*
|
*
|
||||||
* @param array $theme_json Structure to sanitize.
|
* @param array $theme_json Structure to sanitize.
|
||||||
* @return array Sanitized structure.
|
* @return array Sanitized structure.
|
||||||
|
@ -3175,6 +3234,29 @@ class WP_Theme_JSON {
|
||||||
}
|
}
|
||||||
|
|
||||||
$variation_output = static::remove_insecure_styles( $variation_input );
|
$variation_output = static::remove_insecure_styles( $variation_input );
|
||||||
|
|
||||||
|
// Process a variation's elements and element pseudo selector styles.
|
||||||
|
if ( isset( $variation_input['elements'] ) ) {
|
||||||
|
foreach ( $valid_element_names as $element_name ) {
|
||||||
|
$element_input = $variation_input['elements'][ $element_name ] ?? null;
|
||||||
|
if ( $element_input ) {
|
||||||
|
$element_output = static::remove_insecure_styles( $element_input );
|
||||||
|
|
||||||
|
if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] ) ) {
|
||||||
|
foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] as $pseudo_selector ) {
|
||||||
|
if ( isset( $element_input[ $pseudo_selector ] ) ) {
|
||||||
|
$element_output[ $pseudo_selector ] = static::remove_insecure_styles( $element_input[ $pseudo_selector ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! empty( $element_output ) ) {
|
||||||
|
_wp_array_set( $variation_output, array( 'elements', $element_name ), $element_output );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( ! empty( $variation_output ) ) {
|
if ( ! empty( $variation_output ) ) {
|
||||||
_wp_array_set( $sanitized, $variation['path'], $variation_output );
|
_wp_array_set( $sanitized, $variation['path'], $variation_output );
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
* @global string $wp_version
|
* @global string $wp_version
|
||||||
*/
|
*/
|
||||||
$wp_version = '6.6-alpha-58263';
|
$wp_version = '6.6-alpha-58264';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||||
|
|
|
@ -366,6 +366,7 @@ require ABSPATH . WPINC . '/class-wp-block-supports.php';
|
||||||
require ABSPATH . WPINC . '/block-supports/utils.php';
|
require ABSPATH . WPINC . '/block-supports/utils.php';
|
||||||
require ABSPATH . WPINC . '/block-supports/align.php';
|
require ABSPATH . WPINC . '/block-supports/align.php';
|
||||||
require ABSPATH . WPINC . '/block-supports/background.php';
|
require ABSPATH . WPINC . '/block-supports/background.php';
|
||||||
|
require ABSPATH . WPINC . '/block-supports/block-style-variations.php';
|
||||||
require ABSPATH . WPINC . '/block-supports/border.php';
|
require ABSPATH . WPINC . '/block-supports/border.php';
|
||||||
require ABSPATH . WPINC . '/block-supports/colors.php';
|
require ABSPATH . WPINC . '/block-supports/colors.php';
|
||||||
require ABSPATH . WPINC . '/block-supports/custom-classname.php';
|
require ABSPATH . WPINC . '/block-supports/custom-classname.php';
|
||||||
|
|
Loading…
Reference in New Issue