Skip to content

Commit

Permalink
Performance: Skip iteration in block supports elements when not neces…
Browse files Browse the repository at this point in the history
…sary.

Previously there have been three ways in which the block supports elements
code has been performing computation it doesn't need to.

 - It checks for every possible style attribute on a block even if there
   are no possible style attributes available on the block.

 - Once it determines that it needs to add a special class to a block
   it continues scanning through the rest of the attributes.

 - It constructs dot-separated literal key paths for the attributes
   and immediately and repeatedly calls `explode()` on them to create
   an array at runtime.

The combination of these three factors leads to an outsized impact of this
function on the runtime and memory pressure for what it's doing. This patch
removes all three of these inefficiencies:

 - If no elements style attributes exist on the block it immediately returns
   and skips all further processing.

 - It stops scanning block attributes once a single one is found that imposes
   the requirement for the extra class name.

 - It constructs array literals for the key path instead of strings. This
   removes the need to artificially join and explode the keys at runtime.

There should be no functional or visual changes in this patch, but it should
reduce the overall runtime of page renders and require less memory while rendering.
The impact will be proportional to the number of blocks rendered on a page.
  • Loading branch information
dmsnell committed Oct 5, 2023
1 parent b77b8fd commit 26f3d58
Showing 1 changed file with 46 additions and 42 deletions.
88 changes: 46 additions & 42 deletions src/wp-includes/block-supports/elements.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function wp_get_elements_class_name( $block ) {
* @return string Filtered block content.
*/
function wp_render_elements_support( $block_content, $block ) {
if ( ! $block_content || empty( $block['attrs'] ) ) {
if ( ! $block_content || ! isset( $block['attrs']['style']['elements'] ) ) {
return $block_content;
}

Expand All @@ -41,42 +41,42 @@ function wp_render_elements_support( $block_content, $block ) {
'button' => array(
'skip' => wp_should_skip_block_supports_serialization( $block_type, 'color', 'button' ),
'paths' => array(
'style.elements.button.color.text',
'style.elements.button.color.background',
'style.elements.button.color.gradient',
array( 'button', 'color', 'text' ),
array( 'button', 'color', 'background' ),
array( 'button', 'color', 'gradient' ),
),
),
'link' => array(
'skip' => wp_should_skip_block_supports_serialization( $block_type, 'color', 'link' ),
'paths' => array(
'style.elements.link.color.text',
'style.elements.link.:hover.color.text',
array( 'link', 'color', 'text' ),
array( 'link', ':hover', 'color', 'text' ),
),
),
'heading' => array(
'skip' => wp_should_skip_block_supports_serialization( $block_type, 'color', 'heading' ),
'paths' => array(
'style.elements.heading.color.text',
'style.elements.heading.color.background',
'style.elements.heading.color.gradient',
'style.elements.h1.color.text',
'style.elements.h1.color.background',
'style.elements.h1.color.gradient',
'style.elements.h2.color.text',
'style.elements.h2.color.background',
'style.elements.h2.color.gradient',
'style.elements.h3.color.text',
'style.elements.h3.color.background',
'style.elements.h3.color.gradient',
'style.elements.h4.color.text',
'style.elements.h4.color.background',
'style.elements.h4.color.gradient',
'style.elements.h5.color.text',
'style.elements.h5.color.background',
'style.elements.h5.color.gradient',
'style.elements.h6.color.text',
'style.elements.h6.color.background',
'style.elements.h6.color.gradient',
array( 'heading', 'color', 'text' ),
array( 'heading', 'color', 'background' ),
array( 'heading', 'color', 'gradient' ),
array( 'h1', 'color', 'text' ),
array( 'h1', 'color', 'background' ),
array( 'h1', 'color', 'gradient' ),
array( 'h2', 'color', 'text' ),
array( 'h2', 'color', 'background' ),
array( 'h2', 'color', 'gradient' ),
array( 'h3', 'color', 'text' ),
array( 'h3', 'color', 'background' ),
array( 'h3', 'color', 'gradient' ),
array( 'h4', 'color', 'text' ),
array( 'h4', 'color', 'background' ),
array( 'h4', 'color', 'gradient' ),
array( 'h5', 'color', 'text' ),
array( 'h5', 'color', 'background' ),
array( 'h5', 'color', 'gradient' ),
array( 'h6', 'color', 'text' ),
array( 'h6', 'color', 'background' ),
array( 'h6', 'color', 'gradient' ),
),
),
);
Expand All @@ -89,32 +89,36 @@ function wp_render_elements_support( $block_content, $block ) {
return $block_content;
}

$element_colors_set = 0;
$elements_style_attributes = $block['attrs']['style']['elements'];

foreach ( $element_color_properties as $element_config ) {
if ( $element_config['skip'] ) {
continue;
}

foreach ( $element_config['paths'] as $path ) {
if ( null !== _wp_array_get( $block['attrs'], explode( '.', $path ), null ) ) {
++$element_colors_set;
if ( null !== _wp_array_get( $elements_style_attributes, $path, null ) ) {
/*
* It only takes a single custom attribute to require that the custom
* class name be added to the block, so once one is found there's no
* need to continue looking for others.
*
* As is done with the layout hook, this code assumes that the block
* contains a single wrapper and that it's the first element in the
* rendered output. That first element, if it exists, gets the class.
*/
$tags = new WP_HTML_Tag_Processor( $block_content );
if ( $tags->next_tag() ) {
$tags->add_class( wp_get_elements_class_name( $block ) );
}

return $tags->get_updated_html();
}
}
}

if ( ! $element_colors_set ) {
return $block_content;
}

// Like the layout hook this assumes the hook only applies to blocks with a single wrapper.
// Add the class name to the first element, presuming it's the wrapper, if it exists.
$tags = new WP_HTML_Tag_Processor( $block_content );
if ( $tags->next_tag() ) {
$tags->add_class( wp_get_elements_class_name( $block ) );
}

return $tags->get_updated_html();
// If no custom attributes were found then there's nothing to modify.
return $block_content;
}

/**
Expand Down

0 comments on commit 26f3d58

Please sign in to comment.