diff --git a/lib/block-supports/settings.php b/lib/block-supports/settings.php index 0e34c32a8b111a..05cfac8c6ff932 100644 --- a/lib/block-supports/settings.php +++ b/lib/block-supports/settings.php @@ -103,10 +103,8 @@ function _gutenberg_add_block_level_preset_styles( $pre_render, $block ) { ); $theme_json_object = new WP_Theme_JSON_Gutenberg( $theme_json_shape ); - $styles = ''; - // include preset css variables declaration on the stylesheet. - $styles .= $theme_json_object->get_stylesheet( + $theme_json_object->add_stylesheet_to_rules_store( array( 'variables' ), null, array( @@ -116,7 +114,7 @@ function _gutenberg_add_block_level_preset_styles( $pre_render, $block ) { ); // include preset css classes on the the stylesheet. - $styles .= $theme_json_object->get_stylesheet( + $theme_json_object->add_stylesheet_to_rules_store( array( 'presets' ), null, array( @@ -125,10 +123,6 @@ function _gutenberg_add_block_level_preset_styles( $pre_render, $block ) { ) ); - if ( ! empty( $styles ) ) { - gutenberg_enqueue_block_support_styles( $styles ); - } - return null; } diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 9a9aad754227a1..1de2007adaabba 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -582,20 +582,30 @@ public static function get_element_class_name( $element ) { */ const LATEST_SCHEMA = 2; + /** + * The style-engine global styles rules store. + * + * @since 6.3.0 + * @var WP_Style_Engine_CSS_Rules_Store + */ + private $rules_store; + /** * Constructor. * * @since 5.8.0 * - * @param array $theme_json A structure that follows the theme.json schema. - * @param string $origin Optional. What source of data this object represents. - * One of 'default', 'theme', or 'custom'. Default 'theme'. + * @param array $theme_json A structure that follows the theme.json schema. + * @param string $origin Optional. What source of data this object represents. + * One of 'default', 'theme', or 'custom'. Default 'theme'. + * @param string $rules_store Optional. The name of the CSS rules-store to use. */ - public function __construct( $theme_json = array(), $origin = 'theme' ) { + public function __construct( $theme_json = array(), $origin = 'theme', $rules_store = 'global-styles' ) { if ( ! in_array( $origin, static::VALID_ORIGINS, true ) ) { $origin = 'theme'; } + $this->rules_store = WP_Style_Engine_CSS_Rules_Store::get_store( $rules_store ); $this->theme_json = WP_Theme_JSON_Schema::migrate( $theme_json ); $registry = WP_Block_Type_Registry::get_instance(); $valid_block_names = array_keys( $registry->get_all_registered() ); @@ -998,6 +1008,34 @@ public function get_settings() { * @return string The resulting stylesheet. */ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' ), $origins = null, $options = array() ) { + $this->add_stylesheet_to_rules_store( $types, $origins, $options ); + return $this->get_styles_from_rules_store(); + } + + /** + * Get the styles from the rules store. + * + * @since 6.3.0 + */ + public function get_styles_from_rules_store() { + return ( new WP_Style_Engine_Processor() )->add_store( $this->rules_store )->get_css(); + } + + /** + * Adds the styles that result of processing the theme.json structure this object represents. + * + * @since 6.3.0 + * + * @param array $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 array $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. + */ + public function add_stylesheet_to_rules_store( $types = array( 'variables', 'styles', 'presets' ), $origins = null, $options = array() ) { if ( null === $origins ) { $origins = static::VALID_ORIGINS; } @@ -1039,17 +1077,16 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' } } - $stylesheet = ''; - if ( in_array( 'variables', $types, true ) ) { - $stylesheet .= $this->get_css_variables( $setting_nodes, $origins ); + $this->add_css_variables_to_store( $setting_nodes, $origins ); } if ( in_array( 'styles', $types, true ) ) { if ( false !== $root_style_key ) { - $stylesheet .= $this->get_root_layout_rules( $style_nodes[ $root_style_key ]['selector'], $style_nodes[ $root_style_key ] ); + $this->add_root_layout_rules_declarations_to_rules_store( $style_nodes[ $root_style_key ]['selector'], $style_nodes[ $root_style_key ] ); + $this->add_layout_styles_to_rules_store( $style_nodes[ $root_style_key ] ); } - $stylesheet .= $this->get_block_classes( $style_nodes ); + $this->add_block_classes_to_rules_store( $style_nodes ); } elseif ( in_array( 'base-layout-styles', $types, true ) ) { $root_selector = static::ROOT_BLOCK_SELECTOR; $columns_selector = '.wp-block-columns'; @@ -1075,15 +1112,13 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' ); foreach ( $base_styles_nodes as $base_style_node ) { - $stylesheet .= $this->get_layout_styles( $base_style_node ); + $this->add_layout_styles_to_rules_store( $base_style_node ); } } if ( in_array( 'presets', $types, true ) ) { - $stylesheet .= $this->get_preset_classes( $setting_nodes, $origins ); + $this->add_preset_classes_to_rules_store( $setting_nodes, $origins ); } - - return $stylesheet; } /** @@ -1181,6 +1216,22 @@ public function get_template_parts() { return $template_parts; } + /** + * Add block classes to the $rules_store. + * + * @since 6.3.0 + * + * @param array $style_nodes Nodes with styles. + */ + protected function add_block_classes_to_rules_store( $style_nodes ) { + foreach ( $style_nodes as $metadata ) { + if ( null === $metadata['selector'] ) { + continue; + } + static::add_styles_for_block_to_rules_store( $metadata ); + } + } + /** * Converts each style section into a list of rulesets * containing the block styles to be appended to the stylesheet. @@ -1203,16 +1254,8 @@ public function get_template_parts() { * @return string The new stylesheet. */ protected function get_block_classes( $style_nodes ) { - $block_rules = ''; - - foreach ( $style_nodes as $metadata ) { - if ( null === $metadata['selector'] ) { - continue; - } - $block_rules .= static::get_styles_for_block( $metadata ); - } - - return $block_rules; + // @TODO: Deprecate. + return ''; } /** @@ -1224,18 +1267,29 @@ protected function get_block_classes( $style_nodes ) { * @return string Layout styles for the block. */ protected function get_layout_styles( $block_metadata ) { - $block_rules = ''; - $block_type = null; + // @TODO: Deprecate. + return ''; + } + + /** + * Adds the CSS layout rules for a particular block from theme.json layout definitions. + * + * @since 6.3.0 + * + * @param array $block_metadata Metadata about the block to get styles for. + */ + public function add_layout_styles_to_rules_store( $block_metadata ) { + $block_type = null; // Skip outputting layout styles if explicitly disabled. if ( current_theme_supports( 'disable-layout-styles' ) ) { - return $block_rules; + return ''; } if ( isset( $block_metadata['name'] ) ) { $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block_metadata['name'] ); if ( ! block_has_support( $block_type, array( '__experimentalLayout' ), false ) ) { - return $block_rules; + return ''; } } @@ -1298,10 +1352,7 @@ protected function get_layout_styles( $block_metadata ) { foreach ( $spacing_rule['rules'] as $css_property => $css_value ) { $current_css_value = is_string( $css_value ) ? $css_value : $block_gap_value; if ( static::is_safe_css_declaration( $css_property, $current_css_value ) ) { - $declarations[] = array( - 'name' => $css_property, - 'value' => $current_css_value, - ); + $declarations[ $css_property ] = $current_css_value; } } @@ -1323,7 +1374,9 @@ protected function get_layout_styles( $block_metadata ) { $spacing_rule['selector'] ); } - $block_rules .= static::to_ruleset( $layout_selector, $declarations ); + $this->rules_store + ->add_rule( $layout_selector ) + ->add_declarations( $declarations ); } } } @@ -1350,20 +1403,9 @@ protected function get_layout_styles( $block_metadata ) { is_string( $layout_definition['displayMode'] ) && in_array( $layout_definition['displayMode'], $valid_display_modes, true ) ) { - $layout_selector = sprintf( - '%s .%s', - $selector, - $class_name - ); - $block_rules .= static::to_ruleset( - $layout_selector, - array( - array( - 'name' => 'display', - 'value' => $layout_definition['displayMode'], - ), - ) - ); + $this->rules_store + ->add_rule( "{$selector} .{$class_name}" ) + ->add_declarations( array( 'display' => $layout_definition['displayMode'] ) ); } foreach ( $base_style_rules as $base_style_rule ) { @@ -1376,26 +1418,18 @@ protected function get_layout_styles( $block_metadata ) { ) { foreach ( $base_style_rule['rules'] as $css_property => $css_value ) { if ( static::is_safe_css_declaration( $css_property, $css_value ) ) { - $declarations[] = array( - 'name' => $css_property, - 'value' => $css_value, - ); + $declarations[ $css_property ] = $css_value; } } - $layout_selector = sprintf( - '%s .%s%s', - $selector, - $class_name, - $base_style_rule['selector'] - ); - $block_rules .= static::to_ruleset( $layout_selector, $declarations ); + $this->rules_store + ->add_rule( "{$selector} .{$class_name}{$base_style_rule['selector']}" ) + ->add_declarations( $declarations ); } } } } } - return $block_rules; } /** @@ -1428,19 +1462,32 @@ protected function get_layout_styles( $block_metadata ) { * @return string The new stylesheet. */ protected function get_preset_classes( $setting_nodes, $origins ) { - $preset_rules = ''; + // @TODO: Deprecate. + return ''; + } + /** + * Adds new rulesets to the rules store for each preset value. + * + * @since 6.3.0 + * + * @param array $setting_nodes Nodes with settings. + * @param array $origins List of origins to process presets from. + */ + protected function add_preset_classes_to_rules_store( $setting_nodes, $origins ) { foreach ( $setting_nodes as $metadata ) { if ( null === $metadata['selector'] ) { continue; } - $selector = $metadata['selector']; - $node = _wp_array_get( $this->theme_json, $metadata['path'], array() ); - $preset_rules .= static::compute_preset_classes( $node, $selector, $origins ); - } + $selector = $metadata['selector']; + $node = _wp_array_get( $this->theme_json, $metadata['path'], array() ); - return $preset_rules; + $preset_classes_declarations = static::compute_preset_classes_declarations( $node, $selector, $origins ); + foreach ( $preset_classes_declarations as $selector => $declarations ) { + $this->rules_store->add_rule( $selector )->add_declarations( $declarations ); + } + } } /** @@ -1465,25 +1512,39 @@ protected function get_preset_classes( $setting_nodes, $origins ) { * @return string The new stylesheet. */ protected function get_css_variables( $nodes, $origins ) { - $stylesheet = ''; + // @TODO: Deprecate. + return ''; + } + + /** + * Converts each styles section into a list of rulesets, and adds them to the rules store. + * + * @since 6.3.0 Added the `$origins` parameter. + * + * @param array $nodes Nodes with settings. + * @param array $origins List of origins to process. + * @return void + */ + protected function add_css_variables_to_store( $nodes, $origins ) { foreach ( $nodes as $metadata ) { + $declarations = array(); if ( null === $metadata['selector'] ) { continue; } $selector = $metadata['selector']; - $node = _wp_array_get( $this->theme_json, $metadata['path'], array() ); - $declarations = static::compute_preset_vars( $node, $origins ); + $node = _wp_array_get( $this->theme_json, $metadata['path'], array() ); + $presets_declarations = static::compute_preset_vars( $node, $origins ); + foreach ( $presets_declarations as $preset_declaration ) { + $declarations[ $preset_declaration['name'] ] = $preset_declaration['value']; + } $theme_vars_declarations = static::compute_theme_vars( $node ); - foreach ( $theme_vars_declarations as $theme_vars_declaration ) { - $declarations[] = $theme_vars_declaration; + foreach ( $theme_vars_declarations as $theme_declaration ) { + $declarations[ $theme_declaration['name'] ] = $theme_declaration['value']; } - - $stylesheet .= static::to_ruleset( $selector, $declarations ); + $this->rules_store->add_rule( $selector )->add_declarations( $declarations ); } - - return $stylesheet; } /** @@ -1511,6 +1572,20 @@ static function ( $carry, $element ) { return $selector . '{' . $declaration_block . '}'; } + /** + * Converts the named declarations array to a simpler property=>value array. + * + * @param array $declarations Named declarations. + * @return array Property=>value declarations. + */ + protected static function to_simple_declarations( $declarations ) { + $simple_declarations = array(); + foreach ( $declarations as $declaration ) { + $simple_declarations[ $declaration['name'] ] = $declaration['value']; + } + return $simple_declarations; + } + /** * Given a settings array, returns the generated rulesets * for the preset classes. @@ -1524,33 +1599,46 @@ static function ( $carry, $element ) { * @return string The result of processing the presets. */ protected static function compute_preset_classes( $settings, $selector, $origins ) { + // @TODO: Deprecate + return ''; + } + + /** + * Given a settings array, returns the generated rulesets + * for the preset classes. + * + * @since 6.3.0 + * + * @param array $settings Settings to process. + * @param string $selector Selector wrapping the classes. + * @param array $origins List of origins to process. + * @return array The result of processing the presets. + */ + protected static function compute_preset_classes_declarations( $settings, $selector, $origins ) { + $declarations = array(); if ( static::ROOT_BLOCK_SELECTOR === $selector ) { // Classes at the global level do not need any CSS prefixed, // and we don't want to increase its specificity. $selector = ''; } - $stylesheet = ''; + $declarations = array(); foreach ( static::PRESETS_METADATA as $preset_metadata ) { $slugs = static::get_settings_slugs( $settings, $preset_metadata, $origins ); foreach ( $preset_metadata['classes'] as $class => $property ) { foreach ( $slugs as $slug ) { - $css_var = static::replace_slug_in_string( $preset_metadata['css_vars'], $slug ); - $class_name = static::replace_slug_in_string( $class, $slug ); - $stylesheet .= static::to_ruleset( - static::append_to_selector( $selector, $class_name ), - array( - array( - 'name' => $property, - 'value' => 'var(' . $css_var . ') !important', - ), - ) - ); + $css_var = static::replace_slug_in_string( $preset_metadata['css_vars'], $slug ); + $class_name = static::replace_slug_in_string( $class, $slug ); + + $declaration_selector = static::append_to_selector( $selector, $class_name ); + $declarations[ $declaration_selector ] = empty( $declarations[ $declaration_selector ] ) ? array() : $declarations[ $declaration_selector ]; + + $declarations[ $declaration_selector ][ $property ] = 'var(' . $css_var . ') !important'; } } } - return $stylesheet; + return $declarations; } /** @@ -2477,7 +2565,7 @@ function( $pseudo_selector ) use ( $selector ) { static::ROOT_BLOCK_SELECTOR !== $selector && ! empty( $block_metadata['name'] ) ) { - $block_rules .= $this->get_layout_styles( $block_metadata ); + $this->add_layout_styles_to_rules_store( $block_metadata ); } // 5. Generate and append the feature level rulesets. @@ -2493,6 +2581,211 @@ function( $pseudo_selector ) use ( $selector ) { return $block_rules; } + /** + * Add the CSS rules for a particular block from theme.json to the $rules_store. + * + * @since 6.3.0 + * + * @param array $block_metadata Metadata about the block to get styles for. + */ + public function add_styles_for_block_to_rules_store( $block_metadata ) { + $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() ); + $use_root_padding = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments']; + $selector = $block_metadata['selector']; + $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); + + /* + * Process style declarations for block support features the current + * block contains selectors for. Values for a feature with a custom + * selector are filtered from the theme.json node before it is + * processed as normal. + */ + $feature_declarations = array(); + + if ( ! empty( $block_metadata['features'] ) ) { + foreach ( $block_metadata['features'] as $feature_name => $feature_selector ) { + if ( ! empty( $node[ $feature_name ] ) ) { + // Create temporary node containing only the feature data + // to leverage existing `compute_style_properties` function. + $feature = array( $feature_name => $node[ $feature_name ] ); + // Generate the feature's declarations only. + $new_feature_declarations = static::compute_style_properties( $feature, $settings, null, $this->theme_json ); + + // Merge new declarations with any that already exist for + // the feature selector. This may occur when multiple block + // support features use the same custom selector. + if ( isset( $feature_declarations[ $feature_selector ] ) ) { + foreach ( $new_feature_declarations as $new_feature_declaration ) { + $feature_declarations[ $feature_selector ][] = $new_feature_declaration; + } + } else { + $feature_declarations[ $feature_selector ] = $new_feature_declarations; + } + + // Remove the feature from the block's node now the + // styles will be included under the feature level selector. + unset( $node[ $feature_name ] ); + } + } + } + + // If there are style variations, generate the declarations for them, including any feature selectors the block may have. + $style_variation_declarations = array(); + if ( ! empty( $block_metadata['variations'] ) ) { + foreach ( $block_metadata['variations'] as $style_variation ) { + $style_variation_node = _wp_array_get( $this->theme_json, $style_variation['path'], array() ); + $style_variation_selector = $style_variation['selector']; + + // If the block has feature selectors, generate the declarations for them within the current style variation. + if ( ! empty( $block_metadata['features'] ) ) { + $clean_style_variation_selector = trim( $style_variation_selector ); + foreach ( $block_metadata['features'] as $feature_name => $feature_selector ) { + if ( empty( $style_variation_node[ $feature_name ] ) ) { + continue; + } + // If feature selector includes block classname, remove it but leave the whitespace in. + $shortened_feature_selector = str_replace( $block_metadata['selector'] . ' ', ' ', $feature_selector ); + // Prepend the variation selector to the feature selector. + $split_feature_selectors = explode( ',', $shortened_feature_selector ); + $feature_selectors = array_map( + static function( $split_feature_selector ) use ( $clean_style_variation_selector ) { + return $clean_style_variation_selector . $split_feature_selector; + }, + $split_feature_selectors + ); + $combined_feature_selectors = implode( ',', $feature_selectors ); + + // Compute declarations for the feature. + $new_feature_declarations = static::compute_style_properties( array( $feature_name => $style_variation_node[ $feature_name ] ), $settings, null, $this->theme_json ); + + /* + * Merge new declarations with any that already exist for + * the feature selector. This may occur when multiple block + * support features use the same custom selector. + */ + if ( isset( $style_variation_declarations[ $combined_feature_selectors ] ) ) { + $style_variation_declarations[ $combined_feature_selectors ] = array_merge( $style_variation_declarations[ $combined_feature_selectors ], $new_feature_declarations ); + } else { + $style_variation_declarations[ $combined_feature_selectors ] = $new_feature_declarations; + } + + /* + * Remove the feature from the variation's node now the + * styles will be included under the feature level selector. + */ + unset( $style_variation_node[ $feature_name ] ); + } + } + // Compute declarations for remaining styles not covered by feature level selectors. + $style_variation_declarations[ $style_variation_selector ] = static::compute_style_properties( $style_variation_node, $settings, null, $this->theme_json ); + } + } + + /* + * Get a reference to element name from path. + * $block_metadata['path'] = array( 'styles','elements','link' ); + * Make sure that $block_metadata['path'] describes an element node, like [ 'styles', 'element', 'link' ]. + * Skip non-element paths like just ['styles']. + */ + $is_processing_element = in_array( 'elements', $block_metadata['path'], true ); + + $current_element = $is_processing_element ? $block_metadata['path'][ count( $block_metadata['path'] ) - 1 ] : null; + + $element_pseudo_allowed = array(); + + // TODO: Replace array_key_exists() with isset() check once WordPress drops + // support for PHP 5.6. See https://core.trac.wordpress.org/ticket/57067. + if ( array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) { + $element_pseudo_allowed = static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ]; + } + + /* + * Check for allowed pseudo classes (e.g. ":hover") from the $selector ("a:hover"). + * This also resets the array keys. + */ + $pseudo_matches = array_values( + array_filter( + $element_pseudo_allowed, + function( $pseudo_selector ) use ( $selector ) { + return str_contains( $selector, $pseudo_selector ); + } + ) + ); + + $pseudo_selector = isset( $pseudo_matches[0] ) ? $pseudo_matches[0] : null; + + /* + * If the current selector is a pseudo selector that's defined in the allow list for the current + * element then compute the style properties for it. + * Otherwise just compute the styles for the default selector as normal. + */ + if ( $pseudo_selector && isset( $node[ $pseudo_selector ] ) && + // TODO: Replace array_key_exists() with isset() check once WordPress drops + // support for PHP 5.6. See https://core.trac.wordpress.org/ticket/57067. + array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) + && in_array( $pseudo_selector, static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ], true ) + ) { + $declarations = static::compute_style_properties( $node[ $pseudo_selector ], $settings, null, $this->theme_json, $selector, $use_root_padding ); + } else { + $declarations = static::compute_style_properties( $node, $settings, null, $this->theme_json, $selector, $use_root_padding ); + } + + /* + * 1. Separate the declarations that use the general selector + * from the ones using the duotone selector. + */ + $declarations_duotone = array(); + foreach ( $declarations as $index => $declaration ) { + if ( 'filter' === $declaration['name'] ) { + /* + * 'unset' filters happen when a filter is unset + * in the site-editor UI. Because the 'unset' value + * in the user origin overrides the value in the + * theme origin, we can skip rendering anything + * here as no filter needs to be applied anymore. + * So only add declarations to with values other + * than 'unset'. + */ + if ( 'unset' !== $declaration['value'] ) { + $declarations_duotone[] = $declaration; + } + unset( $declarations[ $index ] ); + } + } + + // Update declarations if there are separators with only background color defined. + if ( '.wp-block-separator' === $selector ) { + $declarations = static::update_separator_declarations( $declarations ); + } + + // 2. Generate and append the rules that use the general selector. + $this->rules_store->add_rule( $selector )->add_declarations( static::to_simple_declarations( $declarations ) ); + + // 3. Generate and append the rules that use the duotone selector. + if ( isset( $block_metadata['duotone'] ) && ! empty( $declarations_duotone ) ) { + $selector_duotone = static::scope_selector( $block_metadata['selector'], $block_metadata['duotone'] ); + $this->rules_store->add_rule( $selector_duotone )->add_declarations( static::to_simple_declarations( $declarations_duotone ) ); + } + + // 4. Generate Layout block gap styles. + if ( + static::ROOT_BLOCK_SELECTOR !== $selector && + ! empty( $block_metadata['name'] ) + ) { + $this->add_layout_styles_to_rules_store( $block_metadata ); + } + + // 5. Generate and append the feature level rulesets. + foreach ( $feature_declarations as $feature_selector => $individual_feature_declarations ) { + $this->rules_store->add_rule( $feature_selector )->add_declarations( static::to_simple_declarations( $individual_feature_declarations ) ); + } + + // 6. Generate and append the style variation rulesets. + foreach ( $style_variation_declarations as $style_variation_selector => $individual_style_variation_declarations ) { + $this->rules_store->add_rule( $style_variation_selector )->add_declarations( static::to_simple_declarations( $individual_style_variation_declarations ) ); + } + } + /** * Outputs the CSS for layout rules on the root. * @@ -2503,7 +2796,19 @@ function( $pseudo_selector ) use ( $selector ) { * @return string The additional root rules CSS. */ public function get_root_layout_rules( $selector, $block_metadata ) { - $css = ''; + + // @TODO: Deprecate. + return ''; + } + + /** + * Outputs the CSS declarations for layout rules on the root. + * + * @since 6.3.0 + * + * @param string $selector The root node selector. + */ + public function add_root_layout_rules_declarations_to_rules_store( $selector ) { $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); $use_root_padding = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments']; @@ -2515,7 +2820,7 @@ public function get_root_layout_rules( $selector, $block_metadata ) { * user-generated values take precedence in the CSS cascade. * @link https://github.com/WordPress/gutenberg/issues/36147. */ - $css .= 'body { margin: 0;'; + $this->rules_store->add_rule( 'body' )->add_declarations( array( 'margin' => '0' ) ); /* * If there are content and wide widths in theme.json, output them @@ -2526,46 +2831,106 @@ public function get_root_layout_rules( $selector, $block_metadata ) { $content_size = static::is_safe_css_declaration( 'max-width', $content_size ) ? $content_size : 'initial'; $wide_size = isset( $settings['layout']['wideSize'] ) ? $settings['layout']['wideSize'] : $settings['layout']['contentSize']; $wide_size = static::is_safe_css_declaration( 'max-width', $wide_size ) ? $wide_size : 'initial'; - $css .= '--wp--style--global--content-size: ' . $content_size . ';'; - $css .= '--wp--style--global--wide-size: ' . $wide_size . ';'; - } - $css .= '}'; + $this->rules_store->add_rule( 'body' )->add_declarations( + array( + '--wp--style--global--content-size' => $content_size, + '--wp--style--global--wide-size' => $wide_size, + ) + ); + } if ( $use_root_padding ) { // Top and bottom padding are applied to the outer block container. - $css .= '.wp-site-blocks { padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom); }'; + $this->rules_store->add_rule( '.wp-site-blocks' )->add_declarations( + array( + 'padding-top' => 'var(--wp--style--root--padding-top)', + 'padding-bottom' => 'var(--wp--style--root--padding-bottom)', + ) + ); // Right and left padding are applied to the first container with `.has-global-padding` class. - $css .= '.has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }'; + $this->rules_store->add_rule( '.has-global-padding' )->add_declarations( + array( + 'padding-right' => 'var(--wp--style--root--padding-right)', + 'padding-left' => 'var(--wp--style--root--padding-left)', + ) + ); // Nested containers with `.has-global-padding` class do not get padding. - $css .= '.has-global-padding :where(.has-global-padding) { padding-right: 0; padding-left: 0; }'; + $this->rules_store->add_rule( '.has-global-padding :where(.has-global-padding)' )->add_declarations( + array( + 'padding-right' => '0', + 'padding-left' => '0', + ) + ); // Alignfull children of the container with left and right padding have negative margins so they can still be full width. - $css .= '.has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); }'; + $this->rules_store->add_rule( '.has-global-padding > .alignfull' )->add_declarations( + array( + 'margin-right' => 'calc(var(--wp--style--root--padding-right) * -1)', + 'margin-left' => 'calc(var(--wp--style--root--padding-left) * -1)', + ) + ); // The above rule is negated for alignfull children of nested containers. - $css .= '.has-global-padding :where(.has-global-padding) > .alignfull { margin-right: 0; margin-left: 0; }'; + $this->rules_store->add_rule( '.has-global-padding :where(.has-global-padding) > .alignfull' )->add_declarations( + array( + 'margin-right' => '0', + 'margin-left' => '0', + ) + ); // Some of the children of alignfull blocks without content width should also get padding: text blocks and non-alignfull container blocks. - $css .= '.has-global-padding > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),.wp-block:not(.alignfull),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }'; + $this->rules_store->add_rule( '.has-global-padding > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),.wp-block:not(.alignfull),p,h1,h2,h3,h4,h5,h6,ul,ol)' )->add_declarations( + array( + 'padding-right' => 'var(--wp--style--root--padding-right)', + 'padding-left' => 'var(--wp--style--root--padding-left)', + ) + ); // The above rule also has to be negated for blocks inside nested `.has-global-padding` blocks. - $css .= '.has-global-padding :where(.has-global-padding) > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),.wp-block:not(.alignfull),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: 0; padding-left: 0; }'; + $this->rules_store->add_rule( '.has-global-padding :where(.has-global-padding) > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),.wp-block:not(.alignfull),p,h1,h2,h3,h4,h5,h6,ul,ol)' )->add_declarations( + array( + 'padding-right' => '0', + 'padding-left' => '0', + ) + ); } - $css .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }'; - $css .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }'; - $css .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + $this->rules_store->add_rule( '.wp-site-blocks > .alignleft' )->add_declarations( + array( + 'float' => 'left', + 'margin-right' => '2em', + ) + ); + $this->rules_store->add_rule( '.wp-site-blocks > .alignright' )->add_declarations( + array( + 'float' => 'right', + 'margin-left' => '2em', + ) + ); + $this->rules_store->add_rule( '.wp-site-blocks > .aligncenter' )->add_declarations( + array( + 'justify-content' => 'center', + 'margin-left' => 'auto', + 'margin-right' => 'auto', + ) + ); $block_gap_value = _wp_array_get( $this->theme_json, array( 'styles', 'spacing', 'blockGap' ), '0.5em' ); $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null; if ( $has_block_gap_support ) { $block_gap_value = static::get_property_value( $this->theme_json, array( 'styles', 'spacing', 'blockGap' ) ); - $css .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }'; - $css .= ".wp-site-blocks > * + * { margin-block-start: $block_gap_value; }"; + $this->rules_store->add_rule( '.wp-site-blocks > *' )->add_declarations( + array( + 'margin-block-start' => '0', + 'margin-block-end' => '0', + ) + ); + $this->rules_store->add_rule( '.wp-site-blocks > * + *' )->add_declarations( + array( + 'margin-block-start' => $block_gap_value, + ) + ); // For backwards compatibility, ensure the legacy block gap CSS variable is still available. - $css .= "$selector { --wp--style--block-gap: $block_gap_value; }"; + $this->rules_store->add_rule( $selector )->add_declarations( array( '--wp--style--block-gap' => $block_gap_value ) ); } - $css .= $this->get_layout_styles( $block_metadata ); - - return $css; } /** diff --git a/lib/compat/wordpress-6.1/get-global-styles-and-settings.php b/lib/compat/wordpress-6.1/get-global-styles-and-settings.php index fd6113c7405c4a..e3b29953bd3b87 100644 --- a/lib/compat/wordpress-6.1/get-global-styles-and-settings.php +++ b/lib/compat/wordpress-6.1/get-global-styles-and-settings.php @@ -9,48 +9,5 @@ * Adds global style rules to the inline style for each block. */ function gutenberg_add_global_styles_for_blocks() { - $tree = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data(); - $block_nodes = $tree->get_styles_block_nodes(); - foreach ( $block_nodes as $metadata ) { - $block_css = $tree->get_styles_for_block( $metadata ); - - if ( ! wp_should_load_separate_core_block_assets() ) { - wp_add_inline_style( 'global-styles', $block_css ); - continue; - } - - $stylesheet_handle = 'global-styles'; - if ( isset( $metadata['name'] ) ) { - // These block styles are added on block_render. - // This hooks inline CSS to them so that they are loaded conditionally - // based on whether or not the block is used on the page. - if ( str_starts_with( $metadata['name'], 'core/' ) ) { - $block_name = str_replace( 'core/', '', $metadata['name'] ); - $stylesheet_handle = 'wp-block-' . $block_name; - } - wp_add_inline_style( $stylesheet_handle, $block_css ); - } - - // The likes of block element styles from theme.json do not have $metadata['name'] set. - if ( ! isset( $metadata['name'] ) && ! empty( $metadata['path'] ) ) { - $result = array_values( - array_filter( - $metadata['path'], - function ( $item ) { - if ( str_contains( $item, 'core/' ) ) { - return true; - } - return false; - } - ) - ); - if ( isset( $result[0] ) ) { - if ( str_starts_with( $result[0], 'core/' ) ) { - $block_name = str_replace( 'core/', '', $result[0] ); - $stylesheet_handle = 'wp-block-' . $block_name; - } - wp_add_inline_style( $stylesheet_handle, $block_css ); - } - } - } + // @TODO: Deprecate. } diff --git a/lib/compat/wordpress-6.1/script-loader.php b/lib/compat/wordpress-6.1/script-loader.php index 4948882c113a88..09d8a9225853c1 100644 --- a/lib/compat/wordpress-6.1/script-loader.php +++ b/lib/compat/wordpress-6.1/script-loader.php @@ -68,9 +68,6 @@ function gutenberg_enqueue_global_styles() { wp_register_style( 'global-styles', false, array(), true, true ); wp_add_inline_style( 'global-styles', $stylesheet ); wp_enqueue_style( 'global-styles' ); - - // add each block as an inline css. - gutenberg_add_global_styles_for_blocks(); } remove_action( 'wp_enqueue_scripts', 'wp_enqueue_global_styles' ); diff --git a/lib/compat/wordpress-6.2/get-global-styles-and-settings.php b/lib/compat/wordpress-6.2/get-global-styles-and-settings.php index e02a0466a0b98f..7f3dda0360990f 100644 --- a/lib/compat/wordpress-6.2/get-global-styles-and-settings.php +++ b/lib/compat/wordpress-6.2/get-global-styles-and-settings.php @@ -128,7 +128,6 @@ function gutenberg_get_global_stylesheet( $types = array() ) { * they can override the default presets. * See https://core.trac.wordpress.org/ticket/54782 */ - $styles_variables = ''; if ( in_array( 'variables', $types, true ) ) { /* * We only use the default, theme, and custom origins. @@ -136,9 +135,9 @@ function gutenberg_get_global_stylesheet( $types = array() ) { * at a later phase (render cycle) so we only render the ones in use. * @see wp_add_global_styles_for_blocks */ - $origins = array( 'default', 'theme', 'custom' ); - $styles_variables = $tree->get_stylesheet( array( 'variables' ), $origins ); - $types = array_diff( $types, array( 'variables' ) ); + $origins = array( 'default', 'theme', 'custom' ); + $tree->add_stylesheet_to_rules_store( array( 'variables' ), $origins ); + $types = array_diff( $types, array( 'variables' ) ); } /* @@ -147,7 +146,6 @@ function gutenberg_get_global_stylesheet( $types = array() ) { * - themes without theme.json: only the classes for the presets defined by core * - themes with theme.json: the presets and styles classes, both from core and the theme */ - $styles_rest = ''; if ( ! empty( $types ) ) { /* * We only use the default, theme, and custom origins. @@ -159,9 +157,15 @@ function gutenberg_get_global_stylesheet( $types = array() ) { if ( ! $supports_theme_json ) { $origins = array( 'default' ); } - $styles_rest = $tree->get_stylesheet( $types, $origins ); + $tree->add_stylesheet_to_rules_store( $types, $origins ); + } + + $block_nodes = $tree->get_styles_block_nodes(); + foreach ( $block_nodes as $metadata ) { + $tree->add_styles_for_block_to_rules_store( $metadata ); } - $stylesheet = $styles_variables . $styles_rest; + + $stylesheet = $tree->get_styles_from_rules_store(); if ( $can_use_cached ) { wp_cache_set( $cache_key, $stylesheet, $cache_group ); } diff --git a/lib/compat/wordpress-6.3/blocks.php b/lib/compat/wordpress-6.3/blocks.php new file mode 100644 index 00000000000000..1f1ebee7179c0f --- /dev/null +++ b/lib/compat/wordpress-6.3/blocks.php @@ -0,0 +1,43 @@ += 6.1. + * + * @param string[] $attrs Array of allowed CSS attributes. + * @return string[] CSS attributes. + */ +function gutenberg_safe_style_attrs_6_3( $attrs ) { + $attrs[] = 'display'; + return $attrs; +} +add_filter( 'safe_style_css', 'gutenberg_safe_style_attrs_6_3' ); + +/** + * Update allowed CSS values to match WordPress 6.1. + * + * Note: This should be removed when the minimum required WP version is >= 6.1. + * + * The logic in this function follows that provided in: https://core.trac.wordpress.org/ticket/55966. + * + * @param boolean $allow_css Whether or not the current test string is allowed. + * @param string $css_test_string The CSS string to be tested. + * @return boolean + */ +function gutenberg_safecss_filter_attr_allow_css_6_3( $allow_css, $css_test_string ) { + if ( false === $allow_css ) { + // Allow all "display" values EXCEPT "none". + if ( str_starts_with( $css_test_string, 'display:' ) && str_contains( $css_test_string, 'none' ) ) { + return false; + } + return $allow_css; + } + return $allow_css; +} +add_filter( 'safecss_filter_attr_allow_css', 'gutenberg_safecss_filter_attr_allow_css_6_3', 10, 2 ); diff --git a/lib/load.php b/lib/load.php index a5be015320652f..eac04e7ad6b969 100644 --- a/lib/load.php +++ b/lib/load.php @@ -52,6 +52,7 @@ function gutenberg_is_experiment_enabled( $name ) { require_once __DIR__ . '/compat/wordpress-6.3/class-gutenberg-rest-pattern-directory-controller-6-3.php'; require_once __DIR__ . '/compat/wordpress-6.3/class-gutenberg-rest-templates-controller-6-3.php'; require_once __DIR__ . '/compat/wordpress-6.3/rest-api.php'; + require_once __DIR__ . '/compat/wordpress-6.3/blocks.php'; // Experimental. if ( ! class_exists( 'WP_Rest_Customizer_Nonces' ) ) { diff --git a/packages/style-engine/class-wp-style-engine-css-declarations.php b/packages/style-engine/class-wp-style-engine-css-declarations.php index 6e7fdfc58e08ff..506a4d6030a2ef 100644 --- a/packages/style-engine/class-wp-style-engine-css-declarations.php +++ b/packages/style-engine/class-wp-style-engine-css-declarations.php @@ -157,6 +157,11 @@ protected static function filter_declaration( $property, $value, $spacer = '' ) "{$property}:{$spacer}{$value}" : ''; } + // Allow `display` property to be used. + if ( 'display' === $property && '' !== $filtered_value ) { + return "display:{$spacer}{$filtered_value}"; + } + if ( '' !== $filtered_value ) { return safecss_filter_attr( "{$property}:{$spacer}{$filtered_value}" ); } diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index b46838c0275b1a..80e1e5f5145fad 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -60,12 +60,13 @@ public function test_get_stylesheet_generates_layout_styles( $layout_definitions ), ), ), - 'default' + 'default', + md5( 'test_get_stylesheet_generates_layout_styles' . json_encode( $layout_definitions ) ) ); // Results also include root site blocks styles. $this->assertEquals( - 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: 1em; }body { --wp--style--block-gap: 1em; }body .is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}body .is-layout-flow > * + *{margin-block-start: 1em;margin-block-end: 0;}body .is-layout-flex{gap: 1em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}', + 'body{margin:0;--wp--style--block-gap:1em;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}.wp-site-blocks > * + *{margin-block-start:1em;}body .is-layout-flow > * + *{margin-block-start:1em;margin-block-end:0;}body .is-layout-flex{gap:1em;display:flex;flex-wrap:wrap;align-items:center;}body .is-layout-flow > .alignleft{float:left;margin-inline-start:0;margin-inline-end:2em;}body .is-layout-flow > .alignright{float:right;margin-inline-start:2em;margin-inline-end:0;}body .is-layout-flow > .aligncenter{margin-left:auto !important;margin-right:auto !important;}.wp-site-blocks > *,body .is-layout-flow > *{margin-block-start:0;margin-block-end:0;}', $theme_json->get_stylesheet( array( 'styles' ) ) ); } @@ -115,11 +116,12 @@ public function test_get_stylesheet_generates_valid_block_gap_values_and_skips_n ), ), ), - 'default' + 'default', + md5( 'test_get_stylesheet_generates_valid_block_gap_values_and_skips_null_or_false_values' . json_encode( $layout_definitions ) ) ); $this->assertEquals( - 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: 1rem; }body { --wp--style--block-gap: 1rem; }body .is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}body .is-layout-flow > * + *{margin-block-start: 1rem;margin-block-end: 0;}body .is-layout-flex{gap: 1rem;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}.wp-block-post-content{color: gray;}.wp-block-social-links-is-layout-flow.wp-block-social-links-is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-social-links-is-layout-flow.wp-block-social-links-is-layout-flow > * + *{margin-block-start: 0;margin-block-end: 0;}.wp-block-social-links-is-layout-flex.wp-block-social-links-is-layout-flex{gap: 0;}.wp-block-buttons-is-layout-flow.wp-block-buttons-is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-buttons-is-layout-flow.wp-block-buttons-is-layout-flow > * + *{margin-block-start: 0;margin-block-end: 0;}.wp-block-buttons-is-layout-flex.wp-block-buttons-is-layout-flex{gap: 0;}', + 'body{margin:0;--wp--style--block-gap:1rem;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}.wp-site-blocks > * + *{margin-block-start:1rem;}body .is-layout-flow > * + *{margin-block-start:1rem;margin-block-end:0;}body .is-layout-flex{gap:1rem;display:flex;flex-wrap:wrap;align-items:center;}body .is-layout-flow > .alignleft{float:left;margin-inline-start:0;margin-inline-end:2em;}body .is-layout-flow > .alignright{float:right;margin-inline-start:2em;margin-inline-end:0;}body .is-layout-flow > .aligncenter{margin-left:auto !important;margin-right:auto !important;}.wp-block-post-content{color:gray;}.wp-site-blocks > *,body .is-layout-flow > *,.wp-block-social-links-is-layout-flow.wp-block-social-links-is-layout-flow > *,.wp-block-social-links-is-layout-flow.wp-block-social-links-is-layout-flow > * + *,.wp-block-buttons-is-layout-flow.wp-block-buttons-is-layout-flow > *,.wp-block-buttons-is-layout-flow.wp-block-buttons-is-layout-flow > * + *{margin-block-start:0;margin-block-end:0;}.wp-block-social-links-is-layout-flex.wp-block-social-links-is-layout-flex,.wp-block-buttons-is-layout-flex.wp-block-buttons-is-layout-flex{gap:0;}', $theme_json->get_stylesheet() ); } @@ -147,12 +149,13 @@ public function test_get_stylesheet_generates_layout_styles_with_spacing_presets ), ), ), - 'default' + 'default', + md5( 'test_get_stylesheet_generates_layout_styles_with_spacing_presets' . json_encode( $layout_definitions ) ) ); // Results also include root site blocks styles. $this->assertEquals( - 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: var(--wp--preset--spacing--60); }body { --wp--style--block-gap: var(--wp--preset--spacing--60); }body .is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}body .is-layout-flow > * + *{margin-block-start: var(--wp--preset--spacing--60);margin-block-end: 0;}body .is-layout-flex{gap: var(--wp--preset--spacing--60);}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}', + 'body{margin:0;--wp--style--block-gap:var(--wp--preset--spacing--60);}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}.wp-site-blocks > * + *{margin-block-start:var(--wp--preset--spacing--60);}body .is-layout-flow > * + *{margin-block-start:var(--wp--preset--spacing--60);margin-block-end:0;}body .is-layout-flex{gap:var(--wp--preset--spacing--60);display:flex;flex-wrap:wrap;align-items:center;}body .is-layout-flow > .alignleft{float:left;margin-inline-start:0;margin-inline-end:2em;}body .is-layout-flow > .alignright{float:right;margin-inline-start:2em;margin-inline-end:0;}body .is-layout-flow > .aligncenter{margin-left:auto !important;margin-right:auto !important;}.wp-site-blocks > *,body .is-layout-flow > *{margin-block-start:0;margin-block-end:0;}', $theme_json->get_stylesheet( array( 'styles' ) ) ); } @@ -180,13 +183,14 @@ public function test_get_stylesheet_generates_fallback_gap_layout_styles( $layou ), ), ), - 'default' + 'default', + md5( 'test_get_stylesheet_generates_fallback_gap_layout_styles' . json_encode( $layout_definitions ) ) ); $stylesheet = $theme_json->get_stylesheet( array( 'styles' ) ); // Results also include root site blocks styles. $this->assertEquals( - 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}', + 'body{margin:0;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}:where(.is-layout-flex){gap:0.5em;}body .is-layout-flow > .alignleft{float:left;margin-inline-start:0;margin-inline-end:2em;}body .is-layout-flow > .alignright{float:right;margin-inline-start:2em;margin-inline-end:0;}body .is-layout-flow > .aligncenter{margin-left:auto !important;margin-right:auto !important;}body .is-layout-flex{display:flex;flex-wrap:wrap;align-items:center;}', $stylesheet ); } @@ -209,13 +213,14 @@ public function test_get_stylesheet_generates_base_fallback_gap_layout_styles( $ ), ), ), - 'default' + 'default', + md5( 'test_get_stylesheet_generates_base_fallback_gap_layout_styles' . json_encode( $layout_definitions ) ) ); $stylesheet = $theme_json->get_stylesheet( array( 'base-layout-styles' ) ); // Note the `base-layout-styles` includes a fallback gap for the Columns block for backwards compatibility. $this->assertEquals( - ':where(.is-layout-flex){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}', + ':where(.is-layout-flex){gap:0.5em;}body .is-layout-flow > .alignleft{float:left;margin-inline-start:0;margin-inline-end:2em;}body .is-layout-flow > .alignright{float:right;margin-inline-start:2em;margin-inline-end:0;}body .is-layout-flow > .aligncenter{margin-left:auto !important;margin-right:auto !important;}body .is-layout-flex{display:flex;flex-wrap:wrap;align-items:center;}:where(.wp-block-columns.is-layout-flex){gap:2em;}', $stylesheet ); } @@ -239,7 +244,8 @@ public function test_get_stylesheet_skips_layout_styles( $layout_definitions ) { ), ), ), - 'default' + 'default', + md5( 'test_get_stylesheet_skips_layout_styles' . json_encode( $layout_definitions ) ) ); $stylesheet = $theme_json->get_stylesheet( array( 'base-layout-styles' ) ); remove_theme_support( 'disable-layout-styles' ); @@ -456,18 +462,14 @@ public function test_get_stylesheet() { ), ), 'misc' => 'value', - ) + ), + 'theme', + 'test_get_stylesheet' ); - $variables = 'body{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}'; - $styles = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{color: var(--wp--preset--color--grey);}a:where(:not(.wp-element-button)){background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;min-height: 50vh;padding: 24px;}.wp-block-group a:where(:not(.wp-element-button)){color: #111;}.wp-block-heading{color: #123456;}.wp-block-heading a:where(:not(.wp-element-button)){background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a:where(:not(.wp-element-button)){background-color: #777;color: #555;}.wp-block-post-excerpt{column-count: 2;}.wp-block-image{margin-bottom: 30px;}.wp-block-image img, .wp-block-image .wp-block-image__crop-area{border-top-left-radius: 10px;border-bottom-right-radius: 1em;}'; - $presets = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-small-font-family{font-family: var(--wp--preset--font-family--small) !important;}.has-big-font-family{font-family: var(--wp--preset--font-family--big) !important;}'; - $all = $variables . $styles . $presets; + $styles = 'body{--wp--preset--color--grey:grey;--wp--preset--font-family--small:14px;--wp--preset--font-family--big:41px;margin:0;color:var(--wp--preset--color--grey);}.wp-block-group{--wp--custom--base-font:16;--wp--custom--line-height--small:1.2;--wp--custom--line-height--medium:1.4;--wp--custom--line-height--large:1.8;border-radius:10px;min-height:50vh;padding:24px;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}a:where(:not(.wp-element-button)){background-color:#333;color:#111;}.wp-block-group a:where(:not(.wp-element-button)){color:#111;}.wp-block-heading a:where(:not(.wp-element-button)){background-color:#333;color:#111;font-size:60px;}.wp-block-post-date a:where(:not(.wp-element-button)){background-color:#777;color:#555;}.wp-block-post-excerpt{column-count:2;}.wp-block-image{margin-bottom:30px;}.wp-block-image img, .wp-block-image .wp-block-image__crop-area{border-top-left-radius:10px;border-bottom-right-radius:1em;}.has-grey-color{color:var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color:var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color:var(--wp--preset--color--grey) !important;}.has-small-font-family{font-family:var(--wp--preset--font-family--small) !important;}.has-big-font-family{font-family:var(--wp--preset--font-family--big) !important;}.wp-block-heading,.wp-block-post-date{color:#123456;}'; - $this->assertEquals( $all, $theme_json->get_stylesheet() ); - $this->assertEquals( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) ); - $this->assertEquals( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) ); - $this->assertEquals( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) ); + $this->assertEquals( $styles, $theme_json->get_stylesheet() ); } /** @@ -493,10 +495,12 @@ public function test_shadow_preset_styles() { ), ), ), - ) + ), + 'theme', + 'test_shadow_preset_styles' ); - $styles = 'body{--wp--preset--shadow--natural: 5px 5px 5px 0 black;--wp--preset--shadow--sharp: 5px 5px black;}'; + $styles = 'body{--wp--preset--shadow--natural:5px 5px 5px 0 black;--wp--preset--shadow--sharp:5px 5px black;}'; $this->assertEquals( $styles, $theme_json->get_stylesheet() ); $this->assertEquals( $styles, $theme_json->get_stylesheet( array( 'variables' ) ) ); } @@ -530,12 +534,12 @@ public function test_get_shadow_styles_for_blocks() { ), ), ), - ) + ), + 'theme', + 'test_get_shadow_styles_for_blocks' ); - $global_styles = 'body{--wp--preset--shadow--natural: 5px 5px 0 0 black;}body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - $element_styles = 'a:where(:not(.wp-element-button)){box-shadow: var(--wp--preset--shadow--natural);}.wp-element-button, .wp-block-button__link{box-shadow: var(--wp--preset--shadow--natural);}p{box-shadow: var(--wp--preset--shadow--natural);}'; - $styles = $global_styles . $element_styles; + $styles = 'body{--wp--preset--shadow--natural:5px 5px 0 0 black;margin:0;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}a:where(:not(.wp-element-button)),.wp-element-button, .wp-block-button__link,p{box-shadow:var(--wp--preset--shadow--natural);}'; $this->assertEquals( $styles, $theme_json->get_stylesheet() ); } @@ -570,14 +574,12 @@ public function test_get_stylesheet_handles_whitelisted_element_pseudo_selectors ), ), ), - ) + ), + 'theme', + 'test_get_stylesheet_handles_whitelisted_element_pseudo_selectors' ); - $base_styles = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - - $element_styles = 'a:where(:not(.wp-element-button)){background-color: red;color: green;}a:where(:not(.wp-element-button)):hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}a:where(:not(.wp-element-button)):focus{background-color: black;color: yellow;}'; - - $expected = $base_styles . $element_styles; + $expected = 'body{margin:0;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}a:where(:not(.wp-element-button)){background-color:red;color:green;}a:where(:not(.wp-element-button)):hover{background-color:green;color:red;font-size:10em;text-transform:uppercase;}a:where(:not(.wp-element-button)):focus{background-color:black;color:yellow;}'; $this->assertEquals( $expected, $theme_json->get_stylesheet() ); $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); @@ -609,14 +611,12 @@ public function test_get_stylesheet_handles_only_pseudo_selector_rules_for_given ), ), ), - ) + ), + 'theme', + 'test_get_stylesheet_handles_only_pseudo_selector_rules_for_given_property' ); - $base_styles = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - - $element_styles = 'a:where(:not(.wp-element-button)):hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}a:where(:not(.wp-element-button)):focus{background-color: black;color: yellow;}'; - - $expected = $base_styles . $element_styles; + $expected = 'body{margin:0;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}a:where(:not(.wp-element-button)):hover{background-color:green;color:red;font-size:10em;text-transform:uppercase;}a:where(:not(.wp-element-button)):focus{background-color:black;color:yellow;}'; $this->assertEquals( $expected, $theme_json->get_stylesheet() ); $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); @@ -648,14 +648,12 @@ public function test_get_stylesheet_ignores_pseudo_selectors_on_non_whitelisted_ ), ), ), - ) + ), + 'theme', + 'test_get_stylesheet_ignores_pseudo_selectors_on_non_whitelisted_elements' ); - $base_styles = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - - $element_styles = 'h4{background-color: red;color: green;}'; - - $expected = $base_styles . $element_styles; + $expected = 'body{margin:0;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}h4{background-color:red;color:green;}'; $this->assertEquals( $expected, $theme_json->get_stylesheet() ); $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); @@ -687,14 +685,12 @@ public function test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors() { ), ), ), - ) + ), + 'theme', + 'test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors' ); - $base_styles = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - - $element_styles = 'a:where(:not(.wp-element-button)){background-color: red;color: green;}a:where(:not(.wp-element-button)):hover{background-color: green;color: red;}'; - - $expected = $base_styles . $element_styles; + $expected = 'body{margin:0;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}a:where(:not(.wp-element-button)){background-color:red;color:green;}a:where(:not(.wp-element-button)):hover{background-color:green;color:red;}'; $this->assertEquals( $expected, $theme_json->get_stylesheet() ); $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); @@ -735,14 +731,12 @@ public function test_get_stylesheet_handles_priority_of_elements_vs_block_elemen ), ), ), - ) + ), + 'theme', + 'test_get_stylesheet_handles_priority_of_elements_vs_block_elements_pseudo_selectors' ); - $base_styles = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - - $element_styles = '.wp-block-group a:where(:not(.wp-element-button)){background-color: red;color: green;}.wp-block-group a:where(:not(.wp-element-button)):hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}.wp-block-group a:where(:not(.wp-element-button)):focus{background-color: black;color: yellow;}'; - - $expected = $base_styles . $element_styles; + $expected = 'body{margin:0;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}.wp-block-group a:where(:not(.wp-element-button)){background-color:red;color:green;}.wp-block-group a:where(:not(.wp-element-button)):hover{background-color:green;color:red;font-size:10em;text-transform:uppercase;}.wp-block-group a:where(:not(.wp-element-button)):focus{background-color:black;color:yellow;}'; $this->assertEquals( $expected, $theme_json->get_stylesheet() ); $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); @@ -782,14 +776,12 @@ public function test_get_stylesheet_handles_whitelisted_block_level_element_pseu ), ), ), - ) + ), + 'theme', + 'test_get_stylesheet_handles_whitelisted_block_level_element_pseudo_selectors' ); - $base_styles = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - - $element_styles = 'a:where(:not(.wp-element-button)){background-color: red;color: green;}a:where(:not(.wp-element-button)):hover{background-color: green;color: red;}.wp-block-group a:where(:not(.wp-element-button)):hover{background-color: black;color: yellow;}'; - - $expected = $base_styles . $element_styles; + $expected = 'body{margin:0;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}a:where(:not(.wp-element-button)){background-color:red;color:green;}a:where(:not(.wp-element-button)):hover{background-color:green;color:red;}.wp-block-group a:where(:not(.wp-element-button)):hover{background-color:black;color:yellow;}'; $this->assertEquals( $expected, $theme_json->get_stylesheet() ); $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); @@ -845,13 +837,12 @@ public function test_get_stylesheet_with_block_support_feature_level_selectors() ), ), ), - ) + ), + 'theme', + 'test_get_stylesheet_with_block_support_feature_level_selectors' ); - $base_styles = 'body{--wp--preset--color--green: green;}body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - $block_styles = '.wp-block-test, .wp-block-test__wrapper{color: green;}.wp-block-test .inner, .wp-block-test__wrapper .inner{border-radius: 9999px;padding: 20px;}.wp-block-test .sub-heading, .wp-block-test__wrapper .sub-heading{font-size: 3em;}'; - $preset_styles = '.has-green-color{color: var(--wp--preset--color--green) !important;}.has-green-background-color{background-color: var(--wp--preset--color--green) !important;}.has-green-border-color{border-color: var(--wp--preset--color--green) !important;}'; - $expected = $base_styles . $block_styles . $preset_styles; + $expected = 'body{--wp--preset--color--green:green;margin:0;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}.wp-block-test, .wp-block-test__wrapper{color:green;}.wp-block-test .inner, .wp-block-test__wrapper .inner{border-radius:9999px;padding:20px;}.wp-block-test .sub-heading, .wp-block-test__wrapper .sub-heading{font-size:3em;}.has-green-color{color:var(--wp--preset--color--green) !important;}.has-green-background-color{background-color:var(--wp--preset--color--green) !important;}.has-green-border-color{border-color:var(--wp--preset--color--green) !important;}'; $this->assertEquals( $expected, $theme_json->get_stylesheet() ); } @@ -1000,10 +991,12 @@ public function test_get_property_value_valid() { ), ), ), - ) + ), + 'theme', + 'test_get_property_value_valid' ); - $expected = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{background-color: #ffffff;color: #000000;}.wp-element-button, .wp-block-button__link{background-color: #000000;color: #ffffff;}'; + $expected = 'body{margin:0;background-color:#ffffff;color:#000000;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}.wp-element-button, .wp-block-button__link{background-color:#000000;color:#ffffff;}'; $this->assertEquals( $expected, $theme_json->get_stylesheet() ); } @@ -1032,10 +1025,12 @@ public function test_get_property_value_loop() { ), ), ), - ) + ), + 'theme', + 'test_get_property_value_loop' ); - $expected = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{background-color: #ffffff;}.wp-element-button, .wp-block-button__link{color: #ffffff;}'; + $expected = 'body{margin:0;background-color:#ffffff;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}.wp-element-button, .wp-block-button__link{color:#ffffff;}'; $this->assertSame( $expected, $theme_json->get_stylesheet() ); } @@ -1063,10 +1058,12 @@ public function test_get_property_value_recursion() { ), ), ), - ) + ), + 'theme', + 'test_get_property_value_recursion' ); - $expected = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{background-color: #ffffff;color: #ffffff;}.wp-element-button, .wp-block-button__link{color: #ffffff;}'; + $expected = 'body{margin:0;background-color:#ffffff;color:#ffffff;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}.wp-element-button, .wp-block-button__link{color:#ffffff;}'; $this->assertEquals( $expected, $theme_json->get_stylesheet() ); } @@ -1086,10 +1083,12 @@ public function test_get_property_value_self() { 'text' => array( 'ref' => 'styles.color.text' ), ), ), - ) + ), + 'theme', + 'test_get_property_value_self' ); - $expected = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{background-color: #ffffff;}'; + $expected = 'body{margin:0;background-color:#ffffff;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}'; $this->assertEquals( $expected, $theme_json->get_stylesheet() ); } @@ -1107,7 +1106,9 @@ public function test_set_spacing_sizes( $spacing_scale, $expected_output ) { 'spacingScale' => $spacing_scale, ), ), - ) + ), + 'theme', + 'test_set_spacing_sizes' ); $theme_json->set_spacing_sizes(); @@ -1349,7 +1350,9 @@ public function test_set_spacing_sizes_when_invalid( $spacing_scale, $expected_o 'spacingScale' => $spacing_scale, ), ), - ) + ), + 'theme', + 'test_set_spacing_sizes_when_invalid' ); $theme_json->set_spacing_sizes(); @@ -1437,7 +1440,9 @@ public function test_get_styles_for_block_with_padding_aware_alignments() { 'settings' => array( 'useRootPaddingAwareAlignments' => true, ), - ) + ), + 'theme', + 'test_get_styles_for_block_with_padding_aware_alignments' ); $metadata = array( @@ -1447,10 +1452,9 @@ public function test_get_styles_for_block_with_padding_aware_alignments() { 'selector' => 'body', ); - $expected = 'body { margin: 0;}.wp-site-blocks { padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom); }.has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }.has-global-padding :where(.has-global-padding) { padding-right: 0; padding-left: 0; }.has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); }.has-global-padding :where(.has-global-padding) > .alignfull { margin-right: 0; margin-left: 0; }.has-global-padding > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),.wp-block:not(.alignfull),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }.has-global-padding :where(.has-global-padding) > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),.wp-block:not(.alignfull),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: 0; padding-left: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{--wp--style--root--padding-top: 10px;--wp--style--root--padding-right: 12px;--wp--style--root--padding-bottom: 10px;--wp--style--root--padding-left: 12px;}'; - $root_rules = $theme_json->get_root_layout_rules( WP_Theme_JSON::ROOT_BLOCK_SELECTOR, $metadata ); - $style_rules = $theme_json->get_styles_for_block( $metadata ); - $this->assertEquals( $expected, $root_rules . $style_rules ); + $expected = 'body{margin:0;--wp--style--root--padding-top:10px;--wp--style--root--padding-right:12px;--wp--style--root--padding-bottom:10px;--wp--style--root--padding-left:12px;}.wp-site-blocks{padding-top:var(--wp--style--root--padding-top);padding-bottom:var(--wp--style--root--padding-bottom);}.has-global-padding > .alignfull{margin-right:calc(var(--wp--style--root--padding-right) * -1);margin-left:calc(var(--wp--style--root--padding-left) * -1);}.has-global-padding :where(.has-global-padding) > .alignfull{margin-right:0;margin-left:0;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}.has-global-padding,.has-global-padding > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),.wp-block:not(.alignfull),p,h1,h2,h3,h4,h5,h6,ul,ol){padding-right:var(--wp--style--root--padding-right);padding-left:var(--wp--style--root--padding-left);}.has-global-padding :where(.has-global-padding),.has-global-padding :where(.has-global-padding) > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),.wp-block:not(.alignfull),p,h1,h2,h3,h4,h5,h6,ul,ol){padding-right:0;padding-left:0;}'; + $theme_json->add_layout_styles_to_rules_store( $metadata ); + $this->assertEquals( $expected, $theme_json->get_stylesheet() ); } public function test_get_styles_for_block_without_padding_aware_alignments() { @@ -1467,7 +1471,9 @@ public function test_get_styles_for_block_without_padding_aware_alignments() { ), ), ), - ) + ), + 'theme', + 'test_get_styles_for_block_without_padding_aware_alignments' ); $metadata = array( @@ -1477,10 +1483,9 @@ public function test_get_styles_for_block_without_padding_aware_alignments() { 'selector' => 'body', ); - $expected = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{padding-top: 10px;padding-right: 12px;padding-bottom: 10px;padding-left: 12px;}'; - $root_rules = $theme_json->get_root_layout_rules( WP_Theme_JSON::ROOT_BLOCK_SELECTOR, $metadata ); - $style_rules = $theme_json->get_styles_for_block( $metadata ); - $this->assertEquals( $expected, $root_rules . $style_rules ); + $expected = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{padding-top: 10px;padding-right: 12px;padding-bottom: 10px;padding-left: 12px;}'; + $theme_json->add_layout_styles_to_rules_store( $metadata ); + $this->assertEquals( $expected, $theme_json->get_stylesheet ); } public function test_get_styles_for_block_with_content_width() { @@ -1493,7 +1498,9 @@ public function test_get_styles_for_block_with_content_width() { 'wideSize' => '1000px', ), ), - ) + ), + 'theme', + 'test_get_styles_for_block_with_content_width' ); $metadata = array( @@ -1503,10 +1510,9 @@ public function test_get_styles_for_block_with_content_width() { 'selector' => 'body', ); - $expected = 'body { margin: 0;--wp--style--global--content-size: 800px;--wp--style--global--wide-size: 1000px;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - $root_rules = $theme_json->get_root_layout_rules( WP_Theme_JSON::ROOT_BLOCK_SELECTOR, $metadata ); - $style_rules = $theme_json->get_styles_for_block( $metadata ); - $this->assertEquals( $expected, $root_rules . $style_rules ); + $expected = 'body { margin: 0;--wp--style--global--content-size: 800px;--wp--style--global--wide-size: 1000px;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + $theme_json->add_layout_styles_to_rules_store( $metadata ); + $this->assertEquals( $expected, $theme_json->get_stylesheet() ); } /** @@ -1524,7 +1530,9 @@ public function test_sanitize_for_block_with_style_variations( $theme_json_varia 'core/quote' => $theme_json_variations, ), ), - ) + ), + 'theme', + 'test_sanitize_for_block_with_style_variations' ); // Validate structure is sanitized. @@ -1646,7 +1654,9 @@ public function test_sanitize_with_invalid_style_variation( $theme_json_variatio 'core/quote' => $theme_json_variations, ), ), - ) + ), + 'theme', + md5( 'test_sanitize_with_invalid_style_variation' . json_encode( $theme_json_variations ) ) ); // Validate structure is sanitized. @@ -1692,7 +1702,9 @@ public function test_get_styles_for_block_with_style_variations( $theme_json_var 'core/quote' => $theme_json_variations, ), ), - ) + ), + 'theme', + md5( 'test_get_styles_for_block_with_style_variations' . json_encode( array( $theme_json_variations, $metadata_variations ) ) ) ); // Validate styles are generated properly. @@ -1818,9 +1830,10 @@ public function test_update_separator_declarations() { ), ), ), - 'default' + 'default', + 'test_update_separator_declarations_1' ); - $expected = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-block-separator{background-color: blue;color: blue;}'; + $expected = 'body{margin:0;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}.wp-block-separator{background-color:blue;color:blue;}'; $stylesheet = $theme_json->get_stylesheet( array( 'styles' ) ); $this->assertEquals( $expected, $stylesheet ); @@ -1839,9 +1852,10 @@ public function test_update_separator_declarations() { ), ), ), - 'default' + 'default', + 'test_update_separator_declarations_2' ); - $expected = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-block-separator{background-color: blue;color: red;}'; + $expected = 'body{margin:0;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}.wp-block-separator{background-color:blue;color:red;}'; $stylesheet = $theme_json->get_stylesheet( array( 'styles' ) ); $this->assertEquals( $expected, $stylesheet ); @@ -1859,9 +1873,10 @@ public function test_update_separator_declarations() { ), ), ), - 'default' + 'default', + 'test_update_separator_declarations_3' ); - $expected = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-block-separator{color: red;}'; + $expected = 'body{margin:0;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}.wp-block-separator{color:red;}'; $stylesheet = $theme_json->get_stylesheet( array( 'styles' ) ); $this->assertEquals( $expected, $stylesheet ); @@ -1883,9 +1898,10 @@ public function test_update_separator_declarations() { ), ), ), - 'default' + 'default', + 'test_update_separator_declarations_4' ); - $expected = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-block-separator{background-color: blue;border-color: pink;color: red;}'; + $expected = 'body{margin:0;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}.wp-block-separator{background-color:blue;border-color:pink;color:red;}'; $stylesheet = $theme_json->get_stylesheet( array( 'styles' ) ); $this->assertEquals( $expected, $stylesheet ); @@ -1906,9 +1922,10 @@ public function test_update_separator_declarations() { ), ), ), - 'default' + 'default', + 'test_update_separator_declarations_5' ); - $expected = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-block-separator{background-color: blue;border-color: pink;}'; + $expected = 'body{margin:0;}.wp-site-blocks > .alignleft{float:left;margin-right:2em;}.wp-site-blocks > .alignright{float:right;margin-left:2em;}.wp-site-blocks > .aligncenter{justify-content:center;margin-left:auto;margin-right:auto;}.wp-block-separator{background-color:blue;border-color:pink;}'; $stylesheet = $theme_json->get_stylesheet( array( 'styles' ) ); $this->assertEquals( $expected, $stylesheet ); @@ -1926,7 +1943,9 @@ public function test_get_custom_css_handles_global_custom_css() { ), ), ), - ) + ), + 'theme', + 'test_get_custom_css_handles_global_custom_css' ); $custom_css = 'body {color:purple;}p{color:red;}'; @@ -2013,7 +2032,9 @@ public function test_process_blocks_custom_css( $input, $expected ) { array( 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, 'styles' => array(), - ) + ), + 'theme', + md5( 'test_process_blocks_custom_css' . json_encode( $input ) ) ); $reflection = new ReflectionMethod( $theme_json, 'process_blocks_custom_css' ); $reflection->setAccessible( true );