Make WordPress Core

Changeset 62359 for trunk


Ignore:
Timestamp:
05/13/2026 07:29:31 PM (3 months ago)
Author:
westonruter
Message:

Block Supports: Improve performance and hardening of block-level custom CSS rendering.

Short-circuits the custom CSS support filter before the more expensive lookups so blocks without custom CSS return faster.

Replaces the regex class name parsing in wp_render_custom_css_class_name() with a cheap str_contains() guard followed by an HTML spec-compliant strtok() walk over the className tokens. This avoids the regex engine for the common case where no wp-custom-css- class is present, and correctly handles tab/form-feed/CR/LF separators as well as classes such as my-wp-custom-css-* that merely contain the prefix as a substring after a hyphen.

Also hardens both functions against malformed parsed blocks (non-string className, missing keys), tightens @phpstan-param array shapes, and corrects the block_has_support() @param to allow WP_Block_Type|null. Lastly, a @return Generator<int, non-empty-string> phpdoc tag is added to WP_HTML_Tag_Processor::class_list().

Developed in https://github.com/WordPress/wordpress-develop/pull/11686 and https://github.com/WordPress/gutenberg/pull/78217

Follow-up to r61678.

Props mukesh27, westonruter, ramonopoly, jonsurrell.
See #64544, #64238.

Location:
trunk
Files:
4 edited

