From ae9d7ec37b9ac923a6a86cb14b344c2559ff711b Mon Sep 17 00:00:00 2001 From: ramonjd Date: Tue, 5 Jul 2022 14:57:31 +1000 Subject: [PATCH] Adding a new method to generate global styles: wp_style_engine_generate_global_styles --- .../style-engine/class-wp-style-engine.php | 92 +++++++++++++-- .../phpunit/class-wp-style-engine-test.php | 110 ++++++++++++++++++ 2 files changed, 194 insertions(+), 8 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 15c803832fcbff..b06046f816ff6f 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -142,17 +142,17 @@ class WP_Style_Engine { ), ), 'spacing' => array( - 'padding' => array( + 'blockGap' => array( 'property_keys' => array( - 'default' => 'padding', - 'individual' => 'padding-%s', - ), - 'path' => array( 'spacing', 'padding' ), - 'css_vars' => array( - 'spacing' => '--wp--preset--spacing--$slug', + // @TODO 'grid-gap' has been deprecated in favor of 'gap'. + // See: https://developer.mozilla.org/en-US/docs/Web/CSS/gap. + // Update the white list in safecss_filter_attr (kses.php). + // See: https://core.trac.wordpress.org/ticket/56122 + 'default' => 'grid-gap', ), + 'path' => array( 'spacing', 'blockGap' ), ), - 'margin' => array( + 'margin' => array( 'property_keys' => array( 'default' => 'margin', 'individual' => 'margin-%s', @@ -162,6 +162,16 @@ class WP_Style_Engine { 'spacing' => '--wp--preset--spacing--$slug', ), ), + 'padding' => array( + 'property_keys' => array( + 'default' => 'padding', + 'individual' => 'padding-%s', + ), + 'path' => array( 'spacing', 'padding' ), + 'css_vars' => array( + 'spacing' => '--wp--preset--spacing--$slug', + ), + ), ), 'typography' => array( 'fontSize' => array( @@ -221,6 +231,16 @@ class WP_Style_Engine { ), ); + /** + * The valid elements that can be found under styles. + * + * @var string[] + */ + const ELEMENTS = array( + 'link' => 'a', + 'h1' => 'h1', + ); + /** * Utility method to retrieve the main instance of the class. * @@ -447,6 +467,53 @@ public function generate( $block_styles, $options ) { return $styles_output; } + public function generate_global_styles( $global_styles, $options ) { + if ( empty( $global_styles ) || ! is_array( $global_styles ) ) { + return null; + } + + // The return stylesheet. + $global_stylesheet = ''; + + // Layer 0: Root. + $root_level_styles = $this->generate( $global_styles, array( 'selector' => 'body' ) ); + + if ( ! empty( $root_level_styles['css'] ) ) { + $global_stylesheet .= $root_level_styles['css'] . ' '; + } + + // Layer 1: Elements. + if ( isset( $global_styles['elements'] ) && is_array( $global_styles['elements'] ) ) { + foreach ( $global_styles['elements'] as $element_name => $element_styles ) { + $selector = isset( static::ELEMENTS[ $element_name ] ) ? static::ELEMENTS[ $element_name ] : null; + if ( ! $selector ) { + continue; + } + $element_level_styles = $this->generate( $element_styles, array( 'selector' => $selector ) ); + if ( ! empty( $element_level_styles['css'] ) ) { + $global_stylesheet .= $element_level_styles['css'] . ' '; + } + } + } + + // Layer 2: Blocks. + if ( isset( $global_styles['blocks'] ) && is_array( $global_styles['blocks'] ) ) { + foreach ( $global_styles['blocks'] as $block_name => $block_styles ) { + $selector = '.wp-block-' . str_replace( '/', '-', str_replace( 'core/', '', $block_name ) ); + $block_level_styles = $this->generate( $block_styles, array( 'selector' => $selector ) ); + if ( ! empty( $block_level_styles['css'] ) ) { + $global_stylesheet .= $block_level_styles['css'] . ' '; + } + } + } + + if ( ! empty( $global_stylesheet ) ) { + return rtrim( $global_stylesheet ); + } + + return null; + } + /** * 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. @@ -523,3 +590,12 @@ function wp_style_engine_generate( $block_styles, $options = array() ) { } return null; } + + +function wp_style_engine_generate_global_styles( $global_styles, $options = array() ) { + if ( class_exists( 'WP_Style_Engine' ) ) { + $style_engine = WP_Style_Engine::get_instance(); + return $style_engine->generate_global_styles( $global_styles, $options ); + } + return null; +} 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 3038364a5fc386..ff802cfa51ba10 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -375,4 +375,114 @@ public function data_generate_styles_fixtures() { ), ); } + + /** + * Tests generating styles and classnames based on various manifestations of the $global_styles argument. + * + * @dataProvider data_generate_global_styles_fixtures + */ + public function test_generate_global_styles( $global_styles, $options, $expected_output ) { + $generated_styles = wp_style_engine_generate_global_styles( $global_styles, $options ); + $this->assertSame( $expected_output, $generated_styles ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_generate_global_styles_fixtures() { + return array( + 'default_return_value' => array( + 'global_styles' => array(), + 'options' => null, + 'expected_output' => null, + ), + 'default_return_valid_top_level_css_rules' => array( + 'global_styles' => array( + 'color' => array( + 'text' => 'var(--wp--preset--color--foreground)', + 'background' => 'var(--wp--preset--color--background)', + ), + 'spacing' => array( + 'blockGap' => '2rem', + 'padding' => array( + 'top' => '10%', + 'right' => '20%', + 'bottom' => '10%', + 'left' => '20%', + ), + ), + 'typography' => array( + 'fontFamily' => 'var(--wp--preset--font-family--system-font)', + 'lineHeight' => 2, + 'fontSize' => '1rem', + ), + ), + 'options' => null, + 'expected_output' => 'body { color: var(--wp--preset--color--foreground); background-color: var(--wp--preset--color--background); padding-top: 10%; padding-right: 20%; padding-bottom: 10%; padding-left: 20%; font-size: 1rem; font-family: var(--wp--preset--font-family--system-font); line-height: 2; }', + ), + 'default_return_valid_element_level_css_rules' => array( + 'global_styles' => array( + 'spacing' => array( + 'margin' => '20%', + ), + 'elements' => array( + 'h1' => array( + 'border' => array( + 'radius' => '0', + ), + 'color' => array( + 'text' => '#ffffff', + 'background' => '#000000', + ), + ), + 'link' => array( + 'typography' => array( + 'fontStyle' => 'underline', + ), + 'margin' => array( + 'bottom' => '20px', + ), + 'color' => array( + 'text' => 'var(--wp--preset--color--foreground)', + ), + ), + ), + ), + 'options' => null, + 'expected_output' => 'body { margin: 20%; } h1 { color: #ffffff; background-color: #000000; border-radius: 0; } a { color: var(--wp--preset--color--foreground); font-style: underline; }', + ), + 'default_return_valid_block_level_css_rules' => array( + 'global_styles' => array( + 'spacing' => array( + 'margin' => '20%', + ), + 'blocks' => array( + 'core/button' => array( + 'border' => array( + 'radius' => '0', + ), + 'color' => array( + 'text' => 'piano-red', + 'background' => 'muddy-waters', + ), + ), + 'core/site-title' => array( + 'typography' => array( + 'fontSize' => 'clamp(2em, 2vw, 4em)', + 'fontFamily' => 'Roboto,Oxygen-Sans,Ubuntu,sans-serif', + 'fontStyle' => 'italic', + ), + 'margin' => array( + 'bottom' => '20px', + ), + ), + ), + ), + 'options' => null, + 'expected_output' => 'body { margin: 20%; } .wp-block-button { color: piano-red; background-color: muddy-waters; border-radius: 0; } .wp-block-site-title { font-family: Roboto,Oxygen-Sans,Ubuntu,sans-serif; font-style: italic; }', + ), + ); + } }