From 8ddb28368a296334dbccbca25721aeb30565189a Mon Sep 17 00:00:00 2001 From: hellofromTonya Date: Wed, 18 Jan 2023 11:40:10 +0000 Subject: [PATCH] Themes: Introduce wp_theme_has_theme_json() for public consumption. Adds `wp_theme_has_theme_json()` for public consumption, to replace the private internal Core-only `WP_Theme_JSON_Resolver::theme_has_support()` method. This new global function checks if a theme or its parent has a `theme.json` file. For performance, results are cached as an integer `1` or `0` in the `'theme_json'` group with `'wp_theme_has_theme_json'` key. This is a non-persistent cache. Why? To make the 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.). Also adds a new public function `wp_clean_theme_json_cache()` to clear the cache on `'switch_theme'` and `start_previewing_theme'`. References: * [https://github.com/WordPress/gutenberg/pull/45168 Gutenberg PR 45168] Add `wp_theme_has_theme_json` as a public API to know whether a theme has a `theme.json`. * [https://github.com/WordPress/gutenberg/pull/45380 Gutenberg PR 45380] Deprecate `WP_Theme_JSON_Resolver:theme_has_support()`. * [https://github.com/WordPress/gutenberg/pull/46150 Gutenberg PR 46150] Make `theme.json` object caches non-persistent. * [https://github.com/WordPress/gutenberg/pull/45979 Gutenberg PR 45979] Don't check if constants set by `wp_initial_constants()` are defined. * [https://github.com/WordPress/gutenberg/pull/45950 Gutenberg PR 45950] Cleaner logic in `wp_theme_has_theme_json`. Follow-up to [54493], [53282], [52744], [52049], [50959]. Props oandregal, afragen, alexstine, aristath, azaozz, costdev, flixos90, hellofromTonya, mamaduka, mcsf, ocean90, spacedmonkey. Fixes #56975. Built from https://develop.svn.wordpress.org/trunk@55086 git-svn-id: http://core.svn.wordpress.org/trunk@54619 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/edit-form-blocks.php | 2 +- wp-admin/site-editor.php | 2 +- wp-includes/block-editor.php | 2 +- wp-includes/block-patterns.php | 2 +- wp-includes/block-supports/layout.php | 4 +- wp-includes/block-template-utils.php | 4 +- wp-includes/class-wp-theme-json-resolver.php | 25 ++----- wp-includes/default-filters.php | 4 +- wp-includes/global-styles-and-settings.php | 73 +++++++++++++++++++- wp-includes/load.php | 2 +- wp-includes/ms-blogs.php | 4 +- wp-includes/script-loader.php | 6 +- wp-includes/theme-templates.php | 2 +- wp-includes/version.php | 2 +- 14 files changed, 95 insertions(+), 39 deletions(-) diff --git a/wp-admin/edit-form-blocks.php b/wp-admin/edit-form-blocks.php index f43c835168c..e324a4e1b7b 100644 --- a/wp-admin/edit-form-blocks.php +++ b/wp-admin/edit-form-blocks.php @@ -203,7 +203,7 @@ static function( $classes ) { 'unlockNonce' => wp_create_nonce( 'update-post_' . $post->ID ), 'ajaxUrl' => admin_url( 'admin-ajax.php' ), ), - 'supportsLayout' => WP_Theme_JSON_Resolver::theme_has_support(), + 'supportsLayout' => wp_theme_has_theme_json(), 'supportsTemplateMode' => current_theme_supports( 'block-templates' ), // Whether or not to load the 'postcustom' meta box is stored as a user meta diff --git a/wp-admin/site-editor.php b/wp-admin/site-editor.php index a8b43b52af7..deb556a6957 100644 --- a/wp-admin/site-editor.php +++ b/wp-admin/site-editor.php @@ -74,7 +74,7 @@ static function( $classes ) { 'styles' => get_block_editor_theme_styles(), 'defaultTemplateTypes' => $indexed_template_types, 'defaultTemplatePartAreas' => get_allowed_block_template_part_areas(), - 'supportsLayout' => WP_Theme_JSON_Resolver::theme_has_support(), + 'supportsLayout' => wp_theme_has_theme_json(), 'supportsTemplatePartsMode' => ! wp_is_block_theme() && current_theme_supports( 'block-template-parts' ), '__unstableHomeTemplate' => $home_template, ); diff --git a/wp-includes/block-editor.php b/wp-includes/block-editor.php index 7af9f2a9006..4227c674c02 100644 --- a/wp-includes/block-editor.php +++ b/wp-includes/block-editor.php @@ -417,7 +417,7 @@ function get_block_editor_settings( array $custom_settings, $block_editor_contex } } - if ( WP_Theme_JSON_Resolver::theme_has_support() ) { + if ( wp_theme_has_theme_json() ) { $block_classes = array( 'css' => 'styles', '__unstableType' => 'theme', diff --git a/wp-includes/block-patterns.php b/wp-includes/block-patterns.php index 074ed33c84b..63398513d48 100644 --- a/wp-includes/block-patterns.php +++ b/wp-includes/block-patterns.php @@ -139,7 +139,7 @@ function _register_remote_theme_patterns() { return; } - if ( ! WP_Theme_JSON_Resolver::theme_has_support() ) { + if ( ! wp_theme_has_theme_json() ) { return; } diff --git a/wp-includes/block-supports/layout.php b/wp-includes/block-supports/layout.php index 7a882a9bab3..93c7364a323 100644 --- a/wp-includes/block-supports/layout.php +++ b/wp-includes/block-supports/layout.php @@ -464,7 +464,7 @@ function wp_restore_group_inner_container( $block_content, $block ) { ); if ( - WP_Theme_JSON_Resolver::theme_has_support() || + wp_theme_has_theme_json() || 1 === preg_match( $group_with_inner_container_regex, $block_content ) || ( isset( $block['attrs']['layout']['type'] ) && 'flex' === $block['attrs']['layout']['type'] ) ) { @@ -527,7 +527,7 @@ function wp_restore_image_outer_container( $block_content, $block ) { )/iUx"; if ( - WP_Theme_JSON_Resolver::theme_has_support() || + wp_theme_has_theme_json() || 0 === preg_match( $image_with_align, $block_content, $matches ) ) { return $block_content; diff --git a/wp-includes/block-template-utils.php b/wp-includes/block-template-utils.php index 826237aa189..66c48db7f13 100644 --- a/wp-includes/block-template-utils.php +++ b/wp-includes/block-template-utils.php @@ -347,7 +347,7 @@ function _get_block_templates_files( $template_type ) { * @return array Template item. */ function _add_block_template_info( $template_item ) { - if ( ! WP_Theme_JSON_Resolver::theme_has_support() ) { + if ( ! wp_theme_has_theme_json() ) { return $template_item; } @@ -370,7 +370,7 @@ function _add_block_template_info( $template_item ) { * @return array Template info. */ function _add_block_template_part_area_info( $template_info ) { - if ( WP_Theme_JSON_Resolver::theme_has_support() ) { + if ( wp_theme_has_theme_json() ) { $theme_data = WP_Theme_JSON_Resolver::get_theme_data( array(), array( 'with_supports' => false ) )->get_template_parts(); } diff --git a/wp-includes/class-wp-theme-json-resolver.php b/wp-includes/class-wp-theme-json-resolver.php index e4afc3c1489..3abc3142e95 100644 --- a/wp-includes/class-wp-theme-json-resolver.php +++ b/wp-includes/class-wp-theme-json-resolver.php @@ -57,14 +57,6 @@ class WP_Theme_JSON_Resolver { */ protected static $theme = null; - /** - * Whether or not the theme supports theme.json. - * - * @since 5.8.0 - * @var bool - */ - protected static $theme_has_support = null; - /** * Container for data coming from the user. * @@ -295,7 +287,7 @@ public static function get_theme_data( $deprecated = array(), $options = array() * and merge the static::$theme upon that. */ $theme_support_data = WP_Theme_JSON::get_from_editor_settings( get_default_block_editor_settings() ); - if ( ! static::theme_has_support() ) { + if ( ! wp_theme_has_theme_json() ) { if ( ! isset( $theme_support_data['settings']['color'] ) ) { $theme_support_data['settings']['color'] = array(); } @@ -421,11 +413,11 @@ public static function get_user_data_from_wp_global_styles( $theme, $create_post /* * Bail early if the theme does not support a theme.json. * - * Since WP_Theme_JSON_Resolver::theme_has_support() only supports the active + * Since wp_theme_has_theme_json() only supports the active * theme, the extra condition for whether $theme is the active theme is * present here. */ - if ( $theme->get_stylesheet() === get_stylesheet() && ! static::theme_has_support() ) { + if ( $theme->get_stylesheet() === get_stylesheet() && ! wp_theme_has_theme_json() ) { return array(); } @@ -602,18 +594,14 @@ public static function get_user_global_styles_post_id() { * * @since 5.8.0 * @since 5.9.0 Added a check in the parent theme. + * @deprecated 6.2.0 Use wp_theme_has_theme_json() instead. * * @return bool */ public static function theme_has_support() { - if ( ! isset( static::$theme_has_support ) ) { - static::$theme_has_support = ( - static::get_file_path_from_theme( 'theme.json' ) !== '' || - static::get_file_path_from_theme( 'theme.json', true ) !== '' - ); - } + _deprecated_function( __METHOD__, '6.2.0', 'wp_theme_has_theme_json()' ); - return static::$theme_has_support; + return wp_theme_has_theme_json(); } /** @@ -656,7 +644,6 @@ public static function clean_cached_data() { static::$theme = null; static::$user = null; static::$user_custom_post_type_id = null; - static::$theme_has_support = null; static::$i18n_schema = null; } diff --git a/wp-includes/default-filters.php b/wp-includes/default-filters.php index 5c623e371b1..4e6340700cc 100644 --- a/wp-includes/default-filters.php +++ b/wp-includes/default-filters.php @@ -346,8 +346,8 @@ add_action( 'init', '_register_core_block_patterns_and_categories' ); add_action( 'init', 'check_theme_switched', 99 ); add_action( 'init', array( 'WP_Block_Supports', 'init' ), 22 ); -add_action( 'switch_theme', array( 'WP_Theme_JSON_Resolver', 'clean_cached_data' ) ); -add_action( 'start_previewing_theme', array( 'WP_Theme_JSON_Resolver', 'clean_cached_data' ) ); +add_action( 'switch_theme', 'wp_clean_theme_json_cache' ); +add_action( 'start_previewing_theme', 'wp_clean_theme_json_cache' ); add_action( 'after_switch_theme', '_wp_menus_changed' ); add_action( 'after_switch_theme', '_wp_sidebars_changed' ); add_action( 'wp_print_styles', 'print_emoji_styles' ); diff --git a/wp-includes/global-styles-and-settings.php b/wp-includes/global-styles-and-settings.php index b6c8c91b464..d9379266875 100644 --- a/wp-includes/global-styles-and-settings.php +++ b/wp-includes/global-styles-and-settings.php @@ -102,7 +102,7 @@ function wp_get_global_stylesheet( $types = array() ) { $tree = WP_Theme_JSON_Resolver::get_merged_data(); - $supports_theme_json = WP_Theme_JSON_Resolver::theme_has_support(); + $supports_theme_json = wp_theme_has_theme_json(); if ( empty( $types ) && ! $supports_theme_json ) { $types = array( 'variables', 'presets', 'base-layout-styles' ); } elseif ( empty( $types ) ) { @@ -184,7 +184,7 @@ function wp_get_global_styles_svg_filters() { } } - $supports_theme_json = WP_Theme_JSON_Resolver::theme_has_support(); + $supports_theme_json = wp_theme_has_theme_json(); $origins = array( 'default', 'theme', 'custom' ); if ( ! $supports_theme_json ) { @@ -255,3 +255,72 @@ function ( $item ) { } } } + +/** + * Checks whether a theme or its parent has a theme.json file. + * + * @since 6.2.0 + * + * @return bool Returns true if theme or its parent has a theme.json file, false otherwise. + */ +function wp_theme_has_theme_json() { + /* + * 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.). + * For 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_theme_has_theme_json'; + $theme_has_support = wp_cache_get( $cache_key, $cache_group ); + + /* + * $theme_has_support is stored as an int in the cache. + * + * The reason not to store it as a boolean is to avoid working + * with the $found parameter which apparently had some issues in some implementations + * @see https://developer.wordpress.org/reference/functions/wp_cache_get/ + * + * 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. + */ + if ( ! WP_DEBUG && is_int( $theme_has_support ) ) { + return (bool) $theme_has_support; + } + + // Does the theme have its own theme.json? + $theme_has_support = is_readable( get_stylesheet_directory() . '/theme.json' ); + + // Look up the parent if the child does not have a theme.json. + if ( ! $theme_has_support ) { + $theme_has_support = is_readable( get_template_directory() . '/theme.json' ); + } + + $theme_has_support = $theme_has_support ? 1 : 0; + + wp_cache_set( $cache_key, $theme_has_support, $cache_group ); + + return (bool) $theme_has_support; +} + +/** + * Cleans the caches under the theme_json group. + * + * @since 6.2.0 + */ +function wp_clean_theme_json_cache() { + wp_cache_delete( 'wp_theme_has_theme_json', 'theme_json' ); + WP_Theme_JSON_Resolver::clean_cached_data(); +} diff --git a/wp-includes/load.php b/wp-includes/load.php index 4c212086df3..c2450e582f9 100644 --- a/wp-includes/load.php +++ b/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/wp-includes/ms-blogs.php b/wp-includes/ms-blogs.php index 0ea6f85627d..7ff830e9308 100644 --- a/wp-includes/ms-blogs.php +++ b/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/wp-includes/script-loader.php b/wp-includes/script-loader.php index 1444727f9da..de525789369 100644 --- a/wp-includes/script-loader.php +++ b/wp-includes/script-loader.php @@ -1620,7 +1620,7 @@ function wp_default_styles( $styles ) { ); // Only load the default layout and margin styles for themes without theme.json file. - if ( ! WP_Theme_JSON_Resolver::theme_has_support() ) { + if ( ! wp_theme_has_theme_json() ) { $wp_edit_blocks_dependencies[] = 'wp-editor-classic-layout-styles'; } @@ -3667,7 +3667,7 @@ function _wp_theme_json_webfonts_handler() { * @since 6.1.0 */ function wp_enqueue_classic_theme_styles() { - if ( ! WP_Theme_JSON_Resolver::theme_has_support() ) { + if ( ! wp_theme_has_theme_json() ) { $suffix = wp_scripts_get_suffix(); wp_register_style( 'classic-theme-styles', '/' . WPINC . "/css/classic-themes$suffix.css", array(), true ); wp_enqueue_style( 'classic-theme-styles' ); @@ -3685,7 +3685,7 @@ function wp_enqueue_classic_theme_styles() { * @return array A filtered array of editor settings. */ function wp_add_editor_classic_theme_styles( $editor_settings ) { - if ( WP_Theme_JSON_Resolver::theme_has_support() ) { + if ( wp_theme_has_theme_json() ) { return $editor_settings; } diff --git a/wp-includes/theme-templates.php b/wp-includes/theme-templates.php index 7ef010eea5f..ae71852a370 100644 --- a/wp-includes/theme-templates.php +++ b/wp-includes/theme-templates.php @@ -209,7 +209,7 @@ function the_block_template_skip_link() { * @since 5.8.0 */ function wp_enable_block_templates() { - if ( wp_is_block_theme() || WP_Theme_JSON_Resolver::theme_has_support() ) { + if ( wp_is_block_theme() || wp_theme_has_theme_json() ) { add_theme_support( 'block-templates' ); } } diff --git a/wp-includes/version.php b/wp-includes/version.php index 240001569e1..4219f0e278c 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.2-alpha-55085'; +$wp_version = '6.2-alpha-55086'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.