From 08400745c7f04cabdabe4d2a34de239a1b442ea5 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 15 Jul 2022 15:23:55 +1000 Subject: [PATCH 01/29] Enqueuing block support styles version 1. --- lib/block-supports/elements.php | 13 +- .../style-engine/class-wp-style-engine.php | 119 +++++++++++++++++- 2 files changed, 118 insertions(+), 14 deletions(-) diff --git a/lib/block-supports/elements.php b/lib/block-supports/elements.php index b0328c6a5f227c..b4024079d39882 100644 --- a/lib/block-supports/elements.php +++ b/lib/block-supports/elements.php @@ -104,18 +104,7 @@ function gutenberg_render_elements_support_styles( $pre_render, $block ) { $class_name = gutenberg_get_elements_class_name( $block ); $link_block_styles = isset( $element_block_styles['link'] ) ? $element_block_styles['link'] : null; - if ( $link_block_styles ) { - $styles = gutenberg_style_engine_get_styles( - $link_block_styles, - array( - 'selector' => ".$class_name a", - ) - ); - - if ( ! empty( $styles['css'] ) ) { - gutenberg_enqueue_block_support_styles( $styles['css'] ); - } - } + gutenberg_style_engine_enqueue_block_supports_styles( ".$class_name a", $link_block_styles ); return null; } diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index c2d778066ca071..4466023b5f8e61 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -30,6 +30,15 @@ class WP_Style_Engine { */ private static $instance = null; + /** + * Instance of WP_Style_Engine_CSS_Rules_Store to hold block supports CSS rules. + * + * @var array + */ + private static $stores = array( + 'block-supports' => null, + ); + /** * Style definitions that contain the instructions to * parse/output valid Gutenberg styles from a block's attributes. @@ -221,6 +230,16 @@ class WP_Style_Engine { ), ); + /** + * Private constructor to prevent instantiation. + */ + private function __construct() { + foreach ( static::$stores as $store_key => $store_instance ) { + static::$stores[ $store_key ] = WP_Style_Engine_CSS_Rules_Store::get_store( $store_key ); + } + static::enqueue_registered_styles( array( __CLASS__, 'enqueue_rendered_styles' ) ); + } + /** * Utility method to retrieve the main instance of the class. * @@ -236,6 +255,67 @@ public static function get_instance() { return static::$instance; } + /** + * Taken from gutenberg_enqueue_block_support_styles() + * + * This function takes care of adding inline styles + * in the proper place, depending on the theme in use. + * + * For block themes, it's loaded in the head. + * For classic ones, it's loaded in the body + * because the wp_head action happens before + * the render_block. + * + * @param callable $callable A user-defined callback function for a WordPress hook. + * @param int $priority To set the priority for the add_action. + * + * @see gutenberg_enqueue_block_support_styles() + */ + protected static function enqueue_registered_styles( $callable, $priority = 10 ) { + if ( ! $callable ) { + return; + } + $action_hook_name = 'wp_footer'; + if ( wp_is_block_theme() ) { + $action_hook_name = 'wp_head'; + } + add_action( 'wp_enqueue_scripts', $callable ); + add_action( + $action_hook_name, + $callable, + $priority + ); + } + + /** + * Fetches, processes and compiles stored styles, then renders them to the page. + */ + public static function enqueue_rendered_styles() { + foreach ( static::$stores as $store_key => $store_instance ) { + if ( ! $store_instance ) { + continue; + } + + $css_rules = $store_instance->get_all_rules(); + + if ( empty( $css_rules ) ) { + continue; + } + + $styles_output = ''; + + foreach ( $css_rules as $selector => $css_rule ) { + $styles_output .= $css_rule->get_css(); + } + + if ( ! empty( $styles_output ) ) { + wp_register_style( $store_key, false, array(), true, true ); + wp_add_inline_style( $store_key, $styles_output ); + wp_enqueue_style( $store_key ); + } + } + } + /** * Extracts the slug in kebab case from a preset string, e.g., "heavenly-blue" from 'var:preset|color|heavenlyBlue'. * @@ -388,6 +468,7 @@ protected static function get_css_declarations( $style_value, $style_definition, * @param array $block_styles The style object. * @param array $options array( * 'selector' => (string) When a selector is passed, `generate()` will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. + * 'enqueue' => (boolean) When `true` will attempt to store and enqueue for rendering on the frontend. * 'convert_vars_to_classnames' => (boolean) Whether to skip converting CSS var:? values to var( --wp--preset--* ) values. Default is `false`. * );. * @@ -423,8 +504,9 @@ public function get_styles( $block_styles, $options ) { } // Build CSS rules output. - $css_selector = isset( $options['selector'] ) ? $options['selector'] : null; - $css_declarations = new WP_Style_Engine_CSS_Declarations( $css_declarations ); + $css_selector = isset( $options['selector'] ) ? $options['selector'] : null; + $should_store_and_enqueue = isset( $options['enqueue'] ) && true === $options['enqueue']; + $css_declarations = new WP_Style_Engine_CSS_Declarations( $css_declarations ); // The return object. $styles_output = array(); @@ -437,6 +519,10 @@ public function get_styles( $block_styles, $options ) { // Return an entire rule if there is a selector. if ( $css_selector ) { $styles_output['css'] = $css_selector . ' { ' . $css . ' }'; + if ( $should_store_and_enqueue ) { + $stored_css_rule = static::$stores['block-supports']->get_rule( $css_selector ); + $stored_css_rule->set_declarations( $css_declarations ); + } } } @@ -529,3 +615,32 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { } return null; } + +/** + * Global public interface method to WP_Style_Engine->get_block_supports_styles to generate block styles from a single block style object + * and then, via the `enqueue` flag, will enqueue them for rendering on the frontend in a block-supports inline style tag. + * + * @access public + * + * @param string $selector A CSS selector. + * @param array $block_styles The value of a block's attributes.style. + * + * @return array|null array( + * 'styles' => (string) A CSS ruleset or declarations block formatted to be placed in an HTML `style` attribute or tag. + * 'declarations' => (array) An array of property/value pairs representing parsed CSS declarations. + * 'classnames' => (string) Classnames separated by a space. + * ); + */ +function wp_style_engine_enqueue_block_supports_styles( $selector, $block_styles ) { + if ( empty( $selector ) || empty( $block_styles ) ) { + return null; + } + if ( class_exists( 'WP_Style_Engine' ) ) { + $options = array( + 'enqueue' => true, + 'selector' => $selector, + ); + return WP_Style_Engine::get_instance()->get_block_supports_styles( $block_styles, $options ); + } + return null; +} From 6a42821818c9b12b62d5c6db4c6c506608253f51 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 15 Jul 2022 15:49:44 +1000 Subject: [PATCH 02/29] Linter, this one's for you. --- packages/style-engine/class-wp-style-engine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 4466023b5f8e61..451cb8152ff7a2 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -304,7 +304,7 @@ public static function enqueue_rendered_styles() { $styles_output = ''; - foreach ( $css_rules as $selector => $css_rule ) { + foreach ( $css_rules as $selector => $css_rule ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $styles_output .= $css_rule->get_css(); } From 1f2b4a866cbec584ae4e5f4dd6baabe1e38890b6 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 15 Jul 2022 18:47:41 +1000 Subject: [PATCH 03/29] Post trunk merge cleanup and update tests. --- packages/style-engine/class-wp-style-engine-css-rule.php | 4 ++-- packages/style-engine/class-wp-style-engine.php | 5 +++-- .../phpunit/class-wp-style-engine-css-rule-test.php | 8 ++++---- .../style-engine/phpunit/class-wp-style-engine-test.php | 2 ++ 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine-css-rule.php b/packages/style-engine/class-wp-style-engine-css-rule.php index 9e77420f0577c2..e8397d1548aeee 100644 --- a/packages/style-engine/class-wp-style-engine-css-rule.php +++ b/packages/style-engine/class-wp-style-engine-css-rule.php @@ -51,7 +51,7 @@ public function __construct( $selector = '', $declarations = array() ) { * * @param string $selector The CSS selector. * - * @return WP_Style_Engine_CSS_Rule Returns the object to allow chaining of methods. + * @return WP_Style_Engine_CSS_Rule|void Returns the object to allow chaining of methods. */ public function set_selector( $selector ) { if ( empty( $selector ) ) { @@ -110,6 +110,6 @@ public function get_selector() { * @return string */ public function get_css() { - return $this->get_selector() . ' {' . $this->declarations->get_declarations_string() . '}'; + return $this->get_selector() . ' { ' . $this->declarations->get_declarations_string() . ' }'; } } diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 451cb8152ff7a2..b39d6c0d3cf9f4 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -518,9 +518,10 @@ public function get_styles( $block_styles, $options ) { $styles_output['declarations'] = $css_declarations->get_declarations(); // Return an entire rule if there is a selector. if ( $css_selector ) { - $styles_output['css'] = $css_selector . ' { ' . $css . ' }'; + $css_rule = new WP_Style_Engine_CSS_Rule( $css_selector, $css_declarations ); + $styles_output['css'] = $css_rule->get_css(); if ( $should_store_and_enqueue ) { - $stored_css_rule = static::$stores['block-supports']->get_rule( $css_selector ); + $stored_css_rule = static::$stores['block-supports']->add_rule( $css_selector ); $stored_css_rule->set_declarations( $css_declarations ); } } diff --git a/packages/style-engine/phpunit/class-wp-style-engine-css-rule-test.php b/packages/style-engine/phpunit/class-wp-style-engine-css-rule-test.php index 80547d998fb876..0f58a5a7d1a3b7 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-css-rule-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-css-rule-test.php @@ -27,7 +27,7 @@ public function test_instantiate_with_selector_and_rules() { $this->assertSame( $selector, $css_rule->get_selector() ); - $expected = "$selector {{$css_declarations->get_declarations_string()}}"; + $expected = "$selector { {$css_declarations->get_declarations_string()} }"; $this->assertSame( $expected, $css_rule->get_css() ); } @@ -45,7 +45,7 @@ public function test_dedupe_properties_in_rules() { $css_rule = new WP_Style_Engine_CSS_Rule( $selector, $first_declaration ); $css_rule->add_declarations( new WP_Style_Engine_CSS_Declarations( $overwrite_first_declaration ) ); - $expected = '.taggart {font-size: 4px;}'; + $expected = '.taggart { font-size: 4px; }'; $this->assertSame( $expected, $css_rule->get_css() ); } @@ -60,7 +60,7 @@ public function test_add_declarations() { $css_rule = new WP_Style_Engine_CSS_Rule( '.hill-street-blues', $some_css_declarations ); $css_rule->add_declarations( $some_more_css_declarations ); - $expected = '.hill-street-blues {margin-top: 10px; font-size: 1rem;}'; + $expected = '.hill-street-blues { margin-top: 10px; font-size: 1rem; }'; $this->assertSame( $expected, $css_rule->get_css() ); } @@ -89,7 +89,7 @@ public function test_get_css() { ); $css_declarations = new WP_Style_Engine_CSS_Declarations( $input_declarations ); $css_rule = new WP_Style_Engine_CSS_Rule( $selector, $css_declarations ); - $expected = "$selector {{$css_declarations->get_declarations_string()}}"; + $expected = "$selector { {$css_declarations->get_declarations_string()} }"; $this->assertSame( $expected, $css_rule->get_css() ); } diff --git a/packages/style-engine/phpunit/class-wp-style-engine-test.php b/packages/style-engine/phpunit/class-wp-style-engine-test.php index 81ca7f931f7644..aa5dc693fe6015 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -7,6 +7,8 @@ */ require __DIR__ . '/../class-wp-style-engine-css-declarations.php'; +require __DIR__ . '/../class-wp-style-engine-css-rule.php'; +require __DIR__ . '/../class-wp-style-engine-css-rules-store.php'; require __DIR__ . '/../class-wp-style-engine.php'; /** From 5a5107335738a3a443c82439058430b93e2d2ab4 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Mon, 18 Jul 2022 11:25:54 +1000 Subject: [PATCH 04/29] Removed spacing around curly braces in CSS rules. Updated tests. We could maybe add a prettify option down the road. Juggling methods around to cater for adding styles to (any) store. Also making return values consistent. --- .../class-wp-style-engine-css-rule.php | 2 +- .../style-engine/class-wp-style-engine.php | 301 ++++++++++-------- .../class-wp-style-engine-css-rule-test.php | 8 +- .../phpunit/class-wp-style-engine-test.php | 8 +- 4 files changed, 181 insertions(+), 138 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine-css-rule.php b/packages/style-engine/class-wp-style-engine-css-rule.php index e8397d1548aeee..5429b282f328db 100644 --- a/packages/style-engine/class-wp-style-engine-css-rule.php +++ b/packages/style-engine/class-wp-style-engine-css-rule.php @@ -110,6 +110,6 @@ public function get_selector() { * @return string */ public function get_css() { - return $this->get_selector() . ' { ' . $this->declarations->get_declarations_string() . ' }'; + return $this->get_selector() . ' {' . $this->declarations->get_declarations_string() . '}'; } } diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index b39d6c0d3cf9f4..4df77d3d09b866 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -230,6 +230,63 @@ class WP_Style_Engine { ), ); + /** + * Util: Extracts the slug in kebab case from a preset string, e.g., "heavenly-blue" from 'var:preset|color|heavenlyBlue'. + * + * @param string? $style_value A single css preset value. + * @param string $property_key The CSS property that is the second element of the preset string. Used for matching. + * + * @return string|null The slug, or null if not found. + */ + protected static function get_slug_from_preset_value( $style_value, $property_key ) { + if ( is_string( $style_value ) && strpos( $style_value, "var:preset|{$property_key}|" ) !== false ) { + $index_to_splice = strrpos( $style_value, '|' ) + 1; + return _wp_to_kebab_case( substr( $style_value, $index_to_splice ) ); + } + return null; + } + + /** + * Util: Generates a css var string, eg var(--wp--preset--color--background) from a preset string, eg. `var:preset|space|50`. + * + * @param string $style_value A single css preset value. + * @param array $css_vars The css var patterns used to generate the var string. + * + * @return string|null The css var, or null if no match for slug found. + */ + protected static function get_css_var_value( $style_value, $css_vars ) { + foreach ( $css_vars as $property_key => $css_var_pattern ) { + $slug = static::get_slug_from_preset_value( $style_value, $property_key ); + if ( $slug ) { + $var = strtr( + $css_var_pattern, + array( '$slug' => $slug ) + ); + return "var($var)"; + } + } + return null; + } + + /** + * Util: Checks whether an incoming block style value is valid. + * + * @param string? $style_value A single css preset value. + * + * @return boolean + */ + protected static function is_valid_style_value( $style_value ) { + if ( '0' === $style_value ) { + return true; + } + + if ( empty( $style_value ) ) { + return false; + } + + return true; + } + /** * Private constructor to prevent instantiation. */ @@ -237,7 +294,8 @@ private function __construct() { foreach ( static::$stores as $store_key => $store_instance ) { static::$stores[ $store_key ] = WP_Style_Engine_CSS_Rules_Store::get_store( $store_key ); } - static::enqueue_registered_styles( array( __CLASS__, 'enqueue_rendered_styles' ) ); + // Register the hook callback to render stored styles to the page. + static::render_styles( array( __CLASS__, 'process_and_enqueue_stored_styles' ) ); } /** @@ -255,6 +313,25 @@ public static function get_instance() { return static::$instance; } + /** + * Stores a CSS rule using the provide CSS selector and CSS declarations. + * + * @param string $css_selector When a selector is passed, the function will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. + * @param array $css_declarations An array of parsed CSS property => CSS value pairs. + * @param string $store_key A valid key corresponding to an existing store in static::$stores. + * + * @return string A compiled CSS string. + */ + public function store_css_rule( $css_selector, $css_declarations, $store_key ) { + if ( ! $css_selector || ! isset( static::$stores[ $store_key ] ) ) { + return false; + } + $css_declarations = new WP_Style_Engine_CSS_Declarations( $css_declarations ); + $stored_css_rule = static::$stores[ $store_key ]->add_rule( $css_selector ); + $stored_css_rule->add_declarations( $css_declarations ); + return true; + } + /** * Taken from gutenberg_enqueue_block_support_styles() * @@ -271,7 +348,7 @@ public static function get_instance() { * * @see gutenberg_enqueue_block_support_styles() */ - protected static function enqueue_registered_styles( $callable, $priority = 10 ) { + protected static function render_styles( $callable, $priority = 10 ) { if ( ! $callable ) { return; } @@ -290,7 +367,7 @@ protected static function enqueue_registered_styles( $callable, $priority = 10 ) /** * Fetches, processes and compiles stored styles, then renders them to the page. */ - public static function enqueue_rendered_styles() { + public static function process_and_enqueue_stored_styles() { foreach ( static::$stores as $store_key => $store_instance ) { if ( ! $store_instance ) { continue; @@ -304,7 +381,7 @@ public static function enqueue_rendered_styles() { $styles_output = ''; - foreach ( $css_rules as $selector => $css_rule ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + foreach ( $css_rules as $css_rule ) { $styles_output .= $css_rule->get_css(); } @@ -317,60 +394,51 @@ public static function enqueue_rendered_styles() { } /** - * Extracts the slug in kebab case from a preset string, e.g., "heavenly-blue" from 'var:preset|color|heavenlyBlue'. + * Returns classnames and CSS based on the values in a styles object. + * Return values are parsed based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA. * - * @param string? $style_value A single css preset value. - * @param string $property_key The CSS property that is the second element of the preset string. Used for matching. + * @param array $block_styles The style object. + * @param array $options array( + * 'selector' => (string) When a selector is passed, `generate()` will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. + * 'enqueue' => (boolean) When `true` will attempt to store and enqueue for rendering on the frontend. + * 'convert_vars_to_classnames' => (boolean) Whether to skip converting CSS var:? values to var( --wp--preset--* ) values. Default is `false`. + * );. * - * @return string|null The slug, or null if not found. + * @return array array( + * 'css_declarations' => (array) An array of parsed CSS property => CSS value pairs. + * 'classnames' => (array) A flat array of classnames. + * ); */ - protected static function get_slug_from_preset_value( $style_value, $property_key ) { - if ( is_string( $style_value ) && strpos( $style_value, "var:preset|{$property_key}|" ) !== false ) { - $index_to_splice = strrpos( $style_value, '|' ) + 1; - return _wp_to_kebab_case( substr( $style_value, $index_to_splice ) ); + public function parse_block_supports_styles( $block_styles, $options ) { + if ( empty( $block_styles ) || ! is_array( $block_styles ) ) { + return array(); } - return null; - } - /** - * Generates a css var string, eg var(--wp--preset--color--background) from a preset string, eg. `var:preset|space|50`. - * - * @param string $style_value A single css preset value. - * @param array $css_vars The css var patterns used to generate the var string. - * - * @return string|null The css var, or null if no match for slug found. - */ - protected static function get_css_var_value( $style_value, $css_vars ) { - foreach ( $css_vars as $property_key => $css_var_pattern ) { - $slug = static::get_slug_from_preset_value( $style_value, $property_key ); - if ( $slug ) { - $var = strtr( - $css_var_pattern, - array( '$slug' => $slug ) - ); - return "var($var)"; + $css_declarations = array(); + $classnames = array(); + $should_skip_css_vars = isset( $options['convert_vars_to_classnames'] ) && true === $options['convert_vars_to_classnames']; + + // Collect CSS and classnames. + foreach ( static::BLOCK_STYLE_DEFINITIONS_METADATA as $definition_group_key => $definition_group_style ) { + if ( empty( $block_styles[ $definition_group_key ] ) ) { + continue; } - } - return null; - } + foreach ( $definition_group_style as $style_definition ) { + $style_value = _wp_array_get( $block_styles, $style_definition['path'], null ); - /** - * Checks whether an incoming block style value is valid. - * - * @param string? $style_value A single css preset value. - * - * @return boolean - */ - protected static function is_valid_style_value( $style_value ) { - if ( '0' === $style_value ) { - return true; - } + if ( ! static::is_valid_style_value( $style_value ) ) { + continue; + } - if ( empty( $style_value ) ) { - return false; + $classnames = array_merge( $classnames, static::get_classnames( $style_value, $style_definition ) ); + $css_declarations = array_merge( $css_declarations, static::get_css_declarations( $style_value, $style_definition, $should_skip_css_vars ) ); + } } - return true; + return array( + 'classnames' => $classnames, + 'css_declarations' => $css_declarations, + ); } /** @@ -449,7 +517,9 @@ protected static function get_css_declarations( $style_value, $style_definition, if ( is_string( $value ) && strpos( $value, 'var:' ) !== false && ! $should_skip_css_vars && ! empty( $style_definition['css_vars'] ) ) { $value = static::get_css_var_value( $value, $style_definition['css_vars'] ); } + $individual_property = sprintf( $style_property_keys['individual'], _wp_to_kebab_case( $key ) ); + if ( $individual_property && static::is_valid_style_value( $value ) ) { $css_declarations[ $individual_property ] = $value; } @@ -462,77 +532,39 @@ protected static function get_css_declarations( $style_value, $style_definition, } /** - * Returns classnames and CSS based on the values in a styles object. - * Return values are parsed based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA. + * Returns compiled CSS from parsed css_declarations. * - * @param array $block_styles The style object. - * @param array $options array( - * 'selector' => (string) When a selector is passed, `generate()` will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. - * 'enqueue' => (boolean) When `true` will attempt to store and enqueue for rendering on the frontend. - * 'convert_vars_to_classnames' => (boolean) Whether to skip converting CSS var:? values to var( --wp--preset--* ) values. Default is `false`. - * );. + * @param array $css_declarations An array of parsed CSS property => CSS value pairs. + * @param string $css_selector When a selector is passed, the function will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. * - * @return array|null array( - * 'css' => (string) A CSS ruleset formatted to be placed in an HTML `style` attribute or tag. Default is a string of inline styles. - * 'classnames' => (string) Classnames separated by a space. - * ); + * @return string A compiled CSS string. */ - public function get_styles( $block_styles, $options ) { - if ( empty( $block_styles ) || ! is_array( $block_styles ) ) { - return null; - } - - $css_declarations = array(); - $classnames = array(); - $should_skip_css_vars = isset( $options['convert_vars_to_classnames'] ) && true === $options['convert_vars_to_classnames']; - - // Collect CSS and classnames. - foreach ( static::BLOCK_STYLE_DEFINITIONS_METADATA as $definition_group_key => $definition_group_style ) { - if ( empty( $block_styles[ $definition_group_key ] ) ) { - continue; - } - foreach ( $definition_group_style as $style_definition ) { - $style_value = _wp_array_get( $block_styles, $style_definition['path'], null ); - - if ( ! static::is_valid_style_value( $style_value ) ) { - continue; - } - - $classnames = array_merge( $classnames, static::get_classnames( $style_value, $style_definition ) ); - $css_declarations = array_merge( $css_declarations, static::get_css_declarations( $style_value, $style_definition, $should_skip_css_vars ) ); - } + public function compile_css( $css_declarations, $css_selector ) { + if ( empty( $css_declarations ) || ! is_array( $css_declarations ) ) { + return ''; } - // Build CSS rules output. - $css_selector = isset( $options['selector'] ) ? $options['selector'] : null; - $should_store_and_enqueue = isset( $options['enqueue'] ) && true === $options['enqueue']; - $css_declarations = new WP_Style_Engine_CSS_Declarations( $css_declarations ); - - // The return object. - $styles_output = array(); - $css = $css_declarations->get_declarations_string(); - - // Return css, if any. - if ( ! empty( $css ) ) { - $styles_output['css'] = $css; - $styles_output['declarations'] = $css_declarations->get_declarations(); - // Return an entire rule if there is a selector. - if ( $css_selector ) { - $css_rule = new WP_Style_Engine_CSS_Rule( $css_selector, $css_declarations ); - $styles_output['css'] = $css_rule->get_css(); - if ( $should_store_and_enqueue ) { - $stored_css_rule = static::$stores['block-supports']->add_rule( $css_selector ); - $stored_css_rule->set_declarations( $css_declarations ); - } - } + // Return an entire rule if there is a selector. + if ( $css_selector ) { + $css_rule = new WP_Style_Engine_CSS_Rule( $css_selector, $css_declarations ); + return $css_rule->get_css(); + } else { + $css_declarations = new WP_Style_Engine_CSS_Declarations( $css_declarations ); + return $css_declarations->get_declarations_string(); } - - // Return classnames, if any. - if ( ! empty( $classnames ) ) { - $styles_output['classnames'] = implode( ' ', array_unique( $classnames ) ); + } + /** + * Returns a string of classnames, + * + * @param string $classnames A flat array of classnames. + * + * @return string A string of classnames separate by a space. + */ + public function compile_classnames( $classnames ) { + if ( empty( $classnames ) || ! is_array( $classnames ) ) { + return null; } - - return $styles_output; + return implode( ' ', array_unique( $classnames ) ); } /** @@ -604,21 +636,35 @@ protected static function get_individual_property_css_declarations( $style_value * );. * * @return array|null array( - * 'css' => (string) A CSS ruleset or declarations block formatted to be placed in an HTML `style` attribute or tag. - * 'declarations' => (array) An array of property/value pairs representing parsed CSS declarations. - * 'classnames' => (string) Classnames separated by a space. + * 'css' => (string) A CSS ruleset or declarations block formatted to be placed in an HTML `style` attribute or tag. + * 'declarations' => (array) An array of property/value pairs representing parsed CSS declarations. + * 'classnames' => (string) Classnames separated by a space. * ); */ function wp_style_engine_get_styles( $block_styles, $options = array() ) { if ( class_exists( 'WP_Style_Engine' ) ) { - $style_engine = WP_Style_Engine::get_instance(); - return $style_engine->get_styles( $block_styles, $options ); + $defaults = array( + 'selector' => null, + 'convert_vars_to_classnames' => false, + ); + + $options = wp_parse_args( $options, $defaults ); + $style_engine = WP_Style_Engine::get_instance(); + $parsed_styles = $style_engine->parse_block_supports_styles( $block_styles, $options ); + + // Output. + $styles_output = array(); + $styles_output['css'] = $style_engine->compile_css( $parsed_styles['css_declarations'], $options['selector'] ); + $styles_output['declarations'] = $parsed_styles['css_declarations']; + $styles_output['classnames'] = $style_engine->compile_classnames( $parsed_styles['classnames'] ); + + return array_filter( $styles_output ); } - return null; + return array(); } /** - * Global public interface method to WP_Style_Engine->get_block_supports_styles to generate block styles from a single block style object + * Global public interface method to parse block styles from a single block style object * and then, via the `enqueue` flag, will enqueue them for rendering on the frontend in a block-supports inline style tag. * * @access public @@ -626,22 +672,19 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { * @param string $selector A CSS selector. * @param array $block_styles The value of a block's attributes.style. * - * @return array|null array( - * 'styles' => (string) A CSS ruleset or declarations block formatted to be placed in an HTML `style` attribute or tag. - * 'declarations' => (array) An array of property/value pairs representing parsed CSS declarations. - * 'classnames' => (string) Classnames separated by a space. - * ); + * @return boolean Whether the storage process was successful. */ function wp_style_engine_enqueue_block_supports_styles( $selector, $block_styles ) { if ( empty( $selector ) || empty( $block_styles ) ) { - return null; + return false; } if ( class_exists( 'WP_Style_Engine' ) ) { - $options = array( - 'enqueue' => true, + $options = array( 'selector' => $selector, ); - return WP_Style_Engine::get_instance()->get_block_supports_styles( $block_styles, $options ); + $style_engine = WP_Style_Engine::get_instance(); + $parsed_styles = $style_engine->parse_block_supports_styles( $block_styles, $options ); + return $style_engine->store_css_rule( $selector, $parsed_styles['css_declarations'], 'block-supports' ); } - return null; + return false; } diff --git a/packages/style-engine/phpunit/class-wp-style-engine-css-rule-test.php b/packages/style-engine/phpunit/class-wp-style-engine-css-rule-test.php index 0f58a5a7d1a3b7..80547d998fb876 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-css-rule-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-css-rule-test.php @@ -27,7 +27,7 @@ public function test_instantiate_with_selector_and_rules() { $this->assertSame( $selector, $css_rule->get_selector() ); - $expected = "$selector { {$css_declarations->get_declarations_string()} }"; + $expected = "$selector {{$css_declarations->get_declarations_string()}}"; $this->assertSame( $expected, $css_rule->get_css() ); } @@ -45,7 +45,7 @@ public function test_dedupe_properties_in_rules() { $css_rule = new WP_Style_Engine_CSS_Rule( $selector, $first_declaration ); $css_rule->add_declarations( new WP_Style_Engine_CSS_Declarations( $overwrite_first_declaration ) ); - $expected = '.taggart { font-size: 4px; }'; + $expected = '.taggart {font-size: 4px;}'; $this->assertSame( $expected, $css_rule->get_css() ); } @@ -60,7 +60,7 @@ public function test_add_declarations() { $css_rule = new WP_Style_Engine_CSS_Rule( '.hill-street-blues', $some_css_declarations ); $css_rule->add_declarations( $some_more_css_declarations ); - $expected = '.hill-street-blues { margin-top: 10px; font-size: 1rem; }'; + $expected = '.hill-street-blues {margin-top: 10px; font-size: 1rem;}'; $this->assertSame( $expected, $css_rule->get_css() ); } @@ -89,7 +89,7 @@ public function test_get_css() { ); $css_declarations = new WP_Style_Engine_CSS_Declarations( $input_declarations ); $css_rule = new WP_Style_Engine_CSS_Rule( $selector, $css_declarations ); - $expected = "$selector { {$css_declarations->get_declarations_string()} }"; + $expected = "$selector {{$css_declarations->get_declarations_string()}}"; $this->assertSame( $expected, $css_rule->get_css() ); } diff --git a/packages/style-engine/phpunit/class-wp-style-engine-test.php b/packages/style-engine/phpunit/class-wp-style-engine-test.php index aa5dc693fe6015..5018979a886fc2 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -39,13 +39,13 @@ public function data_generate_block_supports_styles_fixtures() { 'default_return_value' => array( 'block_styles' => array(), 'options' => null, - 'expected_output' => null, + 'expected_output' => array(), ), 'inline_invalid_block_styles_empty' => array( 'block_styles' => 'hello world!', 'options' => null, - 'expected_output' => null, + 'expected_output' => array(), ), 'inline_invalid_block_styles_unknown_style' => array( @@ -189,7 +189,7 @@ public function data_generate_block_supports_styles_fixtures() { ), 'options' => array( 'selector' => '.wp-selector > p' ), 'expected_output' => array( - 'css' => '.wp-selector > p { padding-top: 42px; padding-left: 2%; padding-bottom: 44px; padding-right: 5rem; }', + 'css' => '.wp-selector > p {padding-top: 42px; padding-left: 2%; padding-bottom: 44px; padding-right: 5rem;}', 'declarations' => array( 'padding-top' => '42px', 'padding-left' => '2%', @@ -209,7 +209,7 @@ public function data_generate_block_supports_styles_fixtures() { 'selector' => '.wp-selector', ), 'expected_output' => array( - 'css' => '.wp-selector { color: var(--wp--preset--color--my-little-pony); }', + 'css' => '.wp-selector {color: var(--wp--preset--color--my-little-pony);}', 'declarations' => array( 'color' => 'var(--wp--preset--color--my-little-pony)', ), From 55576b9faf2e0f6e355a504485a2325aa75327ca Mon Sep 17 00:00:00 2001 From: ramonjd Date: Tue, 19 Jul 2022 10:36:06 +1000 Subject: [PATCH 05/29] Splitting `wp_style_engine_enqueue_block_supports_styles` and `wp_style_engine_get_block_supports_styles` so we can enqueue styles that don't need parsing, e.g., layout --- lib/block-supports/elements.php | 8 ++++- .../style-engine/class-wp-style-engine.php | 32 +++++++++++-------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/lib/block-supports/elements.php b/lib/block-supports/elements.php index b4024079d39882..b9f9573c598430 100644 --- a/lib/block-supports/elements.php +++ b/lib/block-supports/elements.php @@ -104,7 +104,13 @@ function gutenberg_render_elements_support_styles( $pre_render, $block ) { $class_name = gutenberg_get_elements_class_name( $block ); $link_block_styles = isset( $element_block_styles['link'] ) ? $element_block_styles['link'] : null; - gutenberg_style_engine_enqueue_block_supports_styles( ".$class_name a", $link_block_styles ); + gutenberg_style_engine_get_block_supports_styles( + $link_block_styles, + array( + 'selector' => ".$class_name a", + 'enqueue' => true, + ) + ); return null; } diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 4df77d3d09b866..b0213e75fa8715 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -646,6 +646,7 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { $defaults = array( 'selector' => null, 'convert_vars_to_classnames' => false, + 'enqueue' => false, ); $options = wp_parse_args( $options, $defaults ); @@ -653,10 +654,18 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { $parsed_styles = $style_engine->parse_block_supports_styles( $block_styles, $options ); // Output. - $styles_output = array(); - $styles_output['css'] = $style_engine->compile_css( $parsed_styles['css_declarations'], $options['selector'] ); - $styles_output['declarations'] = $parsed_styles['css_declarations']; - $styles_output['classnames'] = $style_engine->compile_classnames( $parsed_styles['classnames'] ); + $styles_output = array(); + if ( ! empty( $parsed_styles['css_declarations'] ) ) { + $styles_output['css'] = $style_engine->compile_css( $parsed_styles['css_declarations'], $options['selector'] ); + $styles_output['declarations'] = $parsed_styles['css_declarations']; + if ( true === $options['enqueue'] ) { + $style_engine->store_css_rule( $options['selector'], $parsed_styles['css_declarations'], 'block-supports' ); + } + } + + if ( ! empty( $parsed_styles['classnames'] ) ) { + $styles_output['classnames'] = $style_engine->compile_classnames( $parsed_styles['classnames'] ); + } return array_filter( $styles_output ); } @@ -669,22 +678,17 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { * * @access public * - * @param string $selector A CSS selector. - * @param array $block_styles The value of a block's attributes.style. + * @param string $selector A CSS selector. + * @param array $css_declarations An array of CSS definitions, e.g., array( "$property" => "$value" ). * * @return boolean Whether the storage process was successful. */ -function wp_style_engine_enqueue_block_supports_styles( $selector, $block_styles ) { - if ( empty( $selector ) || empty( $block_styles ) ) { +function wp_style_engine_enqueue_block_supports_styles( $selector, $css_declarations ) { + if ( empty( $selector ) || empty( $css_declarations ) ) { return false; } if ( class_exists( 'WP_Style_Engine' ) ) { - $options = array( - 'selector' => $selector, - ); - $style_engine = WP_Style_Engine::get_instance(); - $parsed_styles = $style_engine->parse_block_supports_styles( $block_styles, $options ); - return $style_engine->store_css_rule( $selector, $parsed_styles['css_declarations'], 'block-supports' ); + return WP_Style_Engine::get_instance()->store_css_rule( $selector, $css_declarations, 'block-supports' ); } return false; } From acc6209333d9df0f964584d9cdec8fed368f1fde Mon Sep 17 00:00:00 2001 From: ramonjd Date: Sun, 24 Jul 2022 21:34:03 +1000 Subject: [PATCH 06/29] Integrate the processor class --- packages/style-engine/class-wp-style-engine.php | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index b0213e75fa8715..684ca1029dfafe 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -373,17 +373,8 @@ public static function process_and_enqueue_stored_styles() { continue; } - $css_rules = $store_instance->get_all_rules(); - - if ( empty( $css_rules ) ) { - continue; - } - - $styles_output = ''; - - foreach ( $css_rules as $css_rule ) { - $styles_output .= $css_rule->get_css(); - } + $processor = new WP_Style_Engine_Processor( $store_instance ); + $styles_output = $processor->get_css(); if ( ! empty( $styles_output ) ) { wp_register_style( $store_key, false, array(), true, true ); From 7a22c5bb93421d7d8e902c9d1be6bedd4a5fca2d Mon Sep 17 00:00:00 2001 From: ramonjd Date: Mon, 25 Jul 2022 11:33:07 +1000 Subject: [PATCH 07/29] Migrate layout styles to style engine store. --- lib/block-supports/layout.php | 70 +++---- .../style-engine/class-wp-style-engine.php | 181 +++++++++++------- 2 files changed, 153 insertions(+), 98 deletions(-) diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 43f0e9beffba24..63ae4684c30004 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -39,9 +39,8 @@ function gutenberg_register_layout_support( $block_type ) { * @return string CSS style. */ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support = false, $gap_value = null, $should_skip_gap_serialization = false, $fallback_gap_value = '0.5em', $block_spacing = null ) { - $layout_type = isset( $layout['type'] ) ? $layout['type'] : 'default'; - - $style = ''; + $layout_type = isset( $layout['type'] ) ? $layout['type'] : 'default'; + $layout_styles = array(); if ( 'default' === $layout_type ) { $content_size = isset( $layout['contentSize'] ) ? $layout['contentSize'] : ''; $wide_size = isset( $layout['wideSize'] ) ? $layout['wideSize'] : ''; @@ -55,14 +54,14 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support $wide_max_width_value = wp_strip_all_tags( explode( ';', $wide_max_width_value )[0] ); if ( $content_size || $wide_size ) { - $style = "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull)) {"; - $style .= 'max-width: ' . esc_html( $all_max_width_value ) . ';'; - $style .= 'margin-left: auto !important;'; - $style .= 'margin-right: auto !important;'; - $style .= '}'; + $layout_styles[ "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))" ] = array( + 'max-width' => $all_max_width_value, + 'margin-left' => 'auto !important', + 'margin-right' => 'auto !important', + ); - $style .= "$selector > .alignwide { max-width: " . esc_html( $wide_max_width_value ) . ';}'; - $style .= "$selector .alignfull { max-width: none; }"; + $layout_styles[ "$selector > .alignwide" ] = array( 'max-width' => $wide_max_width_value ); + $layout_styles[ "$selector .alignfull" ] = array( 'max-width' => 'none' ); if ( isset( $block_spacing ) ) { $block_spacing_values = gutenberg_style_engine_get_styles( @@ -74,12 +73,12 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support // Handle negative margins for alignfull children of blocks with custom padding set. // They're added separately because padding might only be set on one side. if ( isset( $block_spacing_values['declarations']['padding-right'] ) ) { - $padding_right = $block_spacing_values['declarations']['padding-right']; - $style .= "$selector > .alignfull { margin-right:calc($padding_right * -1); }"; + $padding_right = $block_spacing_values['declarations']['padding-right']; + $layout_styles[ "$selector > .alignfull" ] = array( 'margin-right' => "calc($padding_right * -1)" ); } if ( isset( $block_spacing_values['declarations']['padding-left'] ) ) { - $padding_left = $block_spacing_values['declarations']['padding-left']; - $style .= "$selector > .alignfull { margin-left: calc($padding_left * -1); }"; + $padding_left = $block_spacing_values['declarations']['padding-left']; + $layout_styles[ "$selector > .alignfull" ] = array( 'margin-left' => "calc($padding_left * -1)" ); } } } @@ -89,8 +88,16 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support $gap_value = isset( $gap_value['top'] ) ? $gap_value['top'] : null; } if ( $gap_value && ! $should_skip_gap_serialization ) { - $style .= "$selector > * { margin-block-start: 0; margin-block-end: 0; }"; - $style .= "$selector > * + * { margin-block-start: $gap_value; margin-block-end: 0; }"; + $layout_styles[ "$selector > *" ] = + array( + 'margin-block-start' => '0', + 'margin-block-end' => '0', + ); + $layout_styles[ "$selector > * + *" ] = + array( + 'margin-block-start' => $gap_value, + 'margin-block-end' => '0', + ); } } } elseif ( 'flex' === $layout_type ) { @@ -113,7 +120,7 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support } if ( ! empty( $layout['flexWrap'] ) && 'nowrap' === $layout['flexWrap'] ) { - $style .= "$selector { flex-wrap: nowrap; }"; + $layout_styles[ $selector ] = array( 'flex-wrap' => 'nowrap' ); } if ( $has_block_gap_support ) { @@ -123,9 +130,7 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support $gap_value = $gap_row === $gap_column ? $gap_row : $gap_row . ' ' . $gap_column; } if ( $gap_value && ! $should_skip_gap_serialization ) { - $style .= "$selector {"; - $style .= "gap: $gap_value;"; - $style .= '}'; + $layout_styles[ $selector ] = array( 'gap' => $gap_value ); } } @@ -136,29 +141,29 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support * by custom css. */ if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { - $style .= "$selector {"; - $style .= "justify-content: {$justify_content_options[ $layout['justifyContent'] ]};"; - $style .= '}'; + $layout_styles[ $selector ] = array( 'justify-content' => $justify_content_options[ $layout['justifyContent'] ] ); } if ( ! empty( $layout['verticalAlignment'] ) && array_key_exists( $layout['verticalAlignment'], $vertical_alignment_options ) ) { - $style .= "$selector {"; - $style .= "align-items: {$vertical_alignment_options[ $layout['verticalAlignment'] ]};"; - $style .= '}'; + $layout_styles[ $selector ] = array( 'align-items' => $vertical_alignment_options[ $layout['verticalAlignment'] ] ); } } else { - $style .= "$selector {"; - $style .= 'flex-direction: column;'; + $layout_styles[ $selector ] = array( + 'flex-direction' => 'column', + 'align-items' => 'flex-start', + ); if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { - $style .= "align-items: {$justify_content_options[ $layout['justifyContent'] ]};"; + $layout_styles[ $selector ] = array( 'align-items' => $justify_content_options[ $layout['justifyContent'] ] ); } else { - $style .= 'align-items: flex-start;'; + $layout_styles[ $selector ] = array( 'align-items' => 'flex-start' ); } - $style .= '}'; } } - return $style; + if ( ! empty( $layout_styles ) ) { + gutenberg_style_engine_add_to_store( 'layout-block-supports', $layout_styles ); + return gutenberg_style_engine_get_stylesheet( 'layout-block-supports' ); + } } /** @@ -253,7 +258,6 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { // Only add container class and enqueue block support styles if unique styles were generated. if ( ! empty( $style ) ) { $class_names[] = $container_class; - wp_enqueue_block_support_styles( $style ); } } diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 684ca1029dfafe..de3de9e20805ee 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -36,7 +36,8 @@ class WP_Style_Engine { * @var array */ private static $stores = array( - 'block-supports' => null, + 'layout-block-supports' => null, + 'block-supports' => null, ); /** @@ -320,16 +321,29 @@ public static function get_instance() { * @param array $css_declarations An array of parsed CSS property => CSS value pairs. * @param string $store_key A valid key corresponding to an existing store in static::$stores. * - * @return string A compiled CSS string. + * @return void. */ - public function store_css_rule( $css_selector, $css_declarations, $store_key ) { + public static function store_css_rule( $css_selector, $css_declarations, $store_key ) { if ( ! $css_selector || ! isset( static::$stores[ $store_key ] ) ) { - return false; + return; } $css_declarations = new WP_Style_Engine_CSS_Declarations( $css_declarations ); $stored_css_rule = static::$stores[ $store_key ]->add_rule( $css_selector ); $stored_css_rule->add_declarations( $css_declarations ); - return true; + } + + /** + * Returns a store by store key. + * + * @param string $store_key A valid key corresponding to an existing store in static::$stores. + * + * @return WP_Style_Engine_CSS_Rules_Store|null The store, if found, otherwise `null`. + */ + public static function get_store( $store_key ) { + if ( ! isset( static::$stores[ $store_key ] ) ) { + return null; + } + return static::$stores[ $store_key ]; } /** @@ -368,19 +382,14 @@ protected static function render_styles( $callable, $priority = 10 ) { * Fetches, processes and compiles stored styles, then renders them to the page. */ public static function process_and_enqueue_stored_styles() { - foreach ( static::$stores as $store_key => $store_instance ) { - if ( ! $store_instance ) { - continue; - } - - $processor = new WP_Style_Engine_Processor( $store_instance ); - $styles_output = $processor->get_css(); - - if ( ! empty( $styles_output ) ) { - wp_register_style( $store_key, false, array(), true, true ); - wp_add_inline_style( $store_key, $styles_output ); - wp_enqueue_style( $store_key ); - } + // 1. Block supports + // @TODO we could loop through static::$stores to enqueue and get the key. + $styles_output = static::compile_stylesheet_from_store( 'block-supports' ) . static::compile_stylesheet_from_store( 'layout-block-supports' ); + + if ( ! empty( $styles_output ) ) { + wp_register_style( 'block-supports', false, array(), true, true ); + wp_add_inline_style( 'block-supports', $styles_output ); + wp_enqueue_style( 'block-supports' ); } } @@ -522,42 +531,6 @@ protected static function get_css_declarations( $style_value, $style_definition, return $css_declarations; } - /** - * Returns compiled CSS from parsed css_declarations. - * - * @param array $css_declarations An array of parsed CSS property => CSS value pairs. - * @param string $css_selector When a selector is passed, the function will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. - * - * @return string A compiled CSS string. - */ - public function compile_css( $css_declarations, $css_selector ) { - if ( empty( $css_declarations ) || ! is_array( $css_declarations ) ) { - return ''; - } - - // Return an entire rule if there is a selector. - if ( $css_selector ) { - $css_rule = new WP_Style_Engine_CSS_Rule( $css_selector, $css_declarations ); - return $css_rule->get_css(); - } else { - $css_declarations = new WP_Style_Engine_CSS_Declarations( $css_declarations ); - return $css_declarations->get_declarations_string(); - } - } - /** - * Returns a string of classnames, - * - * @param string $classnames A flat array of classnames. - * - * @return string A string of classnames separate by a space. - */ - public function compile_classnames( $classnames ) { - if ( empty( $classnames ) || ! is_array( $classnames ) ) { - return null; - } - return implode( ' ', array_unique( $classnames ) ); - } - /** * Style value parser that returns a CSS definition array comprising style properties * that have keys representing individual style properties, otherwise known as longhand CSS properties. @@ -604,6 +577,59 @@ protected static function get_individual_property_css_declarations( $style_value } return $css_declarations; } + + /** + * Returns compiled CSS from parsed css_declarations. + * + * @param array $css_declarations An array of parsed CSS property => CSS value pairs. + * @param string $css_selector When a selector is passed, the function will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. + * + * @return string A compiled CSS string. + */ + public function compile_css( $css_declarations, $css_selector ) { + if ( empty( $css_declarations ) || ! is_array( $css_declarations ) ) { + return ''; + } + + // Return an entire rule if there is a selector. + if ( $css_selector ) { + $css_rule = new WP_Style_Engine_CSS_Rule( $css_selector, $css_declarations ); + return $css_rule->get_css(); + } else { + $css_declarations = new WP_Style_Engine_CSS_Declarations( $css_declarations ); + return $css_declarations->get_declarations_string(); + } + } + + /** + * Returns a string of classnames, + * + * @param string $classnames A flat array of classnames. + * + * @return string A string of classnames separate by a space. + */ + public function compile_classnames( $classnames ) { + if ( empty( $classnames ) || ! is_array( $classnames ) ) { + return null; + } + return implode( ' ', array_unique( $classnames ) ); + } + + /** + * Returns a compiled stylesheet from stored CSS rules. + * + * @param string $store_key A valid key corresponding to an existing store in static::$stores. + * + * @return string A compiled stylesheet from stored CSS rules. + */ + public static function compile_stylesheet_from_store( $store_key ) { + $store = static::get_store( $store_key ); + if ( $store ) { + $processor = new WP_Style_Engine_Processor( $store ); + return $processor->get_css(); + } + return ''; + } } /** @@ -650,7 +676,7 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { $styles_output['css'] = $style_engine->compile_css( $parsed_styles['css_declarations'], $options['selector'] ); $styles_output['declarations'] = $parsed_styles['css_declarations']; if ( true === $options['enqueue'] ) { - $style_engine->store_css_rule( $options['selector'], $parsed_styles['css_declarations'], 'block-supports' ); + $style_engine::store_css_rule( $options['selector'], $parsed_styles['css_declarations'], 'block-supports' ); } } @@ -664,22 +690,47 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { } /** - * Global public interface method to parse block styles from a single block style object - * and then, via the `enqueue` flag, will enqueue them for rendering on the frontend in a block-supports inline style tag. + * Global public interface method to register styles to be enqueued and rendered. + * + * @access public + * + * @param string $store_key A valid store key. + * @param array $css_rules array( + * 'selector' => (string) A CSS selector. + * 'css_declarations' => (boolean) An array of CSS definitions, e.g., array( "$property" => "$value" ). + * );. + * + * @return WP_Style_Engine_CSS_Rules_Store|null The store, if found, otherwise `null`. + */ +function wp_style_engine_add_to_store( $store_key, $css_rules = array() ) { + if ( empty( $store_key ) || empty( $css_rules ) ) { + return null; + } + if ( class_exists( 'WP_Style_Engine' ) ) { + $style_engine = WP_Style_Engine::get_instance(); + foreach ( $css_rules as $selector => $css_declarations ) { + $style_engine::store_css_rule( $selector, $css_declarations, $store_key ); + } + return $style_engine::get_store( $store_key ); + } +} + +/** + * Returns a compiled stylesheet from stored CSS rules. * * @access public * - * @param string $selector A CSS selector. - * @param array $css_declarations An array of CSS definitions, e.g., array( "$property" => "$value" ). + * @param string $store_key A valid store key. * - * @return boolean Whether the storage process was successful. + * @return string A compiled stylesheet from stored CSS rules. */ -function wp_style_engine_enqueue_block_supports_styles( $selector, $css_declarations ) { - if ( empty( $selector ) || empty( $css_declarations ) ) { - return false; +function wp_style_engine_get_stylesheet( $store_key ) { + if ( empty( $store_key ) ) { + return null; } if ( class_exists( 'WP_Style_Engine' ) ) { - return WP_Style_Engine::get_instance()->store_css_rule( $selector, $css_declarations, 'block-supports' ); + return WP_Style_Engine::get_instance()::compile_stylesheet_from_store( $store_key ); } - return false; + return null; } + From 7a6aa603557aa6ed5521609a57f0a99a69b7d099 Mon Sep 17 00:00:00 2001 From: Ramon Date: Wed, 27 Jul 2022 14:39:53 +1000 Subject: [PATCH 08/29] Update packages/style-engine/class-wp-style-engine.php Co-authored-by: Ari Stathopoulos --- .../style-engine/class-wp-style-engine.php | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index de3de9e20805ee..7e2760ddf72fe9 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -659,34 +659,34 @@ public static function compile_stylesheet_from_store( $store_key ) { * ); */ function wp_style_engine_get_styles( $block_styles, $options = array() ) { - if ( class_exists( 'WP_Style_Engine' ) ) { - $defaults = array( - 'selector' => null, - 'convert_vars_to_classnames' => false, - 'enqueue' => false, - ); - - $options = wp_parse_args( $options, $defaults ); - $style_engine = WP_Style_Engine::get_instance(); - $parsed_styles = $style_engine->parse_block_supports_styles( $block_styles, $options ); - - // Output. - $styles_output = array(); - if ( ! empty( $parsed_styles['css_declarations'] ) ) { - $styles_output['css'] = $style_engine->compile_css( $parsed_styles['css_declarations'], $options['selector'] ); - $styles_output['declarations'] = $parsed_styles['css_declarations']; - if ( true === $options['enqueue'] ) { - $style_engine::store_css_rule( $options['selector'], $parsed_styles['css_declarations'], 'block-supports' ); - } - } + if ( ! class_exists( 'WP_Style_Engine' ) ) { + return array(); + } + $defaults = array( + 'selector' => null, + 'convert_vars_to_classnames' => false, + 'enqueue' => false, + ); - if ( ! empty( $parsed_styles['classnames'] ) ) { - $styles_output['classnames'] = $style_engine->compile_classnames( $parsed_styles['classnames'] ); + $options = wp_parse_args( $options, $defaults ); + $style_engine = WP_Style_Engine::get_instance(); + $parsed_styles = $style_engine->parse_block_supports_styles( $block_styles, $options ); + + // Output. + $styles_output = array(); + if ( ! empty( $parsed_styles['css_declarations'] ) ) { + $styles_output['css'] = $style_engine->compile_css( $parsed_styles['css_declarations'], $options['selector'] ); + $styles_output['declarations'] = $parsed_styles['css_declarations']; + if ( true === $options['enqueue'] ) { + $style_engine::store_css_rule( $options['selector'], $parsed_styles['css_declarations'], 'block-supports' ); } + } - return array_filter( $styles_output ); + if ( ! empty( $parsed_styles['classnames'] ) ) { + $styles_output['classnames'] = $style_engine->compile_classnames( $parsed_styles['classnames'] ); } - return array(); + + return array_filter( $styles_output ); } /** From 49b143324057ae752ef9f7738ea3e756ec48a652 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Wed, 27 Jul 2022 08:49:20 +0300 Subject: [PATCH 09/29] Tweaks for #42452 (#42691) * abstract stores * "else" not needed * compile_classnames method not needed * we have a method to get the store here * Make the wp_style_engine_add_to_store function always return a store * wp_style_engine_get_stylesheet - always return string * Merged with base branch. Added test for new method. Co-authored-by: ramonjd Co-authored-by: Ramon --- lib/block-supports/elements.php | 2 +- .../class-wp-style-engine-css-rules-store.php | 19 ++++ .../style-engine/class-wp-style-engine.php | 104 ++++++------------ ...s-wp-style-engine-css-rules-store-test.php | 39 +++++++ 4 files changed, 93 insertions(+), 71 deletions(-) diff --git a/lib/block-supports/elements.php b/lib/block-supports/elements.php index b9f9573c598430..8f026e4de4fbb9 100644 --- a/lib/block-supports/elements.php +++ b/lib/block-supports/elements.php @@ -104,7 +104,7 @@ function gutenberg_render_elements_support_styles( $pre_render, $block ) { $class_name = gutenberg_get_elements_class_name( $block ); $link_block_styles = isset( $element_block_styles['link'] ) ? $element_block_styles['link'] : null; - gutenberg_style_engine_get_block_supports_styles( + gutenberg_style_engine_get_styles( $link_block_styles, array( 'selector' => ".$class_name a", diff --git a/packages/style-engine/class-wp-style-engine-css-rules-store.php b/packages/style-engine/class-wp-style-engine-css-rules-store.php index 1dc4da265accc7..0b0cb356a816e3 100644 --- a/packages/style-engine/class-wp-style-engine-css-rules-store.php +++ b/packages/style-engine/class-wp-style-engine-css-rules-store.php @@ -47,6 +47,25 @@ public static function get_store( $store_name = 'default' ) { } return static::$stores[ $store_name ]; } + + /** + * Get an array of all available stores. + * + * @return WP_Style_Engine_CSS_Rules_Store[] + */ + public static function get_stores() { + return static::$stores; + } + + /** + * Clears all stores from static::$stores. + * + * @return void + */ + public static function remove_all_stores() { + static::$stores = array(); + } + /** * Get an array of all rules. * diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 7e2760ddf72fe9..ee0fbe934f0f33 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -30,16 +30,6 @@ class WP_Style_Engine { */ private static $instance = null; - /** - * Instance of WP_Style_Engine_CSS_Rules_Store to hold block supports CSS rules. - * - * @var array - */ - private static $stores = array( - 'layout-block-supports' => null, - 'block-supports' => null, - ); - /** * Style definitions that contain the instructions to * parse/output valid Gutenberg styles from a block's attributes. @@ -292,9 +282,6 @@ protected static function is_valid_style_value( $style_value ) { * Private constructor to prevent instantiation. */ private function __construct() { - foreach ( static::$stores as $store_key => $store_instance ) { - static::$stores[ $store_key ] = WP_Style_Engine_CSS_Rules_Store::get_store( $store_key ); - } // Register the hook callback to render stored styles to the page. static::render_styles( array( __CLASS__, 'process_and_enqueue_stored_styles' ) ); } @@ -319,31 +306,26 @@ public static function get_instance() { * * @param string $css_selector When a selector is passed, the function will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. * @param array $css_declarations An array of parsed CSS property => CSS value pairs. - * @param string $store_key A valid key corresponding to an existing store in static::$stores. + * @param string $store_key A valid store key. * * @return void. */ public static function store_css_rule( $css_selector, $css_declarations, $store_key ) { - if ( ! $css_selector || ! isset( static::$stores[ $store_key ] ) ) { + if ( empty( $css_selector ) || empty( $css_declarations ) ) { return; } - $css_declarations = new WP_Style_Engine_CSS_Declarations( $css_declarations ); - $stored_css_rule = static::$stores[ $store_key ]->add_rule( $css_selector ); - $stored_css_rule->add_declarations( $css_declarations ); + static::get_store( $store_key )->add_rule( $css_selector )->add_declarations( $css_declarations ); } /** * Returns a store by store key. * - * @param string $store_key A valid key corresponding to an existing store in static::$stores. + * @param string $store_key A store key. * - * @return WP_Style_Engine_CSS_Rules_Store|null The store, if found, otherwise `null`. + * @return WP_Style_Engine_CSS_Rules_Store */ public static function get_store( $store_key ) { - if ( ! isset( static::$stores[ $store_key ] ) ) { - return null; - } - return static::$stores[ $store_key ]; + return WP_Style_Engine_CSS_Rules_Store::get_store( $store_key ); } /** @@ -382,14 +364,16 @@ protected static function render_styles( $callable, $priority = 10 ) { * Fetches, processes and compiles stored styles, then renders them to the page. */ public static function process_and_enqueue_stored_styles() { - // 1. Block supports - // @TODO we could loop through static::$stores to enqueue and get the key. - $styles_output = static::compile_stylesheet_from_store( 'block-supports' ) . static::compile_stylesheet_from_store( 'layout-block-supports' ); - - if ( ! empty( $styles_output ) ) { - wp_register_style( 'block-supports', false, array(), true, true ); - wp_add_inline_style( 'block-supports', $styles_output ); - wp_enqueue_style( 'block-supports' ); + $stores = WP_Style_Engine_CSS_Rules_Store::get_stores(); + + foreach ( $stores as $key => $store ) { + $styles = static::compile_stylesheet_from_store( $key ); + + if ( ! empty( $styles ) ) { + wp_register_style( $key, false, array(), true, true ); + wp_add_inline_style( $key, $styles ); + wp_enqueue_style( $key ); + } } } @@ -595,40 +579,21 @@ public function compile_css( $css_declarations, $css_selector ) { if ( $css_selector ) { $css_rule = new WP_Style_Engine_CSS_Rule( $css_selector, $css_declarations ); return $css_rule->get_css(); - } else { - $css_declarations = new WP_Style_Engine_CSS_Declarations( $css_declarations ); - return $css_declarations->get_declarations_string(); } - } - - /** - * Returns a string of classnames, - * - * @param string $classnames A flat array of classnames. - * - * @return string A string of classnames separate by a space. - */ - public function compile_classnames( $classnames ) { - if ( empty( $classnames ) || ! is_array( $classnames ) ) { - return null; - } - return implode( ' ', array_unique( $classnames ) ); + $css_declarations = new WP_Style_Engine_CSS_Declarations( $css_declarations ); + return $css_declarations->get_declarations_string(); } /** * Returns a compiled stylesheet from stored CSS rules. * - * @param string $store_key A valid key corresponding to an existing store in static::$stores. + * @param string $store_key A valid key. * * @return string A compiled stylesheet from stored CSS rules. */ public static function compile_stylesheet_from_store( $store_key ) { - $store = static::get_store( $store_key ); - if ( $store ) { - $processor = new WP_Style_Engine_Processor( $store ); - return $processor->get_css(); - } - return ''; + $processor = new WP_Style_Engine_Processor( static::get_store( $store_key ) ); + return $processor->get_css(); } } @@ -683,7 +648,7 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { } if ( ! empty( $parsed_styles['classnames'] ) ) { - $styles_output['classnames'] = $style_engine->compile_classnames( $parsed_styles['classnames'] ); + $styles_output['classnames'] = implode( ' ', array_unique( $parsed_styles['classnames'] ) ); } return array_filter( $styles_output ); @@ -700,19 +665,21 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { * 'css_declarations' => (boolean) An array of CSS definitions, e.g., array( "$property" => "$value" ). * );. * - * @return WP_Style_Engine_CSS_Rules_Store|null The store, if found, otherwise `null`. + * @return WP_Style_Engine_CSS_Rules_Store. */ function wp_style_engine_add_to_store( $store_key, $css_rules = array() ) { - if ( empty( $store_key ) || empty( $css_rules ) ) { - return null; + $style_engine = WP_Style_Engine::get_instance(); + if ( empty( $css_rules ) ) { + return $style_engine::get_store( $store_key ); } - if ( class_exists( 'WP_Style_Engine' ) ) { - $style_engine = WP_Style_Engine::get_instance(); - foreach ( $css_rules as $selector => $css_declarations ) { - $style_engine::store_css_rule( $selector, $css_declarations, $store_key ); + + foreach ( $css_rules as $selector => $css_declarations ) { + if ( empty( $selector ) || empty( $css_declarations ) ) { + continue; } - return $style_engine::get_store( $store_key ); + $style_engine::store_css_rule( $selector, $css_declarations, $store_key ); } + return $style_engine::get_store( $store_key ); } /** @@ -726,11 +693,8 @@ function wp_style_engine_add_to_store( $store_key, $css_rules = array() ) { */ function wp_style_engine_get_stylesheet( $store_key ) { if ( empty( $store_key ) ) { - return null; - } - if ( class_exists( 'WP_Style_Engine' ) ) { - return WP_Style_Engine::get_instance()::compile_stylesheet_from_store( $store_key ); + return ''; } - return null; + return WP_Style_Engine::get_instance()::compile_stylesheet_from_store( $store_key ); } diff --git a/packages/style-engine/phpunit/class-wp-style-engine-css-rules-store-test.php b/packages/style-engine/phpunit/class-wp-style-engine-css-rules-store-test.php index 84dc6b5f2e82a1..d037fcd844884a 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-css-rules-store-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-css-rules-store-test.php @@ -14,6 +14,10 @@ * Tests for registering, storing and retrieving CSS Rules. */ class WP_Style_Engine_CSS_Rules_Store_Test extends WP_UnitTestCase { + public function tear_down() { + parent::tear_down(); + WP_Style_Engine_CSS_Rules_Store::remove_all_stores(); + } /** * Should create a new store. */ @@ -36,6 +40,41 @@ public function test_get_store() { $this->assertEquals( $selector, $the_same_fish_store->add_rule( $selector )->get_selector() ); } + /** + * Should return all previously created stores. + */ + public function test_get_stores() { + $burrito_store = WP_Style_Engine_CSS_Rules_Store::get_store( 'burrito' ); + $quesadilla_store = WP_Style_Engine_CSS_Rules_Store::get_store( 'quesadilla' ); + $this->assertEquals( + array( + 'burrito' => $burrito_store, + 'quesadilla' => $quesadilla_store, + ), + WP_Style_Engine_CSS_Rules_Store::get_stores() + ); + } + + /** + * Should delete all previously created stores. + */ + public function test_remove_all_stores() { + $dolmades_store = WP_Style_Engine_CSS_Rules_Store::get_store( 'dolmades' ); + $tzatziki_store = WP_Style_Engine_CSS_Rules_Store::get_store( 'tzatziki' ); + $this->assertEquals( + array( + 'dolmades' => $dolmades_store, + 'tzatziki' => $tzatziki_store, + ), + WP_Style_Engine_CSS_Rules_Store::get_stores() + ); + WP_Style_Engine_CSS_Rules_Store::remove_all_stores(); + $this->assertEquals( + array(), + WP_Style_Engine_CSS_Rules_Store::get_stores() + ); + } + /** * Should return a stored rule. */ From d7893a6d4ec90a76b6172264856708f650c673f7 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Thu, 28 Jul 2022 12:29:05 +1000 Subject: [PATCH 10/29] Adding check for the context argument. Adding tests. --- lib/block-supports/elements.php | 1 + lib/block-supports/layout.php | 6 ++ .../style-engine/class-wp-style-engine.php | 21 +++-- ...s-wp-style-engine-css-rules-store-test.php | 3 + .../phpunit/class-wp-style-engine-test.php | 80 ++++++++++++++++++- 5 files changed, 105 insertions(+), 6 deletions(-) diff --git a/lib/block-supports/elements.php b/lib/block-supports/elements.php index 8f026e4de4fbb9..2a512eab82ca96 100644 --- a/lib/block-supports/elements.php +++ b/lib/block-supports/elements.php @@ -108,6 +108,7 @@ function gutenberg_render_elements_support_styles( $pre_render, $block ) { $link_block_styles, array( 'selector' => ".$class_name a", + 'context' => 'block-supports', 'enqueue' => true, ) ); diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 63ae4684c30004..92a20d4f444f06 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -161,9 +161,15 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support } if ( ! empty( $layout_styles ) ) { + // Add to the style engine store to enqueue and render layout styles. gutenberg_style_engine_add_to_store( 'layout-block-supports', $layout_styles ); + + // Return compiled layout styles to retain backwards compatibility. + // Since https://github.com/WordPress/gutenberg/pull/42452 we no longer call wp_enqueue_block_support_styles in this block supports file. return gutenberg_style_engine_get_stylesheet( 'layout-block-supports' ); } + + return ''; } /** diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index ee0fbe934f0f33..d243d8aafbf93c 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -384,7 +384,6 @@ public static function process_and_enqueue_stored_styles() { * @param array $block_styles The style object. * @param array $options array( * 'selector' => (string) When a selector is passed, `generate()` will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. - * 'enqueue' => (boolean) When `true` will attempt to store and enqueue for rendering on the frontend. * 'convert_vars_to_classnames' => (boolean) Whether to skip converting CSS var:? values to var( --wp--preset--* ) values. Default is `false`. * );. * @@ -393,7 +392,7 @@ public static function process_and_enqueue_stored_styles() { * 'classnames' => (array) A flat array of classnames. * ); */ - public function parse_block_supports_styles( $block_styles, $options ) { + public function parse_block_styles( $block_styles, $options ) { if ( empty( $block_styles ) || ! is_array( $block_styles ) ) { return array(); } @@ -612,9 +611,10 @@ public static function compile_stylesheet_from_store( $store_key ) { * * @param array $block_styles The style object. * @param array $options array( - * 'selector' => (string) When a selector is passed, `generate()` will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. * 'context' => (string) An identifier describing the origin of the style object, e.g., 'block-supports' or 'global-styles'. Default is 'block-supports'. + * 'enqueue' => (boolean) When `true` will attempt to store and enqueue for rendering on the frontend. * 'convert_vars_to_classnames' => (boolean) Whether to skip converting CSS var:? values to var( --wp--preset--* ) values. Default is `false`. + * 'selector' => (string) When a selector is passed, `generate()` will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. * );. * * @return array|null array( @@ -629,21 +629,32 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { } $defaults = array( 'selector' => null, + 'context' => 'block-supports', 'convert_vars_to_classnames' => false, 'enqueue' => false, ); $options = wp_parse_args( $options, $defaults ); $style_engine = WP_Style_Engine::get_instance(); - $parsed_styles = $style_engine->parse_block_supports_styles( $block_styles, $options ); + $parsed_styles = null; + + // Block supports styles. + if ( 'block-supports' === $options['context'] ) { + $parsed_styles = $style_engine->parse_block_styles( $block_styles, $options ); + } // Output. $styles_output = array(); + + if ( ! $parsed_styles ) { + return $styles_output; + } + if ( ! empty( $parsed_styles['css_declarations'] ) ) { $styles_output['css'] = $style_engine->compile_css( $parsed_styles['css_declarations'], $options['selector'] ); $styles_output['declarations'] = $parsed_styles['css_declarations']; if ( true === $options['enqueue'] ) { - $style_engine::store_css_rule( $options['selector'], $parsed_styles['css_declarations'], 'block-supports' ); + $style_engine::store_css_rule( $options['selector'], $parsed_styles['css_declarations'], $options['context'] ); } } diff --git a/packages/style-engine/phpunit/class-wp-style-engine-css-rules-store-test.php b/packages/style-engine/phpunit/class-wp-style-engine-css-rules-store-test.php index d037fcd844884a..9fe664752e4bff 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-css-rules-store-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-css-rules-store-test.php @@ -14,6 +14,9 @@ * Tests for registering, storing and retrieving CSS Rules. */ class WP_Style_Engine_CSS_Rules_Store_Test extends WP_UnitTestCase { + /** + * Tear down after each test. + */ public function tear_down() { parent::tear_down(); WP_Style_Engine_CSS_Rules_Store::remove_all_stores(); diff --git a/packages/style-engine/phpunit/class-wp-style-engine-test.php b/packages/style-engine/phpunit/class-wp-style-engine-test.php index 5018979a886fc2..3dc5ebd1d4cf57 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -6,6 +6,7 @@ * @subpackage style-engine */ +require __DIR__ . '/../class-wp-style-engine-processor.php'; require __DIR__ . '/../class-wp-style-engine-css-declarations.php'; require __DIR__ . '/../class-wp-style-engine-css-rule.php'; require __DIR__ . '/../class-wp-style-engine-css-rules-store.php'; @@ -15,6 +16,14 @@ * Tests for registering, storing and generating styles. */ class WP_Style_Engine_Test extends WP_UnitTestCase { + /** + * Tear down after each test. + */ + public function tear_down() { + parent::tear_down(); + WP_Style_Engine_CSS_Rules_Store::remove_all_stores(); + } + /** * Tests generating block styles and classnames based on various manifestations of the $block_styles argument. * @@ -74,7 +83,7 @@ public function data_generate_block_supports_styles_fixtures() { 'expected_output' => array(), ), - 'valid_inline_css_and_classnames' => array( + 'valid_inline_css_and_classnames_as_default_context' => array( 'block_styles' => array( 'color' => array( 'text' => 'var:preset|color|texas-flood', @@ -102,6 +111,44 @@ public function data_generate_block_supports_styles_fixtures() { ), ), + 'valid_inline_css_and_classnames_with_context' => array( + 'block_styles' => array( + 'color' => array( + 'text' => 'var:preset|color|little-lamb', + ), + 'spacing' => array( + 'margin' => '20px', + ), + ), + 'options' => array( + 'convert_vars_to_classnames' => true, + 'context' => 'block-supports', + ), + 'expected_output' => array( + 'css' => 'margin: 20px;', + 'declarations' => array( + 'margin' => '20px', + ), + 'classnames' => 'has-text-color has-little-lamb-color', + ), + ), + + 'invalid_context' => array( + 'block_styles' => array( + 'color' => array( + 'text' => 'var:preset|color|sugar', + ), + 'spacing' => array( + 'padding' => '20000px', + ), + ), + 'options' => array( + 'convert_vars_to_classnames' => true, + 'context' => 'i-love-doughnuts', + ), + 'expected_output' => array(), + ), + 'inline_valid_box_model_style' => array( 'block_styles' => array( 'spacing' => array( @@ -460,4 +507,35 @@ public function data_generate_block_supports_styles_fixtures() { ), ); } + + /** + * Tests adding rules to a store and retrieving a generated stylesheet. + */ + public function test_add_to_store() { + $styles = array( + '.saruman' => array( + 'color' => 'white', + 'height' => '100px', + 'border-style' => 'solid', + 'align-self' => 'unset', + ), + '.gandalf' => array( + 'color' => 'grey', + 'height' => '90px', + 'border-style' => 'dotted', + 'align-self' => 'safe center', + ), + '.radagast' => array( + 'color' => 'brown', + 'height' => '60px', + 'border-style' => 'dashed', + 'align-self' => 'stretch', + ), + ); + $store = wp_style_engine_add_to_store( 'test-store', $styles ); + $this->assertInstanceOf( 'WP_Style_Engine_CSS_Rules_Store', $store ); + + $compiled_stylesheet = wp_style_engine_get_stylesheet( 'test-store' ); + $this->assertSame( '.saruman {color: white; height: 100px; border-style: solid; align-self: unset;}.gandalf {color: grey; height: 90px; border-style: dotted; align-self: safe center;}.radagast {color: brown; height: 60px; border-style: dashed; align-self: stretch;}', $compiled_stylesheet ); + } } From bc6e39a5aedfc7a169d4a4de6f3118edb0171922 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 29 Jul 2022 15:42:22 +1000 Subject: [PATCH 11/29] Updating the processor so that it's ignorant of stores. Why? So that it can be used to process any CSS and not just stored CSS. Updating layout for backwards compatibility in gutenberg_get_layout_style (returning the styles that are collected in the function body only) Created a new mode for incoming $css_rules to be a collection of selector + css_declaration keys. Removed wp_style_engine_get_stylesheet (from store) since we don't use it yet Added a new function wp_style_engine_get_stylesheet_from_css_rules() that will process and compile a collection of CSS rules, and not store them. --- lib/block-supports/layout.php | 95 +++++++++++++----- .../class-wp-style-engine-processor.php | 61 +++++++----- .../style-engine/class-wp-style-engine.php | 83 ++++++++++++---- .../class-wp-style-engine-processor-test.php | 97 +++++++++++++------ .../phpunit/class-wp-style-engine-test.php | 87 +++++++++++++---- 5 files changed, 305 insertions(+), 118 deletions(-) diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 92a20d4f444f06..3595a3ce4110d7 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -54,15 +54,26 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support $wide_max_width_value = wp_strip_all_tags( explode( ';', $wide_max_width_value )[0] ); if ( $content_size || $wide_size ) { - $layout_styles[ "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))" ] = array( - 'max-width' => $all_max_width_value, - 'margin-left' => 'auto !important', - 'margin-right' => 'auto !important', + array_push( + $layout_styles, + array( + 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", + 'css_declarations' => array( + 'max-width' => $all_max_width_value, + 'margin-left' => 'auto !important', + 'margin-right' => 'auto !important', + ), + ), + array( + 'selector' => "$selector > .alignwide", + 'css_declarations' => array( 'max-width' => $wide_max_width_value ), + ), + array( + 'selector' => "$selector .alignfull", + 'css_declarations' => array( 'max-width' => 'none' ), + ), ); - $layout_styles[ "$selector > .alignwide" ] = array( 'max-width' => $wide_max_width_value ); - $layout_styles[ "$selector .alignfull" ] = array( 'max-width' => 'none' ); - if ( isset( $block_spacing ) ) { $block_spacing_values = gutenberg_style_engine_get_styles( array( @@ -73,12 +84,18 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support // Handle negative margins for alignfull children of blocks with custom padding set. // They're added separately because padding might only be set on one side. if ( isset( $block_spacing_values['declarations']['padding-right'] ) ) { - $padding_right = $block_spacing_values['declarations']['padding-right']; - $layout_styles[ "$selector > .alignfull" ] = array( 'margin-right' => "calc($padding_right * -1)" ); + $padding_right = $block_spacing_values['declarations']['padding-right']; + $layout_styles[] = array( + 'selector' => "$selector > .alignfull", + 'css_declarations' => array( 'margin-right' => "calc($padding_right * -1)" ), + ); } if ( isset( $block_spacing_values['declarations']['padding-left'] ) ) { - $padding_left = $block_spacing_values['declarations']['padding-left']; - $layout_styles[ "$selector > .alignfull" ] = array( 'margin-left' => "calc($padding_left * -1)" ); + $padding_left = $block_spacing_values['declarations']['padding-left']; + $layout_styles[] = array( + 'selector' => "$selector > .alignfull", + 'css_declarations' => array( 'margin-left' => "calc($padding_left * -1)" ), + ); } } } @@ -88,16 +105,23 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support $gap_value = isset( $gap_value['top'] ) ? $gap_value['top'] : null; } if ( $gap_value && ! $should_skip_gap_serialization ) { - $layout_styles[ "$selector > *" ] = + array_push( + $layout_styles, array( - 'margin-block-start' => '0', - 'margin-block-end' => '0', - ); - $layout_styles[ "$selector > * + *" ] = + 'selector' => "$selector > *", + 'css_declarations' => array( + 'margin-block-start' => '0', + 'margin-block-end' => '0', + ), + ), array( - 'margin-block-start' => $gap_value, - 'margin-block-end' => '0', - ); + 'selector' => "$selector > * + *", + 'css_declarations' => array( + 'margin-block-start' => $gap_value, + 'margin-block-end' => '0', + ), + ), + ); } } } elseif ( 'flex' === $layout_type ) { @@ -120,7 +144,10 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support } if ( ! empty( $layout['flexWrap'] ) && 'nowrap' === $layout['flexWrap'] ) { - $layout_styles[ $selector ] = array( 'flex-wrap' => 'nowrap' ); + $layout_styles[] = array( + 'selector' => $selector, + 'css_declarations' => array( 'flex-wrap' => 'nowrap' ), + ); } if ( $has_block_gap_support ) { @@ -130,7 +157,10 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support $gap_value = $gap_row === $gap_column ? $gap_row : $gap_row . ' ' . $gap_column; } if ( $gap_value && ! $should_skip_gap_serialization ) { - $layout_styles[ $selector ] = array( 'gap' => $gap_value ); + $layout_styles[] = array( + 'selector' => $selector, + 'css_declarations' => array( 'gapp' => $gap_value ), + ); } } @@ -141,11 +171,17 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support * by custom css. */ if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { - $layout_styles[ $selector ] = array( 'justify-content' => $justify_content_options[ $layout['justifyContent'] ] ); + $layout_styles[] = array( + 'selector' => $selector, + 'css_declarations' => array( 'justify-content' => $justify_content_options[ $layout['justifyContent'] ] ), + ); } if ( ! empty( $layout['verticalAlignment'] ) && array_key_exists( $layout['verticalAlignment'], $vertical_alignment_options ) ) { - $layout_styles[ $selector ] = array( 'align-items' => $vertical_alignment_options[ $layout['verticalAlignment'] ] ); + $layout_styles[] = array( + 'selector' => $selector, + 'css_declarations' => array( 'align-items' => $vertical_alignment_options[ $layout['verticalAlignment'] ] ), + ); } } else { $layout_styles[ $selector ] = array( @@ -153,9 +189,15 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support 'align-items' => 'flex-start', ); if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { - $layout_styles[ $selector ] = array( 'align-items' => $justify_content_options[ $layout['justifyContent'] ] ); + $layout_styles[] = array( + 'selector' => $selector, + 'css_declarations' => array( 'align-items' => $justify_content_options[ $layout['justifyContent'] ] ), + ); } else { - $layout_styles[ $selector ] = array( 'align-items' => 'flex-start' ); + $layout_styles[] = array( + 'selector' => $selector, + 'css_declarations' => array( 'align-items' => 'flex-start' ), + ); } } } @@ -166,7 +208,8 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support // Return compiled layout styles to retain backwards compatibility. // Since https://github.com/WordPress/gutenberg/pull/42452 we no longer call wp_enqueue_block_support_styles in this block supports file. - return gutenberg_style_engine_get_stylesheet( 'layout-block-supports' ); + var_dump(gutenberg_style_engine_get_stylesheet_from_css_rules( $layout_styles )); + return gutenberg_style_engine_get_stylesheet_from_css_rules( $layout_styles ); } return ''; diff --git a/packages/style-engine/class-wp-style-engine-processor.php b/packages/style-engine/class-wp-style-engine-processor.php index 646ea43e7261a8..c96ee96bafe9c1 100644 --- a/packages/style-engine/class-wp-style-engine-processor.php +++ b/packages/style-engine/class-wp-style-engine-processor.php @@ -12,26 +12,45 @@ } /** - * Compiles styles from a store of CSS rules. + * Compiles styles from a collection of CSS rules. * * @access private */ class WP_Style_Engine_Processor { /** - * The Style-Engine Store object. + * The set of CSS rules that this processor will work on. * - * @var WP_Style_Engine_CSS_Rules_Store + * @var WP_Style_Engine_CSS_Rule[] */ - protected $store; + protected $css_rules = array(); /** * Constructor. * - * @param WP_Style_Engine_CSS_Rules_Store $store The store to render. + * @param WP_Style_Engine_CSS_Rule[] $css_rules An array of WP_Style_Engine_CSS_Rule objects from a store or otherwise. */ - public function __construct( WP_Style_Engine_CSS_Rules_Store $store ) { - $this->store = $store; + public function __construct( $css_rules = array() ) { + $this->add_rules( $css_rules ); + } + + /** + * Adds rules to be processed. + * + * @param WP_Style_Engine_CSS_Rule|WP_Style_Engine_CSS_Rule[] $css_rules A single, or an array of, WP_Style_Engine_CSS_Rule objects from a store or otherwise. + */ + public function add_rules( $css_rules ) { + if ( ! is_array( $css_rules ) ) { + $css_rules = array( $css_rules ); + } + foreach ( $css_rules as $rule ) { + $selector = $rule->get_selector(); + if ( isset( $this->css_rules[ $selector ] ) ) { + $this->css_rules[ $selector ]->add_declarations( $rule->get_declarations() ); + } else { + $this->css_rules[ $rule->get_selector() ] = $rule; + } + } } /** @@ -44,9 +63,8 @@ public function get_css() { $this->combine_rules_selectors(); // Build the CSS. - $css = ''; - $rules = $this->store->get_all_rules(); - foreach ( $rules as $rule ) { + $css = ''; + foreach ( $this->css_rules as $rule ) { $css .= $rule->get_css(); } return $css; @@ -58,14 +76,14 @@ public function get_css() { * @return void */ private function combine_rules_selectors() { - $rules = $this->store->get_all_rules(); - // Build an array of selectors along with the JSON-ified styles to make comparisons easier. $selectors_json = array(); - foreach ( $rules as $selector => $rule ) { - $declarations = $rule->get_declarations()->get_declarations(); + foreach ( $this->css_rules as $index => $rule ) { + + $rule_selector = $rule->get_selector(); + $declarations = $rule->get_declarations()->get_declarations(); ksort( $declarations ); - $selectors_json[ $selector ] = json_encode( $declarations ); + $selectors_json[ $rule_selector ] = wp_json_encode( $declarations ); } // Combine selectors that have the same styles. @@ -76,18 +94,17 @@ private function combine_rules_selectors() { if ( 1 >= count( $duplicates ) ) { continue; } + + $new_declarations = $this->css_rules[ $selector ]->get_declarations(); + foreach ( $duplicates as $key ) { // Unset the duplicates from the $selectors_json array to avoid looping through them as well. unset( $selectors_json[ $key ] ); - // Remove the rules from the store. - $this->store->remove_rule( $key ); + // Remove the rules from the rules collection. + unset( $this->css_rules[ $key ] ); } // Create a new rule with the combined selectors. - $new_rule = $this->store->add_rule( implode( ',', $duplicates ) ); - // Set the declarations. The extra check is in place because `add_rule` in the store can return `null`. - if ( $new_rule ) { - $new_rule->add_declarations( $rules[ $selector ]->get_declarations() ); - } + $this->css_rules[ implode( ',', $duplicates ) ] = new WP_Style_Engine_CSS_Rule( implode( ',', $duplicates ), $new_declarations ); } } } diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index d243d8aafbf93c..0f4a1734c8a5dd 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -304,14 +304,14 @@ public static function get_instance() { /** * Stores a CSS rule using the provide CSS selector and CSS declarations. * + * @param string $store_key A valid store key. * @param string $css_selector When a selector is passed, the function will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. * @param array $css_declarations An array of parsed CSS property => CSS value pairs. - * @param string $store_key A valid store key. * * @return void. */ - public static function store_css_rule( $css_selector, $css_declarations, $store_key ) { - if ( empty( $css_selector ) || empty( $css_declarations ) ) { + public static function store_css_rule( $store_key, $css_selector, $css_declarations ) { + if ( empty( $store_key ) || empty( $css_selector ) || empty( $css_declarations ) ) { return; } static::get_store( $store_key )->add_rule( $css_selector )->add_declarations( $css_declarations ); @@ -367,7 +367,7 @@ public static function process_and_enqueue_stored_styles() { $stores = WP_Style_Engine_CSS_Rules_Store::get_stores(); foreach ( $stores as $key => $store ) { - $styles = static::compile_stylesheet_from_store( $key ); + $styles = static::compile_stylesheet_from_css_rules( $store->get_all_rules() ); if ( ! empty( $styles ) ) { wp_register_style( $key, false, array(), true, true ); @@ -562,14 +562,14 @@ protected static function get_individual_property_css_declarations( $style_value } /** - * Returns compiled CSS from parsed css_declarations. + * Returns compiled CSS from css_declarations. * * @param array $css_declarations An array of parsed CSS property => CSS value pairs. * @param string $css_selector When a selector is passed, the function will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. * * @return string A compiled CSS string. */ - public function compile_css( $css_declarations, $css_selector ) { + public static function compile_css( $css_declarations, $css_selector ) { if ( empty( $css_declarations ) || ! is_array( $css_declarations ) ) { return ''; } @@ -586,12 +586,12 @@ public function compile_css( $css_declarations, $css_selector ) { /** * Returns a compiled stylesheet from stored CSS rules. * - * @param string $store_key A valid key. + * @param WP_Style_Engine_CSS_Rule[] $css_rules An array of WP_Style_Engine_CSS_Rule objects from a store or otherwise. * * @return string A compiled stylesheet from stored CSS rules. */ - public static function compile_stylesheet_from_store( $store_key ) { - $processor = new WP_Style_Engine_Processor( static::get_store( $store_key ) ); + public static function compile_stylesheet_from_css_rules( $css_rules ) { + $processor = new WP_Style_Engine_Processor( $css_rules ); return $processor->get_css(); } } @@ -651,10 +651,10 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { } if ( ! empty( $parsed_styles['css_declarations'] ) ) { - $styles_output['css'] = $style_engine->compile_css( $parsed_styles['css_declarations'], $options['selector'] ); + $styles_output['css'] = $style_engine::compile_css( $parsed_styles['css_declarations'], $options['selector'] ); $styles_output['declarations'] = $parsed_styles['css_declarations']; if ( true === $options['enqueue'] ) { - $style_engine::store_css_rule( $options['selector'], $parsed_styles['css_declarations'], $options['context'] ); + $style_engine::store_css_rule( $options['context'], $options['selector'], $parsed_styles['css_declarations'] ); } } @@ -676,23 +676,66 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { * 'css_declarations' => (boolean) An array of CSS definitions, e.g., array( "$property" => "$value" ). * );. * - * @return WP_Style_Engine_CSS_Rules_Store. + * @return WP_Style_Engine_CSS_Rules_Store|null. */ function wp_style_engine_add_to_store( $store_key, $css_rules = array() ) { + if ( ! class_exists( 'WP_Style_Engine' ) || ! $store_key ) { + return null; + } + $style_engine = WP_Style_Engine::get_instance(); if ( empty( $css_rules ) ) { return $style_engine::get_store( $store_key ); } - foreach ( $css_rules as $selector => $css_declarations ) { - if ( empty( $selector ) || empty( $css_declarations ) ) { + foreach ( $css_rules as $css_rule ) { + if ( ! isset( $css_rule['selector'], $css_rule['css_declarations'] ) ) { continue; } - $style_engine::store_css_rule( $selector, $css_declarations, $store_key ); + $style_engine::store_css_rule( $store_key, $css_rule['selector'], $css_rule['css_declarations'] ); } return $style_engine::get_store( $store_key ); } +/** + * Returns compiled CSS from a collection of selectors and css_declarations. + * This won't add to any store, but is useful for returnin a compiled style sheet from any CSS selector + declarations combos. + * + * @access public + * + * @param array $css_rules array( + * 'selector' => (string) A CSS selector. + * 'css_declarations' => (boolean) An array of CSS definitions, e.g., array( "$property" => "$value" ). + * );. + * + * @return string A compiled CSS string. + */ +function wp_style_engine_get_stylesheet_from_css_rules( $css_rules = array() ) { + if ( ! class_exists( 'WP_Style_Engine' ) ) { + return ''; + } + + $style_engine = WP_Style_Engine::get_instance(); + $css_rule_objects = array(); + + foreach ( $css_rules as $css_rule ) { + if ( ! isset( $css_rule['selector'], $css_rule['css_declarations'] ) ) { + continue; + } + + if ( empty( $css_rule['css_declarations'] ) || ! is_array( $css_rule['css_declarations'] ) ) { + continue; + } + $css_rule_objects[] = new WP_Style_Engine_CSS_Rule( $css_rule['selector'], $css_rule['css_declarations'] ); + } + + if ( empty( $css_rule_objects ) ) { + return ''; + } + + return $style_engine::compile_stylesheet_from_css_rules( $css_rule_objects ); +} + /** * Returns a compiled stylesheet from stored CSS rules. * @@ -702,10 +745,12 @@ function wp_style_engine_add_to_store( $store_key, $css_rules = array() ) { * * @return string A compiled stylesheet from stored CSS rules. */ -function wp_style_engine_get_stylesheet( $store_key ) { - if ( empty( $store_key ) ) { +function wp_style_engine_get_stylesheet_from_store( $store_key ) { + if ( empty( $store_key ) || ! class_exists( 'WP_Style_Engine' ) ) { return ''; } - return WP_Style_Engine::get_instance()::compile_stylesheet_from_store( $store_key ); -} + $style_engine = WP_Style_Engine::get_instance(); + $store = $style_engine::get_store( $store_key ); + return WP_Style_Engine::get_instance()::compile_stylesheet_from_css_rules( $store->get_all_rules() ); +} diff --git a/packages/style-engine/phpunit/class-wp-style-engine-processor-test.php b/packages/style-engine/phpunit/class-wp-style-engine-processor-test.php index 8070024adf3133..f60c8df6f0d837 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-processor-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-processor-test.php @@ -14,12 +14,34 @@ * Tests for compiling and rendering styles from a store of CSS rules. */ class WP_Style_Engine_Processor_Test extends WP_UnitTestCase { + /** + * Should compile CSS rules. + */ + public function test_return_rules_as_css() { + $a_nice_css_rule = new WP_Style_Engine_CSS_Rule( '.a-nice-rule' ); + $a_nice_css_rule->add_declarations( + array( + 'color' => 'var(--nice-color)', + 'background-color' => 'purple', + ) + ); + $a_nicer_css_rule = new WP_Style_Engine_CSS_Rule( '.a-nicer-rule' ); + $a_nicer_css_rule->add_declarations( + array( + 'font-family' => 'Nice sans', + 'font-size' => '1em', + 'background-color' => 'purple', + ) + ); + $a_nice_processor = new WP_Style_Engine_Processor( array( $a_nice_css_rule, $a_nicer_css_rule ) ); + $this->assertEquals( '.a-nice-rule {color: var(--nice-color); background-color: purple;}.a-nicer-rule {font-family: Nice sans; font-size: 1em; background-color: purple;}', $a_nice_processor->get_css() ); + } + /** * Should compile CSS rules from the store. */ public function test_return_store_rules_as_css() { - $a_nice_store = WP_Style_Engine_CSS_Rules_Store_Gutenberg::get_store( 'nice' ); - $a_nice_renderer = new WP_Style_Engine_Processor_Gutenberg( $a_nice_store ); + $a_nice_store = WP_Style_Engine_CSS_Rules_Store_Gutenberg::get_store( 'nice' ); $a_nice_store->add_rule( '.a-nice-rule' )->add_declarations( array( 'color' => 'var(--nice-color)', @@ -33,7 +55,7 @@ public function test_return_store_rules_as_css() { 'background-color' => 'purple', ) ); - + $a_nice_renderer = new WP_Style_Engine_Processor_Gutenberg( $a_nice_store->get_all_rules() ); $this->assertEquals( '.a-nice-rule {color: var(--nice-color); background-color: purple;}.a-nicer-rule {font-family: Nice sans; font-size: 1em; background-color: purple;}', $a_nice_renderer->get_css() ); } @@ -41,87 +63,100 @@ public function test_return_store_rules_as_css() { * Should merge CSS declarations. */ public function test_dedupe_and_merge_css_declarations() { - $an_excellent_store = WP_Style_Engine_CSS_Rules_Store_Gutenberg::get_store( 'excellent' ); - $an_excellent_renderer = new WP_Style_Engine_Processor_Gutenberg( $an_excellent_store ); - $an_excellent_store->add_rule( '.an-excellent-rule' )->add_declarations( + $an_excellent_rule = new WP_Style_Engine_CSS_Rule( '.an-excellent-rule' ); + $an_excellent_processor = new WP_Style_Engine_Processor(); + $an_excellent_rule->add_declarations( array( 'color' => 'var(--excellent-color)', 'border-style' => 'dotted', ) ); - $an_excellent_store->add_rule( '.an-excellent-rule' )->add_declarations( + $an_excellent_processor->add_rules( $an_excellent_rule ); + + $another_excellent_rule = new WP_Style_Engine_CSS_Rule( '.an-excellent-rule' ); + $another_excellent_rule->add_declarations( array( 'color' => 'var(--excellent-color)', 'border-style' => 'dotted', 'border-color' => 'brown', ) ); + $an_excellent_processor->add_rules( $another_excellent_rule ); + $this->assertEquals( '.an-excellent-rule {color: var(--excellent-color); border-style: dotted; border-color: brown;}', $an_excellent_processor->get_css() ); - $this->assertEquals( '.an-excellent-rule {color: var(--excellent-color); border-style: dotted; border-color: brown;}', $an_excellent_renderer->get_css() ); - - $an_excellent_store->add_rule( '.an-excellent-rule' )->add_declarations( + $yet_another_excellent_rule = new WP_Style_Engine_CSS_Rule( '.an-excellent-rule' ); + $yet_another_excellent_rule->add_declarations( array( 'color' => 'var(--excellent-color)', 'border-style' => 'dashed', 'border-width' => '2px', ) ); - - $this->assertEquals( '.an-excellent-rule {color: var(--excellent-color); border-style: dashed; border-color: brown; border-width: 2px;}', $an_excellent_renderer->get_css() ); + $an_excellent_processor->add_rules( $yet_another_excellent_rule ); + $this->assertEquals( '.an-excellent-rule {color: var(--excellent-color); border-style: dashed; border-color: brown; border-width: 2px;}', $an_excellent_processor->get_css() ); } /** * Should combine duplicate CSS rules. */ public function test_combine_css_rules() { - $a_sweet_store = WP_Style_Engine_CSS_Rules_Store_Gutenberg::get_store( 'sweet' ); - $a_sweet_renderer = new WP_Style_Engine_Processor_Gutenberg( $a_sweet_store ); - $a_sweet_store->add_rule( '.a-sweet-rule' )->add_declarations( + $a_sweet_rule = new WP_Style_Engine_CSS_Rule( + '.a-sweet-rule', array( 'color' => 'var(--sweet-color)', 'background-color' => 'purple', ) ); - $a_sweet_store->add_rule( '#an-even-sweeter-rule > marquee' )->add_declarations( + + $a_sweeter_rule = new WP_Style_Engine_CSS_Rule( + '#an-even-sweeter-rule > marquee', array( 'color' => 'var(--sweet-color)', 'background-color' => 'purple', ) ); - $this->assertEquals( '.a-sweet-rule,#an-even-sweeter-rule > marquee {color: var(--sweet-color); background-color: purple;}', $a_sweet_renderer->get_css() ); - } + $a_sweet_processor = new WP_Style_Engine_Processor( array( $a_sweet_rule, $a_sweeter_rule ) ); - /** - * Should combine and store CSS rules. - */ - public function test_store_combined_css_rules() { - $a_lovely_store = WP_Style_Engine_CSS_Rules_Store_Gutenberg::get_store( 'lovely' ); - $a_lovely_renderer = new WP_Style_Engine_Processor_Gutenberg( $a_lovely_store ); - $a_lovely_store->add_rule( '.a-lovely-rule' )->add_declarations( + $this->assertEquals( '.a-sweet-rule,#an-even-sweeter-rule > marquee {color: var(--sweet-color); background-color: purple;}', $a_sweet_processor->get_css() ); + } + /** + * Should combine and store CSS rules. + */ + public function test_combine_previously_added_css_rules() { + $a_lovely_processor = new WP_Style_Engine_Processor(); + $a_lovely_rule = new WP_Style_Engine_CSS_Rule( + '.a-lovely-rule', array( 'border-color' => 'purple', ) ); - $a_lovely_store->add_rule( '.a-lovelier-rule' )->add_declarations( + $a_lovely_processor->add_rules( $a_lovely_rule ); + $a_lovelier_rule = new WP_Style_Engine_CSS_Rule( + '.a-lovelier-rule', array( 'border-color' => 'purple', ) ); + $a_lovely_processor->add_rules( $a_lovelier_rule ); + $this->assertEquals( '.a-lovely-rule,.a-lovelier-rule {border-color: purple;}', $a_lovely_processor->get_css() ); - $this->assertEquals( '.a-lovely-rule,.a-lovelier-rule {border-color: purple;}', $a_lovely_renderer->get_css() ); - - $a_lovely_store->add_rule( '.a-most-lovely-rule' )->add_declarations( + $a_most_lovely_rule = new WP_Style_Engine_CSS_Rule( + '.a-most-lovely-rule', array( 'border-color' => 'purple', ) ); - $a_lovely_store->add_rule( '.a-perfectly-lovely-rule' )->add_declarations( + $a_lovely_processor->add_rules( $a_most_lovely_rule ); + + $a_perfectly_lovely_rule = new WP_Style_Engine_CSS_Rule( + '.a-perfectly-lovely-rule', array( 'border-color' => 'purple', ) ); + $a_lovely_processor->add_rules( $a_perfectly_lovely_rule ); - $this->assertEquals( '.a-lovely-rule,.a-lovelier-rule,.a-most-lovely-rule,.a-perfectly-lovely-rule {border-color: purple;}', $a_lovely_renderer->get_css() ); + $this->assertEquals( '.a-lovely-rule,.a-lovelier-rule,.a-most-lovely-rule,.a-perfectly-lovely-rule {border-color: purple;}', $a_lovely_processor->get_css() ); } } diff --git a/packages/style-engine/phpunit/class-wp-style-engine-test.php b/packages/style-engine/phpunit/class-wp-style-engine-test.php index 3dc5ebd1d4cf57..50a2841b2a2eee 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -29,8 +29,8 @@ public function tear_down() { * * @dataProvider data_generate_block_supports_styles_fixtures * - * @param array $block_styles The incoming block styles object. - * @param array $options Style engine options. + * @param array $block_styles The incoming block styles object. + * @param array $options Style engine options. * @param string $expected_output The expected output. */ public function test_generate_block_supports_styles( $block_styles, $options, $expected_output ) { @@ -512,30 +512,77 @@ public function data_generate_block_supports_styles_fixtures() { * Tests adding rules to a store and retrieving a generated stylesheet. */ public function test_add_to_store() { - $styles = array( - '.saruman' => array( - 'color' => 'white', - 'height' => '100px', - 'border-style' => 'solid', - 'align-self' => 'unset', + $css_rules = array( + array( + 'selector' => '.saruman', + 'css_declarations' => array( + 'color' => 'white', + 'height' => '100px', + 'border-style' => 'solid', + 'align-self' => 'unset', + ), ), - '.gandalf' => array( - 'color' => 'grey', - 'height' => '90px', - 'border-style' => 'dotted', - 'align-self' => 'safe center', + array( + 'selector' => '.gandalf', + 'css_declarations' => array( + 'color' => 'grey', + 'height' => '90px', + 'border-style' => 'dotted', + 'align-self' => 'safe center', + ), ), - '.radagast' => array( - 'color' => 'brown', - 'height' => '60px', - 'border-style' => 'dashed', - 'align-self' => 'stretch', + array( + 'selector' => '.radagast', + 'css_declarations' => array( + 'color' => 'brown', + 'height' => '60px', + 'border-style' => 'dashed', + 'align-self' => 'stretch', + ), ), ); - $store = wp_style_engine_add_to_store( 'test-store', $styles ); + $store = wp_style_engine_add_to_store( 'test-store', $css_rules ); $this->assertInstanceOf( 'WP_Style_Engine_CSS_Rules_Store', $store ); - $compiled_stylesheet = wp_style_engine_get_stylesheet( 'test-store' ); + $compiled_stylesheet = wp_style_engine_get_stylesheet_from_store( 'test-store' ); + $this->assertSame( '.saruman {color: white; height: 100px; border-style: solid; align-self: unset;}.gandalf {color: grey; height: 90px; border-style: dotted; align-self: safe center;}.radagast {color: brown; height: 60px; border-style: dashed; align-self: stretch;}', $compiled_stylesheet ); + } + + /** + * Tests retrieving a generated stylesheet from any rules. + */ + public function test_get_stylesheet_from_css_rules() { + $css_rules = array( + array( + 'selector' => '.saruman', + 'css_declarations' => array( + 'color' => 'white', + 'height' => '100px', + 'border-style' => 'solid', + 'align-self' => 'unset', + ), + ), + array( + 'selector' => '.gandalf', + 'css_declarations' => array( + 'color' => 'grey', + 'height' => '90px', + 'border-style' => 'dotted', + 'align-self' => 'safe center', + ), + ), + array( + 'selector' => '.radagast', + 'css_declarations' => array( + 'color' => 'brown', + 'height' => '60px', + 'border-style' => 'dashed', + 'align-self' => 'stretch', + ), + ), + ); + + $compiled_stylesheet = wp_style_engine_get_stylesheet_from_css_rules( $css_rules ); $this->assertSame( '.saruman {color: white; height: 100px; border-style: solid; align-self: unset;}.gandalf {color: grey; height: 90px; border-style: dotted; align-self: safe center;}.radagast {color: brown; height: 60px; border-style: dashed; align-self: stretch;}', $compiled_stylesheet ); } } From e8a621dc8f93ac7ea4c0294d913f94b3cadf47e6 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 29 Jul 2022 15:43:06 +1000 Subject: [PATCH 12/29] dump var_dump() --- lib/block-supports/layout.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 3595a3ce4110d7..f2d866bce46425 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -208,7 +208,6 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support // Return compiled layout styles to retain backwards compatibility. // Since https://github.com/WordPress/gutenberg/pull/42452 we no longer call wp_enqueue_block_support_styles in this block supports file. - var_dump(gutenberg_style_engine_get_stylesheet_from_css_rules( $layout_styles )); return gutenberg_style_engine_get_stylesheet_from_css_rules( $layout_styles ); } From 9ba523236bf72c0150c4448a226b7c93eb36d01d Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Fri, 29 Jul 2022 09:31:13 +0300 Subject: [PATCH 13/29] Improve the processor --- .../class-wp-style-engine-processor.php | 24 ++++++++++++++----- .../style-engine/class-wp-style-engine.php | 9 ++++--- .../class-wp-style-engine-processor-test.php | 9 ++++--- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine-processor.php b/packages/style-engine/class-wp-style-engine-processor.php index c96ee96bafe9c1..480711241c641d 100644 --- a/packages/style-engine/class-wp-style-engine-processor.php +++ b/packages/style-engine/class-wp-style-engine-processor.php @@ -2,7 +2,7 @@ /** * WP_Style_Engine_Processor * - * Compiles styles from a store of CSS rules. + * Compiles styles from stores or collection of CSS rules. * * @package Gutenberg */ @@ -12,12 +12,19 @@ } /** - * Compiles styles from a collection of CSS rules. + * Compiles styles from stores or collection of CSS rules. * * @access private */ class WP_Style_Engine_Processor { + /** + * The Style-Engine Store objects + * + * @var WP_Style_Engine_CSS_Rules_Store[] + */ + protected $stores = array(); + /** * The set of CSS rules that this processor will work on. * @@ -26,12 +33,12 @@ class WP_Style_Engine_Processor { protected $css_rules = array(); /** - * Constructor. + * Add a store to the processor. * - * @param WP_Style_Engine_CSS_Rule[] $css_rules An array of WP_Style_Engine_CSS_Rule objects from a store or otherwise. + * @param WP_Style_Engine_CSS_Rules_Store $store The store to add. */ - public function __construct( $css_rules = array() ) { - $this->add_rules( $css_rules ); + public function add_store( WP_Style_Engine_CSS_Rules_Store $store ) { + $this->stores[] = $store; } /** @@ -59,6 +66,11 @@ public function add_rules( $css_rules ) { * @return string The computed CSS. */ public function get_css() { + // If we have stores, get the rules from them. + foreach ( $this->stores as $store ) { + $this->add_rules( $store->get_all_rules() ); + } + // Combine CSS selectors that have identical declarations. $this->combine_rules_selectors(); diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 0f4a1734c8a5dd..2e48bf8c42b8a1 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -367,7 +367,9 @@ public static function process_and_enqueue_stored_styles() { $stores = WP_Style_Engine_CSS_Rules_Store::get_stores(); foreach ( $stores as $key => $store ) { - $styles = static::compile_stylesheet_from_css_rules( $store->get_all_rules() ); + $processor = new WP_Style_Engine_Processor(); + $processor->add_store( $store ); + $styles = $processor->get_css(); if ( ! empty( $styles ) ) { wp_register_style( $key, false, array(), true, true ); @@ -591,7 +593,8 @@ public static function compile_css( $css_declarations, $css_selector ) { * @return string A compiled stylesheet from stored CSS rules. */ public static function compile_stylesheet_from_css_rules( $css_rules ) { - $processor = new WP_Style_Engine_Processor( $css_rules ); + $processor = new WP_Style_Engine_Processor(); + $processor->add_rules( $css_rules ); return $processor->get_css(); } } @@ -752,5 +755,5 @@ function wp_style_engine_get_stylesheet_from_store( $store_key ) { $style_engine = WP_Style_Engine::get_instance(); $store = $style_engine::get_store( $store_key ); - return WP_Style_Engine::get_instance()::compile_stylesheet_from_css_rules( $store->get_all_rules() ); + return WP_Style_Engine::compile_stylesheet_from_css_rules( $store->get_all_rules() ); } diff --git a/packages/style-engine/phpunit/class-wp-style-engine-processor-test.php b/packages/style-engine/phpunit/class-wp-style-engine-processor-test.php index f60c8df6f0d837..ebee00f05ce16a 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-processor-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-processor-test.php @@ -33,7 +33,8 @@ public function test_return_rules_as_css() { 'background-color' => 'purple', ) ); - $a_nice_processor = new WP_Style_Engine_Processor( array( $a_nice_css_rule, $a_nicer_css_rule ) ); + $a_nice_processor = new WP_Style_Engine_Processor(); + $a_nice_processor->add_rules( array( $a_nice_css_rule, $a_nicer_css_rule ) ); $this->assertEquals( '.a-nice-rule {color: var(--nice-color); background-color: purple;}.a-nicer-rule {font-family: Nice sans; font-size: 1em; background-color: purple;}', $a_nice_processor->get_css() ); } @@ -55,7 +56,8 @@ public function test_return_store_rules_as_css() { 'background-color' => 'purple', ) ); - $a_nice_renderer = new WP_Style_Engine_Processor_Gutenberg( $a_nice_store->get_all_rules() ); + $a_nice_renderer = new WP_Style_Engine_Processor_Gutenberg(); + $a_nice_renderer->add_store( $a_nice_store ); $this->assertEquals( '.a-nice-rule {color: var(--nice-color); background-color: purple;}.a-nicer-rule {font-family: Nice sans; font-size: 1em; background-color: purple;}', $a_nice_renderer->get_css() ); } @@ -116,7 +118,8 @@ public function test_combine_css_rules() { ) ); - $a_sweet_processor = new WP_Style_Engine_Processor( array( $a_sweet_rule, $a_sweeter_rule ) ); + $a_sweet_processor = new WP_Style_Engine_Processor(); + $a_sweet_processor->add_rules( array( $a_sweet_rule, $a_sweeter_rule ) ); $this->assertEquals( '.a-sweet-rule,#an-even-sweeter-rule > marquee {color: var(--sweet-color); background-color: purple;}', $a_sweet_processor->get_css() ); } From b41af7d8504d54592c5303b5c76a723eece0f0ce Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Fri, 29 Jul 2022 10:35:55 +0300 Subject: [PATCH 14/29] remove trailing commas - compatibility with PHP < 7.2 --- lib/block-supports/layout.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index f2d866bce46425..78ac11594c2276 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -71,7 +71,7 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support array( 'selector' => "$selector .alignfull", 'css_declarations' => array( 'max-width' => 'none' ), - ), + ) ); if ( isset( $block_spacing ) ) { @@ -120,7 +120,7 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support 'margin-block-start' => $gap_value, 'margin-block-end' => '0', ), - ), + ) ); } } From 4ccf65016ed62b3cd369dff2fbf7a75a6b05dacc Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Fri, 29 Jul 2022 10:43:23 +0300 Subject: [PATCH 15/29] rename css_declarations to declarations --- lib/block-supports/layout.php | 52 +++++++++---------- .../style-engine/class-wp-style-engine.php | 34 ++++++------ .../phpunit/class-wp-style-engine-test.php | 24 ++++----- 3 files changed, 55 insertions(+), 55 deletions(-) diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 78ac11594c2276..45c896164bee26 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -57,20 +57,20 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support array_push( $layout_styles, array( - 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", - 'css_declarations' => array( + 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", + 'declarations' => array( 'max-width' => $all_max_width_value, 'margin-left' => 'auto !important', 'margin-right' => 'auto !important', ), ), array( - 'selector' => "$selector > .alignwide", - 'css_declarations' => array( 'max-width' => $wide_max_width_value ), + 'selector' => "$selector > .alignwide", + 'declarations' => array( 'max-width' => $wide_max_width_value ), ), array( - 'selector' => "$selector .alignfull", - 'css_declarations' => array( 'max-width' => 'none' ), + 'selector' => "$selector .alignfull", + 'declarations' => array( 'max-width' => 'none' ), ) ); @@ -86,15 +86,15 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support if ( isset( $block_spacing_values['declarations']['padding-right'] ) ) { $padding_right = $block_spacing_values['declarations']['padding-right']; $layout_styles[] = array( - 'selector' => "$selector > .alignfull", - 'css_declarations' => array( 'margin-right' => "calc($padding_right * -1)" ), + 'selector' => "$selector > .alignfull", + 'declarations' => array( 'margin-right' => "calc($padding_right * -1)" ), ); } if ( isset( $block_spacing_values['declarations']['padding-left'] ) ) { $padding_left = $block_spacing_values['declarations']['padding-left']; $layout_styles[] = array( - 'selector' => "$selector > .alignfull", - 'css_declarations' => array( 'margin-left' => "calc($padding_left * -1)" ), + 'selector' => "$selector > .alignfull", + 'declarations' => array( 'margin-left' => "calc($padding_left * -1)" ), ); } } @@ -108,15 +108,15 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support array_push( $layout_styles, array( - 'selector' => "$selector > *", - 'css_declarations' => array( + 'selector' => "$selector > *", + 'declarations' => array( 'margin-block-start' => '0', 'margin-block-end' => '0', ), ), array( - 'selector' => "$selector > * + *", - 'css_declarations' => array( + 'selector' => "$selector > * + *", + 'declarations' => array( 'margin-block-start' => $gap_value, 'margin-block-end' => '0', ), @@ -145,8 +145,8 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support if ( ! empty( $layout['flexWrap'] ) && 'nowrap' === $layout['flexWrap'] ) { $layout_styles[] = array( - 'selector' => $selector, - 'css_declarations' => array( 'flex-wrap' => 'nowrap' ), + 'selector' => $selector, + 'declarations' => array( 'flex-wrap' => 'nowrap' ), ); } @@ -158,8 +158,8 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support } if ( $gap_value && ! $should_skip_gap_serialization ) { $layout_styles[] = array( - 'selector' => $selector, - 'css_declarations' => array( 'gapp' => $gap_value ), + 'selector' => $selector, + 'declarations' => array( 'gapp' => $gap_value ), ); } } @@ -172,15 +172,15 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support */ if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { $layout_styles[] = array( - 'selector' => $selector, - 'css_declarations' => array( 'justify-content' => $justify_content_options[ $layout['justifyContent'] ] ), + 'selector' => $selector, + 'declarations' => array( 'justify-content' => $justify_content_options[ $layout['justifyContent'] ] ), ); } if ( ! empty( $layout['verticalAlignment'] ) && array_key_exists( $layout['verticalAlignment'], $vertical_alignment_options ) ) { $layout_styles[] = array( - 'selector' => $selector, - 'css_declarations' => array( 'align-items' => $vertical_alignment_options[ $layout['verticalAlignment'] ] ), + 'selector' => $selector, + 'declarations' => array( 'align-items' => $vertical_alignment_options[ $layout['verticalAlignment'] ] ), ); } } else { @@ -190,13 +190,13 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support ); if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { $layout_styles[] = array( - 'selector' => $selector, - 'css_declarations' => array( 'align-items' => $justify_content_options[ $layout['justifyContent'] ] ), + 'selector' => $selector, + 'declarations' => array( 'align-items' => $justify_content_options[ $layout['justifyContent'] ] ), ); } else { $layout_styles[] = array( - 'selector' => $selector, - 'css_declarations' => array( 'align-items' => 'flex-start' ), + 'selector' => $selector, + 'declarations' => array( 'align-items' => 'flex-start' ), ); } } diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 2e48bf8c42b8a1..1f2fee8dde1a38 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -390,8 +390,8 @@ public static function process_and_enqueue_stored_styles() { * );. * * @return array array( - * 'css_declarations' => (array) An array of parsed CSS property => CSS value pairs. - * 'classnames' => (array) A flat array of classnames. + * 'declarations' => (array) An array of parsed CSS property => CSS value pairs. + * 'classnames' => (array) A flat array of classnames. * ); */ public function parse_block_styles( $block_styles, $options ) { @@ -421,8 +421,8 @@ public function parse_block_styles( $block_styles, $options ) { } return array( - 'classnames' => $classnames, - 'css_declarations' => $css_declarations, + 'classnames' => $classnames, + 'declarations' => $css_declarations, ); } @@ -653,11 +653,11 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { return $styles_output; } - if ( ! empty( $parsed_styles['css_declarations'] ) ) { - $styles_output['css'] = $style_engine::compile_css( $parsed_styles['css_declarations'], $options['selector'] ); - $styles_output['declarations'] = $parsed_styles['css_declarations']; + if ( ! empty( $parsed_styles['declarations'] ) ) { + $styles_output['css'] = $style_engine::compile_css( $parsed_styles['declarations'], $options['selector'] ); + $styles_output['declarations'] = $parsed_styles['declarations']; if ( true === $options['enqueue'] ) { - $style_engine::store_css_rule( $options['context'], $options['selector'], $parsed_styles['css_declarations'] ); + $style_engine::store_css_rule( $options['context'], $options['selector'], $parsed_styles['declarations'] ); } } @@ -676,7 +676,7 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { * @param string $store_key A valid store key. * @param array $css_rules array( * 'selector' => (string) A CSS selector. - * 'css_declarations' => (boolean) An array of CSS definitions, e.g., array( "$property" => "$value" ). + * 'declarations' => (boolean) An array of CSS definitions, e.g., array( "$property" => "$value" ). * );. * * @return WP_Style_Engine_CSS_Rules_Store|null. @@ -692,23 +692,23 @@ function wp_style_engine_add_to_store( $store_key, $css_rules = array() ) { } foreach ( $css_rules as $css_rule ) { - if ( ! isset( $css_rule['selector'], $css_rule['css_declarations'] ) ) { + if ( ! isset( $css_rule['selector'], $css_rule['declarations'] ) ) { continue; } - $style_engine::store_css_rule( $store_key, $css_rule['selector'], $css_rule['css_declarations'] ); + $style_engine::store_css_rule( $store_key, $css_rule['selector'], $css_rule['declarations'] ); } return $style_engine::get_store( $store_key ); } /** - * Returns compiled CSS from a collection of selectors and css_declarations. + * Returns compiled CSS from a collection of selectors and declarations. * This won't add to any store, but is useful for returnin a compiled style sheet from any CSS selector + declarations combos. * * @access public * * @param array $css_rules array( - * 'selector' => (string) A CSS selector. - * 'css_declarations' => (boolean) An array of CSS definitions, e.g., array( "$property" => "$value" ). + * 'selector' => (string) A CSS selector. + * 'declarations' => (boolean) An array of CSS definitions, e.g., array( "$property" => "$value" ). * );. * * @return string A compiled CSS string. @@ -722,14 +722,14 @@ function wp_style_engine_get_stylesheet_from_css_rules( $css_rules = array() ) { $css_rule_objects = array(); foreach ( $css_rules as $css_rule ) { - if ( ! isset( $css_rule['selector'], $css_rule['css_declarations'] ) ) { + if ( ! isset( $css_rule['selector'], $css_rule['declarations'] ) ) { continue; } - if ( empty( $css_rule['css_declarations'] ) || ! is_array( $css_rule['css_declarations'] ) ) { + if ( empty( $css_rule['declarations'] ) || ! is_array( $css_rule['declarations'] ) ) { continue; } - $css_rule_objects[] = new WP_Style_Engine_CSS_Rule( $css_rule['selector'], $css_rule['css_declarations'] ); + $css_rule_objects[] = new WP_Style_Engine_CSS_Rule( $css_rule['selector'], $css_rule['declarations'] ); } if ( empty( $css_rule_objects ) ) { diff --git a/packages/style-engine/phpunit/class-wp-style-engine-test.php b/packages/style-engine/phpunit/class-wp-style-engine-test.php index 50a2841b2a2eee..e5338de43c9c88 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -514,8 +514,8 @@ public function data_generate_block_supports_styles_fixtures() { public function test_add_to_store() { $css_rules = array( array( - 'selector' => '.saruman', - 'css_declarations' => array( + 'selector' => '.saruman', + 'declarations' => array( 'color' => 'white', 'height' => '100px', 'border-style' => 'solid', @@ -523,8 +523,8 @@ public function test_add_to_store() { ), ), array( - 'selector' => '.gandalf', - 'css_declarations' => array( + 'selector' => '.gandalf', + 'declarations' => array( 'color' => 'grey', 'height' => '90px', 'border-style' => 'dotted', @@ -532,8 +532,8 @@ public function test_add_to_store() { ), ), array( - 'selector' => '.radagast', - 'css_declarations' => array( + 'selector' => '.radagast', + 'declarations' => array( 'color' => 'brown', 'height' => '60px', 'border-style' => 'dashed', @@ -554,8 +554,8 @@ public function test_add_to_store() { public function test_get_stylesheet_from_css_rules() { $css_rules = array( array( - 'selector' => '.saruman', - 'css_declarations' => array( + 'selector' => '.saruman', + 'declarations' => array( 'color' => 'white', 'height' => '100px', 'border-style' => 'solid', @@ -563,8 +563,8 @@ public function test_get_stylesheet_from_css_rules() { ), ), array( - 'selector' => '.gandalf', - 'css_declarations' => array( + 'selector' => '.gandalf', + 'declarations' => array( 'color' => 'grey', 'height' => '90px', 'border-style' => 'dotted', @@ -572,8 +572,8 @@ public function test_get_stylesheet_from_css_rules() { ), ), array( - 'selector' => '.radagast', - 'css_declarations' => array( + 'selector' => '.radagast', + 'declarations' => array( 'color' => 'brown', 'height' => '60px', 'border-style' => 'dashed', From e30e4fb316a7d709688e137956b52fca300d89bc Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Fri, 29 Jul 2022 10:44:15 +0300 Subject: [PATCH 16/29] remove unused variable Removing unused function wp_style_engine_get_stylesheet_from_store Updating tests to check for merging and deduping --- .../class-wp-style-engine-processor.php | 2 +- .../style-engine/class-wp-style-engine.php | 19 ------- .../phpunit/class-wp-style-engine-test.php | 52 +++++++++++++------ 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine-processor.php b/packages/style-engine/class-wp-style-engine-processor.php index 480711241c641d..713318497da6c8 100644 --- a/packages/style-engine/class-wp-style-engine-processor.php +++ b/packages/style-engine/class-wp-style-engine-processor.php @@ -90,7 +90,7 @@ public function get_css() { private function combine_rules_selectors() { // Build an array of selectors along with the JSON-ified styles to make comparisons easier. $selectors_json = array(); - foreach ( $this->css_rules as $index => $rule ) { + foreach ( $this->css_rules as $rule ) { $rule_selector = $rule->get_selector(); $declarations = $rule->get_declarations()->get_declarations(); diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 1f2fee8dde1a38..19e1086010ac55 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -738,22 +738,3 @@ function wp_style_engine_get_stylesheet_from_css_rules( $css_rules = array() ) { return $style_engine::compile_stylesheet_from_css_rules( $css_rule_objects ); } - -/** - * Returns a compiled stylesheet from stored CSS rules. - * - * @access public - * - * @param string $store_key A valid store key. - * - * @return string A compiled stylesheet from stored CSS rules. - */ -function wp_style_engine_get_stylesheet_from_store( $store_key ) { - if ( empty( $store_key ) || ! class_exists( 'WP_Style_Engine' ) ) { - return ''; - } - - $style_engine = WP_Style_Engine::get_instance(); - $store = $style_engine::get_store( $store_key ); - return WP_Style_Engine::compile_stylesheet_from_css_rules( $store->get_all_rules() ); -} diff --git a/packages/style-engine/phpunit/class-wp-style-engine-test.php b/packages/style-engine/phpunit/class-wp-style-engine-test.php index e5338de43c9c88..d3bf4476e4e528 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -512,6 +512,20 @@ public function data_generate_block_supports_styles_fixtures() { * Tests adding rules to a store and retrieving a generated stylesheet. */ public function test_add_to_store() { + $store = wp_style_engine_add_to_store( 'test-store', array() ); + + // wp_style_engine_add_to_store returns a store object. + $this->assertInstanceOf( 'WP_Style_Engine_CSS_Rules_Store', $store ); + + // Check that the style engine knows about the store. + $stored_store = WP_Style_Engine::get_instance()::get_store( 'test-store' ); + $this->assertInstanceOf( 'WP_Style_Engine_CSS_Rules_Store', $stored_store ); + } + + /** + * Tests retrieving a generated stylesheet from any rules. + */ + public function test_get_stylesheet_from_css_rules() { $css_rules = array( array( 'selector' => '.saruman', @@ -541,48 +555,52 @@ public function test_add_to_store() { ), ), ); - $store = wp_style_engine_add_to_store( 'test-store', $css_rules ); - $this->assertInstanceOf( 'WP_Style_Engine_CSS_Rules_Store', $store ); - $compiled_stylesheet = wp_style_engine_get_stylesheet_from_store( 'test-store' ); + $compiled_stylesheet = wp_style_engine_get_stylesheet_from_css_rules( $css_rules ); $this->assertSame( '.saruman {color: white; height: 100px; border-style: solid; align-self: unset;}.gandalf {color: grey; height: 90px; border-style: dotted; align-self: safe center;}.radagast {color: brown; height: 60px; border-style: dashed; align-self: stretch;}', $compiled_stylesheet ); } /** - * Tests retrieving a generated stylesheet from any rules. + * Tests that incoming styles are deduped and merged. */ - public function test_get_stylesheet_from_css_rules() { + public function test_get_deduped_and_merged_stylesheet() { $css_rules = array( array( - 'selector' => '.saruman', + 'selector' => '.gandalf', 'declarations' => array( - 'color' => 'white', - 'height' => '100px', - 'border-style' => 'solid', - 'align-self' => 'unset', + 'color' => 'grey', + 'height' => '90px', + 'border-style' => 'dotted', ), ), array( 'selector' => '.gandalf', + 'declarations' => array( + 'color' => 'white', + 'height' => '190px', + 'padding' => '10px', + 'margin-bottom' => '100px', + ), + ), + array( + 'selector' => '.dumbledore', 'declarations' => array( 'color' => 'grey', 'height' => '90px', 'border-style' => 'dotted', - 'align-self' => 'safe center', ), ), array( - 'selector' => '.radagast', + 'selector' => '.rincewind', 'declarations' => array( - 'color' => 'brown', - 'height' => '60px', - 'border-style' => 'dashed', - 'align-self' => 'stretch', + 'color' => 'grey', + 'height' => '90px', + 'border-style' => 'dotted', ), ), ); $compiled_stylesheet = wp_style_engine_get_stylesheet_from_css_rules( $css_rules ); - $this->assertSame( '.saruman {color: white; height: 100px; border-style: solid; align-self: unset;}.gandalf {color: grey; height: 90px; border-style: dotted; align-self: safe center;}.radagast {color: brown; height: 60px; border-style: dashed; align-self: stretch;}', $compiled_stylesheet ); + $this->assertSame( '.gandalf {color: white; height: 190px; border-style: dotted; padding: 10px; margin-bottom: 100px;}.dumbledore,.rincewind {color: grey; height: 90px; border-style: dotted;}', $compiled_stylesheet ); } } From 062b920d181d1f53c429f89581bb4ccf799431bb Mon Sep 17 00:00:00 2001 From: ramonjd Date: Mon, 1 Aug 2022 13:14:19 +1000 Subject: [PATCH 17/29] Switch parse_block_styles from public to protected static --- packages/style-engine/class-wp-style-engine.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 19e1086010ac55..ed9cfffc599683 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -394,7 +394,7 @@ public static function process_and_enqueue_stored_styles() { * 'classnames' => (array) A flat array of classnames. * ); */ - public function parse_block_styles( $block_styles, $options ) { + public static function parse_block_styles( $block_styles, $options ) { if ( empty( $block_styles ) || ! is_array( $block_styles ) ) { return array(); } @@ -600,7 +600,7 @@ public static function compile_stylesheet_from_css_rules( $css_rules ) { } /** - * Global public interface method to WP_Style_Engine->get_styles to generate styles from a single style object, e.g., + * Global public interface method to WP_Style_Engine::get_styles to generate styles from a single style object, e.g., * the value of a block's attributes.style object or the top level styles in theme.json. * See: https://developer.wordpress.org/block-editor/reference-guides/theme-json-reference/theme-json-living/#styles and * https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/ @@ -643,7 +643,7 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { // Block supports styles. if ( 'block-supports' === $options['context'] ) { - $parsed_styles = $style_engine->parse_block_styles( $block_styles, $options ); + $parsed_styles = $style_engine::parse_block_styles( $block_styles, $options ); } // Output. @@ -702,7 +702,7 @@ function wp_style_engine_add_to_store( $store_key, $css_rules = array() ) { /** * Returns compiled CSS from a collection of selectors and declarations. - * This won't add to any store, but is useful for returnin a compiled style sheet from any CSS selector + declarations combos. + * This won't add to any store, but is useful for returning a compiled style sheet from any CSS selector + declarations combos. * * @access public * From 5e4164a120fdc3e1db924260f64e7c42aa60485a Mon Sep 17 00:00:00 2001 From: ramonjd Date: Mon, 1 Aug 2022 13:20:45 +1000 Subject: [PATCH 18/29] Now that all methods are static, there's no need to call `get_instance()` --- packages/style-engine/class-wp-style-engine.php | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index ed9cfffc599683..2b5f22e97679de 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -638,12 +638,11 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { ); $options = wp_parse_args( $options, $defaults ); - $style_engine = WP_Style_Engine::get_instance(); $parsed_styles = null; // Block supports styles. if ( 'block-supports' === $options['context'] ) { - $parsed_styles = $style_engine::parse_block_styles( $block_styles, $options ); + $parsed_styles = WP_Style_Engine::parse_block_styles( $block_styles, $options ); } // Output. @@ -654,10 +653,10 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { } if ( ! empty( $parsed_styles['declarations'] ) ) { - $styles_output['css'] = $style_engine::compile_css( $parsed_styles['declarations'], $options['selector'] ); + $styles_output['css'] = WP_Style_Engine::compile_css( $parsed_styles['declarations'], $options['selector'] ); $styles_output['declarations'] = $parsed_styles['declarations']; if ( true === $options['enqueue'] ) { - $style_engine::store_css_rule( $options['context'], $options['selector'], $parsed_styles['declarations'] ); + WP_Style_Engine::store_css_rule( $options['context'], $options['selector'], $parsed_styles['declarations'] ); } } @@ -686,18 +685,17 @@ function wp_style_engine_add_to_store( $store_key, $css_rules = array() ) { return null; } - $style_engine = WP_Style_Engine::get_instance(); if ( empty( $css_rules ) ) { - return $style_engine::get_store( $store_key ); + return WP_Style_Engine::get_store( $store_key ); } foreach ( $css_rules as $css_rule ) { if ( ! isset( $css_rule['selector'], $css_rule['declarations'] ) ) { continue; } - $style_engine::store_css_rule( $store_key, $css_rule['selector'], $css_rule['declarations'] ); + WP_Style_Engine::store_css_rule( $store_key, $css_rule['selector'], $css_rule['declarations'] ); } - return $style_engine::get_store( $store_key ); + return WP_Style_Engine::get_store( $store_key ); } /** @@ -718,7 +716,6 @@ function wp_style_engine_get_stylesheet_from_css_rules( $css_rules = array() ) { return ''; } - $style_engine = WP_Style_Engine::get_instance(); $css_rule_objects = array(); foreach ( $css_rules as $css_rule ) { @@ -736,5 +733,5 @@ function wp_style_engine_get_stylesheet_from_css_rules( $css_rules = array() ) { return ''; } - return $style_engine::compile_stylesheet_from_css_rules( $css_rule_objects ); + return WP_Style_Engine::compile_stylesheet_from_css_rules( $css_rule_objects ); } From fcebf93b2f9cb3181571ae62f1870b52eed0f4fa Mon Sep 17 00:00:00 2001 From: ramonjd Date: Mon, 1 Aug 2022 13:34:51 +1000 Subject: [PATCH 19/29] Revert get_instance() in wp_style_engine_add_to_store because we want to ensure the hook is enqueued here. --- packages/style-engine/class-wp-style-engine.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 2b5f22e97679de..06013b17d222aa 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -600,7 +600,7 @@ public static function compile_stylesheet_from_css_rules( $css_rules ) { } /** - * Global public interface method to WP_Style_Engine::get_styles to generate styles from a single style object, e.g., + * Global public interface method to generate styles from a single style object, e.g., * the value of a block's attributes.style object or the top level styles in theme.json. * See: https://developer.wordpress.org/block-editor/reference-guides/theme-json-reference/theme-json-living/#styles and * https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/ @@ -685,17 +685,20 @@ function wp_style_engine_add_to_store( $store_key, $css_rules = array() ) { return null; } + // Get instance here to ensure that we register hooks to enqueue stored styles. + $style_engine = WP_Style_Engine::get_instance(); + if ( empty( $css_rules ) ) { - return WP_Style_Engine::get_store( $store_key ); + return $style_engine::get_store( $store_key ); } foreach ( $css_rules as $css_rule ) { if ( ! isset( $css_rule['selector'], $css_rule['declarations'] ) ) { continue; } - WP_Style_Engine::store_css_rule( $store_key, $css_rule['selector'], $css_rule['declarations'] ); + $style_engine::store_css_rule( $store_key, $css_rule['selector'], $css_rule['declarations'] ); } - return WP_Style_Engine::get_store( $store_key ); + return $style_engine::get_store( $store_key ); } /** From d0d5fe5fd736aa3a32e4aed537c4513bcc04d857 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Mon, 1 Aug 2022 15:09:00 +1000 Subject: [PATCH 20/29] Adding a test for the 'enqueue' flag. --- .../phpunit/class-wp-style-engine-test.php | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/packages/style-engine/phpunit/class-wp-style-engine-test.php b/packages/style-engine/phpunit/class-wp-style-engine-test.php index d3bf4476e4e528..14938e075fa260 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -27,23 +27,23 @@ public function tear_down() { /** * Tests generating block styles and classnames based on various manifestations of the $block_styles argument. * - * @dataProvider data_generate_block_supports_styles_fixtures + * @dataProvider data_get_styles_fixtures * * @param array $block_styles The incoming block styles object. * @param array $options Style engine options. * @param string $expected_output The expected output. */ - public function test_generate_block_supports_styles( $block_styles, $options, $expected_output ) { + public function test_generate_get_styles( $block_styles, $options, $expected_output ) { $generated_styles = wp_style_engine_get_styles( $block_styles, $options ); $this->assertSame( $expected_output, $generated_styles ); } /** - * Data provider. + * Data provider for test_generate_get_styles(). * * @return array */ - public function data_generate_block_supports_styles_fixtures() { + public function data_get_styles_fixtures() { return array( 'default_return_value' => array( 'block_styles' => array(), @@ -508,6 +508,34 @@ public function data_generate_block_supports_styles_fixtures() { ); } + /** + * Tests adding rules to a store and retrieving a generated stylesheet. + */ + public function test_enqueue_block_styles_store() { + $block_styles = array( + 'spacing' => array( + 'padding' => array( + 'top' => '42px', + 'left' => '2%', + 'bottom' => '44px', + 'right' => '5rem', + ), + ), + ); + + $generated_styles = wp_style_engine_get_styles( + $block_styles, + array( + 'enqueue' => true, + 'context' => 'block-supports', + 'selector' => 'article', + ) + ); + $store = WP_Style_Engine::get_instance()::get_store( 'block-supports' ); + $rule = $store->get_all_rules()['article']; + $this->assertSame( $generated_styles['css'], $rule->get_css() ); + } + /** * Tests adding rules to a store and retrieving a generated stylesheet. */ From e59eb10b5b3f8e6e3e97903fff1690517ad0ed72 Mon Sep 17 00:00:00 2001 From: Ramon Date: Mon, 1 Aug 2022 15:11:17 +1000 Subject: [PATCH 21/29] Update lib/block-supports/layout.php Co-authored-by: Andrew Serong <14988353+andrewserong@users.noreply.github.com> --- lib/block-supports/layout.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 45c896164bee26..8ae0ffc007fa98 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -159,7 +159,7 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support if ( $gap_value && ! $should_skip_gap_serialization ) { $layout_styles[] = array( 'selector' => $selector, - 'declarations' => array( 'gapp' => $gap_value ), + 'declarations' => array( 'gap' => $gap_value ), ); } } From 5d7b8277834fe08fd54666f242a861974e9d4276 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Mon, 1 Aug 2022 15:09:00 +1000 Subject: [PATCH 22/29] Adding a test for the 'enqueue' flag. --- .../style-engine/class-wp-style-engine.php | 13 +++---- .../phpunit/class-wp-style-engine-test.php | 36 ++++++++++++++++--- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 06013b17d222aa..6bba9ef0e305c1 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -283,7 +283,7 @@ protected static function is_valid_style_value( $style_value ) { */ private function __construct() { // Register the hook callback to render stored styles to the page. - static::render_styles( array( __CLASS__, 'process_and_enqueue_stored_styles' ) ); + static::register_actions( array( __CLASS__, 'process_and_enqueue_stored_styles' ) ); } /** @@ -331,7 +331,7 @@ public static function get_store( $store_key ) { /** * Taken from gutenberg_enqueue_block_support_styles() * - * This function takes care of adding inline styles + * This function takes care of registering hooks to add inline styles * in the proper place, depending on the theme in use. * * For block themes, it's loaded in the head. @@ -344,7 +344,7 @@ public static function get_store( $store_key ) { * * @see gutenberg_enqueue_block_support_styles() */ - protected static function render_styles( $callable, $priority = 10 ) { + protected static function register_actions( $callable, $priority = 10 ) { if ( ! $callable ) { return; } @@ -637,12 +637,13 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { 'enqueue' => false, ); + $style_engine = WP_Style_Engine::get_instance(); $options = wp_parse_args( $options, $defaults ); $parsed_styles = null; // Block supports styles. if ( 'block-supports' === $options['context'] ) { - $parsed_styles = WP_Style_Engine::parse_block_styles( $block_styles, $options ); + $parsed_styles = $style_engine::parse_block_styles( $block_styles, $options ); } // Output. @@ -653,10 +654,10 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) { } if ( ! empty( $parsed_styles['declarations'] ) ) { - $styles_output['css'] = WP_Style_Engine::compile_css( $parsed_styles['declarations'], $options['selector'] ); + $styles_output['css'] = $style_engine::compile_css( $parsed_styles['declarations'], $options['selector'] ); $styles_output['declarations'] = $parsed_styles['declarations']; if ( true === $options['enqueue'] ) { - WP_Style_Engine::store_css_rule( $options['context'], $options['selector'], $parsed_styles['declarations'] ); + $style_engine::store_css_rule( $options['context'], $options['selector'], $parsed_styles['declarations'] ); } } diff --git a/packages/style-engine/phpunit/class-wp-style-engine-test.php b/packages/style-engine/phpunit/class-wp-style-engine-test.php index d3bf4476e4e528..14938e075fa260 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -27,23 +27,23 @@ public function tear_down() { /** * Tests generating block styles and classnames based on various manifestations of the $block_styles argument. * - * @dataProvider data_generate_block_supports_styles_fixtures + * @dataProvider data_get_styles_fixtures * * @param array $block_styles The incoming block styles object. * @param array $options Style engine options. * @param string $expected_output The expected output. */ - public function test_generate_block_supports_styles( $block_styles, $options, $expected_output ) { + public function test_generate_get_styles( $block_styles, $options, $expected_output ) { $generated_styles = wp_style_engine_get_styles( $block_styles, $options ); $this->assertSame( $expected_output, $generated_styles ); } /** - * Data provider. + * Data provider for test_generate_get_styles(). * * @return array */ - public function data_generate_block_supports_styles_fixtures() { + public function data_get_styles_fixtures() { return array( 'default_return_value' => array( 'block_styles' => array(), @@ -508,6 +508,34 @@ public function data_generate_block_supports_styles_fixtures() { ); } + /** + * Tests adding rules to a store and retrieving a generated stylesheet. + */ + public function test_enqueue_block_styles_store() { + $block_styles = array( + 'spacing' => array( + 'padding' => array( + 'top' => '42px', + 'left' => '2%', + 'bottom' => '44px', + 'right' => '5rem', + ), + ), + ); + + $generated_styles = wp_style_engine_get_styles( + $block_styles, + array( + 'enqueue' => true, + 'context' => 'block-supports', + 'selector' => 'article', + ) + ); + $store = WP_Style_Engine::get_instance()::get_store( 'block-supports' ); + $rule = $store->get_all_rules()['article']; + $this->assertSame( $generated_styles['css'], $rule->get_css() ); + } + /** * Tests adding rules to a store and retrieving a generated stylesheet. */ From 8d021eeb150320607b05ce893a589e26686d07e7 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 1 Aug 2022 10:04:00 +0300 Subject: [PATCH 23/29] Add named stores to the processor --- .../class-wp-style-engine-css-rules-store.php | 19 +++++++++++++++++++ .../class-wp-style-engine-processor.php | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/style-engine/class-wp-style-engine-css-rules-store.php b/packages/style-engine/class-wp-style-engine-css-rules-store.php index 0b0cb356a816e3..f53706e4384aa0 100644 --- a/packages/style-engine/class-wp-style-engine-css-rules-store.php +++ b/packages/style-engine/class-wp-style-engine-css-rules-store.php @@ -27,6 +27,14 @@ class WP_Style_Engine_CSS_Rules_Store { */ protected static $stores = array(); + + /** + * The store name. + * + * @var string + */ + protected $name = ''; + /** * An array of CSS Rules objects assigned to the store. * @@ -44,6 +52,8 @@ class WP_Style_Engine_CSS_Rules_Store { public static function get_store( $store_name = 'default' ) { if ( ! isset( static::$stores[ $store_name ] ) ) { static::$stores[ $store_name ] = new static(); + // Set the store name. + static::$stores[ $store_name ]->name = $store_name; } return static::$stores[ $store_name ]; } @@ -66,6 +76,15 @@ public static function remove_all_stores() { static::$stores = array(); } + /** + * Get the store name. + * + * @return string + */ + public function get_name() { + return $this->name; + } + /** * Get an array of all rules. * diff --git a/packages/style-engine/class-wp-style-engine-processor.php b/packages/style-engine/class-wp-style-engine-processor.php index 713318497da6c8..b563c621fe17a8 100644 --- a/packages/style-engine/class-wp-style-engine-processor.php +++ b/packages/style-engine/class-wp-style-engine-processor.php @@ -38,7 +38,7 @@ class WP_Style_Engine_Processor { * @param WP_Style_Engine_CSS_Rules_Store $store The store to add. */ public function add_store( WP_Style_Engine_CSS_Rules_Store $store ) { - $this->stores[] = $store; + $this->stores[ $store->get_name() ] = $store; } /** From 5f60026dc85368333c8668d74fabcdf7cf8eaa72 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 1 Aug 2022 11:08:05 +0300 Subject: [PATCH 24/29] avoid setting var for something that only gets used once --- .../style-engine/class-wp-style-engine-processor.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine-processor.php b/packages/style-engine/class-wp-style-engine-processor.php index b563c621fe17a8..2dc9bd5e5c3bc8 100644 --- a/packages/style-engine/class-wp-style-engine-processor.php +++ b/packages/style-engine/class-wp-style-engine-processor.php @@ -91,11 +91,9 @@ private function combine_rules_selectors() { // Build an array of selectors along with the JSON-ified styles to make comparisons easier. $selectors_json = array(); foreach ( $this->css_rules as $rule ) { - - $rule_selector = $rule->get_selector(); - $declarations = $rule->get_declarations()->get_declarations(); + $declarations = $rule->get_declarations()->get_declarations(); ksort( $declarations ); - $selectors_json[ $rule_selector ] = wp_json_encode( $declarations ); + $selectors_json[ $rule->get_selector() ] = wp_json_encode( $declarations ); } // Combine selectors that have the same styles. @@ -107,7 +105,7 @@ private function combine_rules_selectors() { continue; } - $new_declarations = $this->css_rules[ $selector ]->get_declarations(); + $declarations = $this->css_rules[ $selector ]->get_declarations(); foreach ( $duplicates as $key ) { // Unset the duplicates from the $selectors_json array to avoid looping through them as well. @@ -116,7 +114,7 @@ private function combine_rules_selectors() { unset( $this->css_rules[ $key ] ); } // Create a new rule with the combined selectors. - $this->css_rules[ implode( ',', $duplicates ) ] = new WP_Style_Engine_CSS_Rule( implode( ',', $duplicates ), $new_declarations ); + $this->css_rules[ implode( ',', $duplicates ) ] = new WP_Style_Engine_CSS_Rule( implode( ',', $duplicates ), $declarations ); } } } From a63f9cbb987509a47cfe7a2d025c0f48da1fbe6a Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 1 Aug 2022 11:10:40 +0300 Subject: [PATCH 25/29] Only use "else" if absolutely necessary --- packages/style-engine/class-wp-style-engine-processor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine-processor.php b/packages/style-engine/class-wp-style-engine-processor.php index 2dc9bd5e5c3bc8..088513e83284d1 100644 --- a/packages/style-engine/class-wp-style-engine-processor.php +++ b/packages/style-engine/class-wp-style-engine-processor.php @@ -54,9 +54,9 @@ public function add_rules( $css_rules ) { $selector = $rule->get_selector(); if ( isset( $this->css_rules[ $selector ] ) ) { $this->css_rules[ $selector ]->add_declarations( $rule->get_declarations() ); - } else { - $this->css_rules[ $rule->get_selector() ] = $rule; + continue; } + $this->css_rules[ $rule->get_selector() ] = $rule; } } From 0eaef08d759069f8fb7181208e668009f912815d Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 1 Aug 2022 11:15:33 +0300 Subject: [PATCH 26/29] Add a set_name method --- .../class-wp-style-engine-css-rules-store.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/style-engine/class-wp-style-engine-css-rules-store.php b/packages/style-engine/class-wp-style-engine-css-rules-store.php index f53706e4384aa0..d3cc079afe6e96 100644 --- a/packages/style-engine/class-wp-style-engine-css-rules-store.php +++ b/packages/style-engine/class-wp-style-engine-css-rules-store.php @@ -53,7 +53,7 @@ public static function get_store( $store_name = 'default' ) { if ( ! isset( static::$stores[ $store_name ] ) ) { static::$stores[ $store_name ] = new static(); // Set the store name. - static::$stores[ $store_name ]->name = $store_name; + static::$stores[ $store_name ]->set_name( $store_name ); } return static::$stores[ $store_name ]; } @@ -76,6 +76,17 @@ public static function remove_all_stores() { static::$stores = array(); } + /** + * Set the store name. + * + * @param string $name The store name. + * + * @return void + */ + public function set_name( $name ) { + $this->name = $name; + } + /** * Get the store name. * From e4c791bd4908a8514d58cea10494b78fe757c112 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 1 Aug 2022 11:21:14 +0300 Subject: [PATCH 27/29] combine & simplify conditions --- packages/style-engine/class-wp-style-engine.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 6bba9ef0e305c1..1b39636de243a9 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -723,11 +723,7 @@ function wp_style_engine_get_stylesheet_from_css_rules( $css_rules = array() ) { $css_rule_objects = array(); foreach ( $css_rules as $css_rule ) { - if ( ! isset( $css_rule['selector'], $css_rule['declarations'] ) ) { - continue; - } - - if ( empty( $css_rule['declarations'] ) || ! is_array( $css_rule['declarations'] ) ) { + if ( empty( $css_rule['selector'] ) || empty( $css_rule['declarations'] ) || ! is_array( $css_rule['declarations'] ) ) { continue; } $css_rule_objects[] = new WP_Style_Engine_CSS_Rule( $css_rule['selector'], $css_rule['declarations'] ); From 787f79385279fbb43b141c1aeb1d44c0be07b337 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 1 Aug 2022 11:37:15 +0300 Subject: [PATCH 28/29] use empty() instead of isset() checks here --- packages/style-engine/class-wp-style-engine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 1b39636de243a9..365b1283778712 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -694,7 +694,7 @@ function wp_style_engine_add_to_store( $store_key, $css_rules = array() ) { } foreach ( $css_rules as $css_rule ) { - if ( ! isset( $css_rule['selector'], $css_rule['declarations'] ) ) { + if ( empty( $css_rule['selector'] ) || empty( $css_rule['declarations'] ) ) { continue; } $style_engine::store_css_rule( $store_key, $css_rule['selector'], $css_rule['declarations'] ); From 7dd5773a9a3c86aa05c24f0a70ce3c8181822ba0 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 1 Aug 2022 11:43:45 +0300 Subject: [PATCH 29/29] shorten it --- packages/style-engine/class-wp-style-engine.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 365b1283778712..33533fc872f699 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -348,13 +348,9 @@ protected static function register_actions( $callable, $priority = 10 ) { if ( ! $callable ) { return; } - $action_hook_name = 'wp_footer'; - if ( wp_is_block_theme() ) { - $action_hook_name = 'wp_head'; - } add_action( 'wp_enqueue_scripts', $callable ); add_action( - $action_hook_name, + wp_is_block_theme() ? 'wp_head' : 'wp_footer', $callable, $priority ); @@ -472,10 +468,7 @@ protected static function get_classnames( $style_value, $style_definition ) { * @return array An array of CSS definitions, e.g., array( "$property" => "$value" ). */ protected static function get_css_declarations( $style_value, $style_definition, $should_skip_css_vars = false ) { - if ( - isset( $style_definition['value_func'] ) && - is_callable( $style_definition['value_func'] ) - ) { + if ( isset( $style_definition['value_func'] ) && is_callable( $style_definition['value_func'] ) ) { return call_user_func( $style_definition['value_func'], $style_value, $style_definition, $should_skip_css_vars ); }