Skip to content

Commit da12379

Browse files
committed
Block Supports: Improve handling of block class name to avoid fatals.
Add defensive guards to block `className` attribute handling to avoid fatal errors when operating on corrupted block content. While rare in practice, because the logic operates on raw block attributes it needs to be especially defensive about the values it works with. When a block's `className` attribute is not a string, passing it to `preg_match()` or `str_contains()` triggers a fatal error on PHP 8+. In `wp_render_block_style_variation_class_name()`, bail early when `className` is not a string. In `wp_render_layout_support_flag()`, fall back to an empty string when `className` is not a string before the `str_contains()` check. Adds test coverage for both cases. Developed in: WordPress#12516. Props aduth, mciampini, westonruter, isabel_brison, onemaggie, tyxla. Fixes #65625. git-svn-id: https://develop.svn.wordpress.org/trunk@62732 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 4816134 commit da12379

4 files changed

Lines changed: 77 additions & 2 deletions

File tree

src/wp-includes/block-supports/block-style-variations.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,16 @@ function wp_render_block_style_variation_class_name( $block_content, $block ) {
223223
return $block_content;
224224
}
225225

226+
$block_class_name = $block['attrs']['className'];
227+
if ( ! is_string( $block_class_name ) ) {
228+
return $block_content;
229+
}
230+
226231
/*
227232
* Matches a class prefixed by `is-style`, followed by the
228233
* variation slug, then `--`, and finally an instance number.
229234
*/
230-
preg_match( '/\bis-style-(\S+?--\d+)\b/', $block['attrs']['className'], $matches );
235+
preg_match( '/\bis-style-(\S+?--\d+)\b/', $block_class_name, $matches );
231236

232237
if ( empty( $matches ) ) {
233238
return $block_content;

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1160,7 +1160,9 @@ function wp_render_layout_support_flag( $block_content, $block ) {
11601160
// Check if the block has an active style variation with a blockGap value.
11611161
// Only check the registry if the className contains a variation class to avoid unnecessary lookups.
11621162
$variation_block_gap_value = null;
1163-
$block_class_name = $block['attrs']['className'] ?? '';
1163+
$block_class_name = is_string( $block['attrs']['className'] ?? null )
1164+
? $block['attrs']['className']
1165+
: '';
11641166
if ( $block_class_name && str_contains( $block_class_name, 'is-style-' ) && $block_name ) {
11651167
$styles_registry = WP_Block_Styles_Registry::get_instance();
11661168
$registered_styles = $styles_registry->get_registered_styles_for_block( $block_name );

tests/phpunit/tests/block-supports/block-style-variations.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,4 +320,47 @@ public function test_block_style_variation_ref_values() {
320320

321321
$this->assertSameSetsWithIndex( $expected, $variation_data, 'Variation data with resolved ref values does not match' );
322322
}
323+
324+
/**
325+
* Tests that a non-string `className` attribute does not cause a fatal
326+
* error and the block content is returned unmodified.
327+
*
328+
* @covers ::wp_render_block_style_variation_class_name
329+
*/
330+
public function test_block_style_variation_class_name_with_non_string_class_name() {
331+
$block = array(
332+
'blockName' => 'core/paragraph',
333+
'attrs' => array(
334+
'className' => array( '0', '1' ),
335+
),
336+
);
337+
338+
$block_content = "<p class=\"0 1\">Test</p>\n";
339+
340+
$this->assertSame(
341+
$block_content,
342+
wp_render_block_style_variation_class_name( $block_content, $block ),
343+
'Block content should be returned unchanged when className is not a string'
344+
);
345+
}
346+
347+
/**
348+
* Tests to ensure that there are no references to an undefined array key
349+
* if `className` is not assigned.
350+
*
351+
* @covers ::wp_render_block_style_variation_class_name
352+
*/
353+
public function test_block_style_variation_class_name_with_missing_class_name() {
354+
$block = array(
355+
'blockName' => 'core/paragraph',
356+
'attrs' => array(),
357+
);
358+
359+
$block_content = "<p>Test</p>\n";
360+
361+
$this->assertSame(
362+
$block_content,
363+
wp_render_block_style_variation_class_name( $block_content, $block )
364+
);
365+
}
323366
}

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,4 +1053,29 @@ public function data_get_block_style_variation_name_from_registered_style() {
10531053
),
10541054
);
10551055
}
1056+
1057+
/**
1058+
* Tests that a non-string `className` attribute does not cause a fatal
1059+
* when checking for style variation layout styles.
1060+
*
1061+
* @covers ::wp_render_layout_support_flag
1062+
*/
1063+
public function test_layout_support_flag_with_non_string_class_name() {
1064+
$block_content = '<div class="wp-block-group 0 1"></div>';
1065+
$block = array(
1066+
'blockName' => 'core/group',
1067+
'attrs' => array(
1068+
'className' => array( '0', '1' ),
1069+
'layout' => array(
1070+
'type' => 'constrained',
1071+
),
1072+
),
1073+
);
1074+
1075+
$this->assertSame(
1076+
'<div class="wp-block-group 0 1 is-layout-constrained wp-block-group-is-layout-constrained"></div>',
1077+
wp_render_layout_support_flag( $block_content, $block ),
1078+
'Layout support should render the expected markup when className is not a string'
1079+
);
1080+
}
10561081
}

0 commit comments

Comments
 (0)