Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Style engine: add optimize flag and combine functions into wp_style_engine_get_stylesheet #42878

Merged
merged 4 commits into from
Aug 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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