Skip to content

Commit

Permalink
Style engine: enqueue block supports styles in Gutenberg (#42880)
Browse files Browse the repository at this point in the history
* Enqueuing block supports styles in gutenberg
Updating README.md

* get_instance() and constructor no longer needed

* remove $instance declaration

* Rename hook callback to `gutenberg_enqueue_stored_styles`
Hard code a list of core styles that we want to fetch from the store and the order in which we fetch them.

* Removing layout-block-supports store
Chaining store ids for the style tag id attribute so it's clear what's being included. Also adding a comment for debugging for the same purpose.

* Removing layout-block-supports store
Chaining store ids for the style tag id attribute so it's clear what's being included. Also adding a comment for debugging for the same purpose.
Adding tests for enqueuing styles
Updated README.md

* Assign $duplicate_selectors var to avoid duplicate implodes

* Update packages/style-engine/README.md

Co-authored-by: Andrew Serong <[email protected]>

* Apply suggestions from code review

Co-authored-by: Andrew Serong <[email protected]>

* Remove unnecessary conditional

* Remove deprecation notice for now until we can deal with other usages, e.g., gallery/index.php

* For block themes, print stored styles in the header.
For classic themes, in the footer.

* Update packages/style-engine/README.md

Co-authored-by: Sören Wrede <[email protected]>

Co-authored-by: Ari Stathopoulos <[email protected]>
Co-authored-by: Andrew Serong <[email protected]>
Co-authored-by: Sören Wrede <[email protected]>
  • Loading branch information
4 people authored Aug 9, 2022
1 parent ff8538b commit 090171d
Show file tree
Hide file tree
Showing 6 changed files with 333 additions and 109 deletions.
58 changes: 58 additions & 0 deletions lib/compat/wordpress-6.1/script-loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,61 @@ static function () use ( $style ) {
);
}

/**
* Fetches, processes and compiles stored core styles, then combines and renders them to the page.
* Styles are stored via the style engine API. See: packages/style-engine/README.md
*/
function gutenberg_enqueue_stored_styles() {
$is_block_theme = wp_is_block_theme();
$is_classic_theme = ! $is_block_theme;

/*
* For block themes, print stored styles in the header.
* For classic themes, in the footer.
*/
if (
( $is_block_theme && doing_action( 'wp_footer' ) ) ||
( $is_classic_theme && doing_action( 'wp_enqueue_scripts' ) )
) {
return;
}

$core_styles_keys = array( 'block-supports' );
$compiled_core_stylesheet = '';
$style_tag_id = 'core';
foreach ( $core_styles_keys as $style_key ) {
// Add comment to identify core styles sections in debugging.
if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
$compiled_core_stylesheet .= "/**\n * Core styles: $style_key\n */\n";
}
// Chain core store ids to signify what the styles contain.
$style_tag_id .= '-' . $style_key;
$compiled_core_stylesheet .= gutenberg_style_engine_get_stylesheet_from_store( $style_key );
}

// Combine Core styles.
if ( ! empty( $compiled_core_stylesheet ) ) {
wp_register_style( $style_tag_id, false, array(), true, true );
wp_add_inline_style( $style_tag_id, $compiled_core_stylesheet );
wp_enqueue_style( $style_tag_id );
}

// If there are any other stores registered by themes etc, print them out.
$additional_stores = WP_Style_Engine_CSS_Rules_Store_Gutenberg::get_stores();
foreach ( array_keys( $additional_stores ) as $store_name ) {
if ( in_array( $store_name, $core_styles_keys, true ) ) {
continue;
}
$styles = gutenberg_style_engine_get_stylesheet_from_store( $store_name );
if ( ! empty( $styles ) ) {
$key = "wp-style-engine-$store_name";
wp_register_style( $key, false, array(), true, true );
wp_add_inline_style( $key, $styles );
wp_enqueue_style( $key );
}
}
}

