140 * @since 5.9.0 |
140 * @since 5.9.0 |
141 * @since 6.1.0 Added 'base-layout-styles' support. |
141 * @since 6.1.0 Added 'base-layout-styles' support. |
142 * @since 6.6.0 Resolves relative paths in theme.json styles to theme absolute paths. |
142 * @since 6.6.0 Resolves relative paths in theme.json styles to theme absolute paths. |
143 * |
143 * |
144 * @param array $types Optional. Types of styles to load. |
144 * @param array $types Optional. Types of styles to load. |
145 * It accepts as values 'variables', 'presets', 'styles', 'base-layout-styles'. |
145 * See {@see 'WP_Theme_JSON::get_stylesheet'} for all valid types. |
146 * If empty, it'll load the following: |
146 * If empty, it'll load the following: |
147 * - for themes without theme.json: 'variables', 'presets', 'base-layout-styles'. |
147 * - for themes without theme.json: 'variables', 'presets', 'base-layout-styles'. |
148 * - for themes with theme.json: 'variables', 'presets', 'styles'. |
148 * - for themes with theme.json: 'variables', 'presets', 'styles'. |
149 * @return string Stylesheet. |
149 * @return string Stylesheet. |
150 */ |
150 */ |
242 |
242 |
243 return $stylesheet; |
243 return $stylesheet; |
244 } |
244 } |
245 |
245 |
246 /** |
246 /** |
247 * Gets the global styles custom CSS from theme.json. |
|
248 * |
|
249 * @since 6.2.0 |
|
250 * |
|
251 * @return string The global styles custom CSS. |
|
252 */ |
|
253 function wp_get_global_styles_custom_css() { |
|
254 if ( ! wp_theme_has_theme_json() ) { |
|
255 return ''; |
|
256 } |
|
257 /* |
|
258 * Ignore cache when the development mode is set to 'theme', so it doesn't interfere with the theme |
|
259 * developer's workflow. |
|
260 */ |
|
261 $can_use_cached = ! wp_is_development_mode( 'theme' ); |
|
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'; |
|
281 if ( $can_use_cached ) { |
|
282 $cached = wp_cache_get( $cache_key, $cache_group ); |
|
283 if ( $cached ) { |
|
284 return $cached; |
|
285 } |
|
286 } |
|
287 |
|
288 $tree = WP_Theme_JSON_Resolver::get_merged_data(); |
|
289 $stylesheet = $tree->get_custom_css(); |
|
290 |
|
291 if ( $can_use_cached ) { |
|
292 wp_cache_set( $cache_key, $stylesheet, $cache_group ); |
|
293 } |
|
294 |
|
295 return $stylesheet; |
|
296 } |
|
297 |
|
298 /** |
|
299 * Adds global style rules to the inline style for each block. |
247 * Adds global style rules to the inline style for each block. |
300 * |
248 * |
301 * @since 6.1.0 |
249 * @since 6.1.0 |
|
250 * @since 6.7.0 Resolve relative paths in block styles. |
302 * |
251 * |
303 * @global WP_Styles $wp_styles |
252 * @global WP_Styles $wp_styles |
304 */ |
253 */ |
305 function wp_add_global_styles_for_blocks() { |
254 function wp_add_global_styles_for_blocks() { |
306 global $wp_styles; |
255 global $wp_styles; |
307 |
256 |
308 $tree = WP_Theme_JSON_Resolver::get_merged_data(); |
257 $tree = WP_Theme_JSON_Resolver::get_merged_data(); |
|
258 $tree = WP_Theme_JSON_Resolver::resolve_theme_file_uris( $tree ); |
309 $block_nodes = $tree->get_styles_block_nodes(); |
259 $block_nodes = $tree->get_styles_block_nodes(); |
|
260 |
|
261 $can_use_cached = ! wp_is_development_mode( 'theme' ); |
|
262 $update_cache = false; |
|
263 |
|
264 if ( $can_use_cached ) { |
|
265 // Hash the merged WP_Theme_JSON data to bust cache on settings or styles change. |
|
266 $cache_hash = md5( wp_json_encode( $tree->get_raw_data() ) ); |
|
267 $cache_key = 'wp_styles_for_blocks'; |
|
268 $cached = get_transient( $cache_key ); |
|
269 |
|
270 // Reset the cached data if there is no value or if the hash has changed. |
|
271 if ( ! is_array( $cached ) || $cached['hash'] !== $cache_hash ) { |
|
272 $cached = array( |
|
273 'hash' => $cache_hash, |
|
274 'blocks' => array(), |
|
275 ); |
|
276 |
|
277 // Update the cache if the hash has changed. |
|
278 $update_cache = true; |
|
279 } |
|
280 } |
|
281 |
310 foreach ( $block_nodes as $metadata ) { |
282 foreach ( $block_nodes as $metadata ) { |
311 $block_css = $tree->get_styles_for_block( $metadata ); |
283 |
312 |
284 if ( $can_use_cached ) { |
313 if ( ! wp_should_load_separate_core_block_assets() ) { |
285 // Use the block name as the key for cached CSS data. Otherwise, use a hash of the metadata. |
|
286 $cache_node_key = isset( $metadata['name'] ) ? $metadata['name'] : md5( wp_json_encode( $metadata ) ); |
|
287 |
|
288 if ( isset( $cached['blocks'][ $cache_node_key ] ) ) { |
|
289 $block_css = $cached['blocks'][ $cache_node_key ]; |
|
290 } else { |
|
291 $block_css = $tree->get_styles_for_block( $metadata ); |
|
292 $cached['blocks'][ $cache_node_key ] = $block_css; |
|
293 |
|
294 // Update the cache if the cache contents have changed. |
|
295 $update_cache = true; |
|
296 } |
|
297 } else { |
|
298 $block_css = $tree->get_styles_for_block( $metadata ); |
|
299 } |
|
300 |
|
301 if ( ! wp_should_load_block_assets_on_demand() ) { |
314 wp_add_inline_style( 'global-styles', $block_css ); |
302 wp_add_inline_style( 'global-styles', $block_css ); |
315 continue; |
303 continue; |
316 } |
304 } |
317 |
305 |
318 $stylesheet_handle = 'global-styles'; |
306 $stylesheet_handle = 'global-styles'; |
319 |
307 |
320 /* |
308 /* |
321 * When `wp_should_load_separate_core_block_assets()` is true, block styles are |
309 * When `wp_should_load_block_assets_on_demand()` is true, block styles are |
322 * enqueued for each block on the page in class WP_Block's render function. |
310 * 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. |
311 * 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 |
312 * 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 |
313 * only for blocks on the page, thus we check if the block's handle is in the queue |
326 * before adding the inline style. |
314 * before adding the inline style. |
327 * This conditional loading only applies to core blocks. |
315 * This conditional loading only applies to core blocks. |
|
316 * TODO: Explore how this could be expanded to third-party blocks as well. |
328 */ |
317 */ |
329 if ( isset( $metadata['name'] ) ) { |
318 if ( isset( $metadata['name'] ) ) { |
330 if ( str_starts_with( $metadata['name'], 'core/' ) ) { |
319 if ( str_starts_with( $metadata['name'], 'core/' ) ) { |
331 $block_name = str_replace( 'core/', '', $metadata['name'] ); |
320 $block_name = str_replace( 'core/', '', $metadata['name'] ); |
332 $block_handle = 'wp-block-' . $block_name; |
321 $block_handle = 'wp-block-' . $block_name; |