Skip to content

Commit

Permalink
Style engine: add optimize flag and combine functions into wp_style_e…
Browse files Browse the repository at this point in the history
…ngine_get_stylesheet (#42878)

* Added an optimize flag to toggle combining selectors
Adding tests
Updating comments

* Merged `wp_style_engine_get_stylesheet_from_css_rules()` and `wp_style_engine_add_to_store()` into `wp_style_engine_get_stylesheet()`

* Default $options value to avoid "Too few arguments" warning in PHP unit tests

* Rename wp_style_engine_get_stylesheet to wp_style_engine_get_stylesheet_from_css_rules
Formatting tests for readability
  • Loading branch information
ramonjd authored Aug 3, 2022
1 parent f9b7ef3 commit 6004cb1
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 64 deletions.
3 changes: 0 additions & 3 deletions lib/block-supports/elements.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,6 @@ function gutenberg_render_elements_support_styles( $pre_render, $block ) {

/*
* For now we only care about link color.
* This code in the future when we have a public API
* should take advantage of WP_Theme_JSON_Gutenberg::compute_style_properties
* and work for any element and style.
*/
$skip_link_color_serialization = gutenberg_should_skip_block_supports_serialization( $block_type, 'color', 'link' );

Expand Down
10 changes: 7 additions & 3 deletions lib/block-supports/layout.php
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,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_from_css_rules( $layout_styles );
return gutenberg_style_engine_get_stylesheet_from_css_rules(
$layout_styles,
array(
'context' => 'layout-block-supports',
'enqueue' => true,
)
);
}

return '';
Expand Down
15 changes: 13 additions & 2 deletions packages/style-engine/class-wp-style-engine-processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,27 @@ public function add_rules( $css_rules ) {
/**
* Get the CSS rules as a string.
*
* @param array $options array(
* 'optimize' => (boolean) Whether to optimize the CSS output, e.g., combine rules.
* );.
*
* @return string The computed CSS.
*/
public function get_css() {
public function get_css( $options = array() ) {
$defaults = array(
'optimize' => true,
);
$options = wp_parse_args( $options, $defaults );

// 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();
if ( true === $options['optimize'] ) {
$this->combine_rules_selectors();
}

// Build the CSS.
$css = '';
Expand Down
68 changes: 25 additions & 43 deletions packages/style-engine/class-wp-style-engine.php
Original file line number Diff line number Diff line change
Expand Up @@ -623,15 +623,14 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) {
if ( ! class_exists( 'WP_Style_Engine' ) ) {
return array();
}
$defaults = array(
$defaults = array(
'selector' => null,
'context' => 'block-supports',
'convert_vars_to_classnames' => false,
'enqueue' => false,
);

$style_engine = WP_Style_Engine::get_instance();
$options = wp_parse_args( $options, $defaults );
$style_engine = WP_Style_Engine::get_instance();
$parsed_styles = null;

// Block supports styles.
Expand Down Expand Up @@ -661,70 +660,53 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) {
return array_filter( $styles_output );
}

/**
* 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.
* 'declarations' => (boolean) An array of CSS definitions, e.g., array( "$property" => "$value" ).
* );.
*
* @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;
}

// 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 $style_engine::get_store( $store_key );
}

foreach ( $css_rules as $css_rule ) {
if ( empty( $css_rule['selector'] ) || empty( $css_rule['declarations'] ) ) {
continue;
}
$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 declarations.
* This won't add to any store, but is useful for returning a compiled style sheet from any CSS selector + declarations combos.
*
* @access public
*
* @param array $css_rules array(
* 'selector' => (string) A CSS selector.
* 'declarations' => (boolean) An array of CSS definitions, e.g., array( "$property" => "$value" ).
* @param array<array> $css_rules array(
* array(
* 'selector' => (string) A CSS selector.
* declarations' => (boolean) An array of CSS definitions, e.g., array( "$property" => "$value" ).
* )
* );.
* @param array<string> $options array(
* '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.
* );.
*
* @return string A compiled CSS string.
*/
function wp_style_engine_get_stylesheet_from_css_rules( $css_rules = array() ) {
if ( ! class_exists( 'WP_Style_Engine' ) ) {
function wp_style_engine_get_stylesheet_from_css_rules( $css_rules, $options = array() ) {
if ( ! class_exists( 'WP_Style_Engine' ) || empty( $css_rules ) ) {
return '';
}

$defaults = array(
'context' => 'block-supports',
'enqueue' => false,
);
$options = wp_parse_args( $options, $defaults );
$style_engine = WP_Style_Engine::get_instance();
$css_rule_objects = array();

foreach ( $css_rules as $css_rule ) {
if ( empty( $css_rule['selector'] ) || empty( $css_rule['declarations'] ) || ! is_array( $css_rule['declarations'] ) ) {
continue;
}

if ( true === $options['enqueue'] ) {
$style_engine::store_css_rule( $options['context'], $css_rule['selector'], $css_rule['declarations'] );
}

$css_rule_objects[] = new WP_Style_Engine_CSS_Rule( $css_rule['selector'], $css_rule['declarations'] );
}

if ( empty( $css_rule_objects ) ) {
return '';
}

return WP_Style_Engine::compile_stylesheet_from_css_rules( $css_rule_objects );
return $style_engine::compile_stylesheet_from_css_rules( $css_rule_objects );
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,17 @@ public function test_return_rules_as_css() {
);
$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() );
$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_store = WP_Style_Engine_CSS_Rules_Store::get_store( 'nice' );
$a_nice_store->add_rule( '.a-nice-rule' )->add_declarations(
array(
'color' => 'var(--nice-color)',
Expand All @@ -56,9 +59,12 @@ public function test_return_store_rules_as_css() {
'background-color' => 'purple',
)
);
$a_nice_renderer = new WP_Style_Engine_Processor_Gutenberg();
$a_nice_renderer = new WP_Style_Engine_Processor();
$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() );
$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()
);
}

/**
Expand All @@ -84,7 +90,10 @@ public function test_dedupe_and_merge_css_declarations() {
)
);
$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_processor->get_css()
);

$yet_another_excellent_rule = new WP_Style_Engine_CSS_Rule( '.an-excellent-rule' );
$yet_another_excellent_rule->add_declarations(
Expand All @@ -95,7 +104,47 @@ public function test_dedupe_and_merge_css_declarations() {
)
);
$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() );
$this->assertEquals(
'.an-excellent-rule {color: var(--excellent-color); border-style: dashed; border-color: brown; border-width: 2px;}',
$an_excellent_processor->get_css()
);
}

/**
* Should print out uncombined selectors duplicate CSS rules.
*/
public function test_output_verbose_css_rules() {
$a_sweet_rule = new WP_Style_Engine_CSS_Rule(
'.a-sweet-rule',
array(
'color' => 'var(--sweet-color)',
'background-color' => 'purple',
)
);

$a_sweeter_rule = new WP_Style_Engine_CSS_Rule(
'#an-even-sweeter-rule > marquee',
array(
'color' => 'var(--sweet-color)',
'background-color' => 'purple',
)
);

$the_sweetest_rule = new WP_Style_Engine_CSS_Rule(
'.the-sweetest-rule-of-all a',
array(
'color' => 'var(--sweet-color)',
'background-color' => 'purple',
)
);

$a_sweet_processor = new WP_Style_Engine_Processor();
$a_sweet_processor->add_rules( array( $a_sweet_rule, $a_sweeter_rule, $the_sweetest_rule ) );

$this->assertEquals(
'.a-sweet-rule {color: var(--sweet-color); background-color: purple;}#an-even-sweeter-rule > marquee {color: var(--sweet-color); background-color: purple;}.the-sweetest-rule-of-all a {color: var(--sweet-color); background-color: purple;}',
$a_sweet_processor->get_css( array( 'optimize' => false ) )
);
}

/**
Expand All @@ -121,7 +170,10 @@ public function test_combine_css_rules() {
$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() );
$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.
Expand Down Expand Up @@ -160,6 +212,9 @@ public function test_combine_previously_added_css_rules() {
);
$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_processor->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()
);
}
}
35 changes: 30 additions & 5 deletions packages/style-engine/phpunit/class-wp-style-engine-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -540,14 +540,39 @@ public function test_enqueue_block_styles_store() {
* 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 );
$css_rules = array(
array(
'selector' => '.frodo',
'declarations' => array(
'color' => 'brown',
'height' => '10px',
'width' => '30px',
'border-style' => 'dotted',
),
),
array(
'selector' => '.samwise',
'declarations' => array(
'color' => 'brown',
'height' => '20px',
'width' => '50px',
'border-style' => 'solid',
),
),
);
$compiled_stylesheet = wp_style_engine_get_stylesheet_from_css_rules(
$css_rules,
array(
'context' => 'test-store',
'enqueue' => true,
)
);

// Check that the style engine knows about the store.
$stored_store = WP_Style_Engine::get_instance()::get_store( 'test-store' );
$style_engine = WP_Style_Engine::get_instance();
$stored_store = $style_engine::get_store( 'test-store' );
$this->assertInstanceOf( 'WP_Style_Engine_CSS_Rules_Store', $stored_store );
$this->assertSame( $compiled_stylesheet, $style_engine::compile_stylesheet_from_css_rules( $stored_store->get_all_rules() ) );
}

/**
Expand Down

0 comments on commit 6004cb1

Please sign in to comment.