PluginProbe
Gutenberg / 23.3.2
Gutenberg v23.3.2
23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 7.4.0 All 402 releases
gutenberg / lib / global-styles-and-settings.php

global-styles-and-settings.php in Gutenberg 23.3.2, at lib/global-styles-and-settings.php

415 lines 14.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * API to interact with global settings & styles.
4 *
5 * @package gutenberg
6 */
7
8 /**
9 * Returns the stylesheet resulting of merging core, theme, and user data.
10 *
11 * @param array $types Types of styles to load. Optional.
12 * See {@see 'WP_Theme_JSON::get_stylesheet'} for all valid types.
13 * If empty, will load: 'variables', 'presets', 'styles'.
14 *
15 * @return string Stylesheet.
16 */
17 function gutenberg_get_global_stylesheet( $types = array() ) {
18 // Ignore cache when `WP_DEBUG` is enabled, so it doesn't interfere with the theme developers workflow.
19 $can_use_cached = empty( $types ) && ! WP_DEBUG;
20 $cache_key = 'gutenberg_get_global_stylesheet';
21 $cache_group = 'theme_json';
22 if ( $can_use_cached ) {
23 $cached = wp_cache_get( $cache_key, $cache_group );
24 if ( $cached ) {
25 return $cached;
26 }
27 }
28 $tree = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data();
29 $tree = WP_Theme_JSON_Resolver_Gutenberg::resolve_theme_file_uris( $tree );
30
31 if ( empty( $types ) ) {
32 $types = array( 'variables', 'presets', 'styles' );
33 }
34
35 /*
36 * Enable base layout styles only mode for classic themes without theme.json.
37 * This skips alignment styles that target .wp-site-blocks which is only used by block themes.
38 */
39 $options = array();
40 if ( ! wp_is_block_theme() && ! wp_theme_has_theme_json() ) {
41 $options['base_layout_styles'] = true;
42 }
43
44 /*
45 * If variables are part of the stylesheet,
46 * we add them.
47 *
48 * This is so themes without a theme.json still work as before 5.9:
49 * they can override the default presets.
50 * See https://core.trac.wordpress.org/ticket/54782
51 */
52 $styles_variables = '';
53 if ( in_array( 'variables', $types, true ) ) {
54 /*
55 * We only use the default, theme, and custom origins.
56 * This is because styles for blocks origin are added
57 * at a later phase (render cycle) so we only render the ones in use.
58 * @see wp_add_global_styles_for_blocks
59 */
60 $origins = array( 'default', 'theme', 'custom' );
61 $styles_variables = $tree->get_stylesheet( array( 'variables' ), $origins, $options );
62 $types = array_diff( $types, array( 'variables' ) );
63 }
64
65 /*
66 * For the remaining types (presets, styles), we do consider origins:
67 *
68 * - themes without theme.json: only the classes for the presets defined by core
69 * - themes with theme.json: the presets and styles classes, both from core and the theme
70 */
71 $styles_rest = '';
72 if ( ! empty( $types ) ) {
73 /*
74 * We only use the default, theme, and custom origins.
75 * This is because styles for blocks origin are added
76 * at a later phase (render cycle) so we only render the ones in use.
77 * @see wp_add_global_styles_for_blocks
78 */
79 $origins = array( 'default', 'theme', 'custom' );
80 $styles_rest = $tree->get_stylesheet( $types, $origins, $options );
81 }
82 $stylesheet = $styles_variables . $styles_rest;
83 if ( $can_use_cached ) {
84 wp_cache_set( $cache_key, $stylesheet, $cache_group );
85 }
86 return $stylesheet;
87 }
88
89 /**
90 * Function to get the settings resulting of merging core, theme, and user data.
91 *
92 * @param array $path Path to the specific setting to retrieve. Optional.
93 * If empty, will return all settings.
94 * @param array $context {
95 * Metadata to know where to retrieve the $path from. Optional.
96 *
97 * @type string $block_name Which block to retrieve the settings from.
98 * If empty, it'll return the settings for the global context.
99 * @type string $origin Which origin to take data from.
100 * Valid values are 'all' (core, theme, and user) or 'base' (core and theme).
101 * If empty or unknown, 'all' is used.
102 * }
103 *
104 * @return array The settings to retrieve.
105 */
106 function gutenberg_get_global_settings( $path = array(), $context = array() ) {
107 if ( ! empty( $context['block_name'] ) ) {
108 $new_path = array( 'blocks', $context['block_name'] );
109 foreach ( $path as $subpath ) {
110 $new_path[] = $subpath;
111 }
112 $path = $new_path;
113 }
114
115 // This is the default value when no origin is provided or when it is 'all'.
116 $origin = 'custom';
117 if ( isset( $context['origin'] ) && 'base' === $context['origin'] ) {
118 $origin = 'theme';
119 }
120
121 $cache_group = 'theme_json';
122 $cache_key = 'gutenberg_get_global_settings_' . $origin;
123 $settings = wp_cache_get( $cache_key, $cache_group );
124
125 if ( false === $settings || WP_DEBUG ) {
126 $settings = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data( $origin )->get_settings();
127 wp_cache_set( $cache_key, $settings, $cache_group );
128 }
129
130 return _wp_array_get( $settings, $path, $settings );
131 }
132
133 /**
134 * Gets the global styles custom css from theme.json.
135 *
136 * @deprecated Gutenberg 18.6.0 Use {@see 'gutenberg_get_global_stylesheet'} instead for top-level custom CSS, or {@see 'WP_Theme_JSON_Gutenberg::get_styles_for_block'} for block-level custom CSS.
137 *
138 * @return string
139 */
140 function gutenberg_get_global_styles_custom_css() {
141 _deprecated_function( __FUNCTION__, 'Gutenberg 18.6.0', 'gutenberg_get_global_stylesheet' );
142 // Ignore cache when `WP_DEBUG` is enabled, so it doesn't interfere with the theme developers workflow.
143 $can_use_cached = ! WP_DEBUG;
144 $cache_key = 'gutenberg_get_global_custom_css';
145 $cache_group = 'theme_json';
146 if ( $can_use_cached ) {
147 $cached = wp_cache_get( $cache_key, $cache_group );
148 if ( $cached ) {
149 return $cached;
150 }
151 }
152
153 $tree = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data();
154 $stylesheet = $tree->get_custom_css();
155
156 if ( $can_use_cached ) {
157 wp_cache_set( $cache_key, $stylesheet, $cache_group );
158 }
159
160 return $stylesheet;
161 }
162
163 /**
164 * Gets the global styles base custom CSS from theme.json.
165 *
166 * @since 6.6.0
167 *
168 * @return string The global base custom CSS.
169 */
170 function gutenberg_get_global_styles_base_custom_css() {
171 _deprecated_function( __FUNCTION__, 'Gutenberg 18.6.0', 'gutenberg_get_global_stylesheet' );
172
173 $can_use_cached = ! WP_DEBUG;
174
175 $cache_key = 'gutenberg_get_global_styles_base_custom_css';
176 $cache_group = 'theme_json';
177 if ( $can_use_cached ) {
178 $cached = wp_cache_get( $cache_key, $cache_group );
179 if ( $cached ) {
180 return $cached;
181 }
182 }
183
184 $tree = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data();
185 $stylesheet = $tree->get_base_custom_css();
186
187 if ( $can_use_cached ) {
188 wp_cache_set( $cache_key, $stylesheet, $cache_group );
189 }
190
191 return $stylesheet;
192 }
193
194 /**
195 * Adds the global styles per-block custom CSS from theme.json
196 * to the inline style for each block.
197 *
198 * @since 6.6.0
199 *
200 * @global WP_Styles $wp_styles
201 */
202 function gutenberg_add_global_styles_block_custom_css() {
203 _deprecated_function( __FUNCTION__, 'Gutenberg 18.6.0', 'gutenberg_add_global_styles_for_blocks' );
204 global $wp_styles;
205
206 if ( ! wp_should_load_separate_core_block_assets() ) {
207 return;
208 }
209
210 $tree = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data();
211 $block_nodes = $tree->get_block_custom_css_nodes();
212
213 foreach ( $block_nodes as $metadata ) {
214 $block_css = $tree->get_block_custom_css( $metadata['css'], $metadata['selector'] );
215
216 $stylesheet_handle = 'global-styles';
217
218 /*
219 * When `wp_should_load_separate_core_block_assets()` is true, follow a similar
220 * logic to the one in `gutenberg_add_global_styles_for_blocks` to add the custom
221 * css only when the block is rendered.
222 */
223 if ( isset( $metadata['name'] ) ) {
224 if ( str_starts_with( $metadata['name'], 'core/' ) ) {
225 $block_name = str_replace( 'core/', '', $metadata['name'] );
226 $block_handle = 'wp-block-' . $block_name;
227 if ( in_array( $block_handle, $wp_styles->queue, true ) ) {
228 wp_add_inline_style( $stylesheet_handle, $block_css );
229 }
230 } else {
231 wp_add_inline_style( $stylesheet_handle, $block_css );
232 }
233 }
234 }
235 }
236
237
238 /**
239 * Adds global style rules to the inline style for each block.
240 *
241 * @global WP_Styles $wp_styles
242 *
243 * @return void
244 */
245 function gutenberg_add_global_styles_for_blocks() {
246 global $wp_styles;
247 $tree = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data();
248 $tree = WP_Theme_JSON_Resolver_Gutenberg::resolve_theme_file_uris( $tree );
249 $block_nodes = $tree->get_styles_block_nodes();
250
251 $can_use_cached = ! wp_is_development_mode( 'theme' );
252 $update_cache = false;
253
254 if ( $can_use_cached ) {
255 // Hash the merged WP_Theme_JSON data to bust cache on settings or styles change.
256 $cache_hash = md5( wp_json_encode( $tree->get_raw_data() ) );
257 $cache_key = 'wp_styles_for_blocks';
258 $cached = get_transient( $cache_key );
259
260 // Reset the cached data if there is no value or if the hash has changed.
261 if ( ! is_array( $cached ) || $cached['hash'] !== $cache_hash ) {
262 $cached = array(
263 'hash' => $cache_hash,
264 'blocks' => array(),
265 );
266
267 // Update the cache if the hash has changed.
268 $update_cache = true;
269 }
270 }
271
272 foreach ( $block_nodes as $metadata ) {
273 if ( $can_use_cached ) {
274 // Generate a unique cache key based on the full metadata to ensure pseudo-selectors and other variations get unique keys.
275 $cache_node_key = md5( wp_json_encode( $metadata ) );
276
277 if ( isset( $cached['blocks'][ $cache_node_key ] ) ) {
278 $block_css = $cached['blocks'][ $cache_node_key ];
279 } else {
280 $block_css = $tree->get_styles_for_block( $metadata );
281 $cached['blocks'][ $cache_node_key ] = $block_css;
282
283 // Update the cache if the cache contents have changed.
284 $update_cache = true;
285 }
286 } else {
287 $block_css = $tree->get_styles_for_block( $metadata );
288 }
289
290 if ( ! wp_should_load_separate_core_block_assets() ) {
291 wp_add_inline_style( 'global-styles', $block_css );
292 continue;
293 }
294
295 $stylesheet_handle = 'global-styles';
296
297 /*
298 * When `wp_should_load_separate_core_block_assets()` is true, block styles are
299 * enqueued for each block on the page in class WP_Block's render function.
300 * This means there will be a handle in the styles queue for each of those blocks.
301 * Block-specific global styles should be attached to the global-styles handle, but
302 * only for blocks on the page, thus we check if the block's handle is in the queue
303 * before adding the inline style.
304 * This conditional loading only applies to core blocks.
305 */
306 if ( isset( $metadata['name'] ) ) {
307 if ( str_starts_with( $metadata['name'], 'core/' ) ) {
308 $block_name = str_replace( 'core/', '', $metadata['name'] );
309 $block_handle = 'wp-block-' . $block_name;
310 if ( in_array( $block_handle, $wp_styles->queue, true ) ) {
311 wp_add_inline_style( $stylesheet_handle, $block_css );
312 }
313 } else {
314 wp_add_inline_style( $stylesheet_handle, $block_css );
315 }
316 }
317
318 // The likes of block element styles from theme.json do not have $metadata['name'] set.
319 if ( ! isset( $metadata['name'] ) && ! empty( $metadata['path'] ) ) {
320 $block_name = wp_get_block_name_from_theme_json_path( $metadata['path'] );
321 if ( $block_name ) {
322 if ( str_starts_with( $block_name, 'core/' ) ) {
323 $block_name = str_replace( 'core/', '', $block_name );
324 $block_handle = 'wp-block-' . $block_name;
325 if ( in_array( $block_handle, $wp_styles->queue, true ) ) {
326 wp_add_inline_style( $stylesheet_handle, $block_css );
327 }
328 } else {
329 wp_add_inline_style( $stylesheet_handle, $block_css );
330 }
331 }
332 }
333 }
334
335 if ( $update_cache ) {
336 set_transient( $cache_key, $cached );
337 }
338 }
339
340 /**
341 * Private function to clean the caches used by gutenberg_get_global_settings method.
342 *
343 * @access private
344 */
345 function _gutenberg_clean_theme_json_caches() {
346 wp_cache_delete( 'wp_theme_has_theme_json', 'theme_json' );
347 wp_cache_delete( 'gutenberg_get_global_stylesheet', 'theme_json' );
348 wp_cache_delete( 'gutenberg_get_global_settings_custom', 'theme_json' );
349 wp_cache_delete( 'gutenberg_get_global_settings_theme', 'theme_json' );
350 wp_cache_delete( 'gutenberg_get_global_custom_css', 'theme_json' );
351 wp_cache_delete( 'gutenberg_get_global_styles_base_custom_css', 'theme_json' );
352 WP_Theme_JSON_Resolver_Gutenberg::clean_cached_data();
353 }
354 add_action( 'start_previewing_theme', '_gutenberg_clean_theme_json_caches' );
355 add_action( 'switch_theme', '_gutenberg_clean_theme_json_caches' );
356
357 /**
358 * Gets the styles resulting of merging core, theme, and user data.
359 *
360 * @since 5.9.0
361 * @since 6.3.0 the internal link format "var:preset|color|secondary" is resolved
362 * to "var(--wp--preset--font-size--small)" so consumers don't have to.
363 * @since 6.3.0 `transforms` is now usable in the `context` parameter. In case [`transforms`]['resolve_variables']
364 * is defined, variables are resolved to their value in the styles.
365 *
366 * @param array $path Path to the specific style to retrieve. Optional.
367 * If empty, will return all styles.
368 * @param array $context {
369 * Metadata to know where to retrieve the $path from. Optional.
370 *
371 * @type string $block_name Which block to retrieve the styles from.
372 * If empty, it'll return the styles for the global context.
373 * @type string $origin Which origin to take data from.
374 * Valid values are 'all' (core, theme, and user) or 'base' (core and theme).
375 * If empty or unknown, 'all' is used.
376 * @type array $transforms Which transformation(s) to apply.
377 * Valid value is array( 'resolve-variables' ).
378 * If defined, variables are resolved to their value in the styles.
379 * }
380 * @return array The styles to retrieve.
381 */
382 function gutenberg_get_global_styles( $path = array(), $context = array() ) {
383 if ( ! empty( $context['block_name'] ) ) {
384 $path = array_merge( array( 'blocks', $context['block_name'] ), $path );
385 }
386
387 $origin = 'custom';
388 if ( isset( $context['origin'] ) && 'base' === $context['origin'] ) {
389 $origin = 'theme';
390 }
391
392 $resolve_variables = isset( $context['transforms'] )
393 && is_array( $context['transforms'] )
394 && in_array( 'resolve-variables', $context['transforms'], true );
395
396 $merged_data = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data( $origin );
397 if ( $resolve_variables ) {
398 $merged_data = WP_Theme_JSON_Gutenberg::resolve_variables( $merged_data );
399 }
400 $styles = $merged_data->get_raw_data()['styles'];
401 return _wp_array_get( $styles, $path, $styles );
402 }
403
404 /**
405 * Returns the current theme's wanted patterns (slugs) to be
406 * registered from Pattern Directory.
407 *
408 * @since 6.3.0
409 *
410 * @return string[]
411 */
412 function gutenberg_get_theme_directory_pattern_slugs() {
413 return WP_Theme_JSON_Resolver_Gutenberg::get_theme_data( array(), array( 'with_supports' => false ) )->get_patterns();
414 }
415