Commit f8d212b06a for wordpress.org
commit f8d212b06ab5a1e3e0cd80e4e3bb0a71c362df1f
Author: jonsurrell <jonsurrell@git.wordpress.org>
Date: Thu Oct 15 07:56:50 2026 +0000
Editor: Cache the theme.json data merged from all origins.
`WP_Theme_JSON_Resolver::get_merged_data()` merged all origins on every call, including once for each rendered block with an `is-style-*` class. Cache the result until a block is registered or `wp_clean_theme_json_cache()` is called, and remove the redundant cache in `wp_get_global_settings()`. Theme support changes made after the first merge require `wp_clean_theme_json_cache()`.
Backports https://github.com/WordPress/gutenberg/pull/81979.
Developed in: https://github.com/WordPress/wordpress-develop/pull/14071
Props jonsurrell, peterwilsoncc, isabel_brison, ramonopoly.
Fixes #66280. See #62249.
Built from https://develop.svn.wordpress.org/trunk@64354
git-svn-id: http://core.svn.wordpress.org/trunk@63504 1a063a9b-81f0-0310-95a4-ce76da25c4cd
diff --git a/wp-includes/block-supports/layout.php b/wp-includes/block-supports/layout.php
index 0162ae8d5a..dc3b56c017 100644
--- a/wp-includes/block-supports/layout.php
+++ b/wp-includes/block-supports/layout.php
@@ -1022,8 +1022,6 @@ function wp_get_layout_style( $selector, $layout, $has_block_gap_support = false
* @return string Filtered block content.
*/
function wp_render_layout_support_flag( $block_content, $block ) {
- static $global_styles = null;
-
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
$block_supports_layout = block_has_support( $block_type, 'layout', false ) || block_has_support( $block_type, '__experimentalLayout', false );
$style_attr = $block['attrs']['style'] ?? array();
@@ -1241,10 +1239,8 @@ function wp_render_layout_support_flag( $block_content, $block ) {
// Get default blockGap value from global styles for use in layouts like grid.
// Check style variation first, then block-specific styles, then fall back to root styles.
- $block_name = $block['blockName'] ?? '';
- if ( null === $global_styles ) {
- $global_styles = wp_get_global_styles();
- }
+ $block_name = $block['blockName'] ?? '';
+ $global_styles = wp_get_global_styles();
// Check if the block has an active style variation with a blockGap value.
// Only check the registry if the className contains a variation class to avoid unnecessary lookups.
diff --git a/wp-includes/class-wp-theme-json-resolver.php b/wp-includes/class-wp-theme-json-resolver.php
index 05eedbcd40..c8129e1ebc 100644
--- a/wp-includes/class-wp-theme-json-resolver.php
+++ b/wp-includes/class-wp-theme-json-resolver.php
@@ -24,6 +24,7 @@ class WP_Theme_JSON_Resolver {
* Container for keep track of registered blocks.
*
* @since 6.1.0
+ * @since 7.2.0 Added the `merged` entry.
* @var array
*/
protected static $blocks_cache = array(
@@ -31,8 +32,17 @@ class WP_Theme_JSON_Resolver {
'blocks' => array(),
'theme' => array(),
'user' => array(),
+ 'merged' => array(),
);
+ /**
+ * Merged data keyed by origin.
+ *
+ * @since 7.2.0
+ * @var array
+ */
+ protected static $merged = array();
+
/**
* Container for data coming from core.
*
@@ -192,9 +202,11 @@ class WP_Theme_JSON_Resolver {
* Checks whether the registered blocks were already processed for this origin.
*
* @since 6.1.0
+ * @since 7.2.0 Added the 'merged' origin.
*
* @param string $origin Data source for which to cache the blocks.
- * Valid values are 'core', 'blocks', 'theme', and 'user'.
+ * Valid values are 'core', 'blocks', 'theme', 'user',
+ * and 'merged'.
* @return bool True on success, false otherwise.
*/
protected static function has_same_registered_blocks( $origin ) {
@@ -638,6 +650,7 @@ class WP_Theme_JSON_Resolver {
* added the `$origin` parameter.
* @since 6.1.0 Added block data and generation of spacingSizes array.
* @since 6.2.0 Changed ' $origin' parameter values to 'default', 'blocks', 'theme' or 'custom'.
+ * @since 7.2.0 Caches the merged data per origin for the request and returns a copy of it.
*
* @param string $origin Optional. To what level should we merge data: 'default', 'blocks', 'theme' or 'custom'.
* 'custom' is used as default value as well as fallback value if the origin is unknown.
@@ -648,25 +661,39 @@ class WP_Theme_JSON_Resolver {
_deprecated_argument( __FUNCTION__, '5.9.0' );
}
- $result = new WP_Theme_JSON();
- $result->merge( static::get_core_data() );
- if ( 'default' === $origin ) {
- return $result;
+ if ( ! in_array( $origin, array( 'default', 'blocks', 'theme', 'custom' ), true ) ) {
+ $origin = 'custom';
}
- $result->merge( static::get_block_data() );
- if ( 'blocks' === $origin ) {
- return $result;
+ /*
+ * Discard the merged data when blocks were registered after the last merge.
+ *
+ * This check detects new blocks, not theme support changes. Call
+ * clean_cached_data() after changing theme supports to refresh the merged data.
+ */
+ if ( ! static::has_same_registered_blocks( 'merged' ) ) {
+ static::$merged = array();
+ }
+ if ( isset( static::$merged[ $origin ] ) ) {
+ return clone static::$merged[ $origin ];
}
- $result->merge( static::get_theme_data() );
- if ( 'theme' === $origin ) {
- return $result;
+ $result = new WP_Theme_JSON();
+ $result->merge( static::get_core_data() );
+ if ( 'default' !== $origin ) {
+ $result->merge( static::get_block_data() );
+ }
+ if ( 'theme' === $origin || 'custom' === $origin ) {
+ $result->merge( static::get_theme_data() );
+ }
+ if ( 'custom' === $origin ) {
+ $result->merge( static::get_user_data() );
}
- $result->merge( static::get_user_data() );
+ static::$merged[ $origin ] = $result;
- return $result;
+ // Return a clone so callers can modify the result without changing the cache.
+ return clone $result;
}
/**
@@ -733,16 +760,13 @@ class WP_Theme_JSON_Resolver {
* and `$i18n_schema` variables to reset.
* @since 6.1.0 Added the `$blocks` and `$blocks_cache` variables
* to reset.
+ * @since 7.2.0 Added the `$merged` variable to reset.
*/
public static function clean_cached_data() {
static::$core = null;
static::$blocks = null;
- static::$blocks_cache = array(
- 'core' => array(),
- 'blocks' => array(),
- 'theme' => array(),
- 'user' => array(),
- );
+ static::$blocks_cache = array_fill_keys( array_keys( static::$blocks_cache ), array() );
+ static::$merged = array();
static::$theme = null;
static::$user = null;
static::$user_custom_post_type_id = null;
diff --git a/wp-includes/global-styles-and-settings.php b/wp-includes/global-styles-and-settings.php
index 2315eef1ad..8c9affa79a 100644
--- a/wp-includes/global-styles-and-settings.php
+++ b/wp-includes/global-styles-and-settings.php
@@ -9,6 +9,7 @@
* Gets the settings resulting of merging core, theme, and user data.
*
* @since 5.9.0
+ * @since 7.2.0 Removed the per-request cache; WP_Theme_JSON_Resolver::get_merged_data() caches the merged data.
*
* @param array $path Path to the specific setting to retrieve. Optional.
* If empty, will return all settings.
@@ -32,53 +33,13 @@ function wp_get_global_settings( $path = array(), $context = array() ) {
$path = $new_path;
}
- /*
- * This is the default value when no origin is provided or when it is 'all'.
- *
- * The $origin is used as part of the cache key. Changes here need to account
- * for clearing the cache appropriately.
- */
+ // This is the default value when no origin is provided or when it is 'all'.
$origin = 'custom';
if ( isset( $context['origin'] ) && 'base' === $context['origin'] ) {
$origin = 'theme';
}
- /*
- * By using the 'theme_json' group, this data is marked to be non-persistent across requests.
- * See `wp_cache_add_non_persistent_groups` in src/wp-includes/load.php and other places.
- *
- * 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:
- * 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_group = 'theme_json';
- $cache_key = 'wp_get_global_settings_' . $origin;
-
- /*
- * 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' );
-
- $settings = false;
- if ( $can_use_cached ) {
- $settings = wp_cache_get( $cache_key, $cache_group );
- }
-
- if ( false === $settings ) {
- $settings = WP_Theme_JSON_Resolver::get_merged_data( $origin )->get_settings();
- if ( $can_use_cached ) {
- wp_cache_set( $cache_key, $settings, $cache_group );
- }
- }
+ $settings = WP_Theme_JSON_Resolver::get_merged_data( $origin )->get_settings();
return _wp_array_get( $settings, $path, $settings );
}
@@ -452,8 +413,6 @@ function wp_theme_has_theme_json() {
function wp_clean_theme_json_cache() {
wp_cache_delete( 'wp_get_global_stylesheet', 'theme_json' );
wp_cache_delete( 'wp_get_global_styles_svg_filters', 'theme_json' );
- wp_cache_delete( 'wp_get_global_settings_custom', 'theme_json' );
- wp_cache_delete( 'wp_get_global_settings_theme', 'theme_json' );
wp_cache_delete( 'wp_get_global_styles_custom_css', 'theme_json' );
wp_cache_delete( 'wp_get_theme_data_template_parts', 'theme_json' );
WP_Theme_JSON_Resolver::clean_cached_data();
diff --git a/wp-includes/version.php b/wp-includes/version.php
index 261f66d56d..5163cc6b44 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
-$wp_version = '7.2-alpha-64353';
+$wp_version = '7.2-alpha-64354';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.