1<?php
2/**
3 * Style engine: Public functions
4 *
5 * This file contains a variety of public functions developers can use to interact with
6 * the Style Engine API.
7 *
8 * @package WordPress
9 * @subpackage StyleEngine
10 * @since 6.1.0
11 */
12
13/**
14 * Global public interface method to generate styles from a single style object,
15 * e.g. the value of a block's attributes.style object or the top level styles in theme.json.
16 *
17 * Example usage:
18 *
19 * $styles = wp_style_engine_get_styles(
20 * array(
21 * 'color' => array( 'text' => '#cccccc' ),
22 * )
23 * );
24 *
25 * Returns:
26 *
27 * array(
28 * 'css' => 'color: #cccccc',
29 * 'declarations' => array( 'color' => '#cccccc' ),
30 * 'classnames' => 'has-color',
31 * )
32 *
33 * @since 6.1.0
34 *
35 * @see https://developer.wordpress.org/block-editor/reference-guides/theme-json-reference/theme-json-living/#styles
36 * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/
37 *
38 * @param array $block_styles The style object.
39 * @param array $options {
40 * Optional. An array of options. Default empty array.
41 *
42 * @type string|null $context An identifier describing the origin of the style object,
43 * e.g. 'block-supports' or 'global-styles'. Default null.
44 * When set, the style engine will attempt to store the CSS rules,
45 * where a selector is also passed.
46 * @type bool $convert_vars_to_classnames Whether to skip converting incoming CSS var patterns,
47 * e.g. `var:preset|<PRESET_TYPE>|<PRESET_SLUG>`,
48 * to `var( --wp--preset--* )` values. Default false.
49 * @type string $selector Optional. When a selector is passed,
50 * the value of `$css` in the return value will comprise
51 * a full CSS rule `$selector { ...$css_declarations }`,
52 * otherwise, the value will be a concatenated string
53 * of CSS declarations.
54 * }
55 * @return array {
56 * @type string $css A CSS ruleset or declarations block
57 * formatted to be placed in an HTML `style` attribute or tag.
58 * @type string[] $declarations An associative array of CSS definitions,
59 * e.g. `array( "$property" => "$value", "$property" => "$value" )`.
60 * @type string $classnames Classnames separated by a space.
61 * }
62 */
63function wp_style_engine_get_styles( $block_styles, $options = array() ) {
64 $options = wp_parse_args(
65 $options,
66 array(
67 'selector' => null,
68 'context' => null,
69 'convert_vars_to_classnames' => false,
70 )
71 );
72
73 $parsed_styles = WP_Style_Engine::parse_block_styles( $block_styles, $options );
74
75 // Output.
76 $styles_output = array();
77
78 if ( ! empty( $parsed_styles['declarations'] ) ) {
79 $styles_output['css'] = WP_Style_Engine::compile_css( $parsed_styles['declarations'], $options['selector'] );
80 $styles_output['declarations'] = $parsed_styles['declarations'];
81 if ( ! empty( $options['context'] ) ) {
82 WP_Style_Engine::store_css_rule( $options['context'], $options['selector'], $parsed_styles['declarations'] );
83 }
84 }
85
86 if ( ! empty( $parsed_styles['classnames'] ) ) {
87 $styles_output['classnames'] = implode( ' ', array_unique( $parsed_styles['classnames'] ) );
88 }
89
90 return array_filter( $styles_output );
91}
92
93/**
94 * Returns compiled CSS from a collection of selectors and declarations.
95 * Useful for returning a compiled stylesheet from any collection of CSS selector + declarations.
96 *
97 * Example usage:
98 *
99 * $css_rules = array(
100 * array(
101 * 'selector' => '.elephant-are-cool',
102 * 'declarations' => array(
103 * 'color' => 'gray',
104 * 'width' => '3em',
105 * ),
106 * ),
107 * );
108 *
109 * $css = wp_style_engine_get_stylesheet_from_css_rules( $css_rules );
110 *
111 * Returns:
112 *
113 * .elephant-are-cool{color:gray;width:3em}
114 *
115 * @since 6.1.0
116 * @since 6.6.0 Added support for `$rules_group` in the `$css_rules` array.
117 *
118 * @param array $css_rules {
119 * Required. A collection of CSS rules.
120 *
121 * @type array ...$0 {
122 * @type string $rules_group A parent CSS selector in the case of nested CSS,
123 * or a CSS nested @rule, such as `@media (min-width: 80rem)` or `@layer module`.
124 * @type string $selector A CSS selector.
125 * @type string[] $declarations An associative array of CSS definitions,
126 * e.g. `array( "$property" => "$value", "$property" => "$value" )`.
127 * }
128 * }
129 * @param array $options {
130 * Optional. An array of options. Default empty array.
131 *
132 * @type string|null $context An identifier describing the origin of the style object,
133 * e.g. 'block-supports' or 'global-styles'. Default 'block-supports'.
134 * When set, the style engine will attempt to store the CSS rules.
135 * @type bool $optimize Whether to optimize the CSS output, e.g. combine rules.
136 * Default false.
137 * @type bool $prettify Whether to add new lines and indents to output.
138 * Defaults to whether the `SCRIPT_DEBUG` constant is defined.
139 * }
140 * @return string A string of compiled CSS declarations, or empty string.
141 */
142function wp_style_engine_get_stylesheet_from_css_rules( $css_rules, $options = array() ) {
143 if ( empty( $css_rules ) ) {
144 return '';
145 }
146
147 $options = wp_parse_args(
148 $options,
149 array(
150 'context' => null,
151 )
152 );
153
154 $css_rule_objects = array();
155 foreach ( $css_rules as $css_rule ) {
156 if ( empty( $css_rule['selector'] ) || empty( $css_rule['declarations'] ) || ! is_array( $css_rule['declarations'] ) ) {
157 continue;
158 }
159
160 $rules_group = $css_rule['rules_group'] ?? null;
161 if ( ! empty( $options['context'] ) ) {
162 WP_Style_Engine::store_css_rule( $options['context'], $css_rule['selector'], $css_rule['declarations'], $rules_group );
163 }
164
165 $css_rule_objects[] = new WP_Style_Engine_CSS_Rule( $css_rule['selector'], $css_rule['declarations'], $rules_group );
166 }
167
168 if ( empty( $css_rule_objects ) ) {
169 return '';
170 }
171
172 return WP_Style_Engine::compile_stylesheet_from_css_rules( $css_rule_objects, $options );
173}
174
175/**
176 * Returns compiled CSS from a store, if found.
177 *
178 * @since 6.1.0
179 *
180 * @param string $context A valid context name, corresponding to an existing store key.
181 * @param array $options {
182 * Optional. An array of options. Default empty array.
183 *
184 * @type bool $optimize Whether to optimize the CSS output, e.g. combine rules.
185 * Default false.
186 * @type bool $prettify Whether to add new lines and indents to output.
187 * Defaults to whether the `SCRIPT_DEBUG` constant is defined.
188 * }
189 * @return string A compiled CSS string.
190 */
191function wp_style_engine_get_stylesheet_from_context( $context, $options = array() ) {
192 return WP_Style_Engine::compile_stylesheet_from_css_rules( WP_Style_Engine::get_store( $context )->get_all_rules(), $options );
193}
194