diff -r 48c4eec2b7e6 -r 8c2e4d02f4ef wp/wp-includes/global-styles-and-settings.php --- a/wp/wp-includes/global-styles-and-settings.php Fri Sep 05 18:40:08 2025 +0200 +++ b/wp/wp-includes/global-styles-and-settings.php Fri Sep 05 18:52:52 2025 +0200 @@ -142,7 +142,7 @@ * @since 6.6.0 Resolves relative paths in theme.json styles to theme absolute paths. * * @param array $types Optional. Types of styles to load. - * It accepts as values 'variables', 'presets', 'styles', 'base-layout-styles'. + * See {@see 'WP_Theme_JSON::get_stylesheet'} for all valid types. * If empty, it'll load the following: * - for themes without theme.json: 'variables', 'presets', 'base-layout-styles'. * - for themes with theme.json: 'variables', 'presets', 'styles'. @@ -244,61 +244,10 @@ } /** - * Gets the global styles custom CSS from theme.json. - * - * @since 6.2.0 - * - * @return string The global styles custom CSS. - */ -function wp_get_global_styles_custom_css() { - if ( ! wp_theme_has_theme_json() ) { - return ''; - } - /* - * Ignore cache when the development mode is set to 'theme', so it doesn't interfere with the theme - * developer's workflow. - */ - $can_use_cached = ! wp_is_development_mode( 'theme' ); - - /* - * By using the 'theme_json' group, this data is marked to be non-persistent across requests. - * @see `wp_cache_add_non_persistent_groups()`. - * - * The rationale for this is to make sure derived data from theme.json - * is always fresh from the potential modifications done via hooks - * that can use dynamic data (modify the stylesheet depending on some option, - * settings depending on user permissions, etc.). - * See some of the existing hooks to modify theme.json behavior: - * @see https://make.wordpress.org/core/2022/10/10/filters-for-theme-json-data/ - * - * A different alternative considered was to invalidate the cache upon certain - * events such as options add/update/delete, user meta, etc. - * It was judged not enough, hence this approach. - * @see https://github.com/WordPress/gutenberg/pull/45372 - */ - $cache_key = 'wp_get_global_styles_custom_css'; - $cache_group = 'theme_json'; - if ( $can_use_cached ) { - $cached = wp_cache_get( $cache_key, $cache_group ); - if ( $cached ) { - return $cached; - } - } - - $tree = WP_Theme_JSON_Resolver::get_merged_data(); - $stylesheet = $tree->get_custom_css(); - - if ( $can_use_cached ) { - wp_cache_set( $cache_key, $stylesheet, $cache_group ); - } - - return $stylesheet; -} - -/** * Adds global style rules to the inline style for each block. * * @since 6.1.0 + * @since 6.7.0 Resolve relative paths in block styles. * * @global WP_Styles $wp_styles */ @@ -306,11 +255,50 @@ global $wp_styles; $tree = WP_Theme_JSON_Resolver::get_merged_data(); + $tree = WP_Theme_JSON_Resolver::resolve_theme_file_uris( $tree ); $block_nodes = $tree->get_styles_block_nodes(); + + $can_use_cached = ! wp_is_development_mode( 'theme' ); + $update_cache = false; + + if ( $can_use_cached ) { + // Hash the merged WP_Theme_JSON data to bust cache on settings or styles change. + $cache_hash = md5( wp_json_encode( $tree->get_raw_data() ) ); + $cache_key = 'wp_styles_for_blocks'; + $cached = get_transient( $cache_key ); + + // Reset the cached data if there is no value or if the hash has changed. + if ( ! is_array( $cached ) || $cached['hash'] !== $cache_hash ) { + $cached = array( + 'hash' => $cache_hash, + 'blocks' => array(), + ); + + // Update the cache if the hash has changed. + $update_cache = true; + } + } + foreach ( $block_nodes as $metadata ) { - $block_css = $tree->get_styles_for_block( $metadata ); + + if ( $can_use_cached ) { + // Use the block name as the key for cached CSS data. Otherwise, use a hash of the metadata. + $cache_node_key = isset( $metadata['name'] ) ? $metadata['name'] : md5( wp_json_encode( $metadata ) ); - if ( ! wp_should_load_separate_core_block_assets() ) { + if ( isset( $cached['blocks'][ $cache_node_key ] ) ) { + $block_css = $cached['blocks'][ $cache_node_key ]; + } else { + $block_css = $tree->get_styles_for_block( $metadata ); + $cached['blocks'][ $cache_node_key ] = $block_css; + + // Update the cache if the cache contents have changed. + $update_cache = true; + } + } else { + $block_css = $tree->get_styles_for_block( $metadata ); + } + + if ( ! wp_should_load_block_assets_on_demand() ) { wp_add_inline_style( 'global-styles', $block_css ); continue; } @@ -318,13 +306,14 @@ $stylesheet_handle = 'global-styles'; /* - * When `wp_should_load_separate_core_block_assets()` is true, block styles are + * When `wp_should_load_block_assets_on_demand()` is true, block styles are * enqueued for each block on the page in class WP_Block's render function. * This means there will be a handle in the styles queue for each of those blocks. * Block-specific global styles should be attached to the global-styles handle, but * only for blocks on the page, thus we check if the block's handle is in the queue * before adding the inline style. * This conditional loading only applies to core blocks. + * TODO: Explore how this could be expanded to third-party blocks as well. */ if ( isset( $metadata['name'] ) ) { if ( str_starts_with( $metadata['name'], 'core/' ) ) { @@ -354,6 +343,10 @@ } } } + + if ( $update_cache ) { + set_transient( $cache_key, $cached ); + } } /**