From 748bb7d73a7da5b8ec02b706338d44ce5165515d Mon Sep 17 00:00:00 2001 From: spacedmonkey Date: Thu, 13 Jul 2023 11:34:28 +0000 Subject: [PATCH] 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. Built from https://develop.svn.wordpress.org/trunk@56226 git-svn-id: http://core.svn.wordpress.org/trunk@55738 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/block-supports/duotone.php | 6 +- wp-includes/class-wp-duotone.php | 152 ++++++++++++++----------- wp-includes/deprecated.php | 3 +- wp-includes/version.php | 2 +- 4 files changed, 88 insertions(+), 75 deletions(-) diff --git a/wp-includes/block-supports/duotone.php b/wp-includes/block-supports/duotone.php index b7964aa478..a90eb762ba 100644 --- a/wp-includes/block-supports/duotone.php +++ b/wp-includes/block-supports/duotone.php @@ -40,12 +40,8 @@ WP_Block_Supports::get_instance()->register( ) ); -// Set up metadata prior to rendering any blocks. -add_action( 'wp_loaded', array( 'WP_Duotone', 'set_global_styles_presets' ), 10 ); -add_action( 'wp_loaded', array( 'WP_Duotone', 'set_global_style_block_names' ), 10 ); - // Add classnames to blocks using duotone support. -add_filter( 'render_block', array( 'WP_Duotone', 'render_duotone_support' ), 10, 2 ); +add_filter( 'render_block', array( 'WP_Duotone', 'render_duotone_support' ), 10, 3 ); // Enqueue styles. // Block styles (core-block-supports-inline-css) before the style engine (wp_enqueue_stored_styles). diff --git a/wp-includes/class-wp-duotone.php b/wp-includes/class-wp-duotone.php index b29f38acf5..70d4798ba1 100644 --- a/wp-includes/class-wp-duotone.php +++ b/wp-includes/class-wp-duotone.php @@ -54,7 +54,7 @@ class WP_Duotone { * * @var array */ - private static $global_styles_block_names = array(); + private static $global_styles_block_names; /** * An array of duotone filter data from global, theme, and custom presets. @@ -78,7 +78,7 @@ class WP_Duotone { * * @var array */ - private static $global_styles_presets = array(); + private static $global_styles_presets; /** * All of the duotone filter data from presets for CSS custom properties on @@ -575,7 +575,7 @@ class WP_Duotone { $slug = self::get_slug_from_attribute( $duotone_attr ); $filter_id = self::get_filter_id( $slug ); - return array_key_exists( $filter_id, self::$global_styles_presets ); + return array_key_exists( $filter_id, self::get_all_global_styles_presets() ); } /** @@ -897,7 +897,8 @@ class WP_Duotone { * @param string $filter_value The filter CSS value. e.g. 'url(#wp-duotone-blue-orange)' or 'unset'. */ private static function enqueue_global_styles_preset( $filter_id, $duotone_selector, $filter_value ) { - if ( ! array_key_exists( $filter_id, self::$global_styles_presets ) ) { + $global_styles_presets = self::get_all_global_styles_presets(); + if ( ! array_key_exists( $filter_id, $global_styles_presets ) ) { $error_message = sprintf( /* translators: %s: duotone filter ID */ __( 'The duotone id "%s" is not registered in theme.json settings' ), @@ -906,8 +907,8 @@ class WP_Duotone { _doing_it_wrong( __METHOD__, $error_message, '6.3.0' ); return; } - self::$used_global_styles_presets[ $filter_id ] = self::$global_styles_presets[ $filter_id ]; - self::enqueue_custom_filter( $filter_id, $duotone_selector, $filter_value, self::$global_styles_presets[ $filter_id ] ); + self::$used_global_styles_presets[ $filter_id ] = $global_styles_presets[ $filter_id ]; + self::enqueue_custom_filter( $filter_id, $duotone_selector, $filter_value, $global_styles_presets[ $filter_id ] ); } /** @@ -920,16 +921,11 @@ class WP_Duotone { * @param WP_Block_Type $block_type Block Type. */ public static function register_duotone_support( $block_type ) { - $has_duotone_support = false; - if ( property_exists( $block_type, 'supports' ) ) { - /* - * Previous `color.__experimentalDuotone` support flag is migrated - * to `filter.duotone` via `block_type_metadata_settings` filter. - */ - $has_duotone_support = _wp_array_get( $block_type->supports, array( 'filter', 'duotone' ), null ); - } - - if ( $has_duotone_support ) { + /* + * Previous `color.__experimentalDuotone` support flag is migrated + * to `filter.duotone` via `block_type_metadata_settings` filter. + */ + if ( block_has_support( $block_type, array( 'filter', 'duotone' ), null ) ) { if ( ! $block_type->attributes ) { $block_type->attributes = array(); } @@ -948,45 +944,43 @@ class WP_Duotone { * This handles selectors defined in `color.__experimentalDuotone` support * if `filter.duotone` support is not defined. * - * @param string $block_name The block name. - * * @internal - * * @since 6.3.0 * - * @return string The CSS selector or null if there is no support. + * @param WP_Block_Type $block_type Block type to check for support. + * @return string|null The CSS selector or null if there is no support. */ - private static function get_selector( $block_name ) { - $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block_name ); - - if ( $block_type && property_exists( $block_type, 'supports' ) ) { - /* - * Backwards compatibility with `supports.color.__experimentalDuotone` - * is provided via the `block_type_metadata_settings` filter. If - * `supports.filter.duotone` has not been set and the experimental - * property has been, the experimental property value is copied into - * `supports.filter.duotone`. - */ - $duotone_support = _wp_array_get( $block_type->supports, array( 'filter', 'duotone' ), false ); - if ( ! $duotone_support ) { - return null; - } - - /* - * If the experimental duotone support was set, that value is to be - * treated as a selector and requires scoping. - */ - $experimental_duotone = _wp_array_get( $block_type->supports, array( 'color', '__experimentalDuotone' ), false ); - if ( $experimental_duotone ) { - $root_selector = wp_get_block_css_selector( $block_type ); - return is_string( $experimental_duotone ) - ? WP_Theme_JSON::scope_selector( $root_selector, $experimental_duotone ) - : $root_selector; - } - - // Regular filter.duotone support uses filter.duotone selectors with fallbacks. - return wp_get_block_css_selector( $block_type, array( 'filter', 'duotone' ), true ); + private static function get_selector( $block_type ) { + if ( ! ( $block_type instanceof WP_Block_Type ) ) { + return null; } + + /* + * Backward compatibility with `supports.color.__experimentalDuotone` + * is provided via the `block_type_metadata_settings` filter. If + * `supports.filter.duotone` has not been set and the experimental + * property has been, the experimental property value is copied into + * `supports.filter.duotone`. + */ + $duotone_support = block_has_support( $block_type, array( 'filter', 'duotone' ) ); + if ( ! $duotone_support ) { + return null; + } + + /* + * If the experimental duotone support was set, that value is to be + * treated as a selector and requires scoping. + */ + $experimental_duotone = _wp_array_get( $block_type->supports, array( 'color', '__experimentalDuotone' ), false ); + if ( $experimental_duotone ) { + $root_selector = wp_get_block_css_selector( $block_type ); + return is_string( $experimental_duotone ) + ? WP_Theme_JSON::scope_selector( $root_selector, $experimental_duotone ) + : $root_selector; + } + + // Regular filter.duotone support uses filter.duotone selectors with fallbacks. + return wp_get_block_css_selector( $block_type, array( 'filter', 'duotone' ), true ); } /** @@ -997,12 +991,18 @@ class WP_Duotone { * use duotone preset filters. * * @since 6.3.0 + * + * @return array An array of global styles presets, keyed on the filter ID. */ - public static function set_global_styles_presets() { + private static function get_all_global_styles_presets() { + if ( isset( self::$global_styles_presets ) ) { + return self::$global_styles_presets; + } // Get the per block settings from the theme.json. $tree = wp_get_global_settings(); $presets_by_origin = _wp_array_get( $tree, array( 'color', 'duotone' ), array() ); + self::$global_styles_presets = array(); foreach ( $presets_by_origin as $presets ) { foreach ( $presets as $preset ) { $filter_id = self::get_filter_id( _wp_to_kebab_case( $preset['slug'] ) ); @@ -1010,6 +1010,8 @@ class WP_Duotone { self::$global_styles_presets[ $filter_id ] = $preset; } } + + return self::$global_styles_presets; } /** @@ -1019,13 +1021,20 @@ class WP_Duotone { * duotone filters defined in the theme.json global styles. * * @since 6.3.0 + * + * @return string[] An array of global style block slugs, keyed on the block name. */ - public static function set_global_style_block_names() { + private static function get_all_global_style_block_names() { + if ( isset( self::$global_styles_block_names ) ) { + return self::$global_styles_block_names; + } // Get the per block settings from the theme.json. $tree = WP_Theme_JSON_Resolver::get_merged_data(); $block_nodes = $tree->get_styles_block_nodes(); $theme_json = $tree->get_raw_data(); + self::$global_styles_block_names = array(); + foreach ( $block_nodes as $block_node ) { // This block definition doesn't include any duotone settings. Skip it. if ( empty( $block_node['duotone'] ) ) { @@ -1046,6 +1055,7 @@ class WP_Duotone { self::$global_styles_block_names[ $block_node['name'] ] = $slug; } } + return self::$global_styles_block_names; } /** @@ -1056,22 +1066,28 @@ class WP_Duotone { * * @since 6.3.0 * - * @param string $block_content Rendered block content. - * @param array $block Block object. - * @return string Filtered block content. + * @param string $block_content Rendered block content. + * @param array $block Block object. + * @param WP_Block $wp_block The block instance. + * @return string Filtered block content. */ - public static function render_duotone_support( $block_content, $block ) { - $duotone_selector = self::get_selector( $block['blockName'] ); + public static function render_duotone_support( $block_content, $block, $wp_block ) { + if ( empty( $block_content ) || ! $block['blockName'] ) { + return $block_content; + } + $duotone_selector = self::get_selector( $wp_block->block_type ); + + if ( ! $duotone_selector ) { + return $block_content; + } + + $global_styles_block_names = self::get_all_global_style_block_names(); // The block should have a duotone attribute or have duotone defined in its theme.json to be processed. $has_duotone_attribute = isset( $block['attrs']['style']['color']['duotone'] ); - $has_global_styles_duotone = array_key_exists( $block['blockName'], self::$global_styles_block_names ); + $has_global_styles_duotone = array_key_exists( $block['blockName'], $global_styles_block_names ); - if ( - empty( $block_content ) || - ! $duotone_selector || - ( ! $has_duotone_attribute && ! $has_global_styles_duotone ) - ) { + if ( ! $has_duotone_attribute && ! $has_global_styles_duotone ) { return $block_content; } @@ -1119,7 +1135,7 @@ class WP_Duotone { self::enqueue_custom_filter( $filter_id, $duotone_selector, $filter_value, $filter_data ); } } elseif ( $has_global_styles_duotone ) { - $slug = self::$global_styles_block_names[ $block['blockName'] ]; // e.g. 'blue-orange'. + $slug = $global_styles_block_names[ $block['blockName'] ]; // e.g. 'blue-orange'. $filter_id = self::get_filter_id( $slug ); // e.g. 'wp-duotone-filter-blue-orange'. $filter_value = self::get_css_var( $slug ); // e.g. 'var(--wp--preset--duotone--blue-orange)'. @@ -1206,14 +1222,15 @@ class WP_Duotone { * @return array The editor settings with duotone SVGs and CSS custom properties. */ public static function add_editor_settings( $settings ) { - if ( ! empty( self::$global_styles_presets ) ) { + $global_styles_presets = self::get_all_global_styles_presets(); + if ( ! empty( $global_styles_presets ) ) { if ( ! isset( $settings['styles'] ) ) { $settings['styles'] = array(); } $settings['styles'][] = array( // For the editor we can add all of the presets by default. - 'assets' => self::get_svg_definitions( self::$global_styles_presets ), + 'assets' => self::get_svg_definitions( $global_styles_presets ), // The 'svgs' type is new in 6.3 and requires the corresponding JS changes in the EditorStyles component to work. '__unstableType' => 'svgs', // These styles not generated by global styles, so this must be false or they will be stripped out in wp_get_block_editor_settings. @@ -1222,7 +1239,7 @@ class WP_Duotone { $settings['styles'][] = array( // For the editor we can add all of the presets by default. - 'css' => self::get_global_styles_presets( self::$global_styles_presets ), + 'css' => self::get_global_styles_presets( $global_styles_presets ), // This must be set and must be something other than 'theme' or they will be stripped out in the post editor component. '__unstableType' => 'presets', // These styles are no longer generated by global styles, so this must be false or they will be stripped out in wp_get_block_editor_settings. @@ -1242,7 +1259,6 @@ class WP_Duotone { * * @param array $settings Current block type settings. * @param array $metadata Block metadata as read in via block.json. - * * @return array Filtered block type settings. */ public static function migrate_experimental_duotone_support_flag( $settings, $metadata ) { diff --git a/wp-includes/deprecated.php b/wp-includes/deprecated.php index 812bf54f23..169b4cc227 100644 --- a/wp-includes/deprecated.php +++ b/wp-includes/deprecated.php @@ -5215,7 +5215,8 @@ function wp_register_duotone_support( $block_type ) { */ function wp_render_duotone_support( $block_content, $block ) { _deprecated_function( __FUNCTION__, '6.3.0', 'WP_Duotone::render_duotone_support()' ); - return WP_Duotone::render_duotone_support( $block_content, $block ); + $wp_block = new WP_Block( $block ); + return WP_Duotone::render_duotone_support( $block_content, $block, $wp_block ); } /** diff --git a/wp-includes/version.php b/wp-includes/version.php index 285e039b34..454e3f6647 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.3-beta4-56225'; +$wp_version = '6.3-beta4-56226'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.