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

Block Styles: Extend block style variations as mechanism for achieving section styling #6662

424 changes: 424 additions & 0 deletions src/wp-includes/block-supports/block-style-variations.php

Large diffs are not rendered by default.

34 changes: 32 additions & 2 deletions src/wp-includes/class-wp-theme-json-resolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -701,16 +701,46 @@ private static function recursively_iterate_json( $dir ) {
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.
*
Copy link
Member

Choose a reason for hiding this comment

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

No empty line between "@param" and "@return"

* @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.
*
* @since 6.0.0
* @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.
*
Copy link
Member

Choose a reason for hiding this comment

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

Same here

* @return array
*/
public static function get_style_variations() {
public static function get_style_variations( $scope = 'theme' ) {
$variation_files = array();
$variations = array();
$base_directory = get_stylesheet_directory() . '/styles';
Expand All @@ -733,7 +763,7 @@ public static function get_style_variations() {
ksort( $variation_files );
foreach ( $variation_files as $path => $file ) {
$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' ) );
$variation = ( new WP_Theme_JSON( $translated ) )->get_raw_data();
if ( empty( $variation['title'] ) ) {
Expand Down
104 changes: 93 additions & 11 deletions src/wp-includes/class-wp-theme-json.php
Original file line number Diff line number Diff line change
Expand Up @@ -346,9 +346,11 @@ class WP_Theme_JSON {
* @since 5.9.0 Renamed from `ALLOWED_TOP_LEVEL_KEYS` to `VALID_TOP_LEVEL_KEYS`,
* added the `customTemplates` and `templateParts` values.
* @since 6.3.0 Added the `description` value.
* @since 6.6.0 Added `blockTypes` to support block style variation theme.json partials.
* @var string[]
*/
const VALID_TOP_LEVEL_KEYS = array(
'blockTypes',
'customTemplates',
'description',
'patterns',
Expand Down Expand Up @@ -823,6 +825,7 @@ protected static function do_opt_in_into_settings( &$context ) {
* @since 5.8.0
* @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.6.0 Updated schema to allow extended block style variations.
*
* @param array $input Structure to sanitize.
* @param array $valid_block_names List of valid block names.
Expand Down Expand Up @@ -881,6 +884,27 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n

$schema_styles_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 ) {
// Build the schema for each block style variation.
$style_variation_names = array();
Expand All @@ -897,12 +921,9 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n

$schema_styles_variations = array();
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;
}

Expand All @@ -913,6 +934,12 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n
$schema['settings']['blocks'] = $schema_settings_blocks;
$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.
foreach ( array( 'styles', 'settings' ) as $subtree ) {
if ( ! isset( $input[ $subtree ] ) ) {
Expand Down Expand Up @@ -1016,16 +1043,36 @@ protected static function prepend_to_selector( $selector, $to_prepend ) {
* @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.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.
*/
protected static function get_blocks_metadata() {
$registry = WP_Block_Type_Registry::get_instance();
$blocks = $registry->get_all_registered();
$registry = WP_Block_Type_Registry::get_instance();
$blocks = $registry->get_all_registered();
$style_registry = WP_Block_Styles_Registry::get_instance();

// Is there metadata for all currently registered blocks?
$blocks = array_diff_key( $blocks, static::$blocks_metadata );
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;
}

Expand Down Expand Up @@ -1060,11 +1107,20 @@ protected static function get_blocks_metadata() {
}

// If the block has style variations, append their selectors to the block metadata.
$style_selectors = array();
if ( ! empty( $block_type->styles ) ) {
$style_selectors = array();
foreach ( $block_type->styles as $style ) {
$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;
}
}
Expand Down Expand Up @@ -1158,16 +1214,18 @@ public function get_settings() {
* @since 5.8.0
* @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.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:
* - `variables`: only the CSS Custom Properties for presets & custom ones.
* - `styles`: only the styles section in theme.json.
* - `presets`: only the classes for the presets.
* @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).
* The options currently supported are 'scope' that makes sure all style are scoped to a
* given selector, and root_selector which overwrites and forces a given selector to be
* used on the root node.
* The options currently supported are:
* - 'scope' that makes sure all style are scoped to a given selector
* - `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.
Comment on lines +1225 to +1228
Copy link
Member

Choose a reason for hiding this comment

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

Need some space to align the document.

* @return string The resulting stylesheet.
*/
public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' ), $origins = null, $options = array() ) {
Expand Down Expand Up @@ -1220,7 +1278,7 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets'
}

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_block_classes( $style_nodes );
Expand Down Expand Up @@ -3114,6 +3172,7 @@ protected static function filter_slugs( $node, $slugs ) {
*
* @since 5.9.0
* @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.
* @return array Sanitized structure.
Expand Down Expand Up @@ -3175,6 +3234,29 @@ public static function remove_insecure_properties( $theme_json ) {
}

$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 ) ) {
_wp_array_set( $sanitized, $variation['path'], $variation_output );
}
Expand Down
1 change: 1 addition & 0 deletions src/wp-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@
require ABSPATH . WPINC . '/block-supports/utils.php';
require ABSPATH . WPINC . '/block-supports/align.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/colors.php';
require ABSPATH . WPINC . '/block-supports/custom-classname.php';
Expand Down
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,10 @@
{
"version": 3,
"blockTypes": [ "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,4 @@
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"version": 3,
"blockTypes": [ "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": 3,
"blockTypes": [ "core/group", "core/columns" ],
"styles": {
"color": {
"background": "midnightblue",
"text": "lightblue"
}
}
}
Loading
Loading