Legend:

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

    r62299 r62359  
    1313 * @param array $parsed_block The parsed block.
    1414 * @return array The same parsed block with custom CSS class name added if appropriate.
     15 *
     16 * @phpstan-param array{
     17 *     blockName: string|null,
     18 *     attrs: array{
     19 *         className?: string,
     20 *         style?: array{
     21 *             css?: string,
     22 *             ...
     23 *         },
     24 *         ...
     25 *     },
     26 *     ...
     27 * } $parsed_block
    1528 */
    1629function wp_render_custom_css_support_styles( $parsed_block ) {
     30        $custom_css = $parsed_block['attrs']['style']['css'] ?? null;
     31        if ( ! is_string( $custom_css ) || '' === trim( $custom_css ) ) {
     32                return $parsed_block;
     33        }
     34
    1735        $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $parsed_block['blockName'] );
    18 
    1936        if ( ! block_has_support( $block_type, 'customCSS', true ) ) {
    20                 return $parsed_block;
    21         }
    22 
    23         $custom_css = trim( $parsed_block['attrs']['style']['css'] ?? '' );
    24 
    25         if ( empty( $custom_css ) ) {
    2637                return $parsed_block;
    2738        }
     
    3344
    3445        // Generate a unique class name for this block instance.
    35         $class_name         = wp_unique_id_from_values( $parsed_block, 'wp-custom-css-' );
    36         $updated_class_name = isset( $parsed_block['attrs']['className'] )
    37                 ? $parsed_block['attrs']['className'] . " $class_name"
     46        $class_name          = wp_unique_id_from_values( $parsed_block, 'wp-custom-css-' );
     47        $existing_class_name = $parsed_block['attrs']['className'] ?? null;
     48        $updated_class_name  = is_string( $existing_class_name )
     49                ? "$existing_class_name $class_name"
    3850                : $class_name;
    3951
     
    6981 * Applies the custom CSS class name to the block's rendered HTML.
    7082 *
    71  * The class name is generated in `wp_render_custom_css_support_styles`
     83 * The class name is generated in {@see wp_render_custom_css_support_styles()}
    7284 * and stored in block attributes. This filter adds it to the actual markup.
    7385 *
     
    7789 * @param array  $block         Block object.
    7890 * @return string               Filtered block content.
     91 *
     92 * @phpstan-param array{
     93 *     attrs: array{
     94 *         className?: string,
     95 *         ...
     96 *     },
     97 *     ...
     98 * } $block
    7999 */
    80100function wp_render_custom_css_class_name( $block_content, $block ) {
    81         $class_string = $block['attrs']['className'] ?? '';
    82         preg_match( '/\bwp-custom-css-\S+\b/', $class_string, $matches );
    83 
    84         if ( empty( $matches ) ) {
     101        $class_name_attr = $block['attrs']['className'] ?? null;
     102
     103        if ( ! is_string( $class_name_attr ) || ! str_contains( $class_name_attr, 'wp-custom-css-' ) ) {
     104                return $block_content;
     105        }
     106
     107        // Parse out the 'wp-custom-css-*' class name added by wp_render_custom_css_support_styles().
     108        $custom_class_name = null;
     109        $token_delimiter   = " \t\f\r\n";
     110        $class_token       = strtok( $class_name_attr, $token_delimiter );
     111        while ( false !== $class_token ) {
     112                if ( str_starts_with( $class_token, 'wp-custom-css-' ) ) {
     113                        $custom_class_name = $class_token;
     114                        break;
     115                }
     116                $class_token = strtok( $token_delimiter );
     117        }
     118        if ( null === $custom_class_name ) {
    85119                return $block_content;
    86120        }
     
    90124        if ( $tags->next_tag() ) {
    91125                $tags->add_class( 'has-custom-css' );
    92                 $tags->add_class( $matches[0] );
     126                $tags->add_class( $custom_class_name );
    93127        }
    94128
  • trunk/src/wp-includes/blocks.php

    r62219 r62359  
    26052605 * @since 6.4.0 The `$feature` parameter now supports a string.
    26062606 *
    2607  * @param WP_Block_Type $block_type    Block type to check for support.
    2608  * @param string|array  $feature       Feature slug, or path to a specific feature to check support for.
    2609  * @param mixed         $default_value Optional. Fallback value for feature support. Default false.
     2607 * @param WP_Block_Type|null $block_type    Block type to check for support.
     2608 * @param string|array       $feature       Feature slug, or path to a specific feature to check support for.
     2609 * @param mixed              $default_value Optional. Fallback value for feature support. Default false.
    26102610 * @return bool Whether the feature is supported.
    26112611 */
  • trunk/src/wp-includes/html-api/class-wp-html-tag-processor.php

    r61934 r62359  
    11761176         *
    11771177         * @since 6.4.0
     1178         *
     1179         * @return Generator<int, non-empty-string>
    11781180         */
    11791181        public function class_list() {
  • trunk/tests/phpunit/tests/block-supports/wpRenderCustomCssClassName.php

    r61678 r62359  
    3030         * Data provider.
    3131         *
    32          * @return array
     32         * @return array<string, array{
     33         *     block_content: string,
     34         *     block: array{
     35         *         blockName: string,
     36         *         attrs: array{
     37         *             className: string,
     38         *         },
     39         *     },
     40         *     expected_class: string,
     41         * }>
    3342         */
    34         public function data_adds_class_to_content() {
     43        public function data_adds_class_to_content(): array {
    3544                return array(
    3645                        'class is added to block content'           => array(
     
    5362                                ),
    5463                                'expected_class' => 'wp-custom-css-mixed123',
     64                        ),
     65                        'class between whitespace is added'         => array(
     66                                'block_content'  => '<div class="wp-block-paragraph">Test content</div>',
     67                                'block'          => array(
     68                                        'blockName' => 'core/paragraph',
     69                                        'attrs'     => array(
     70                                                'className' => "\twp-custom-css-123abc\t",
     71                                        ),
     72                                ),
     73                                'expected_class' => 'wp-custom-css-123abc',
    5574                        ),
    5675                );
     
    114133                                ),
    115134                        ),
     135                        'prefixed custom CSS class'     => array(
     136                                'block_content' => '<div class="wp-block-paragraph">Test content</div>',
     137                                'block'         => array(
     138                                        'blockName' => 'core/paragraph',
     139                                        'attrs'     => array(
     140                                                'className' => 'my-wp-custom-css-456def',
     141                                        ),
     142                                ),
     143                        ),
    116144                        'className is not set in attrs' => array(
    117145                                'block_content' => '<div class="wp-block-paragraph">Test content</div>',
Note: See TracChangeset for help on using the changeset viewer.