wp/wp-includes/global-styles-and-settings.php
changeset 22 8c2e4d02f4ef
parent 21 48c4eec2b7e6
--- 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 );
+	}
 }
 
 /**