Make WordPress Core

Changeset 54800


Ignore:
Timestamp:
11/10/2022 10:40:59 PM (2 years ago)
Author:
flixos90
Message:

Editor: Avoid running certain logic around theme.json parsing unnecessarily for classic themes.

Here's what it does:

  • Do not load and parse theme-i18n.json schema if the theme does not have a theme.json file.
  • Fix the variable caching layer around the theme's theme.json parsing so that a parent's theme theme.json is cached as well.
  • Do not run a WP_Query for global styles for a user when the theme does not have a theme.json.

In a basic WordPress setup, this changeset improves wp_head execution time for classic themes by 10%, and overall response time for both block themes and classic themes by 4%. This may seem like a small win, but 4% reduced overall response time is actually quite a bit for one change, and it is worth mentioning that this is just one of several other little performance tweaks which are being worked on to improve performance of theme.json parsing further.

Props flixos90, manuilov, oandregal, peterwilsoncc, spacedmonkey.
Merges [54799] to the 6.1 branch.
Fixes #56945.

Location:
branches/6.1
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • branches/6.1

  • branches/6.1/src/wp-includes/class-wp-theme-json-resolver.php

    r54779 r54800  
    247247
    248248        if ( null === static::$theme || ! static::has_same_registered_blocks( 'theme' ) ) {
    249             $theme_json_data = static::read_json_file( static::get_file_path_from_theme( 'theme.json' ) );
    250             $theme_json_data = static::translate( $theme_json_data, wp_get_theme()->get( 'TextDomain' ) );
     249            $theme_json_file = static::get_file_path_from_theme( 'theme.json' );
     250            if ( '' !== $theme_json_file ) {
     251                $theme_json_data = static::read_json_file( $theme_json_file );
     252                $theme_json_data = static::translate( $theme_json_data, wp_get_theme()->get( 'TextDomain' ) );
     253            } else {
     254                $theme_json_data = array();
     255            }
    251256
    252257            /**
     
    260265            $theme_json_data = $theme_json->get_data();
    261266            static::$theme   = new WP_Theme_JSON( $theme_json_data );
    262         }
    263 
    264         if ( wp_get_theme()->parent() ) {
    265             // Get parent theme.json.
    266             $parent_theme_json_data = static::read_json_file( static::get_file_path_from_theme( 'theme.json', true ) );
    267             $parent_theme_json_data = static::translate( $parent_theme_json_data, wp_get_theme()->parent()->get( 'TextDomain' ) );
    268             $parent_theme           = new WP_Theme_JSON( $parent_theme_json_data );
    269 
    270             /*
    271              * Merge the child theme.json into the parent theme.json.
    272              * The child theme takes precedence over the parent.
    273              */
    274             $parent_theme->merge( static::$theme );
    275             static::$theme = $parent_theme;
     267
     268            if ( wp_get_theme()->parent() ) {
     269                // Get parent theme.json.
     270                $parent_theme_json_file = static::get_file_path_from_theme( 'theme.json', true );
     271                if ( '' !== $parent_theme_json_file ) {
     272                    $parent_theme_json_data = static::read_json_file( $parent_theme_json_file );
     273                    $parent_theme_json_data = static::translate( $parent_theme_json_data, wp_get_theme()->parent()->get( 'TextDomain' ) );
     274                    $parent_theme           = new WP_Theme_JSON( $parent_theme_json_data );
     275
     276                    /*
     277                     * Merge the child theme.json into the parent theme.json.
     278                     * The child theme takes precedence over the parent.
     279                     */
     280                    $parent_theme->merge( static::$theme );
     281                    static::$theme = $parent_theme;
     282                }
     283            }
    276284        }
    277285
     
    404412            $theme = wp_get_theme();
    405413        }
     414
     415        /*
     416         * Bail early if the theme does not support a theme.json.
     417         *
     418         * Since WP_Theme_JSON_Resolver::theme_has_support() only supports the active
     419         * theme, the extra condition for whether $theme is the active theme is
     420         * present here.
     421         */
     422        if ( $theme->get_stylesheet() === get_stylesheet() && ! static::theme_has_support() ) {
     423            return array();
     424        }
     425
    406426        $user_cpt         = array();
    407427        $post_type_filter = 'wp_global_styles';
     
    583603        if ( ! isset( static::$theme_has_support ) ) {
    584604            static::$theme_has_support = (
    585                 is_readable( static::get_file_path_from_theme( 'theme.json' ) ) ||
    586                 is_readable( static::get_file_path_from_theme( 'theme.json', true ) )
     605                static::get_file_path_from_theme( 'theme.json' ) !== '' ||
     606                static::get_file_path_from_theme( 'theme.json', true ) !== ''
    587607            );
    588608        }
  • branches/6.1/src/wp-includes/class-wp-theme-json.php

    r54778 r54800  
    29402940        $spacing_scale = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'spacingScale' ), array() );
    29412941
    2942         if ( ! is_numeric( $spacing_scale['steps'] )
     2942        if ( ! isset( $spacing_scale['steps'] )
     2943            || ! is_numeric( $spacing_scale['steps'] )
    29432944            || ! isset( $spacing_scale['mediumStep'] )
    29442945            || ! isset( $spacing_scale['unit'] )
  • branches/6.1/tests/phpunit/tests/theme/wpThemeJsonResolver.php

    r54707 r54800  
    3535
    3636    /**
    37      * Queries.
    38      *
    39      * @var array
    40      */
    41     private $queries = array();
    42 
    43     /**
    4437     * WP_Theme_JSON_Resolver::$blocks_cache property.
    4538     *
     
    10699        add_filter( 'stylesheet_root', array( $this, 'filter_set_theme_root' ) );
    107100        add_filter( 'template_root', array( $this, 'filter_set_theme_root' ) );
    108         $this->queries = array();
     101
    109102        // Clear caches.
    110103        wp_clean_themes_cache();
     
    128121    public function filter_set_locale_to_polish() {
    129122        return 'pl_PL';
    130     }
    131 
    132     function filter_db_query( $query ) {
    133         if ( preg_match( '#post_type = \'wp_global_styles\'#', $query ) ) {
    134             $this->queries[] = $query;
    135         }
    136         return $query;
    137123    }
    138124
     
    635621     */
    636622    function test_get_user_data_from_wp_global_styles_does_not_use_uncached_queries() {
     623        // Switch to a theme that does have support.
     624        switch_theme( 'block-theme' );
    637625        wp_set_current_user( self::$administrator_id );
    638626        $theme = wp_get_theme();
    639627        WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles( $theme );
    640         add_filter( 'query', array( $this, 'filter_db_query' ) );
    641         $query_count = count( $this->queries );
     628        $global_styles_query_count = 0;
     629        add_filter(
     630            'query',
     631            function( $query ) use ( &$global_styles_query_count ) {
     632                if ( preg_match( '#post_type = \'wp_global_styles\'#', $query ) ) {
     633                    $global_styles_query_count++;
     634                }
     635                return $query;
     636            }
     637        );
    642638        for ( $i = 0; $i < 3; $i++ ) {
    643639            WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles( $theme );
    644640            WP_Theme_JSON_Resolver::clean_cached_data();
    645641        }
    646         $query_count = count( $this->queries ) - $query_count;
    647         $this->assertSame( 0, $query_count, 'Unexpected SQL queries detected for the wp_global_style post type prior to creation.' );
     642        $this->assertSame( 0, $global_styles_query_count, 'Unexpected SQL queries detected for the wp_global_style post type prior to creation.' );
    648643
    649644        $user_cpt = WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles( $theme );
     
    653648        $this->assertNotEmpty( $user_cpt, 'User CPT is expected not to be empty.' );
    654649
    655         $query_count = count( $this->queries );
     650        $global_styles_query_count = 0;
    656651        for ( $i = 0; $i < 3; $i ++ ) {
    657652            $new_user_cpt = WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles( $theme );
     
    659654            $this->assertSameSets( $user_cpt, $new_user_cpt, "User CPTs do not match on run {$i}." );
    660655        }
    661         $query_count = count( $this->queries ) - $query_count;
    662         $this->assertSame( 1, $query_count, 'Unexpected SQL queries detected for the wp_global_style post type after creation.' );
     656        $this->assertSame( 1, $global_styles_query_count, 'Unexpected SQL queries detected for the wp_global_style post type after creation.' );
    663657    }
    664658
     
    667661     */
    668662    function test_get_user_data_from_wp_global_styles_does_not_use_uncached_queries_for_logged_out_users() {
     663        // Switch to a theme that does have support.
     664        switch_theme( 'block-theme' );
    669665        $theme = wp_get_theme();
    670666        WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles( $theme );
    671         add_filter( 'query', array( $this, 'filter_db_query' ) );
    672         $query_count = count( $this->queries );
     667        $query_count = get_num_queries();
    673668        for ( $i = 0; $i < 3; $i++ ) {
    674669            WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles( $theme );
    675670            WP_Theme_JSON_Resolver::clean_cached_data();
    676671        }
    677         $query_count = count( $this->queries ) - $query_count;
     672        $query_count = get_num_queries() - $query_count;
    678673        $this->assertSame( 0, $query_count, 'Unexpected SQL queries detected for the wp_global_style post type prior to creation.' );
    679674
     
    683678
    684679    /**
     680     * @ticket 56945
     681     * @covers WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles
     682     */
     683    function test_get_user_data_from_wp_global_styles_does_not_run_for_theme_without_support() {
     684        // The 'default' theme does not support theme.json.
     685        switch_theme( 'default' );
     686        wp_set_current_user( self::$administrator_id );
     687        $theme = wp_get_theme();
     688
     689        $start_queries = get_num_queries();
     690
     691        // When theme.json is not supported, the method should not run a query and always return an empty result.
     692        $user_cpt = WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles( $theme );
     693        $this->assertEmpty( $user_cpt, 'User CPT is expected to be empty.' );
     694        $this->assertSame( 0, get_num_queries() - $start_queries, 'Unexpected SQL query detected for theme without theme.json support.' );
     695
     696        $user_cpt = WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles( $theme, true );
     697        $this->assertEmpty( $user_cpt, 'User CPT is expected to be empty.' );
     698        $this->assertSame( 0, get_num_queries() - $start_queries, 'Unexpected SQL query detected for theme without theme.json support.' );
     699    }
     700
     701    /**
    685702     * @ticket 55392
    686703     * @covers WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles
    687704     */
    688705    function test_get_user_data_from_wp_global_styles_does_exist() {
     706        // Switch to a theme that does have support.
     707        switch_theme( 'block-theme' );
    689708        $theme = wp_get_theme();
    690709        $post1 = WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles( $theme, true );
     
    702721     */
    703722    function test_get_user_data_from_wp_global_styles_create_post() {
     723        // Switch to a theme that does have support.
     724        switch_theme( 'block-theme' );
    704725        $theme = wp_get_theme( 'testing' );
    705726        $post1 = WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles( $theme );
     
    719740     */
    720741    function test_get_user_data_from_wp_global_styles_filter_state() {
     742        // Switch to a theme that does have support.
     743        switch_theme( 'block-theme' );
    721744        $theme = wp_get_theme( 'foo' );
    722745        $post1 = WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles( $theme, true, array( 'publish' ) );
     
    750773        $this->assertTrue( $line_height, 'lineHeight setting after add_theme_support() should be true.' );
    751774    }
     775
     776    /**
     777     * @ticket 56945
     778     * @covers WP_Theme_JSON_Resolver::get_theme_data
     779     */
     780    function test_get_theme_data_does_not_parse_theme_json_if_not_present() {
     781        // The 'default' theme does not support theme.json.
     782        switch_theme( 'default' );
     783
     784        $theme_json_resolver = new WP_Theme_JSON_Resolver();
     785
     786        // Force-unset $i18n_schema property to "unload" translation schema.
     787        $property = new ReflectionProperty( $theme_json_resolver, 'i18n_schema' );
     788        $property->setAccessible( true );
     789        $property->setValue( null );
     790
     791        // A completely empty theme.json data set still has the 'version' key when parsed.
     792        $empty_theme_json = array( 'version' => WP_Theme_JSON::LATEST_SCHEMA );
     793
     794        // Call using 'with_supports' set to false, so that the method only considers theme.json.
     795        $theme_data = $theme_json_resolver->get_theme_data( array(), array( 'with_supports' => false ) );
     796        $this->assertInstanceOf( 'WP_Theme_JSON', $theme_data, 'Theme data should be an instance of WP_Theme_JSON.' );
     797        $this->assertSame( $empty_theme_json, $theme_data->get_raw_data(), 'Theme data should be empty without theme support.' );
     798        $this->assertNull( $property->getValue(), 'Theme i18n schema should not have been loaded without theme support.' );
     799    }
    752800}
Note: See TracChangeset for help on using the changeset viewer.