Skip to content

Commit

Permalink
Editor: Fix performance regression in WP_Theme_JSON_Resolver.
Browse files Browse the repository at this point in the history
A significant performance regression was added late in WP 6.1 beta cycle when some of the existing caching for `theme.json` processing was removed. The rationale for removing the caching was this code was now used before all the blocks are registered (aka get template data, etc.) and resulted in stale cache that created issues (see [WordPress/gutenberg#44434 Gutenberg Issue 44434] and [WordPress/gutenberg#44619 Gutenberg Issue 44619]). The changes were limited to only reads from the file system. However, it introduced a big impact in performance.

This commit adds caching and checks for blocks with different origins. How? It add caching for the calculated data for core, theme, and user based on the blocks that are registered. If the blocks haven't changed since the last time they were calculated for the origin, the cached data is returned. Otherwise, the data is recalculated and cached.

Essentially, this brings back the previous cache, but refreshing it when the blocks change.

It partially adds unit tests for these changes. Additional tests will be added.

References:
* [WordPress/gutenberg#44772 Performance regression in WP 6.1 for theme.json processing]

Follow-up to [54251], [54399].

Props aristath, oandregal, bernhard-reiter, spacedmonkey, hellofromTonya.
See #56467.

git-svn-id: https://develop.svn.wordpress.org/trunk@54493 602fd350-edb4-49c9-b593-d223f7449a82
  • Loading branch information
hellofromtonya authored and = committed Nov 4, 2022
1 parent 5c7c14a commit 94309d1
Show file tree
Hide file tree
Showing 2 changed files with 332 additions and 15 deletions.
106 changes: 91 additions & 15 deletions src/wp-includes/class-wp-theme-json-resolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@
#[AllowDynamicProperties]
class WP_Theme_JSON_Resolver {

/**
* Container for keep track of registered blocks.
*
* @since 6.1.0
* @var array
*/
protected static $blocks_cache = array(
'core' => array(),
'blocks' => array(),
'theme' => array(),
'user' => array(),
);

/**
* Container for data coming from core.
*
Expand All @@ -28,6 +41,14 @@ class WP_Theme_JSON_Resolver {
*/
protected static $core = null;

/**
* Container for data coming from the blocks.
*
* @since 6.1.0
* @var WP_Theme_JSON
*/
protected static $blocks = null;

/**
* Container for data coming from the theme.
*
Expand Down Expand Up @@ -145,6 +166,10 @@ protected static function translate( $theme_json, $domain = 'default' ) {
* @return WP_Theme_JSON Entity that holds core data.
*/
public static function get_core_data() {
if ( null !== static::$core && static::has_same_registered_blocks( 'core' ) ) {
return static::$core;
}

$config = static::read_json_file( __DIR__ . '/theme.json' );
$config = static::translate( $config );

Expand All @@ -162,6 +187,37 @@ public static function get_core_data() {
return static::$core;
}

/**
* Checks whether the registered blocks were already processed for this origin.
*
* @since 6.1.0
*
* @param string $origin Data source for which to cache the blocks.
* Valid values are 'core', 'blocks', 'theme', and 'user'.
* @return bool True on success, false otherwise.
*/
protected static function has_same_registered_blocks( $origin ) {
// Bail out if the origin is invalid.
if ( ! isset( static::$blocks_cache[ $origin ] ) ) {
return false;
}

$registry = WP_Block_Type_Registry::get_instance();
$blocks = $registry->get_all_registered();

// Is there metadata for all currently registered blocks?
$block_diff = array_diff_key( $blocks, static::$blocks_cache[ $origin ] );
if ( empty( $block_diff ) ) {
return true;
}

foreach ( $blocks as $block_name => $block_type ) {
static::$blocks_cache[ $origin ][ $block_name ] = true;
}

return false;
}

/**
* Returns the theme's data.
*
Expand Down Expand Up @@ -189,19 +245,21 @@ public static function get_theme_data( $deprecated = array(), $options = array()

$options = wp_parse_args( $options, array( 'with_supports' => true ) );

$theme_json_data = static::read_json_file( static::get_file_path_from_theme( 'theme.json' ) );
$theme_json_data = static::translate( $theme_json_data, wp_get_theme()->get( 'TextDomain' ) );
if ( null === static::$theme || ! static::has_same_registered_blocks( 'theme' ) ) {
$theme_json_data = static::read_json_file( static::get_file_path_from_theme( 'theme.json' ) );
$theme_json_data = static::translate( $theme_json_data, wp_get_theme()->get( 'TextDomain' ) );

/**
* Filters the data provided by the theme for global styles and settings.
*
* @since 6.1.0
*
* @param WP_Theme_JSON_Data Class to access and update the underlying data.
*/
$theme_json = apply_filters( 'theme_json_theme', new WP_Theme_JSON_Data( $theme_json_data, 'theme' ) );
$theme_json_data = $theme_json->get_data();
static::$theme = new WP_Theme_JSON( $theme_json_data );
/**
* Filters the data provided by the theme for global styles and settings.
*
* @since 6.1.0
*
* @param WP_Theme_JSON_Data Class to access and update the underlying data.
*/
$theme_json = apply_filters( 'theme_json_theme', new WP_Theme_JSON_Data( $theme_json_data, 'theme' ) );
$theme_json_data = $theme_json->get_data();
static::$theme = new WP_Theme_JSON( $theme_json_data );
}

if ( wp_get_theme()->parent() ) {
// Get parent theme.json.
Expand Down Expand Up @@ -258,7 +316,6 @@ public static function get_theme_data( $deprecated = array(), $options = array()
}
$with_theme_supports = new WP_Theme_JSON( $theme_support_data );
$with_theme_supports->merge( static::$theme );

return $with_theme_supports;
}

Expand All @@ -272,7 +329,12 @@ public static function get_theme_data( $deprecated = array(), $options = array()
public static function get_block_data() {
$registry = WP_Block_Type_Registry::get_instance();
$blocks = $registry->get_all_registered();
$config = array( 'version' => 2 );

if ( null !== static::$blocks && static::has_same_registered_blocks( 'blocks' ) ) {
return static::$blocks;
}

$config = array( 'version' => 2 );
foreach ( $blocks as $block_name => $block_type ) {
if ( isset( $block_type->supports['__experimentalStyle'] ) ) {
$config['styles']['blocks'][ $block_name ] = static::remove_json_comments( $block_type->supports['__experimentalStyle'] );
Expand All @@ -298,7 +360,8 @@ public static function get_block_data() {
$theme_json = apply_filters( 'theme_json_blocks', new WP_Theme_JSON_Data( $config, 'blocks' ) );
$config = $theme_json->get_data();

return new WP_Theme_JSON( $config, 'blocks' );
static::$blocks = new WP_Theme_JSON( $config, 'blocks' );
return static::$blocks;
}

/**
Expand Down Expand Up @@ -407,6 +470,10 @@ public static function get_user_data_from_wp_global_styles( $theme, $create_post
* @return WP_Theme_JSON Entity that holds styles for user data.
*/
public static function get_user_data() {
if ( null !== static::$user && static::has_same_registered_blocks( 'user' ) ) {
return static::$user;
}

$config = array();
$user_cpt = static::get_user_data_from_wp_global_styles( wp_get_theme() );

Expand Down Expand Up @@ -562,9 +629,18 @@ protected static function get_file_path_from_theme( $file_name, $template = fals
* @since 5.8.0
* @since 5.9.0 Added the `$user`, `$user_custom_post_type_id`,
* and `$i18n_schema` variables to reset.
* @since 6.1.0 Added the `$blocks` and `$blocks_cache` variables
* 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::$theme = null;
static::$user = null;
static::$user_custom_post_type_id = null;
Expand Down
Loading

0 comments on commit 94309d1

Please sign in to comment.