diff --git a/src/wp-includes/global-styles-and-settings.php b/src/wp-includes/global-styles-and-settings.php index ac73c889e5ad8..a814b5fe3b7c8 100644 --- a/src/wp-includes/global-styles-and-settings.php +++ b/src/wp-includes/global-styles-and-settings.php @@ -85,18 +85,34 @@ function wp_get_global_styles( $path = array(), $context = array() ) { * @return string Stylesheet. */ function wp_get_global_stylesheet( $types = array() ) { - // Return cached value if it can be used and exists. - // It's cached by theme to make sure that theme switching clears the cache. - $can_use_cached = ( - ( empty( $types ) ) && - ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) && - ( ! defined( 'SCRIPT_DEBUG' ) || ! SCRIPT_DEBUG ) && - ( ! defined( 'REST_REQUEST' ) || ! REST_REQUEST ) && - ! is_admin() - ); - $transient_name = 'global_styles_' . get_stylesheet(); + /* + * Ignore cache when `WP_DEBUG` is enabled, so it doesn't interfere with the theme + * developer's workflow. + * + * @todo Replace `WP_DEBUG` once an "in development mode" check is available in Core. + */ + $can_use_cached = empty( $types ) && ! WP_DEBUG; + + /* + * 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_group = 'theme_json'; + $cache_key = 'wp_get_global_stylesheet'; if ( $can_use_cached ) { - $cached = get_transient( $transient_name ); + $cached = wp_cache_get( $cache_key, $cache_group ); if ( $cached ) { return $cached; } @@ -152,11 +168,8 @@ function wp_get_global_stylesheet( $types = array() ) { } $stylesheet = $styles_variables . $styles_rest; - if ( $can_use_cached ) { - // Cache for a minute. - // This cache doesn't need to be any longer, we only want to avoid spikes on high-traffic sites. - set_transient( $transient_name, $stylesheet, MINUTE_IN_SECONDS ); + wp_cache_set( $cache_key, $stylesheet, $cache_group ); } return $stylesheet; @@ -303,5 +316,6 @@ function wp_theme_has_theme_json() { * @since 6.2.0 */ function wp_clean_theme_json_cache() { + wp_cache_delete( 'wp_get_global_stylesheet', 'theme_json' ); WP_Theme_JSON_Resolver::clean_cached_data(); } diff --git a/src/wp-includes/load.php b/src/wp-includes/load.php index 4c212086df34e..c2450e582f958 100644 --- a/src/wp-includes/load.php +++ b/src/wp-includes/load.php @@ -753,7 +753,7 @@ function wp_start_object_cache() { ) ); - wp_cache_add_non_persistent_groups( array( 'counts', 'plugins' ) ); + wp_cache_add_non_persistent_groups( array( 'counts', 'plugins', 'theme_json' ) ); } $first_init = false; diff --git a/src/wp-includes/ms-blogs.php b/src/wp-includes/ms-blogs.php index c5a988693c2de..9f2916d7f984d 100644 --- a/src/wp-includes/ms-blogs.php +++ b/src/wp-includes/ms-blogs.php @@ -575,7 +575,7 @@ function switch_to_blog( $new_blog_id, $deprecated = null ) { ); } - wp_cache_add_non_persistent_groups( array( 'counts', 'plugins' ) ); + wp_cache_add_non_persistent_groups( array( 'counts', 'plugins', 'theme_json' ) ); } } @@ -666,7 +666,7 @@ function restore_current_blog() { ); } - wp_cache_add_non_persistent_groups( array( 'counts', 'plugins' ) ); + wp_cache_add_non_persistent_groups( array( 'counts', 'plugins', 'theme_json' ) ); } } diff --git a/tests/phpunit/includes/abstract-testcase.php b/tests/phpunit/includes/abstract-testcase.php index bae787a42dee3..fa048cdfa703a 100644 --- a/tests/phpunit/includes/abstract-testcase.php +++ b/tests/phpunit/includes/abstract-testcase.php @@ -401,7 +401,7 @@ public static function flush_cache() { ) ); - wp_cache_add_non_persistent_groups( array( 'counts', 'plugins' ) ); + wp_cache_add_non_persistent_groups( array( 'counts', 'plugins', 'theme_json' ) ); } /** diff --git a/tests/phpunit/tests/theme/wpGetGlobalStylesheet.php b/tests/phpunit/tests/theme/wpGetGlobalStylesheet.php index 710f77d0caf0d..a2c0f962d27fb 100644 --- a/tests/phpunit/tests/theme/wpGetGlobalStylesheet.php +++ b/tests/phpunit/tests/theme/wpGetGlobalStylesheet.php @@ -270,4 +270,18 @@ public function test_should_enqueue_stored_styles() { 'Registered styles with handle of "wp-style-engine-my-styles" do not match expected value from the Style Engine store.' ); } + /** + * Tests that switching themes recalculates the stylesheet. + * + * @ticket 56970 + */ + public function test_switching_themes_should_recalculate_stylesheet() { + $stylesheet_for_default_theme = wp_get_global_stylesheet(); + switch_theme( 'block-theme' ); + $stylesheet_for_block_theme = wp_get_global_stylesheet(); + switch_theme( WP_DEFAULT_THEME ); + + $this->assertStringNotContainsString( '--wp--preset--font-size--custom: 100px;', $stylesheet_for_default_theme, 'custom font size (100px) not present for default theme' ); + $this->assertStringContainsString( '--wp--preset--font-size--custom: 100px;', $stylesheet_for_block_theme, 'custom font size (100px) is present for block theme' ); + } }