Skip to content

Commit 20b5d10

Browse files
committed
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 WordPress#11686 and WordPress/gutenberg#78217 Follow-up to r61678. Props mukesh27, westonruter, ramonopoly, jonsurrell. See #64544, #64238. git-svn-id: https://develop.svn.wordpress.org/trunk@62359 602fd350-edb4-49c9-b593-d223f7449a82
1 parent a1f2b42 commit 20b5d10

4 files changed

Lines changed: 83 additions & 19 deletions

File tree

src/wp-includes/block-supports/custom-css.php

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,28 @@
1212
*
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
*/
1629
function wp_render_custom_css_support_styles( $parsed_block ) {
17-
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $parsed_block['blockName'] );
18-
19-
if ( ! block_has_support( $block_type, 'customCSS', true ) ) {
30+
$custom_css = $parsed_block['attrs']['style']['css'] ?? null;
31+
if ( ! is_string( $custom_css ) || '' === trim( $custom_css ) ) {
2032
return $parsed_block;
2133
}
2234

23-
$custom_css = trim( $parsed_block['attrs']['style']['css'] ?? '' );
24-
25-
if ( empty( $custom_css ) ) {
35+
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $parsed_block['blockName'] );
36+
if ( ! block_has_support( $block_type, 'customCSS', true ) ) {
2637
return $parsed_block;
2738
}
2839

@@ -32,9 +43,10 @@ function wp_render_custom_css_support_styles( $parsed_block ) {
3243
}
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

4052
_wp_array_set( $parsed_block, array( 'attrs', 'className' ), $updated_class_name );
@@ -68,28 +80,50 @@ function wp_enqueue_block_custom_css() {
6880
/**
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
*
7486
* @since 7.0.0
7587
*
7688
* @param string $block_content Rendered block content.
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
*/
80100
function 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 );
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+
}
83106

84-
if ( empty( $matches ) ) {
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
}
87121

88122
$tags = new WP_HTML_Tag_Processor( $block_content );
89123

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

95129
return $tags->get_updated_html();

src/wp-includes/blocks.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2604,9 +2604,9 @@ function unregister_block_style( $block_name, $block_style_name ) {
26042604
* @since 5.8.0
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
*/
26122612
function block_has_support( $block_type, $feature, $default_value = false ) {

src/wp-includes/html-api/class-wp-html-tag-processor.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,6 +1175,8 @@ public function paused_at_incomplete_token(): bool {
11751175
* // Outputs: "free <egg> lang-en "
11761176
*
11771177
* @since 6.4.0
1178+
*
1179+
* @return Generator<int, non-empty-string>
11781180
*/
11791181
public function class_list() {
11801182
if ( self::STATE_MATCHED_TAG !== $this->parser_state ) {

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

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,18 @@ public function test_adds_class_to_content( $block_content, $block, $expected_cl
2929
/**
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(
3746
'block_content' => '<div class="wp-block-paragraph">Test content</div>',
@@ -53,6 +62,16 @@ public function data_adds_class_to_content() {
5362
),
5463
'expected_class' => 'wp-custom-css-mixed123',
5564
),
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',
74+
),
5675
);
5776
}
5877

@@ -113,6 +132,15 @@ public function data_returns_unchanged_content() {
113132
),
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>',
118146
'block' => array(

0 commit comments

Comments
 (0)