/**
* This applies a filter to the list of style nodes that comes from `get_style_nodes` in WP_Theme_JSON.
* This particular filter removes all of the blocks from the array.
Expand Down Expand Up @@ -109,5 +164,8 @@ function gutenberg_enqueue_global_styles() {
remove_action( 'wp_enqueue_scripts', 'gutenberg_enqueue_global_styles_assets' );
remove_action( 'wp_footer', 'gutenberg_enqueue_global_styles_assets' );

// Enqueue global styles, and then block supports styles.
add_action( 'wp_enqueue_scripts', 'gutenberg_enqueue_global_styles' );
add_action( 'wp_footer', 'gutenberg_enqueue_global_styles', 1 );
add_action( 'wp_enqueue_scripts', 'gutenberg_enqueue_stored_styles' );
add_action( 'wp_footer', 'gutenberg_enqueue_stored_styles', 1 );
166 changes: 162 additions & 4 deletions packages/style-engine/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,158 @@

The Style Engine powering global styles and block customizations.

## Backend API

### wp_style_engine_get_styles()

Global public function to generate styles from a single style object, e.g., the value of
a [block's attributes.style object](https://developer.wordpress.org/block-editor/reference-guides/theme-json-reference/theme-json-living/#styles)
or
the [top level styles in theme.json](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/)
.

_Parameters_

- _$block_styles_ `array` A block's `attributes.style` object or the top level styles in theme.json
- _$options_ `array<string|boolean>` An array of options to determine the output.
- _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 in a `style` tag on the site 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.

_Returns_
`array<string|array>|null`

```php
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.
);
```

It will return compiled CSS declarations for inline styles, or, where a selector is provided, a complete CSS rule.

To enqueue a style for rendering in the site's frontend, the `$options` array requires the following:

1. **selector (string)** - this is the CSS selector for your block style CSS declarations.
2. **context (string)** - this tells the style engine where to store the styles. Styles in the same context will be
batched together and printed in the same HTML style tag. The default is `'block-supports'`.
3. **enqueue (boolean)** - tells the style engine to store the styles.

`wp_style_engine_get_styles` will return the compiled CSS and CSS declarations array.

#### Usage

```php
$block_styles = array(
'spacing' => array( 'padding' => '100px' )
);
$styles = wp_style_engine_get_styles(
$block_styles,
array(
'selector' => '.a-selector',
'context' => 'block-supports',
'enqueue' => true,
)
);
print_r( $styles );

/*
array(
'css' => '.a-selector{padding:10px}'
'declarations' => array( 'padding' => '100px' )
)
*/
```

### wp_style_engine_get_stylesheet_from_css_rules()

Use this function to compile and return a stylesheet for any CSS rules. The style engine will automatically merge declarations and combine selectors.

This function acts as a CSS compiler, but will also enqueue styles for rendering where `enqueue` and `context` strings are passed in the options.

_Parameters_

- _$css_rules_ `array<array>`
- _$options_ `array<string|boolean>` An array of options to determine the output.
- _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 store using the `context` value as a key.

_Returns_
`string` A compiled CSS string based on `$css_rules`.

#### Usage

```php
$styles = array(
array(
'selector'. => '.wp-pumpkin',
'declarations' => array( 'color' => 'orange' )
),
array(
'selector'. => '.wp-tomato',
'declarations' => array( 'color' => 'red' )
),
array(
'selector'. => '.wp-tomato',
'declarations' => array( 'padding' => '100px' )
),
array(
'selector'. => '.wp-kumquat',
'declarations' => array( 'color' => 'orange' )
),
);

$stylesheet = wp_style_engine_get_stylesheet_from_css_rules(
$styles,
array(
'context' => 'block-supports', // Indicates that these styles should be stored with block supports CSS.
'enqueue' => true, // Render the styles for output.
)
);
print_r( $stylesheet ); // .wp-pumpkin, .wp-kumquat {color:orange}.wp-tomato{color:red;padding:100px}
```

### wp_style_engine_get_stylesheet_from_store()

Returns compiled CSS from a store, if found.

_Parameters_

- _$store_key_ `string` An identifier describing the origin of the style object, e.g., 'block-supports' or ' global-styles'. Default is 'block-supports'.

_Returns_
`string` A compiled CSS string from the stored CSS rules.

#### Usage

```php
// First register some styles.
$styles = array(
array(
'selector'. => '.wp-apple',
'declarations' => array( 'color' => 'green' )
),
);

$stylesheet = wp_style_engine_get_stylesheet_from_css_rules(
$styles,
array(
'context' => 'fruit-styles',
'enqueue' => true,
)
);

// Later, fetch compiled rules from store.
$stylesheet = gutenberg_style_engine_get_stylesheet_from_store( 'fruit-styles' );
print_r( $stylesheet ); // .wp-apple{color:green;}
```

## Installation (JS only)

Install the module
Expand All @@ -10,13 +162,18 @@ Install the module
npm install @wordpress/style-engine --save
```

_This package assumes that your code will run in an **ES2015+** environment. If you're using an environment that has limited or no support for such language features and APIs, you should include [the polyfill shipped in `@wordpress/babel-preset-default`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/babel-preset-default#polyfill) in your code._
_This package assumes that your code will run in an **ES2015+** environment. If you're using an environment that has
limited or no support for such language features and APIs, you should
include [the polyfill shipped in `@wordpress/babel-preset-default`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/babel-preset-default#polyfill)
in your code._

## Important

This Package is considered experimental at the moment. The idea is to have a package used to generate styles based on a style object that is consistent between: backend, frontend, block style object and theme.json.
This Package is considered experimental at the moment. The idea is to have a package used to generate styles based on a
style object that is consistent between: backend, frontend, block style object and theme.json.

Because this package is experimental and still in development it does not yet generate a `wp.styleEngine` global. To get there, the following tasks need to be completed:
Because this package is experimental and still in development it does not yet generate a `wp.styleEngine` global. To get
there, the following tasks need to be completed:

**TODO List:**

Expand All @@ -26,7 +183,8 @@ Because this package is experimental and still in development it does not yet ge
- Support generating styles in the backend (block supports and theme.json stylesheet). (Ongoing)
- Refactor all block styles to use the style engine server side. (Ongoing)
- Consolidate global and block style rendering and enqueuing
- Refactor all blocks to consistently use the "style" attribute for all customizations (get rid of the preset specific attributes).
- Refactor all blocks to consistently use the "style" attribute for all customizations (get rid of the preset specific
attributes).

See [Tracking: Add a Style Engine to manage rendering block styles #38167](https://github.com/WordPress/gutenberg/issues/38167)

Expand Down
3 changes: 2 additions & 1 deletion packages/style-engine/class-wp-style-engine-processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ 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 ), $declarations );
$duplicate_selectors = implode( ',', $duplicates );
$this->css_rules[ $duplicate_selectors ] = new WP_Style_Engine_CSS_Rule( $duplicate_selectors, $declarations );
}
}
}
Loading

0 comments on commit 090171d

Please sign in to comment.