Make WordPress Core

Changeset 58334


Ignore:
Timestamp:
06/04/2024 02:50:24 PM (3 weeks ago)
Author:
joemcgill
Message:

Editor: Cache global styles for blocks.

This caches the generated CSS from block nodes in merged Theme JSON data to avoid repeated costly operations required to compute style properties for blocks. The generated CSS is saved to a transient that expires every hour.

Props thekt12, spacedmonkey, pereirinha, mukesh27, isabel_brison, oandregal, andrewserong, ramonjd.
Fixes #59595.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/global-styles-and-settings.php

    r58262 r58334  
    308308    $tree        = WP_Theme_JSON_Resolver::get_merged_data();
    309309    $block_nodes = $tree->get_styles_block_nodes();
     310
     311    $can_use_cached = ! wp_is_development_mode( 'theme' );
     312    if ( $can_use_cached ) {
     313        // Hash global settings and block nodes together to optimize performance of key generation.
     314        $hash = md5(
     315            wp_json_encode(
     316                array(
     317                    'global_setting' => wp_get_global_settings(),
     318                    'block_nodes'    => $block_nodes,
     319                )
     320            )
     321        );
     322
     323        $cache_key = "wp_styles_for_blocks:$hash";
     324        $cached    = get_site_transient( $cache_key );
     325        if ( ! is_array( $cached ) ) {
     326            $cached = array();
     327        }
     328    }
     329
     330    $update_cache = false;
     331
    310332    foreach ( $block_nodes as $metadata ) {
    311         $block_css = $tree->get_styles_for_block( $metadata );
     333
     334        if ( $can_use_cached ) {
     335            // Use the block name as the key for cached CSS data. Otherwise, use a hash of the metadata.
     336            $cache_node_key = isset( $metadata['name'] ) ? $metadata['name'] : md5( wp_json_encode( $metadata ) );
     337
     338            if ( isset( $cached[ $cache_node_key ] ) ) {
     339                $block_css = $cached[ $cache_node_key ];
     340            } else {
     341                $block_css                 = $tree->get_styles_for_block( $metadata );
     342                $cached[ $cache_node_key ] = $block_css;
     343                $update_cache              = true;
     344            }
     345        } else {
     346            $block_css = $tree->get_styles_for_block( $metadata );
     347        }
    312348
    313349        if ( ! wp_should_load_separate_core_block_assets() ) {
     
    355391        }
    356392    }
     393
     394    if ( $update_cache ) {
     395        set_site_transient( $cache_key, $cached, HOUR_IN_SECONDS );
     396    }
    357397}
    358398
  • trunk/tests/phpunit/tests/theme/wpAddGlobalStylesForBlocks.php

    r58295 r58334  
    7777
    7878    /**
     79     * Ensure that the block cache is set for global styles.
     80     *
     81     * @ticket 59595
     82     */
     83    public function test_styles_for_blocks_cache_is_set() {
     84        $this->set_up_third_party_block();
     85
     86        wp_register_style( 'global-styles', false, array(), true, true );
     87
     88        $cache_key                = $this->get_wp_styles_for_blocks_cache_key();
     89        $styles_for_blocks_before = get_site_transient( $cache_key );
     90        $this->assertFalse( $styles_for_blocks_before );
     91
     92        wp_add_global_styles_for_blocks();
     93
     94        $styles_for_blocks_after = get_site_transient( $cache_key );
     95        $this->assertNotEmpty( $styles_for_blocks_after );
     96    }
     97
     98    /**
     99     * Confirm that the block cache is skipped when in dev mode for themes.
     100     *
     101     * @ticket 59595
     102     */
     103    public function test_styles_for_blocks_skips_cache_in_dev_mode() {
     104        global $_wp_tests_development_mode;
     105
     106        $orig_dev_mode = $_wp_tests_development_mode;
     107
     108        // Setting development mode to theme should skip the cache.
     109        $_wp_tests_development_mode = 'theme';
     110
     111        wp_register_style( 'global-styles', false, array(), true, true );
     112
     113        // Initial register of global styles.
     114        wp_add_global_styles_for_blocks();
     115
     116        $cache_key                 = $this->get_wp_styles_for_blocks_cache_key();
     117        $styles_for_blocks_initial = get_site_transient( $cache_key );
     118
     119        // Cleanup.
     120        $_wp_tests_development_mode = $orig_dev_mode;
     121
     122        $this->assertFalse( $styles_for_blocks_initial );
     123    }
     124
     125    /**
     126     * Confirm that the block cache is updated if the block meta has changed.
     127     *
     128     * @ticket 59595
     129     */
     130    public function test_styles_for_blocks_cache_is_skipped() {
     131        wp_register_style( 'global-styles', false, array(), true, true );
     132
     133        // Initial register of global styles.
     134        wp_add_global_styles_for_blocks();
     135
     136        $cache_key                 = $this->get_wp_styles_for_blocks_cache_key();
     137        $styles_for_blocks_initial = get_site_transient( $cache_key );
     138        $this->assertNotEmpty( $styles_for_blocks_initial, 'Initial cache was not set.' );
     139
     140        $this->set_up_third_party_block();
     141
     142        /*
     143         * Call register of global styles again to ensure the cache is updated.
     144         * In normal conditions, this function is only called once per request.
     145         */
     146        wp_add_global_styles_for_blocks();
     147
     148        $cache_key                 = $this->get_wp_styles_for_blocks_cache_key();
     149        $styles_for_blocks_updated = get_site_transient( $cache_key );
     150        $this->assertNotEmpty( $styles_for_blocks_updated, 'Updated cache was not set.' );
     151
     152        $this->assertNotEquals(
     153            $styles_for_blocks_initial,
     154            $styles_for_blocks_updated,
     155            'Block style cache was not updated.'
     156        );
     157    }
     158
     159    /**
    79160     * @ticket 56915
    80161     * @ticket 61165
     
    254335        return is_array( $actual ) ? $actual : array();
    255336    }
     337
     338    /**
     339     * Get cache key for `wp_styles_for_blocks`.
     340     *
     341     * @return string The cache key.
     342     */
     343    private function get_wp_styles_for_blocks_cache_key() {
     344        $tree        = WP_Theme_JSON_Resolver::get_merged_data();
     345        $block_nodes = $tree->get_styles_block_nodes();
     346        // md5 is a costly operation, so we hashing global settings and block_node in a single call.
     347        $hash = md5(
     348            wp_json_encode(
     349                array(
     350                    'global_setting' => wp_get_global_settings(),
     351                    'block_nodes'    => $block_nodes,
     352                )
     353            )
     354        );
     355
     356        return "wp_styles_for_blocks:$hash";
     357    }
    256358}
Note: See TracChangeset for help on using the changeset viewer.