PluginProbe
Gutenberg / 19.6.1
Gutenberg v19.6.1
24.0.0 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 All 403 releases
gutenberg / lib / global-styles-and-settings.php

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

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