19 * If empty, it'll return the settings for the global context. |
19 * If empty, it'll return the settings for the global context. |
20 * @type string $origin Which origin to take data from. |
20 * @type string $origin Which origin to take data from. |
21 * Valid values are 'all' (core, theme, and user) or 'base' (core and theme). |
21 * Valid values are 'all' (core, theme, and user) or 'base' (core and theme). |
22 * If empty or unknown, 'all' is used. |
22 * If empty or unknown, 'all' is used. |
23 * } |
23 * } |
24 * |
24 * @return mixed The settings array or individual setting value to retrieve. |
25 * @return array The settings to retrieve. |
|
26 */ |
25 */ |
27 function wp_get_global_settings( $path = array(), $context = array() ) { |
26 function wp_get_global_settings( $path = array(), $context = array() ) { |
28 if ( ! empty( $context['block_name'] ) ) { |
27 if ( ! empty( $context['block_name'] ) ) { |
29 $path = array_merge( array( 'blocks', $context['block_name'] ), $path ); |
28 $new_path = array( 'blocks', $context['block_name'] ); |
30 } |
29 foreach ( $path as $subpath ) { |
31 |
30 $new_path[] = $subpath; |
|
31 } |
|
32 $path = $new_path; |
|
33 } |
|
34 |
|
35 /* |
|
36 * This is the default value when no origin is provided or when it is 'all'. |
|
37 * |
|
38 * The $origin is used as part of the cache key. Changes here need to account |
|
39 * for clearing the cache appropriately. |
|
40 */ |
32 $origin = 'custom'; |
41 $origin = 'custom'; |
33 if ( isset( $context['origin'] ) && 'base' === $context['origin'] ) { |
42 if ( |
|
43 ! wp_theme_has_theme_json() || |
|
44 ( isset( $context['origin'] ) && 'base' === $context['origin'] ) |
|
45 ) { |
34 $origin = 'theme'; |
46 $origin = 'theme'; |
35 } |
47 } |
36 |
48 |
37 $settings = WP_Theme_JSON_Resolver::get_merged_data( $origin )->get_settings(); |
49 /* |
|
50 * By using the 'theme_json' group, this data is marked to be non-persistent across requests. |
|
51 * See `wp_cache_add_non_persistent_groups` in src/wp-includes/load.php and other places. |
|
52 * |
|
53 * The rationale for this is to make sure derived data from theme.json |
|
54 * is always fresh from the potential modifications done via hooks |
|
55 * that can use dynamic data (modify the stylesheet depending on some option, |
|
56 * settings depending on user permissions, etc.). |
|
57 * See some of the existing hooks to modify theme.json behavior: |
|
58 * https://make.wordpress.org/core/2022/10/10/filters-for-theme-json-data/ |
|
59 * |
|
60 * A different alternative considered was to invalidate the cache upon certain |
|
61 * events such as options add/update/delete, user meta, etc. |
|
62 * It was judged not enough, hence this approach. |
|
63 * See https://github.com/WordPress/gutenberg/pull/45372 |
|
64 */ |
|
65 $cache_group = 'theme_json'; |
|
66 $cache_key = 'wp_get_global_settings_' . $origin; |
|
67 |
|
68 /* |
|
69 * Ignore cache when the development mode is set to 'theme', so it doesn't interfere with the theme |
|
70 * developer's workflow. |
|
71 */ |
|
72 $can_use_cached = ! wp_is_development_mode( 'theme' ); |
|
73 |
|
74 $settings = false; |
|
75 if ( $can_use_cached ) { |
|
76 $settings = wp_cache_get( $cache_key, $cache_group ); |
|
77 } |
|
78 |
|
79 if ( false === $settings ) { |
|
80 $settings = WP_Theme_JSON_Resolver::get_merged_data( $origin )->get_settings(); |
|
81 if ( $can_use_cached ) { |
|
82 wp_cache_set( $cache_key, $settings, $cache_group ); |
|
83 } |
|
84 } |
38 |
85 |
39 return _wp_array_get( $settings, $path, $settings ); |
86 return _wp_array_get( $settings, $path, $settings ); |
40 } |
87 } |
41 |
88 |
42 /** |
89 /** |
43 * Function to get the styles resulting of merging core, theme, and user data. |
90 * Gets the styles resulting of merging core, theme, and user data. |
44 * |
91 * |
45 * @since 5.9.0 |
92 * @since 5.9.0 |
|
93 * @since 6.3.0 the internal link format "var:preset|color|secondary" is resolved |
|
94 * to "var(--wp--preset--font-size--small)" so consumers don't have to. |
|
95 * @since 6.3.0 `transforms` is now usable in the `context` parameter. In case [`transforms`]['resolve_variables'] |
|
96 * is defined, variables are resolved to their value in the styles. |
46 * |
97 * |
47 * @param array $path Path to the specific style to retrieve. Optional. |
98 * @param array $path Path to the specific style to retrieve. Optional. |
48 * If empty, will return all styles. |
99 * If empty, will return all styles. |
49 * @param array $context { |
100 * @param array $context { |
50 * Metadata to know where to retrieve the $path from. Optional. |
101 * Metadata to know where to retrieve the $path from. Optional. |
66 $origin = 'custom'; |
119 $origin = 'custom'; |
67 if ( isset( $context['origin'] ) && 'base' === $context['origin'] ) { |
120 if ( isset( $context['origin'] ) && 'base' === $context['origin'] ) { |
68 $origin = 'theme'; |
121 $origin = 'theme'; |
69 } |
122 } |
70 |
123 |
71 $styles = WP_Theme_JSON_Resolver::get_merged_data( $origin )->get_raw_data()['styles']; |
124 $resolve_variables = isset( $context['transforms'] ) |
72 |
125 && is_array( $context['transforms'] ) |
|
126 && in_array( 'resolve-variables', $context['transforms'], true ); |
|
127 |
|
128 $merged_data = WP_Theme_JSON_Resolver::get_merged_data( $origin ); |
|
129 if ( $resolve_variables ) { |
|
130 $merged_data = WP_Theme_JSON::resolve_variables( $merged_data ); |
|
131 } |
|
132 $styles = $merged_data->get_raw_data()['styles']; |
73 return _wp_array_get( $styles, $path, $styles ); |
133 return _wp_array_get( $styles, $path, $styles ); |
74 } |
134 } |
75 |
135 |
|
136 |
76 /** |
137 /** |
77 * Returns the stylesheet resulting of merging core, theme, and user data. |
138 * Returns the stylesheet resulting of merging core, theme, and user data. |
78 * |
139 * |
79 * @since 5.9.0 |
140 * @since 5.9.0 |
80 * |
141 * @since 6.1.0 Added 'base-layout-styles' support. |
81 * @param array $types Types of styles to load. Optional. |
142 * @since 6.6.0 Resolves relative paths in theme.json styles to theme absolute paths. |
82 * It accepts 'variables', 'styles', 'presets' as values. |
143 * |
83 * If empty, it'll load all for themes with theme.json support |
144 * @param array $types Optional. Types of styles to load. |
84 * and only [ 'variables', 'presets' ] for themes without theme.json support. |
145 * It accepts as values 'variables', 'presets', 'styles', 'base-layout-styles'. |
85 * |
146 * If empty, it'll load the following: |
|
147 * - for themes without theme.json: 'variables', 'presets', 'base-layout-styles'. |
|
148 * - for themes with theme.json: 'variables', 'presets', 'styles'. |
86 * @return string Stylesheet. |
149 * @return string Stylesheet. |
87 */ |
150 */ |
88 function wp_get_global_stylesheet( $types = array() ) { |
151 function wp_get_global_stylesheet( $types = array() ) { |
89 // Return cached value if it can be used and exists. |
152 /* |
90 // It's cached by theme to make sure that theme switching clears the cache. |
153 * Ignore cache when the development mode is set to 'theme', so it doesn't interfere with the theme |
91 $can_use_cached = ( |
154 * developer's workflow. |
92 ( empty( $types ) ) && |
155 */ |
93 ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) && |
156 $can_use_cached = empty( $types ) && ! wp_is_development_mode( 'theme' ); |
94 ( ! defined( 'SCRIPT_DEBUG' ) || ! SCRIPT_DEBUG ) && |
157 |
95 ( ! defined( 'REST_REQUEST' ) || ! REST_REQUEST ) && |
158 /* |
96 ! is_admin() |
159 * By using the 'theme_json' group, this data is marked to be non-persistent across requests. |
97 ); |
160 * @see `wp_cache_add_non_persistent_groups()`. |
98 $transient_name = 'global_styles_' . get_stylesheet(); |
161 * |
|
162 * The rationale for this is to make sure derived data from theme.json |
|
163 * is always fresh from the potential modifications done via hooks |
|
164 * that can use dynamic data (modify the stylesheet depending on some option, |
|
165 * settings depending on user permissions, etc.). |
|
166 * See some of the existing hooks to modify theme.json behavior: |
|
167 * @see https://make.wordpress.org/core/2022/10/10/filters-for-theme-json-data/ |
|
168 * |
|
169 * A different alternative considered was to invalidate the cache upon certain |
|
170 * events such as options add/update/delete, user meta, etc. |
|
171 * It was judged not enough, hence this approach. |
|
172 * @see https://github.com/WordPress/gutenberg/pull/45372 |
|
173 */ |
|
174 $cache_group = 'theme_json'; |
|
175 $cache_key = 'wp_get_global_stylesheet'; |
99 if ( $can_use_cached ) { |
176 if ( $can_use_cached ) { |
100 $cached = get_transient( $transient_name ); |
177 $cached = wp_cache_get( $cache_key, $cache_group ); |
101 if ( $cached ) { |
178 if ( $cached ) { |
102 return $cached; |
179 return $cached; |
103 } |
180 } |
104 } |
181 } |
105 |
182 |
106 $tree = WP_Theme_JSON_Resolver::get_merged_data(); |
183 $tree = WP_Theme_JSON_Resolver::resolve_theme_file_uris( WP_Theme_JSON_Resolver::get_merged_data() ); |
107 |
184 $supports_theme_json = wp_theme_has_theme_json(); |
108 $supports_theme_json = WP_Theme_JSON_Resolver::theme_has_support(); |
185 |
109 if ( empty( $types ) && ! $supports_theme_json ) { |
186 if ( empty( $types ) && ! $supports_theme_json ) { |
110 $types = array( 'variables', 'presets' ); |
187 $types = array( 'variables', 'presets', 'base-layout-styles' ); |
111 } elseif ( empty( $types ) ) { |
188 } elseif ( empty( $types ) ) { |
112 $types = array( 'variables', 'styles', 'presets' ); |
189 $types = array( 'variables', 'styles', 'presets' ); |
113 } |
190 } |
114 |
191 |
115 /* |
192 /* |
116 * If variables are part of the stylesheet, |
193 * If variables are part of the stylesheet, then add them. |
117 * we add them for all origins (default, theme, user). |
|
118 * This is so themes without a theme.json still work as before 5.9: |
194 * This is so themes without a theme.json still work as before 5.9: |
119 * they can override the default presets. |
195 * they can override the default presets. |
120 * See https://core.trac.wordpress.org/ticket/54782 |
196 * See https://core.trac.wordpress.org/ticket/54782 |
121 */ |
197 */ |
122 $styles_variables = ''; |
198 $styles_variables = ''; |
123 if ( in_array( 'variables', $types, true ) ) { |
199 if ( in_array( 'variables', $types, true ) ) { |
124 $styles_variables = $tree->get_stylesheet( array( 'variables' ) ); |
200 /* |
|
201 * Only use the default, theme, and custom origins. Why? |
|
202 * Because styles for `blocks` origin are added at a later phase |
|
203 * (i.e. in the render cycle). Here, only the ones in use are rendered. |
|
204 * @see wp_add_global_styles_for_blocks |
|
205 */ |
|
206 $origins = array( 'default', 'theme', 'custom' ); |
|
207 $styles_variables = $tree->get_stylesheet( array( 'variables' ), $origins ); |
125 $types = array_diff( $types, array( 'variables' ) ); |
208 $types = array_diff( $types, array( 'variables' ) ); |
126 } |
209 } |
127 |
210 |
128 /* |
211 /* |
129 * For the remaining types (presets, styles), we do consider origins: |
212 * For the remaining types (presets, styles), we do consider origins: |
131 * - themes without theme.json: only the classes for the presets defined by core |
214 * - themes without theme.json: only the classes for the presets defined by core |
132 * - themes with theme.json: the presets and styles classes, both from core and the theme |
215 * - themes with theme.json: the presets and styles classes, both from core and the theme |
133 */ |
216 */ |
134 $styles_rest = ''; |
217 $styles_rest = ''; |
135 if ( ! empty( $types ) ) { |
218 if ( ! empty( $types ) ) { |
|
219 /* |
|
220 * Only use the default, theme, and custom origins. Why? |
|
221 * Because styles for `blocks` origin are added at a later phase |
|
222 * (i.e. in the render cycle). Here, only the ones in use are rendered. |
|
223 * @see wp_add_global_styles_for_blocks |
|
224 */ |
136 $origins = array( 'default', 'theme', 'custom' ); |
225 $origins = array( 'default', 'theme', 'custom' ); |
137 if ( ! $supports_theme_json ) { |
226 /* |
|
227 * If the theme doesn't have theme.json but supports both appearance tools and color palette, |
|
228 * the 'theme' origin should be included so color palette presets are also output. |
|
229 */ |
|
230 if ( ! $supports_theme_json && ( current_theme_supports( 'appearance-tools' ) || current_theme_supports( 'border' ) ) && current_theme_supports( 'editor-color-palette' ) ) { |
|
231 $origins = array( 'default', 'theme' ); |
|
232 } elseif ( ! $supports_theme_json ) { |
138 $origins = array( 'default' ); |
233 $origins = array( 'default' ); |
139 } |
234 } |
140 $styles_rest = $tree->get_stylesheet( $types, $origins ); |
235 $styles_rest = $tree->get_stylesheet( $types, $origins ); |
141 } |
236 } |
142 |
237 |
143 $stylesheet = $styles_variables . $styles_rest; |
238 $stylesheet = $styles_variables . $styles_rest; |
144 |
|
145 if ( $can_use_cached ) { |
239 if ( $can_use_cached ) { |
146 // Cache for a minute. |
240 wp_cache_set( $cache_key, $stylesheet, $cache_group ); |
147 // This cache doesn't need to be any longer, we only want to avoid spikes on high-traffic sites. |
|
148 set_transient( $transient_name, $stylesheet, MINUTE_IN_SECONDS ); |
|
149 } |
241 } |
150 |
242 |
151 return $stylesheet; |
243 return $stylesheet; |
152 } |
244 } |
153 |
245 |
154 /** |
246 /** |
155 * Returns a string containing the SVGs to be referenced as filters (duotone). |
247 * Gets the global styles custom CSS from theme.json. |
156 * |
248 * |
157 * @since 5.9.1 |
249 * @since 6.2.0 |
158 * |
250 * |
159 * @return string |
251 * @return string The global styles custom CSS. |
160 */ |
252 */ |
161 function wp_get_global_styles_svg_filters() { |
253 function wp_get_global_styles_custom_css() { |
162 // Return cached value if it can be used and exists. |
254 if ( ! wp_theme_has_theme_json() ) { |
163 // It's cached by theme to make sure that theme switching clears the cache. |
255 return ''; |
164 $can_use_cached = ( |
256 } |
165 ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) && |
257 /* |
166 ( ! defined( 'SCRIPT_DEBUG' ) || ! SCRIPT_DEBUG ) && |
258 * Ignore cache when the development mode is set to 'theme', so it doesn't interfere with the theme |
167 ( ! defined( 'REST_REQUEST' ) || ! REST_REQUEST ) && |
259 * developer's workflow. |
168 ! is_admin() |
260 */ |
169 ); |
261 $can_use_cached = ! wp_is_development_mode( 'theme' ); |
170 $transient_name = 'global_styles_svg_filters_' . get_stylesheet(); |
262 |
|
263 /* |
|
264 * By using the 'theme_json' group, this data is marked to be non-persistent across requests. |
|
265 * @see `wp_cache_add_non_persistent_groups()`. |
|
266 * |
|
267 * The rationale for this is to make sure derived data from theme.json |
|
268 * is always fresh from the potential modifications done via hooks |
|
269 * that can use dynamic data (modify the stylesheet depending on some option, |
|
270 * settings depending on user permissions, etc.). |
|
271 * See some of the existing hooks to modify theme.json behavior: |
|
272 * @see https://make.wordpress.org/core/2022/10/10/filters-for-theme-json-data/ |
|
273 * |
|
274 * A different alternative considered was to invalidate the cache upon certain |
|
275 * events such as options add/update/delete, user meta, etc. |
|
276 * It was judged not enough, hence this approach. |
|
277 * @see https://github.com/WordPress/gutenberg/pull/45372 |
|
278 */ |
|
279 $cache_key = 'wp_get_global_styles_custom_css'; |
|
280 $cache_group = 'theme_json'; |
171 if ( $can_use_cached ) { |
281 if ( $can_use_cached ) { |
172 $cached = get_transient( $transient_name ); |
282 $cached = wp_cache_get( $cache_key, $cache_group ); |
173 if ( $cached ) { |
283 if ( $cached ) { |
174 return $cached; |
284 return $cached; |
175 } |
285 } |
176 } |
286 } |
177 |
287 |
178 $supports_theme_json = WP_Theme_JSON_Resolver::theme_has_support(); |
288 $tree = WP_Theme_JSON_Resolver::get_merged_data(); |
179 |
289 $stylesheet = $tree->get_custom_css(); |
180 $origins = array( 'default', 'theme', 'custom' ); |
|
181 if ( ! $supports_theme_json ) { |
|
182 $origins = array( 'default' ); |
|
183 } |
|
184 |
|
185 $tree = WP_Theme_JSON_Resolver::get_merged_data(); |
|
186 $svgs = $tree->get_svg_filters( $origins ); |
|
187 |
290 |
188 if ( $can_use_cached ) { |
291 if ( $can_use_cached ) { |
189 // Cache for a minute, same as wp_get_global_stylesheet. |
292 wp_cache_set( $cache_key, $stylesheet, $cache_group ); |
190 set_transient( $transient_name, $svgs, MINUTE_IN_SECONDS ); |
293 } |
191 } |
294 |
192 |
295 return $stylesheet; |
193 return $svgs; |
296 } |
194 } |
297 |
|
298 /** |
|
299 * Adds global style rules to the inline style for each block. |
|
300 * |
|
301 * @since 6.1.0 |
|
302 * |
|
303 * @global WP_Styles $wp_styles |
|
304 */ |
|
305 function wp_add_global_styles_for_blocks() { |
|
306 global $wp_styles; |
|
307 |
|
308 $tree = WP_Theme_JSON_Resolver::get_merged_data(); |
|
309 $block_nodes = $tree->get_styles_block_nodes(); |
|
310 foreach ( $block_nodes as $metadata ) { |
|
311 $block_css = $tree->get_styles_for_block( $metadata ); |
|
312 |
|
313 if ( ! wp_should_load_separate_core_block_assets() ) { |
|
314 wp_add_inline_style( 'global-styles', $block_css ); |
|
315 continue; |
|
316 } |
|
317 |
|
318 $stylesheet_handle = 'global-styles'; |
|
319 |
|
320 /* |
|
321 * When `wp_should_load_separate_core_block_assets()` is true, block styles are |
|
322 * enqueued for each block on the page in class WP_Block's render function. |
|
323 * This means there will be a handle in the styles queue for each of those blocks. |
|
324 * Block-specific global styles should be attached to the global-styles handle, but |
|
325 * only for blocks on the page, thus we check if the block's handle is in the queue |
|
326 * before adding the inline style. |
|
327 * This conditional loading only applies to core blocks. |
|
328 */ |
|
329 if ( isset( $metadata['name'] ) ) { |
|
330 if ( str_starts_with( $metadata['name'], 'core/' ) ) { |
|
331 $block_name = str_replace( 'core/', '', $metadata['name'] ); |
|
332 $block_handle = 'wp-block-' . $block_name; |
|
333 if ( in_array( $block_handle, $wp_styles->queue, true ) ) { |
|
334 wp_add_inline_style( $stylesheet_handle, $block_css ); |
|
335 } |
|
336 } else { |
|
337 wp_add_inline_style( $stylesheet_handle, $block_css ); |
|
338 } |
|
339 } |
|
340 |
|
341 // The likes of block element styles from theme.json do not have $metadata['name'] set. |
|
342 if ( ! isset( $metadata['name'] ) && ! empty( $metadata['path'] ) ) { |
|
343 $block_name = wp_get_block_name_from_theme_json_path( $metadata['path'] ); |
|
344 if ( $block_name ) { |
|
345 if ( str_starts_with( $block_name, 'core/' ) ) { |
|
346 $block_name = str_replace( 'core/', '', $block_name ); |
|
347 $block_handle = 'wp-block-' . $block_name; |
|
348 if ( in_array( $block_handle, $wp_styles->queue, true ) ) { |
|
349 wp_add_inline_style( $stylesheet_handle, $block_css ); |
|
350 } |
|
351 } else { |
|
352 wp_add_inline_style( $stylesheet_handle, $block_css ); |
|
353 } |
|
354 } |
|
355 } |
|
356 } |
|
357 } |
|
358 |
|
359 /** |
|
360 * Gets the block name from a given theme.json path. |
|
361 * |
|
362 * @since 6.3.0 |
|
363 * @access private |
|
364 * |
|
365 * @param array $path An array of keys describing the path to a property in theme.json. |
|
366 * @return string Identified block name, or empty string if none found. |
|
367 */ |
|
368 function wp_get_block_name_from_theme_json_path( $path ) { |
|
369 // Block name is expected to be the third item after 'styles' and 'blocks'. |
|
370 if ( |
|
371 count( $path ) >= 3 |
|
372 && 'styles' === $path[0] |
|
373 && 'blocks' === $path[1] |
|
374 && str_contains( $path[2], '/' ) |
|
375 ) { |
|
376 return $path[2]; |
|
377 } |
|
378 |
|
379 /* |
|
380 * As fallback and for backward compatibility, allow any core block to be |
|
381 * at any position. |
|
382 */ |
|
383 $result = array_values( |
|
384 array_filter( |
|
385 $path, |
|
386 static function ( $item ) { |
|
387 if ( str_contains( $item, 'core/' ) ) { |
|
388 return true; |
|
389 } |
|
390 return false; |
|
391 } |
|
392 ) |
|
393 ); |
|
394 if ( isset( $result[0] ) ) { |
|
395 return $result[0]; |
|
396 } |
|
397 return ''; |
|
398 } |
|
399 |
|
400 /** |
|
401 * Checks whether a theme or its parent has a theme.json file. |
|
402 * |
|
403 * @since 6.2.0 |
|
404 * |
|
405 * @return bool Returns true if theme or its parent has a theme.json file, false otherwise. |
|
406 */ |
|
407 function wp_theme_has_theme_json() { |
|
408 static $theme_has_support = array(); |
|
409 |
|
410 $stylesheet = get_stylesheet(); |
|
411 |
|
412 if ( |
|
413 isset( $theme_has_support[ $stylesheet ] ) && |
|
414 /* |
|
415 * Ignore static cache when the development mode is set to 'theme', to avoid interfering with |
|
416 * the theme developer's workflow. |
|
417 */ |
|
418 ! wp_is_development_mode( 'theme' ) |
|
419 ) { |
|
420 return $theme_has_support[ $stylesheet ]; |
|
421 } |
|
422 |
|
423 $stylesheet_directory = get_stylesheet_directory(); |
|
424 $template_directory = get_template_directory(); |
|
425 |
|
426 // This is the same as get_theme_file_path(), which isn't available in load-styles.php context |
|
427 if ( $stylesheet_directory !== $template_directory && file_exists( $stylesheet_directory . '/theme.json' ) ) { |
|
428 $path = $stylesheet_directory . '/theme.json'; |
|
429 } else { |
|
430 $path = $template_directory . '/theme.json'; |
|
431 } |
|
432 |
|
433 /** This filter is documented in wp-includes/link-template.php */ |
|
434 $path = apply_filters( 'theme_file_path', $path, 'theme.json' ); |
|
435 |
|
436 $theme_has_support[ $stylesheet ] = file_exists( $path ); |
|
437 |
|
438 return $theme_has_support[ $stylesheet ]; |
|
439 } |
|
440 |
|
441 /** |
|
442 * Cleans the caches under the theme_json group. |
|
443 * |
|
444 * @since 6.2.0 |
|
445 */ |
|
446 function wp_clean_theme_json_cache() { |
|
447 wp_cache_delete( 'wp_get_global_stylesheet', 'theme_json' ); |
|
448 wp_cache_delete( 'wp_get_global_styles_svg_filters', 'theme_json' ); |
|
449 wp_cache_delete( 'wp_get_global_settings_custom', 'theme_json' ); |
|
450 wp_cache_delete( 'wp_get_global_settings_theme', 'theme_json' ); |
|
451 wp_cache_delete( 'wp_get_global_styles_custom_css', 'theme_json' ); |
|
452 wp_cache_delete( 'wp_get_theme_data_template_parts', 'theme_json' ); |
|
453 WP_Theme_JSON_Resolver::clean_cached_data(); |
|
454 } |
|
455 |
|
456 /** |
|
457 * Returns the current theme's wanted patterns (slugs) to be |
|
458 * registered from Pattern Directory. |
|
459 * |
|
460 * @since 6.3.0 |
|
461 * |
|
462 * @return string[] |
|
463 */ |
|
464 function wp_get_theme_directory_pattern_slugs() { |
|
465 return WP_Theme_JSON_Resolver::get_theme_data( array(), array( 'with_supports' => false ) )->get_patterns(); |
|
466 } |
|
467 |
|
468 /** |
|
469 * Returns the metadata for the custom templates defined by the theme via theme.json. |
|
470 * |
|
471 * @since 6.4.0 |
|
472 * |
|
473 * @return array Associative array of `$template_name => $template_data` pairs, |
|
474 * with `$template_data` having "title" and "postTypes" fields. |
|
475 */ |
|
476 function wp_get_theme_data_custom_templates() { |
|
477 return WP_Theme_JSON_Resolver::get_theme_data( array(), array( 'with_supports' => false ) )->get_custom_templates(); |
|
478 } |
|
479 |
|
480 /** |
|
481 * Returns the metadata for the template parts defined by the theme. |
|
482 * |
|
483 * @since 6.4.0 |
|
484 * |
|
485 * @return array Associative array of `$part_name => $part_data` pairs, |
|
486 * with `$part_data` having "title" and "area" fields. |
|
487 */ |
|
488 function wp_get_theme_data_template_parts() { |
|
489 $cache_group = 'theme_json'; |
|
490 $cache_key = 'wp_get_theme_data_template_parts'; |
|
491 $can_use_cached = ! wp_is_development_mode( 'theme' ); |
|
492 |
|
493 $metadata = false; |
|
494 if ( $can_use_cached ) { |
|
495 $metadata = wp_cache_get( $cache_key, $cache_group ); |
|
496 if ( false !== $metadata ) { |
|
497 return $metadata; |
|
498 } |
|
499 } |
|
500 |
|
501 if ( false === $metadata ) { |
|
502 $metadata = WP_Theme_JSON_Resolver::get_theme_data( array(), array( 'with_supports' => false ) )->get_template_parts(); |
|
503 if ( $can_use_cached ) { |
|
504 wp_cache_set( $cache_key, $metadata, $cache_group ); |
|
505 } |
|
506 } |
|
507 |
|
508 return $metadata; |
|
509 } |
|
510 |
|
511 /** |
|
512 * Determines the CSS selector for the block type and property provided, |
|
513 * returning it if available. |
|
514 * |
|
515 * @since 6.3.0 |
|
516 * |
|
517 * @param WP_Block_Type $block_type The block's type. |
|
518 * @param string|array $target The desired selector's target, `root` or array path. |
|
519 * @param boolean $fallback Whether to fall back to broader selector. |
|
520 * |
|
521 * @return string|null CSS selector or `null` if no selector available. |
|
522 */ |
|
523 function wp_get_block_css_selector( $block_type, $target = 'root', $fallback = false ) { |
|
524 if ( empty( $target ) ) { |
|
525 return null; |
|
526 } |
|
527 |
|
528 $has_selectors = ! empty( $block_type->selectors ); |
|
529 |
|
530 // Root Selector. |
|
531 |
|
532 // Calculated before returning as it can be used as fallback for |
|
533 // feature selectors later on. |
|
534 $root_selector = null; |
|
535 |
|
536 if ( $has_selectors && isset( $block_type->selectors['root'] ) ) { |
|
537 // Use the selectors API if available. |
|
538 $root_selector = $block_type->selectors['root']; |
|
539 } elseif ( isset( $block_type->supports['__experimentalSelector'] ) && is_string( $block_type->supports['__experimentalSelector'] ) ) { |
|
540 // Use the old experimental selector supports property if set. |
|
541 $root_selector = $block_type->supports['__experimentalSelector']; |
|
542 } else { |
|
543 // If no root selector found, generate default block class selector. |
|
544 $block_name = str_replace( '/', '-', str_replace( 'core/', '', $block_type->name ) ); |
|
545 $root_selector = ".wp-block-{$block_name}"; |
|
546 } |
|
547 |
|
548 // Return selector if it's the root target we are looking for. |
|
549 if ( 'root' === $target ) { |
|
550 return $root_selector; |
|
551 } |
|
552 |
|
553 // If target is not `root` we have a feature or subfeature as the target. |
|
554 // If the target is a string convert to an array. |
|
555 if ( is_string( $target ) ) { |
|
556 $target = explode( '.', $target ); |
|
557 } |
|
558 |
|
559 // Feature Selectors ( May fallback to root selector ). |
|
560 if ( 1 === count( $target ) ) { |
|
561 $fallback_selector = $fallback ? $root_selector : null; |
|
562 |
|
563 // Prefer the selectors API if available. |
|
564 if ( $has_selectors ) { |
|
565 // Look for selector under `feature.root`. |
|
566 $path = array( current( $target ), 'root' ); |
|
567 $feature_selector = _wp_array_get( $block_type->selectors, $path, null ); |
|
568 |
|
569 if ( $feature_selector ) { |
|
570 return $feature_selector; |
|
571 } |
|
572 |
|
573 // Check if feature selector is set via shorthand. |
|
574 $feature_selector = _wp_array_get( $block_type->selectors, $target, null ); |
|
575 |
|
576 return is_string( $feature_selector ) ? $feature_selector : $fallback_selector; |
|
577 } |
|
578 |
|
579 // Try getting old experimental supports selector value. |
|
580 $path = array( current( $target ), '__experimentalSelector' ); |
|
581 $feature_selector = _wp_array_get( $block_type->supports, $path, null ); |
|
582 |
|
583 // Nothing to work with, provide fallback or null. |
|
584 if ( null === $feature_selector ) { |
|
585 return $fallback_selector; |
|
586 } |
|
587 |
|
588 // Scope the feature selector by the block's root selector. |
|
589 return WP_Theme_JSON::scope_selector( $root_selector, $feature_selector ); |
|
590 } |
|
591 |
|
592 // Subfeature selector |
|
593 // This may fallback either to parent feature or root selector. |
|
594 $subfeature_selector = null; |
|
595 |
|
596 // Use selectors API if available. |
|
597 if ( $has_selectors ) { |
|
598 $subfeature_selector = _wp_array_get( $block_type->selectors, $target, null ); |
|
599 } |
|
600 |
|
601 // Only return if we have a subfeature selector. |
|
602 if ( $subfeature_selector ) { |
|
603 return $subfeature_selector; |
|
604 } |
|
605 |
|
606 // To this point we don't have a subfeature selector. If a fallback |
|
607 // has been requested, remove subfeature from target path and return |
|
608 // results of a call for the parent feature's selector. |
|
609 if ( $fallback ) { |
|
610 return wp_get_block_css_selector( $block_type, $target[0], $fallback ); |
|
611 } |
|
612 |
|
613 return null; |
|
614 } |