Make WordPress Core

Changeset 56226


Ignore:
Timestamp:
07/13/2023 11:32:19 AM (18 months ago)
Author:
spacedmonkey
Message:

Editor: Lazily load Duotone settings only when needed.

Introduced in [56101] the WP_Duotone class, hooks into the wp_loaded action to load duotone style data from global styles. Hooking in early in the bootstrap process caused a number of problems. This hook, triggered an error on installing, as this lookup for global styles, would result in a global post trying to be created, even before the table existed. Additionally, this implementation caused a severe performance regression, as duotone styling data was loaded unnecessarily for requests that did not require such data, such as REST API calls or actions within the wp-admin interface.

In this change, refactor the WP_Duotone to lazily load the global styles and theme.json data, only when a block that supports duotone is encountered. The method render_duotone_support was change to take a third parameter to reuse the existing WP_Block_Type object passed to the filter, to save it being looked up again. The code has also got improved type checking and the use of the util function block_has_support. Furthermore, the code's readability has been improved, along with enhancements to the documentation blocks.

Props Chouby, spacedmonkey, SergeyBiryukov, swissspidy, costdev, joemcgill, flixos90, mukesh27, nazmul111, ajlende, isabel_brison.
Fixes #58673.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/block-supports/duotone.php

    r56101 r56226  
    4141);
    4242
    43 // Set up metadata prior to rendering any blocks.
    44 add_action( 'wp_loaded', array( 'WP_Duotone', 'set_global_styles_presets' ), 10 );
    45 add_action( 'wp_loaded', array( 'WP_Duotone', 'set_global_style_block_names' ), 10 );
    46 
    4743// Add classnames to blocks using duotone support.
    48 add_filter( 'render_block', array( 'WP_Duotone', 'render_duotone_support' ), 10, 2 );
     44add_filter( 'render_block', array( 'WP_Duotone', 'render_duotone_support' ), 10, 3 );
    4945
    5046// Enqueue styles.
  • trunk/src/wp-includes/class-wp-duotone.php

    r56225 r56226  
    5555     * @var array
    5656     */
    57     private static $global_styles_block_names = array();
     57    private static $global_styles_block_names;
    5858
    5959    /**
     
    7979     * @var array
    8080     */
    81     private static $global_styles_presets = array();
     81    private static $global_styles_presets;
    8282
    8383    /**
     
    576576        $filter_id = self::get_filter_id( $slug );
    577577
    578         return array_key_exists( $filter_id, self::$global_styles_presets );
     578        return array_key_exists( $filter_id, self::get_all_global_styles_presets() );
    579579    }
    580580
     
    898898     */
    899899    private static function enqueue_global_styles_preset( $filter_id, $duotone_selector, $filter_value ) {
    900         if ( ! array_key_exists( $filter_id, self::$global_styles_presets ) ) {
     900        $global_styles_presets = self::get_all_global_styles_presets();
     901        if ( ! array_key_exists( $filter_id, $global_styles_presets ) ) {
    901902            $error_message = sprintf(
    902903                /* translators: %s: duotone filter ID */
     
    907908            return;
    908909        }
    909         self::$used_global_styles_presets[ $filter_id ] = self::$global_styles_presets[ $filter_id ];
    910         self::enqueue_custom_filter( $filter_id, $duotone_selector, $filter_value, self::$global_styles_presets[ $filter_id ] );
     910        self::$used_global_styles_presets[ $filter_id ] = $global_styles_presets[ $filter_id ];
     911        self::enqueue_custom_filter( $filter_id, $duotone_selector, $filter_value, $global_styles_presets[ $filter_id ] );
    911912    }
    912913
     
    921922     */
    922923    public static function register_duotone_support( $block_type ) {
    923         $has_duotone_support = false;
    924         if ( property_exists( $block_type, 'supports' ) ) {
    925             /*
    926              * Previous `color.__experimentalDuotone` support flag is migrated
    927              * to `filter.duotone` via `block_type_metadata_settings` filter.
    928              */
    929             $has_duotone_support = _wp_array_get( $block_type->supports, array( 'filter', 'duotone' ), null );
    930         }
    931 
    932         if ( $has_duotone_support ) {
     924        /*
     925         * Previous `color.__experimentalDuotone` support flag is migrated
     926         * to `filter.duotone` via `block_type_metadata_settings` filter.
     927         */
     928        if ( block_has_support( $block_type, array( 'filter', 'duotone' ), null ) ) {
    933929            if ( ! $block_type->attributes ) {
    934930                $block_type->attributes = array();
     
    949945     * if `filter.duotone` support is not defined.
    950946     *
    951      * @param string $block_name The block name.
    952      *
    953      * @internal
    954      *
    955      * @since 6.3.0
    956      *
    957      * @return string The CSS selector or null if there is no support.
    958      */
    959     private static function get_selector( $block_name ) {
    960         $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block_name );
    961 
    962         if ( $block_type && property_exists( $block_type, 'supports' ) ) {
    963             /*
    964              * Backwards compatibility with `supports.color.__experimentalDuotone`
    965              * is provided via the `block_type_metadata_settings` filter. If
    966              * `supports.filter.duotone` has not been set and the experimental
    967              * property has been, the experimental property value is copied into
    968              * `supports.filter.duotone`.
    969              */
    970             $duotone_support = _wp_array_get( $block_type->supports, array( 'filter', 'duotone' ), false );
    971             if ( ! $duotone_support ) {
    972                 return null;
    973             }
    974 
    975             /*
    976              * If the experimental duotone support was set, that value is to be
    977              * treated as a selector and requires scoping.
    978              */
    979             $experimental_duotone = _wp_array_get( $block_type->supports, array( 'color', '__experimentalDuotone' ), false );
    980             if ( $experimental_duotone ) {
    981                 $root_selector = wp_get_block_css_selector( $block_type );
    982                 return is_string( $experimental_duotone )
    983                     ? WP_Theme_JSON::scope_selector( $root_selector, $experimental_duotone )
    984                     : $root_selector;
    985             }
    986 
    987             // Regular filter.duotone support uses filter.duotone selectors with fallbacks.
    988             return wp_get_block_css_selector( $block_type, array( 'filter', 'duotone' ), true );
    989         }
     947     * @internal
     948     * @since 6.3.0
     949     *
     950     * @param WP_Block_Type $block_type Block type to check for support.
     951     * @return string|null The CSS selector or null if there is no support.
     952     */
     953    private static function get_selector( $block_type ) {
     954        if ( ! ( $block_type instanceof WP_Block_Type ) ) {
     955            return null;
     956        }
     957
     958        /*
     959         * Backward compatibility with `supports.color.__experimentalDuotone`
     960         * is provided via the `block_type_metadata_settings` filter. If
     961         * `supports.filter.duotone` has not been set and the experimental
     962         * property has been, the experimental property value is copied into
     963         * `supports.filter.duotone`.
     964         */
     965        $duotone_support = block_has_support( $block_type, array( 'filter', 'duotone' ) );
     966        if ( ! $duotone_support ) {
     967            return null;
     968        }
     969
     970        /*
     971         * If the experimental duotone support was set, that value is to be
     972         * treated as a selector and requires scoping.
     973         */
     974        $experimental_duotone = _wp_array_get( $block_type->supports, array( 'color', '__experimentalDuotone' ), false );
     975        if ( $experimental_duotone ) {
     976            $root_selector = wp_get_block_css_selector( $block_type );
     977            return is_string( $experimental_duotone )
     978                ? WP_Theme_JSON::scope_selector( $root_selector, $experimental_duotone )
     979                : $root_selector;
     980        }
     981
     982        // Regular filter.duotone support uses filter.duotone selectors with fallbacks.
     983        return wp_get_block_css_selector( $block_type, array( 'filter', 'duotone' ), true );
    990984    }
    991985
     
    998992     *
    999993     * @since 6.3.0
    1000      */
    1001     public static function set_global_styles_presets() {
     994     *
     995     * @return array An array of global styles presets, keyed on the filter ID.
     996     */
     997    private static function get_all_global_styles_presets() {
     998        if ( isset( self::$global_styles_presets ) ) {
     999            return self::$global_styles_presets;
     1000        }
    10021001        // Get the per block settings from the theme.json.
    10031002        $tree              = wp_get_global_settings();
    10041003        $presets_by_origin = _wp_array_get( $tree, array( 'color', 'duotone' ), array() );
    10051004
     1005        self::$global_styles_presets = array();
    10061006        foreach ( $presets_by_origin as $presets ) {
    10071007            foreach ( $presets as $preset ) {
     
    10111011            }
    10121012        }
     1013
     1014        return self::$global_styles_presets;
    10131015    }
    10141016
     
    10201022     *
    10211023     * @since 6.3.0
    1022      */
    1023     public static function set_global_style_block_names() {
     1024     *
     1025     * @return string[] An array of global style block slugs, keyed on the block name.
     1026     */
     1027    private static function get_all_global_style_block_names() {
     1028        if ( isset( self::$global_styles_block_names ) ) {
     1029            return self::$global_styles_block_names;
     1030        }
    10241031        // Get the per block settings from the theme.json.
    10251032        $tree        = WP_Theme_JSON_Resolver::get_merged_data();
    10261033        $block_nodes = $tree->get_styles_block_nodes();
    10271034        $theme_json  = $tree->get_raw_data();
     1035
     1036        self::$global_styles_block_names = array();
    10281037
    10291038        foreach ( $block_nodes as $block_node ) {
     
    10471056            }
    10481057        }
     1058        return self::$global_styles_block_names;
    10491059    }
    10501060
     
    10571067     * @since 6.3.0
    10581068     *
    1059      * @param  string $block_content Rendered block content.
    1060      * @param  array  $block         Block object.
    1061      * @return string                Filtered block content.
    1062      */
    1063     public static function render_duotone_support( $block_content, $block ) {
    1064         $duotone_selector = self::get_selector( $block['blockName'] );
     1069     * @param  string   $block_content Rendered block content.
     1070     * @param  array    $block         Block object.
     1071     * @param  WP_Block $wp_block      The block instance.
     1072     * @return string Filtered block content.
     1073     */
     1074    public static function render_duotone_support( $block_content, $block, $wp_block ) {
     1075        if ( empty( $block_content ) || ! $block['blockName'] ) {
     1076            return $block_content;
     1077        }
     1078        $duotone_selector = self::get_selector( $wp_block->block_type );
     1079
     1080        if ( ! $duotone_selector ) {
     1081            return $block_content;
     1082        }
     1083
     1084        $global_styles_block_names = self::get_all_global_style_block_names();
    10651085
    10661086        // The block should have a duotone attribute or have duotone defined in its theme.json to be processed.
    10671087        $has_duotone_attribute     = isset( $block['attrs']['style']['color']['duotone'] );
    1068         $has_global_styles_duotone = array_key_exists( $block['blockName'], self::$global_styles_block_names );
    1069 
    1070         if (
    1071             empty( $block_content ) ||
    1072             ! $duotone_selector ||
    1073             ( ! $has_duotone_attribute && ! $has_global_styles_duotone )
    1074         ) {
     1088        $has_global_styles_duotone = array_key_exists( $block['blockName'], $global_styles_block_names );
     1089
     1090        if ( ! $has_duotone_attribute && ! $has_global_styles_duotone ) {
    10751091            return $block_content;
    10761092        }
     
    11201136            }
    11211137        } elseif ( $has_global_styles_duotone ) {
    1122             $slug         = self::$global_styles_block_names[ $block['blockName'] ]; // e.g. 'blue-orange'.
     1138            $slug         = $global_styles_block_names[ $block['blockName'] ]; // e.g. 'blue-orange'.
    11231139            $filter_id    = self::get_filter_id( $slug ); // e.g. 'wp-duotone-filter-blue-orange'.
    11241140            $filter_value = self::get_css_var( $slug ); // e.g. 'var(--wp--preset--duotone--blue-orange)'.
     
    12071223     */
    12081224    public static function add_editor_settings( $settings ) {
    1209         if ( ! empty( self::$global_styles_presets ) ) {
     1225        $global_styles_presets = self::get_all_global_styles_presets();
     1226        if ( ! empty( $global_styles_presets ) ) {
    12101227            if ( ! isset( $settings['styles'] ) ) {
    12111228                $settings['styles'] = array();
     
    12141231            $settings['styles'][] = array(
    12151232                // For the editor we can add all of the presets by default.
    1216                 'assets'         => self::get_svg_definitions( self::$global_styles_presets ),
     1233                'assets'         => self::get_svg_definitions( $global_styles_presets ),
    12171234                // The 'svgs' type is new in 6.3 and requires the corresponding JS changes in the EditorStyles component to work.
    12181235                '__unstableType' => 'svgs',
     
    12231240            $settings['styles'][] = array(
    12241241                // For the editor we can add all of the presets by default.
    1225                 'css'            => self::get_global_styles_presets( self::$global_styles_presets ),
     1242                'css'            => self::get_global_styles_presets( $global_styles_presets ),
    12261243                // This must be set and must be something other than 'theme' or they will be stripped out in the post editor <Editor> component.
    12271244                '__unstableType' => 'presets',
     
    12431260     * @param array $settings Current block type settings.
    12441261     * @param array $metadata Block metadata as read in via block.json.
    1245      *
    12461262     * @return array Filtered block type settings.
    12471263     */
  • trunk/src/wp-includes/deprecated.php

    r56223 r56226  
    52165216function wp_render_duotone_support( $block_content, $block ) {
    52175217    _deprecated_function( __FUNCTION__, '6.3.0', 'WP_Duotone::render_duotone_support()' );
    5218     return WP_Duotone::render_duotone_support( $block_content, $block );
     5218    $wp_block = new WP_Block( $block );
     5219    return WP_Duotone::render_duotone_support( $block_content, $block, $wp_block );
    52195220}
    52205221
  • trunk/tests/phpunit/tests/block-supports/duotone.php

    r56101 r56226  
    2828            'attrs'     => array( 'style' => array( 'color' => array( 'duotone' => 'var:preset|duotone|blue-orange' ) ) ),
    2929        );
     30        $wp_block      = new WP_Block( $block );
    3031        $block_content = '<figure class="wp-block-image size-full"><img src="/my-image.jpg" /></figure>';
    3132        $expected      = '<figure class="wp-block-image size-full wp-duotone-blue-orange"><img src="/my-image.jpg" /></figure>';
    32         $this->assertSame( $expected, WP_Duotone::render_duotone_support( $block_content, $block ) );
     33        $this->assertSame( $expected, WP_Duotone::render_duotone_support( $block_content, $block, $wp_block ) );
    3334    }
    3435
     
    4546            'attrs'     => array( 'style' => array( 'color' => array( 'duotone' => 'unset' ) ) ),
    4647        );
     48        $wp_block      = new WP_Block( $block );
    4749        $block_content = '<figure class="wp-block-image size-full"><img src="/my-image.jpg" /></figure>';
    4850        $expected      = '/<figure class="wp-block-image size-full wp-duotone-unset-\d+"><img src="\\/my-image.jpg" \\/><\\/figure>/';
    49         $this->assertMatchesRegularExpression( $expected, WP_Duotone::render_duotone_support( $block_content, $block ) );
     51        $this->assertMatchesRegularExpression( $expected, WP_Duotone::render_duotone_support( $block_content, $block, $wp_block ) );
    5052    }
    5153
     
    6062            'attrs'     => array( 'style' => array( 'color' => array( 'duotone' => array( '#FFFFFF', '#000000' ) ) ) ),
    6163        );
     64        $wp_block      = new WP_Block( $block );
    6265        $block_content = '<figure class="wp-block-image size-full"><img src="/my-image.jpg" /></figure>';
    6366        $expected      = '/<figure class="wp-block-image size-full wp-duotone-ffffff-000000-\d+"><img src="\\/my-image.jpg" \\/><\\/figure>/';
    64         $this->assertMatchesRegularExpression( $expected, WP_Duotone::render_duotone_support( $block_content, $block ) );
     67        $this->assertMatchesRegularExpression( $expected, WP_Duotone::render_duotone_support( $block_content, $block, $wp_block ) );
    6568    }
    6669
  • trunk/tests/phpunit/tests/blocks/supportedStyles.php

    r55457 r56226  
    696696        $this->register_block_type( 'core/example', $block_type_settings );
    697697
    698         $block = array(
     698        $block    = array(
    699699            'blockName'    => 'core/example',
    700700            'attrs'        => array(),
     
    703703            'innerHTML'    => array(),
    704704        );
     705        $wp_block = new WP_Block( $block );
    705706
    706707        // Custom error handler's see Warnings even if they are suppressed by the @ symbol.
     
    715716        // HTML5 elements like <time> are not supported by the DOMDocument parser used by the block supports feature.
    716717        // This specific example is emitted by the "Display post date" setting in the latest-posts block.
    717         apply_filters( 'render_block', '<div><time datetime="2020-06-18T04:01:43+10:00" class="wp-block-latest-posts__post-date">June 18, 2020</time></div>', $block );
     718        apply_filters( 'render_block', '<div><time datetime="2020-06-18T04:01:43+10:00" class="wp-block-latest-posts__post-date">June 18, 2020</time></div>', $block, $wp_block );
    718719
    719720        restore_error_handler();
Note: See TracChangeset for help on using the changeset viewer.