Skip to content

Commit fc53820

Browse files
committed
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. git-svn-id: https://develop.svn.wordpress.org/trunk@56226 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 23a1516 commit fc53820

File tree

5 files changed

+94
-77
lines changed

5 files changed

+94
-77
lines changed

src/wp-includes/block-supports/duotone.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,8 @@
4040
)
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 );
44+
add_filter( 'render_block', array( 'WP_Duotone', 'render_duotone_support' ), 10, 3 );
4945

5046
// Enqueue styles.
5147
// Block styles (core-block-supports-inline-css) before the style engine (wp_enqueue_stored_styles).

src/wp-includes/class-wp-duotone.php

Lines changed: 82 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class WP_Duotone {
5454
*
5555
* @var array
5656
*/
57-
private static $global_styles_block_names = array();
57+
private static $global_styles_block_names;
5858

5959
/**
6060
* An array of duotone filter data from global, theme, and custom presets.
@@ -78,7 +78,7 @@ class WP_Duotone {
7878
*
7979
* @var array
8080
*/
81-
private static $global_styles_presets = array();
81+
private static $global_styles_presets;
8282

8383
/**
8484
* All of the duotone filter data from presets for CSS custom properties on
@@ -575,7 +575,7 @@ private static function is_preset( $duotone_attr ) {
575575
$slug = self::get_slug_from_attribute( $duotone_attr );
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

581581
/**
@@ -897,7 +897,8 @@ private static function enqueue_custom_filter( $filter_id, $duotone_selector, $f
897897
* @param string $filter_value The filter CSS value. e.g. 'url(#wp-duotone-blue-orange)' or 'unset'.
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 */
903904
__( 'The duotone id "%s" is not registered in theme.json settings' ),
@@ -906,8 +907,8 @@ private static function enqueue_global_styles_preset( $filter_id, $duotone_selec
906907
_doing_it_wrong( __METHOD__, $error_message, '6.3.0' );
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

913914
/**
@@ -920,16 +921,11 @@ private static function enqueue_global_styles_preset( $filter_id, $duotone_selec
920921
* @param WP_Block_Type $block_type Block Type.
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();
935931
}
@@ -948,45 +944,43 @@ public static function register_duotone_support( $block_type ) {
948944
* This handles selectors defined in `color.__experimentalDuotone` support
949945
* if `filter.duotone` support is not defined.
950946
*
951-
* @param string $block_name The block name.
952-
*
953947
* @internal
954-
*
955948
* @since 6.3.0
956949
*
957-
* @return string The CSS selector or null if there is no support.
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.
958952
*/
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-
}
953+
private static function get_selector( $block_type ) {
954+
if ( ! ( $block_type instanceof WP_Block_Type ) ) {
955+
return null;
956+
}
974957

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-
}
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+
}
986969

987-
// Regular filter.duotone support uses filter.duotone selectors with fallbacks.
988-
return wp_get_block_css_selector( $block_type, array( 'filter', 'duotone' ), true );
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;
989980
}
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

992986
/**
@@ -997,19 +991,27 @@ private static function get_selector( $block_name ) {
997991
* use duotone preset filters.
998992
*
999993
* @since 6.3.0
994+
*
995+
* @return array An array of global styles presets, keyed on the filter ID.
1000996
*/
1001-
public static function set_global_styles_presets() {
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 ) {
10081008
$filter_id = self::get_filter_id( _wp_to_kebab_case( $preset['slug'] ) );
10091009

10101010
self::$global_styles_presets[ $filter_id ] = $preset;
10111011
}
10121012
}
1013+
1014+
return self::$global_styles_presets;
10131015
}
10141016

10151017
/**
@@ -1019,13 +1021,20 @@ public static function set_global_styles_presets() {
10191021
* duotone filters defined in the theme.json global styles.
10201022
*
10211023
* @since 6.3.0
1024+
*
1025+
* @return string[] An array of global style block slugs, keyed on the block name.
10221026
*/
1023-
public static function set_global_style_block_names() {
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();
10281035

1036+
self::$global_styles_block_names = array();
1037+
10291038
foreach ( $block_nodes as $block_node ) {
10301039
// This block definition doesn't include any duotone settings. Skip it.
10311040
if ( empty( $block_node['duotone'] ) ) {
@@ -1046,6 +1055,7 @@ public static function set_global_style_block_names() {
10461055
self::$global_styles_block_names[ $block_node['name'] ] = $slug;
10471056
}
10481057
}
1058+
return self::$global_styles_block_names;
10491059
}
10501060

10511061
/**
@@ -1056,22 +1066,28 @@ public static function set_global_style_block_names() {
10561066
*
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.
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.
10621073
*/
1063-
public static function render_duotone_support( $block_content, $block ) {
1064-
$duotone_selector = self::get_selector( $block['blockName'] );
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 );
1088+
$has_global_styles_duotone = array_key_exists( $block['blockName'], $global_styles_block_names );
10691089

1070-
if (
1071-
empty( $block_content ) ||
1072-
! $duotone_selector ||
1073-
( ! $has_duotone_attribute && ! $has_global_styles_duotone )
1074-
) {
1090+
if ( ! $has_duotone_attribute && ! $has_global_styles_duotone ) {
10751091
return $block_content;
10761092
}
10771093

@@ -1119,7 +1135,7 @@ public static function render_duotone_support( $block_content, $block ) {
11191135
self::enqueue_custom_filter( $filter_id, $duotone_selector, $filter_value, $filter_data );
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)'.
11251141

@@ -1206,14 +1222,15 @@ public static function output_footer_assets() {
12061222
* @return array The editor settings with duotone SVGs and CSS custom properties.
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();
12121229
}
12131230

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',
12191236
// 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 @@ public static function add_editor_settings( $settings ) {
12221239

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',
12281245
// 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 @@ public static function add_editor_settings( $settings ) {
12421259
*
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
*/
12481264
public static function migrate_experimental_duotone_support_flag( $settings, $metadata ) {

src/wp-includes/deprecated.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5215,7 +5215,8 @@ function wp_register_duotone_support( $block_type ) {
52155215
*/
52165216
function 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

52215222
/**

tests/phpunit/tests/block-supports/duotone.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ public function test_render_duotone_support_preset() {
2727
'blockName' => 'core/image',
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

3536
/**
@@ -44,9 +45,10 @@ public function test_render_duotone_support_css() {
4445
'blockName' => 'core/image',
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

5254
/**
@@ -59,9 +61,10 @@ public function test_render_duotone_support_custom() {
5961
'blockName' => 'core/image',
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

6770
/**

tests/phpunit/tests/blocks/supportedStyles.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -695,13 +695,14 @@ public function test_render_block_suppresses_warnings_without_at_suppression() {
695695
);
696696
$this->register_block_type( 'core/example', $block_type_settings );
697697

698-
$block = array(
698+
$block = array(
699699
'blockName' => 'core/example',
700700
'attrs' => array(),
701701
'innerBlock' => array(),
702702
'innerContent' => 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.
707708
$errors = array();
@@ -714,7 +715,7 @@ static function ( $errno = 0, $errstr = '' ) use ( &$errors ) {
714715

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();
720721

0 commit comments

Comments
 (0)