From 57b548bd623f540ae5e86c00fe043e6d7368795e Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Fri, 6 Feb 2026 20:19:32 +0900 Subject: [PATCH 01/17] get_block_wrapper_attributes: Ensures that user-provided attributes override the attributes generated by block supports --- src/wp-includes/class-wp-block-supports.php | 10 +- .../phpunit/tests/blocks/supportedStyles.php | 123 ++++++++++++++---- 2 files changed, 105 insertions(+), 28 deletions(-) diff --git a/src/wp-includes/class-wp-block-supports.php b/src/wp-includes/class-wp-block-supports.php index ec5bc9c8d6846..f922db285b4d2 100644 --- a/src/wp-includes/class-wp-block-supports.php +++ b/src/wp-includes/class-wp-block-supports.php @@ -181,8 +181,9 @@ function get_block_wrapper_attributes( $extra_attributes = array() ) { // This is hardcoded on purpose. // We only support a fixed list of attributes. - $attributes_to_merge = array( 'style', 'class', 'id', 'aria-label' ); - $attributes = array(); + $attributes_to_merge = array( 'style', 'class', 'id', 'aria-label' ); + $attributes_to_override = array( 'id', 'aria-label' ); + $attributes = array(); foreach ( $attributes_to_merge as $attribute_name ) { if ( empty( $new_attributes[ $attribute_name ] ) && empty( $extra_attributes[ $attribute_name ] ) ) { continue; @@ -198,6 +199,11 @@ function get_block_wrapper_attributes( $extra_attributes = array() ) { continue; } + if ( in_array( $attribute_name, $attributes_to_override, true ) ) { + $attributes[ $attribute_name ] = $extra_attributes[ $attribute_name ]; + continue; + } + $attributes[ $attribute_name ] = $extra_attributes[ $attribute_name ] . ' ' . $new_attributes[ $attribute_name ]; } diff --git a/tests/phpunit/tests/blocks/supportedStyles.php b/tests/phpunit/tests/blocks/supportedStyles.php index c733b7218d8c5..9e77ca69eb218 100644 --- a/tests/phpunit/tests/blocks/supportedStyles.php +++ b/tests/phpunit/tests/blocks/supportedStyles.php @@ -90,37 +90,17 @@ private function get_content_from_block( $block ) { /** * Returns the rendered output for the current block. * - * @param array $block Block to render. + * @param array $block Block to render. + * @param array $extra_attributes Extra attributes to pass to get_block_wrapper_attributes(). * @return string Rendered output for the current block. */ - private function render_example_block( $block ) { + private function render_example_block( $block, $extra_attributes = array() ) { WP_Block_Supports::init(); WP_Block_Supports::$block_to_render = $block; - $wrapper_attributes = get_block_wrapper_attributes( - array( - 'class' => 'foo-bar-class', - 'style' => 'test: style;', - ) - ); + $wrapper_attributes = get_block_wrapper_attributes( $extra_attributes ); return '
' . self::BLOCK_CONTENT . '
'; } - /** - * Runs assertions that the rendered output has expected class/style attrs. - * - * @param array $block Block to render. - * @param string $expected_classes Expected output class attr string. - * @param string $expected_styles Expected output styles attr string. - */ - private function assert_styles_and_classes_match( $block, $expected_classes, $expected_styles ) { - $styled_block = $this->render_example_block( $block ); - $class_list = $this->get_attribute_from_block( 'class', $styled_block ); - $style_list = $this->get_attribute_from_block( 'style', $styled_block ); - - $this->assertSame( $expected_classes, $class_list, 'Class list does not match expected classes' ); - $this->assertSame( $expected_styles, $style_list, 'Style list does not match expected styles' ); - } - /** * Runs assertions that the rendered output has expected content and class/style attrs. * @@ -129,7 +109,13 @@ private function assert_styles_and_classes_match( $block, $expected_classes, $ex * @param string $expected_styles Expected output styles attr string. */ private function assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ) { - $styled_block = $this->render_example_block( $block ); + $styled_block = $this->render_example_block( + $block, + array( + 'class' => 'foo-bar-class', + 'style' => 'test: style;', + ) + ); // Ensure blocks to not add extra whitespace. $this->assertSame( $styled_block, trim( $styled_block ) ); @@ -158,7 +144,13 @@ private function assert_content_and_styles_and_classes_match( $block, $expected_ * @param string $expected_aria_label Expected output aria-label attr string. */ private function assert_content_and_aria_label_match( $block, $expected_aria_label ) { - $styled_block = $this->render_example_block( $block ); + $styled_block = $this->render_example_block( + $block, + array( + 'class' => 'foo-bar-class', + 'style' => 'test: style;', + ) + ); $content = $this->get_content_from_block( $styled_block ); $this->assertSame( self::BLOCK_CONTENT, $content, 'Block content does not match expected content' ); @@ -169,6 +161,7 @@ private function assert_content_and_aria_label_match( $block, $expected_aria_lab ); } + /** * Tests color support for named color support for named colors. */ @@ -201,6 +194,40 @@ public function test_named_color_support() { $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } + /** + * Ensures that class and style attributes from extra attributes and block supports are merged. + */ + public function test_block_wrapper_attributes_merge() { + $block_type_settings = array( + 'attributes' => array(), + 'supports' => array( + 'color' => true, + ), + 'render_callback' => true, + ); + $this->register_block_type( 'core/example-merge', $block_type_settings ); + + $block = array( + 'blockName' => 'core/example-merge', + 'attrs' => array( + 'style' => array( + 'color' => array( + 'text' => '#000', + 'background' => '#fff', + ), + ), + ), + 'innerBlock' => array(), + 'innerContent' => array(), + 'innerHTML' => array(), + ); + + $expected_styles = 'test: style;color:#000;background-color:#fff;'; + $expected_classes = 'foo-bar-class wp-block-example-merge has-text-color has-background'; + + $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); + } + /** * Tests color support for custom colors. */ @@ -728,6 +755,50 @@ public function test_aria_label_support() { $this->assert_content_and_aria_label_match( $block, 'Label' ); } + /** + * Ensures that user-provided attributes override the attributes generated by block supports. + */ + public function test_block_wrapper_attributes_prefer_user_id_and_aria_label_over_generated() { + $block_type_settings = array( + 'attributes' => array(), + 'supports' => array( + 'ariaLabel' => true, + 'anchor' => true, + ), + ); + $this->register_block_type( 'core/example-override', $block_type_settings ); + + $block = array( + 'blockName' => 'core/example-override', + 'attrs' => array( + 'ariaLabel' => 'Generated label', + 'anchor' => 'generated-id', + ), + 'innerBlock' => array(), + 'innerContent' => array(), + 'innerHTML' => array(), + ); + + $styled_block = $this->render_example_block( + $block, + array( + 'aria-label' => 'User label', + 'id' => 'user-id', + ) + ); + + $this->assertSame( + 'User label', + $this->get_attribute_from_block( 'aria-label', $styled_block ), + 'Aria-label should prefer user-provided value over generated one' + ); + $this->assertSame( + 'user-id', + $this->get_attribute_from_block( 'id', $styled_block ), + 'Id should prefer user-provided value over generated one' + ); + } + /** * Ensures libxml_internal_errors is being used instead of @ warning suppression */ From dd6a4a506b41f81c4d3121faf3000f3eea11ef5e Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Mon, 9 Feb 2026 22:39:09 +0900 Subject: [PATCH 02/17] Remove double blank lines Co-authored-by: Weston Ruter --- tests/phpunit/tests/blocks/supportedStyles.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/phpunit/tests/blocks/supportedStyles.php b/tests/phpunit/tests/blocks/supportedStyles.php index 9e77ca69eb218..6cba06ee38db0 100644 --- a/tests/phpunit/tests/blocks/supportedStyles.php +++ b/tests/phpunit/tests/blocks/supportedStyles.php @@ -161,7 +161,6 @@ private function assert_content_and_aria_label_match( $block, $expected_aria_lab ); } - /** * Tests color support for named color support for named colors. */ From 68fab57f2b9939698a6a5d3e47f82ab360caeb15 Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Mon, 9 Feb 2026 22:39:39 +0900 Subject: [PATCH 03/17] Update PHPDoc Co-authored-by: Weston Ruter --- tests/phpunit/tests/blocks/supportedStyles.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/phpunit/tests/blocks/supportedStyles.php b/tests/phpunit/tests/blocks/supportedStyles.php index 6cba06ee38db0..87a9e14e4b59d 100644 --- a/tests/phpunit/tests/blocks/supportedStyles.php +++ b/tests/phpunit/tests/blocks/supportedStyles.php @@ -195,6 +195,9 @@ public function test_named_color_support() { /** * Ensures that class and style attributes from extra attributes and block supports are merged. + * + * @ticket 64603 + * @covers WP_Block_Supports::get_block_wrapper_attributes() */ public function test_block_wrapper_attributes_merge() { $block_type_settings = array( From bd3be96993462675db2246f8d82838a65aa99116 Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Mon, 9 Feb 2026 22:39:52 +0900 Subject: [PATCH 04/17] Update PHPDoc Co-authored-by: Weston Ruter --- tests/phpunit/tests/blocks/supportedStyles.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/phpunit/tests/blocks/supportedStyles.php b/tests/phpunit/tests/blocks/supportedStyles.php index 87a9e14e4b59d..99e0516b348ad 100644 --- a/tests/phpunit/tests/blocks/supportedStyles.php +++ b/tests/phpunit/tests/blocks/supportedStyles.php @@ -759,6 +759,9 @@ public function test_aria_label_support() { /** * Ensures that user-provided attributes override the attributes generated by block supports. + * + * @ticket 64603 + * @covers WP_Block_Supports::get_block_wrapper_attributes() */ public function test_block_wrapper_attributes_prefer_user_id_and_aria_label_over_generated() { $block_type_settings = array( From d5dcbb8f8e224df173f4613c44716a3a5dad3dca Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Mon, 9 Feb 2026 22:49:24 +0900 Subject: [PATCH 05/17] Remove space --- tests/phpunit/tests/blocks/supportedStyles.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/blocks/supportedStyles.php b/tests/phpunit/tests/blocks/supportedStyles.php index 99e0516b348ad..f60ecadbc6d9c 100644 --- a/tests/phpunit/tests/blocks/supportedStyles.php +++ b/tests/phpunit/tests/blocks/supportedStyles.php @@ -759,7 +759,7 @@ public function test_aria_label_support() { /** * Ensures that user-provided attributes override the attributes generated by block supports. - * + * * @ticket 64603 * @covers WP_Block_Supports::get_block_wrapper_attributes() */ From 5cbc4b5b3b933f3167618de12efe7b5633c2db6c Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Thu, 12 Feb 2026 20:08:11 +0900 Subject: [PATCH 06/17] Simplify logic --- src/wp-includes/class-wp-block-supports.php | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/wp-includes/class-wp-block-supports.php b/src/wp-includes/class-wp-block-supports.php index f922db285b4d2..247de79fe9658 100644 --- a/src/wp-includes/class-wp-block-supports.php +++ b/src/wp-includes/class-wp-block-supports.php @@ -181,10 +181,14 @@ function get_block_wrapper_attributes( $extra_attributes = array() ) { // This is hardcoded on purpose. // We only support a fixed list of attributes. - $attributes_to_merge = array( 'style', 'class', 'id', 'aria-label' ); - $attributes_to_override = array( 'id', 'aria-label' ); - $attributes = array(); - foreach ( $attributes_to_merge as $attribute_name ) { + $handled_attributes = array( + 'style' => true, + 'class' => true, + 'id' => false, + 'aria-label' => false, + ); + $attributes = array(); + foreach ( $handled_attributes as $attribute_name => $is_merged ) { if ( empty( $new_attributes[ $attribute_name ] ) && empty( $extra_attributes[ $attribute_name ] ) ) { continue; } @@ -199,16 +203,15 @@ function get_block_wrapper_attributes( $extra_attributes = array() ) { continue; } - if ( in_array( $attribute_name, $attributes_to_override, true ) ) { + if ( $is_merged ) { + $attributes[ $attribute_name ] = $extra_attributes[ $attribute_name ] . ' ' . $new_attributes[ $attribute_name ]; + } else { $attributes[ $attribute_name ] = $extra_attributes[ $attribute_name ]; - continue; } - - $attributes[ $attribute_name ] = $extra_attributes[ $attribute_name ] . ' ' . $new_attributes[ $attribute_name ]; } foreach ( $extra_attributes as $attribute_name => $value ) { - if ( ! in_array( $attribute_name, $attributes_to_merge, true ) ) { + if ( ! isset( $handled_attributes[ $attribute_name ] ) ) { $attributes[ $attribute_name ] = $value; } } From 46877b9defb7a8d6972b56f3920ea8d950b16153 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Tue, 10 Mar 2026 19:18:40 +0900 Subject: [PATCH 07/17] Add more safeguards --- src/wp-includes/class-wp-block-supports.php | 61 +++-- .../phpunit/tests/blocks/supportedStyles.php | 244 +++++++++++++----- 2 files changed, 212 insertions(+), 93 deletions(-) diff --git a/src/wp-includes/class-wp-block-supports.php b/src/wp-includes/class-wp-block-supports.php index 247de79fe9658..6ee23dc6bcf30 100644 --- a/src/wp-includes/class-wp-block-supports.php +++ b/src/wp-includes/class-wp-block-supports.php @@ -179,39 +179,48 @@ function get_block_wrapper_attributes( $extra_attributes = array() ) { return ''; } - // This is hardcoded on purpose. - // We only support a fixed list of attributes. - $handled_attributes = array( - 'style' => true, - 'class' => true, - 'id' => false, - 'aria-label' => false, + // Attribute values are concatenated or overridden depending on the attribute type. + // This is hardcoded on purpose, as we only support a fixed list of attributes. + $attribute_merge_callbacks = array( + 'style' => function ( $new_attribute, $extra_attribute ) { + $styles = array_filter( array( + rtrim( trim( $extra_attribute ), ';' ), + rtrim( trim( $new_attribute ), ';' ), + ) ); + return safecss_filter_attr( implode( ';', array_filter( $styles ) ) ); + }, + 'class' => function ( $new_attribute, $extra_attribute ) { + $classes = array_merge( + wp_parse_list( $extra_attribute ), + wp_parse_list( $new_attribute ) + ); + $classes = array_unique( array_filter( array_map( 'sanitize_html_class', $classes ) ) ); + return implode( ' ', $classes ); + }, + 'id' => function ( $new_attribute, $extra_attribute ) { + return $extra_attribute !== '' ? $extra_attribute : $new_attribute; + }, + 'aria-label' => function ( $new_attribute, $extra_attribute ) { + return $extra_attribute !== '' ? $extra_attribute : $new_attribute; + }, ); - $attributes = array(); - foreach ( $handled_attributes as $attribute_name => $is_merged ) { - if ( empty( $new_attributes[ $attribute_name ] ) && empty( $extra_attributes[ $attribute_name ] ) ) { - continue; - } - if ( empty( $new_attributes[ $attribute_name ] ) ) { - $attributes[ $attribute_name ] = $extra_attributes[ $attribute_name ]; - continue; - } + $attributes = array(); + foreach ( $attribute_merge_callbacks as $attribute_name => $merge_callback ) { + $new_attribute = isset( $new_attributes[ $attribute_name ] ) ? $new_attributes[ $attribute_name ] : ''; + $extra_attribute = isset( $extra_attributes[ $attribute_name ] ) ? $extra_attributes[ $attribute_name ] : ''; + $new_attribute = is_string( $new_attribute ) ? $new_attribute : ''; + $extra_attribute = is_string( $extra_attribute ) ? $extra_attribute : ''; - if ( empty( $extra_attributes[ $attribute_name ] ) ) { - $attributes[ $attribute_name ] = $new_attributes[ $attribute_name ]; - continue; - } + if ( '' === $new_attribute && '' === $extra_attribute ) { + continue; + } - if ( $is_merged ) { - $attributes[ $attribute_name ] = $extra_attributes[ $attribute_name ] . ' ' . $new_attributes[ $attribute_name ]; - } else { - $attributes[ $attribute_name ] = $extra_attributes[ $attribute_name ]; + $attributes[ $attribute_name ] = $merge_callback( $new_attribute, $extra_attribute ); } - } foreach ( $extra_attributes as $attribute_name => $value ) { - if ( ! isset( $handled_attributes[ $attribute_name ] ) ) { + if ( ! isset( $attribute_merge_callbacks[ $attribute_name ] ) ) { $attributes[ $attribute_name ] = $value; } } diff --git a/tests/phpunit/tests/blocks/supportedStyles.php b/tests/phpunit/tests/blocks/supportedStyles.php index f60ecadbc6d9c..410443434f6c5 100644 --- a/tests/phpunit/tests/blocks/supportedStyles.php +++ b/tests/phpunit/tests/blocks/supportedStyles.php @@ -113,7 +113,7 @@ private function assert_content_and_styles_and_classes_match( $block, $expected_ $block, array( 'class' => 'foo-bar-class', - 'style' => 'test: style;', + 'style' => 'margin-top: 2px;', ) ); @@ -148,7 +148,7 @@ private function assert_content_and_aria_label_match( $block, $expected_aria_lab $block, array( 'class' => 'foo-bar-class', - 'style' => 'test: style;', + 'style' => 'margin-top: 2px;', ) ); $content = $this->get_content_from_block( $styled_block ); @@ -188,7 +188,7 @@ public function test_named_color_support() { ); $expected_classes = 'foo-bar-class wp-block-example has-text-color has-red-color has-background has-black-background-color'; - $expected_styles = 'test: style;'; + $expected_styles = 'margin-top: 2px'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } @@ -224,7 +224,7 @@ public function test_block_wrapper_attributes_merge() { 'innerHTML' => array(), ); - $expected_styles = 'test: style;color:#000;background-color:#fff;'; + $expected_styles = 'margin-top: 2px;color:#000;background-color:#fff'; $expected_classes = 'foo-bar-class wp-block-example-merge has-text-color has-background'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); @@ -261,7 +261,7 @@ public function test_custom_color_support() { 'innerHTML' => array(), ); - $expected_styles = 'test: style;color:#000;background-color:#fff;'; + $expected_styles = 'margin-top: 2px;color:#000;background-color:#fff'; $expected_classes = 'foo-bar-class wp-block-example has-text-color has-background'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); @@ -293,7 +293,7 @@ public function test_named_gradient_support() { ); $expected_classes = 'foo-bar-class wp-block-example has-background has-red-gradient-background'; - $expected_styles = 'test: style;'; + $expected_styles = 'margin-top: 2px'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } @@ -324,7 +324,7 @@ public function test_custom_gradient_support() { ); $expected_classes = 'foo-bar-class wp-block-example has-background'; - $expected_styles = 'test: style; background:some-gradient-style;'; + $expected_styles = 'margin-top: 2px;background:some-gradient-style'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } @@ -360,7 +360,7 @@ public function test_color_unsupported() { ); $expected_classes = 'foo-bar-class wp-block-example'; - $expected_styles = 'test: style;'; + $expected_styles = 'margin-top: 2px'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } @@ -390,7 +390,7 @@ public function test_named_font_size() { ); $expected_classes = 'foo-bar-class wp-block-example has-large-font-size'; - $expected_styles = 'test: style;'; + $expected_styles = 'margin-top: 2px'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } @@ -420,7 +420,7 @@ public function test_custom_font_size() { ); $expected_classes = 'foo-bar-class wp-block-example'; - $expected_styles = 'test: style; font-size:10px;'; + $expected_styles = 'margin-top: 2px;font-size:10px'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } @@ -447,7 +447,7 @@ public function test_font_size_unsupported() { ); $expected_classes = 'foo-bar-class wp-block-example'; - $expected_styles = 'test: style;'; + $expected_styles = 'margin-top: 2px'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } @@ -477,7 +477,7 @@ public function test_line_height() { ); $expected_classes = 'foo-bar-class wp-block-example'; - $expected_styles = 'test: style; line-height:10;'; + $expected_styles = 'margin-top: 2px;line-height:10'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } @@ -503,7 +503,7 @@ public function test_line_height_unsupported() { ); $expected_classes = 'foo-bar-class wp-block-example'; - $expected_styles = 'test: style;'; + $expected_styles = 'margin-top: 2px'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } @@ -531,7 +531,7 @@ public function test_block_alignment() { ); $expected_classes = 'foo-bar-class wp-block-example alignwide'; - $expected_styles = 'test: style;'; + $expected_styles = 'margin-top: 2px'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } @@ -557,7 +557,7 @@ public function test_block_alignment_unsupported() { ); $expected_classes = 'foo-bar-class wp-block-example'; - $expected_styles = 'test: style;'; + $expected_styles = 'margin-top: 2px'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } @@ -604,7 +604,7 @@ public function test_all_supported() { ); $expected_classes = 'foo-bar-class wp-block-example has-text-color has-background alignwide'; - $expected_styles = 'test: style; color:#000; background-color:#fff; font-size:10px; line-height:20;'; + $expected_styles = 'margin-top: 2px;color:#000;background-color:#fff;font-size:10px;line-height:20'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } @@ -647,7 +647,7 @@ public function test_one_supported() { ); $expected_classes = 'foo-bar-class wp-block-example'; - $expected_styles = 'test: style; font-size:10px;'; + $expected_styles = 'margin-top: 2px;font-size:10px'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } @@ -672,7 +672,7 @@ public function test_custom_classnames_support() { 'innerHTML' => array(), ); - $expected_styles = 'test: style;'; + $expected_styles = 'margin-top: 2px'; $expected_classes = 'foo-bar-class wp-block-example my-custom-classname'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); @@ -700,7 +700,7 @@ public function test_custom_classnames_support_opt_out() { 'innerHTML' => array(), ); - $expected_styles = 'test: style;'; + $expected_styles = 'margin-top: 2px'; $expected_classes = 'foo-bar-class wp-block-example'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); @@ -726,7 +726,7 @@ public function test_generated_classnames_support_opt_out() { 'innerHTML' => array(), ); - $expected_styles = 'test: style;'; + $expected_styles = 'margin-top: 2px'; $expected_classes = 'foo-bar-class'; $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); @@ -757,53 +757,6 @@ public function test_aria_label_support() { $this->assert_content_and_aria_label_match( $block, 'Label' ); } - /** - * Ensures that user-provided attributes override the attributes generated by block supports. - * - * @ticket 64603 - * @covers WP_Block_Supports::get_block_wrapper_attributes() - */ - public function test_block_wrapper_attributes_prefer_user_id_and_aria_label_over_generated() { - $block_type_settings = array( - 'attributes' => array(), - 'supports' => array( - 'ariaLabel' => true, - 'anchor' => true, - ), - ); - $this->register_block_type( 'core/example-override', $block_type_settings ); - - $block = array( - 'blockName' => 'core/example-override', - 'attrs' => array( - 'ariaLabel' => 'Generated label', - 'anchor' => 'generated-id', - ), - 'innerBlock' => array(), - 'innerContent' => array(), - 'innerHTML' => array(), - ); - - $styled_block = $this->render_example_block( - $block, - array( - 'aria-label' => 'User label', - 'id' => 'user-id', - ) - ); - - $this->assertSame( - 'User label', - $this->get_attribute_from_block( 'aria-label', $styled_block ), - 'Aria-label should prefer user-provided value over generated one' - ); - $this->assertSame( - 'user-id', - $this->get_attribute_from_block( 'id', $styled_block ), - 'Id should prefer user-provided value over generated one' - ); - } - /** * Ensures libxml_internal_errors is being used instead of @ warning suppression */ @@ -840,4 +793,161 @@ static function ( $errno = 0, $errstr = '' ) use ( &$errors ) { $this->assertEmpty( $errors, 'Libxml errors should be dropped.' ); } + + /** + * Ensures that style, class, id, and aria-label attributes are correctly merged or overridden + * in get_block_wrapper_attributes(). + * + * @ticket 64603 + * @covers ::get_block_wrapper_attributes + * + * @dataProvider data_get_block_wrapper_attributes_merge_or_override + * + * @param array $data { + * Data from the provider. + * + * @type array $block_type_settings Block type settings. + * @type array $block_attrs Block attributes. + * @type array $extra_attributes Extra attributes passed to get_block_wrapper_attributes(). + * @type string $expected_attribute Expected attribute string (e.g. 'id="user-id"'). + * } + */ + public function test_get_block_wrapper_attributes_merge_and_override( $data ) { + $block_name = 'core/example'; + $block_type_settings = array_merge( + array( + 'attributes' => array(), + 'render_callback' => true, + ), + $data['block_type_settings'] + ); + $this->register_block_type( $block_name, $block_type_settings ); + + $block = array( + 'blockName' => $block_name, + 'attrs' => $data['block_attrs'], + 'innerBlock' => array(), + 'innerContent' => array(), + 'innerHTML' => array(), + ); + + WP_Block_Supports::init(); + WP_Block_Supports::$block_to_render = $block; + + $wrapper_attributes = get_block_wrapper_attributes( $data['extra_attributes'] ); + + $this->assertStringContainsString( $data['expected_attribute'], $wrapper_attributes ); + } + + /** + * Data provider for test_get_block_wrapper_attributes_merge_and_override. + * + * @return array[] Array of test cases. + */ + public function data_get_block_wrapper_attributes_merge_or_override() { + return array( + 'extra style attributes are merged with block values' => array( + array( + 'block_type_settings' => array( + 'supports' => array( + 'color' => true, + ), + ), + 'block_attrs' => array( + 'style' => array( + 'color' => array( + 'text' => '#000', + ), + ), + ), + 'extra_attributes' => array( + // Redundant trailing semicolons should be stripped + 'style' => 'margin-top: 2px;;;', + ), + 'expected_attribute' => 'style="margin-top: 2px;color:#000"', + ), + ), + 'extra class attributes are merged with block values' => array( + array( + 'block_type_settings' => array( + 'supports' => array( + 'color' => true, + ), + ), + 'block_attrs' => array( + 'style' => array( + 'color' => array( + 'text' => '#000', + ), + ), + ), + 'extra_attributes' => array( + // Duplicate class names should be merged + 'class' => 'extra-class has-text-color', + ), + 'expected_attribute' => 'class="extra-class has-text-color wp-block-example"', + ), + ), + 'extra attributes override block-generated id' => array( + array( + 'block_type_settings' => array( + 'supports' => array( + 'anchor' => true, + ), + ), + 'block_attrs' => array( + 'anchor' => 'block-id', + ), + 'extra_attributes' => array( + 'id' => 'user-id', + ), + 'expected_attribute' => 'id="user-id"', + ), + ), + 'block-generated id is used when no extra provided' => array( + array( + 'block_type_settings' => array( + 'supports' => array( + 'anchor' => true, + ), + ), + 'block_attrs' => array( + 'anchor' => 'block-id', + ), + 'extra_attributes' => array(), + 'expected_attribute' => 'id="block-id"', + ), + ), + 'extra attributes override block-generated aria-label' => array( + array( + 'block_type_settings' => array( + 'supports' => array( + 'ariaLabel' => true, + ), + ), + 'block_attrs' => array( + 'ariaLabel' => 'Block aria-label', + ), + 'extra_attributes' => array( + 'aria-label' => 'User aria-label', + ), + 'expected_attribute' => 'aria-label="User aria-label"', + ), + ), + 'block-generated aria-label is used when no extra provided' => array( + array( + 'block_type_settings' => array( + 'supports' => array( + 'ariaLabel' => true, + ), + ), + 'block_attrs' => array( + 'ariaLabel' => 'Block aria-label', + ), + 'extra_attributes' => array(), + 'expected_attribute' => 'aria-label="Block aria-label"', + ), + ), + ); + } } From 517f69c4ba6c5138fd8cb8e6b0eaa7fdc6c9c766 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Tue, 10 Mar 2026 19:22:44 +0900 Subject: [PATCH 08/17] Fix PHPCS error --- src/wp-includes/class-wp-block-supports.php | 32 ++++++++-------- .../phpunit/tests/blocks/supportedStyles.php | 38 +++++++++---------- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/wp-includes/class-wp-block-supports.php b/src/wp-includes/class-wp-block-supports.php index 6ee23dc6bcf30..850ef8c3ffeb1 100644 --- a/src/wp-includes/class-wp-block-supports.php +++ b/src/wp-includes/class-wp-block-supports.php @@ -183,10 +183,12 @@ function get_block_wrapper_attributes( $extra_attributes = array() ) { // This is hardcoded on purpose, as we only support a fixed list of attributes. $attribute_merge_callbacks = array( 'style' => function ( $new_attribute, $extra_attribute ) { - $styles = array_filter( array( - rtrim( trim( $extra_attribute ), ';' ), - rtrim( trim( $new_attribute ), ';' ), - ) ); + $styles = array_filter( + array( + rtrim( trim( $extra_attribute ), ';' ), + rtrim( trim( $new_attribute ), ';' ), + ) + ); return safecss_filter_attr( implode( ';', array_filter( $styles ) ) ); }, 'class' => function ( $new_attribute, $extra_attribute ) { @@ -205,20 +207,20 @@ function get_block_wrapper_attributes( $extra_attributes = array() ) { }, ); - $attributes = array(); - foreach ( $attribute_merge_callbacks as $attribute_name => $merge_callback ) { - $new_attribute = isset( $new_attributes[ $attribute_name ] ) ? $new_attributes[ $attribute_name ] : ''; - $extra_attribute = isset( $extra_attributes[ $attribute_name ] ) ? $extra_attributes[ $attribute_name ] : ''; - $new_attribute = is_string( $new_attribute ) ? $new_attribute : ''; - $extra_attribute = is_string( $extra_attribute ) ? $extra_attribute : ''; - - if ( '' === $new_attribute && '' === $extra_attribute ) { - continue; - } + $attributes = array(); + foreach ( $attribute_merge_callbacks as $attribute_name => $merge_callback ) { + $new_attribute = isset( $new_attributes[ $attribute_name ] ) ? $new_attributes[ $attribute_name ] : ''; + $extra_attribute = isset( $extra_attributes[ $attribute_name ] ) ? $extra_attributes[ $attribute_name ] : ''; + $new_attribute = is_string( $new_attribute ) ? $new_attribute : ''; + $extra_attribute = is_string( $extra_attribute ) ? $extra_attribute : ''; - $attributes[ $attribute_name ] = $merge_callback( $new_attribute, $extra_attribute ); + if ( '' === $new_attribute && '' === $extra_attribute ) { + continue; } + $attributes[ $attribute_name ] = $merge_callback( $new_attribute, $extra_attribute ); + } + foreach ( $extra_attributes as $attribute_name => $value ) { if ( ! isset( $attribute_merge_callbacks[ $attribute_name ] ) ) { $attributes[ $attribute_name ] = $value; diff --git a/tests/phpunit/tests/blocks/supportedStyles.php b/tests/phpunit/tests/blocks/supportedStyles.php index 410443434f6c5..bf84defcaf60c 100644 --- a/tests/phpunit/tests/blocks/supportedStyles.php +++ b/tests/phpunit/tests/blocks/supportedStyles.php @@ -813,7 +813,7 @@ static function ( $errno = 0, $errstr = '' ) use ( &$errors ) { * } */ public function test_get_block_wrapper_attributes_merge_and_override( $data ) { - $block_name = 'core/example'; + $block_name = 'core/example'; $block_type_settings = array_merge( array( 'attributes' => array(), @@ -853,18 +853,18 @@ public function data_get_block_wrapper_attributes_merge_or_override() { 'color' => true, ), ), - 'block_attrs' => array( + 'block_attrs' => array( 'style' => array( 'color' => array( 'text' => '#000', ), ), ), - 'extra_attributes' => array( + 'extra_attributes' => array( // Redundant trailing semicolons should be stripped 'style' => 'margin-top: 2px;;;', ), - 'expected_attribute' => 'style="margin-top: 2px;color:#000"', + 'expected_attribute' => 'style="margin-top: 2px;color:#000"', ), ), 'extra class attributes are merged with block values' => array( @@ -874,18 +874,18 @@ public function data_get_block_wrapper_attributes_merge_or_override() { 'color' => true, ), ), - 'block_attrs' => array( + 'block_attrs' => array( 'style' => array( 'color' => array( 'text' => '#000', ), ), ), - 'extra_attributes' => array( + 'extra_attributes' => array( // Duplicate class names should be merged 'class' => 'extra-class has-text-color', ), - 'expected_attribute' => 'class="extra-class has-text-color wp-block-example"', + 'expected_attribute' => 'class="extra-class has-text-color wp-block-example"', ), ), 'extra attributes override block-generated id' => array( @@ -895,13 +895,13 @@ public function data_get_block_wrapper_attributes_merge_or_override() { 'anchor' => true, ), ), - 'block_attrs' => array( + 'block_attrs' => array( 'anchor' => 'block-id', ), - 'extra_attributes' => array( + 'extra_attributes' => array( 'id' => 'user-id', ), - 'expected_attribute' => 'id="user-id"', + 'expected_attribute' => 'id="user-id"', ), ), 'block-generated id is used when no extra provided' => array( @@ -911,11 +911,11 @@ public function data_get_block_wrapper_attributes_merge_or_override() { 'anchor' => true, ), ), - 'block_attrs' => array( + 'block_attrs' => array( 'anchor' => 'block-id', ), - 'extra_attributes' => array(), - 'expected_attribute' => 'id="block-id"', + 'extra_attributes' => array(), + 'expected_attribute' => 'id="block-id"', ), ), 'extra attributes override block-generated aria-label' => array( @@ -925,13 +925,13 @@ public function data_get_block_wrapper_attributes_merge_or_override() { 'ariaLabel' => true, ), ), - 'block_attrs' => array( + 'block_attrs' => array( 'ariaLabel' => 'Block aria-label', ), - 'extra_attributes' => array( + 'extra_attributes' => array( 'aria-label' => 'User aria-label', ), - 'expected_attribute' => 'aria-label="User aria-label"', + 'expected_attribute' => 'aria-label="User aria-label"', ), ), 'block-generated aria-label is used when no extra provided' => array( @@ -941,11 +941,11 @@ public function data_get_block_wrapper_attributes_merge_or_override() { 'ariaLabel' => true, ), ), - 'block_attrs' => array( + 'block_attrs' => array( 'ariaLabel' => 'Block aria-label', ), - 'extra_attributes' => array(), - 'expected_attribute' => 'aria-label="Block aria-label"', + 'extra_attributes' => array(), + 'expected_attribute' => 'aria-label="Block aria-label"', ), ), ); From acf25f678a3869a7322fe7d0c5b9ab8b757983de Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Tue, 10 Mar 2026 19:24:36 +0900 Subject: [PATCH 09/17] Fix PHPCS error --- src/wp-includes/class-wp-block-supports.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/class-wp-block-supports.php b/src/wp-includes/class-wp-block-supports.php index 850ef8c3ffeb1..093640cb19b65 100644 --- a/src/wp-includes/class-wp-block-supports.php +++ b/src/wp-includes/class-wp-block-supports.php @@ -200,10 +200,10 @@ function get_block_wrapper_attributes( $extra_attributes = array() ) { return implode( ' ', $classes ); }, 'id' => function ( $new_attribute, $extra_attribute ) { - return $extra_attribute !== '' ? $extra_attribute : $new_attribute; + return '' !== $extra_attribute ? $extra_attribute : $new_attribute; }, 'aria-label' => function ( $new_attribute, $extra_attribute ) { - return $extra_attribute !== '' ? $extra_attribute : $new_attribute; + return '' !== $extra_attribute ? $extra_attribute : $new_attribute; }, ); From 11e1150619ad041faf80ef8136e1cd6ff6e3e117 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Tue, 10 Mar 2026 19:34:06 +0900 Subject: [PATCH 10/17] unnecessary --- .../phpunit/tests/blocks/supportedStyles.php | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/tests/phpunit/tests/blocks/supportedStyles.php b/tests/phpunit/tests/blocks/supportedStyles.php index bf84defcaf60c..87f59eab18a7a 100644 --- a/tests/phpunit/tests/blocks/supportedStyles.php +++ b/tests/phpunit/tests/blocks/supportedStyles.php @@ -91,13 +91,17 @@ private function get_content_from_block( $block ) { * Returns the rendered output for the current block. * * @param array $block Block to render. - * @param array $extra_attributes Extra attributes to pass to get_block_wrapper_attributes(). * @return string Rendered output for the current block. */ - private function render_example_block( $block, $extra_attributes = array() ) { + private function render_example_block( $block ) { WP_Block_Supports::init(); WP_Block_Supports::$block_to_render = $block; - $wrapper_attributes = get_block_wrapper_attributes( $extra_attributes ); + $wrapper_attributes = get_block_wrapper_attributes( + array( + 'class' => 'foo-bar-class', + 'style' => 'margin-top: 2px;', + ) + ); return '
' . self::BLOCK_CONTENT . '
'; } @@ -109,13 +113,7 @@ private function render_example_block( $block, $extra_attributes = array() ) { * @param string $expected_styles Expected output styles attr string. */ private function assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ) { - $styled_block = $this->render_example_block( - $block, - array( - 'class' => 'foo-bar-class', - 'style' => 'margin-top: 2px;', - ) - ); + $styled_block = $this->render_example_block( $block ); // Ensure blocks to not add extra whitespace. $this->assertSame( $styled_block, trim( $styled_block ) ); @@ -144,13 +142,7 @@ private function assert_content_and_styles_and_classes_match( $block, $expected_ * @param string $expected_aria_label Expected output aria-label attr string. */ private function assert_content_and_aria_label_match( $block, $expected_aria_label ) { - $styled_block = $this->render_example_block( - $block, - array( - 'class' => 'foo-bar-class', - 'style' => 'margin-top: 2px;', - ) - ); + $styled_block = $this->render_example_block( $block ); $content = $this->get_content_from_block( $styled_block ); $this->assertSame( self::BLOCK_CONTENT, $content, 'Block content does not match expected content' ); From 9445bd3b41c93babd1c482db4fc9020621763c8f Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Tue, 10 Mar 2026 19:38:10 +0900 Subject: [PATCH 11/17] Remove unnecessary test --- .../phpunit/tests/blocks/supportedStyles.php | 39 +------------------ 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/tests/phpunit/tests/blocks/supportedStyles.php b/tests/phpunit/tests/blocks/supportedStyles.php index 87f59eab18a7a..7e341ea279713 100644 --- a/tests/phpunit/tests/blocks/supportedStyles.php +++ b/tests/phpunit/tests/blocks/supportedStyles.php @@ -90,7 +90,7 @@ private function get_content_from_block( $block ) { /** * Returns the rendered output for the current block. * - * @param array $block Block to render. + * @param array $block Block to render. * @return string Rendered output for the current block. */ private function render_example_block( $block ) { @@ -185,43 +185,6 @@ public function test_named_color_support() { $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); } - /** - * Ensures that class and style attributes from extra attributes and block supports are merged. - * - * @ticket 64603 - * @covers WP_Block_Supports::get_block_wrapper_attributes() - */ - public function test_block_wrapper_attributes_merge() { - $block_type_settings = array( - 'attributes' => array(), - 'supports' => array( - 'color' => true, - ), - 'render_callback' => true, - ); - $this->register_block_type( 'core/example-merge', $block_type_settings ); - - $block = array( - 'blockName' => 'core/example-merge', - 'attrs' => array( - 'style' => array( - 'color' => array( - 'text' => '#000', - 'background' => '#fff', - ), - ), - ), - 'innerBlock' => array(), - 'innerContent' => array(), - 'innerHTML' => array(), - ); - - $expected_styles = 'margin-top: 2px;color:#000;background-color:#fff'; - $expected_classes = 'foo-bar-class wp-block-example-merge has-text-color has-background'; - - $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); - } - /** * Tests color support for custom colors. */ From 40caa8e99340a6641ddbb37133290a3fe9e4be9c Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Thu, 12 Mar 2026 16:23:06 +0900 Subject: [PATCH 12/17] Add static modifier for style callback function Co-authored-by: Weston Ruter --- src/wp-includes/class-wp-block-supports.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-block-supports.php b/src/wp-includes/class-wp-block-supports.php index 093640cb19b65..060c4cb657c1c 100644 --- a/src/wp-includes/class-wp-block-supports.php +++ b/src/wp-includes/class-wp-block-supports.php @@ -182,7 +182,7 @@ function get_block_wrapper_attributes( $extra_attributes = array() ) { // Attribute values are concatenated or overridden depending on the attribute type. // This is hardcoded on purpose, as we only support a fixed list of attributes. $attribute_merge_callbacks = array( - 'style' => function ( $new_attribute, $extra_attribute ) { + 'style' => static function ( $new_attribute, $extra_attribute ) { $styles = array_filter( array( rtrim( trim( $extra_attribute ), ';' ), From 0ea5ebfd824d26a182ca72a505e15660277da462 Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Thu, 12 Mar 2026 16:23:22 +0900 Subject: [PATCH 13/17] Add static modifier for class callback function Co-authored-by: Weston Ruter --- src/wp-includes/class-wp-block-supports.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-block-supports.php b/src/wp-includes/class-wp-block-supports.php index 060c4cb657c1c..94f83f990dedc 100644 --- a/src/wp-includes/class-wp-block-supports.php +++ b/src/wp-includes/class-wp-block-supports.php @@ -191,7 +191,7 @@ function get_block_wrapper_attributes( $extra_attributes = array() ) { ); return safecss_filter_attr( implode( ';', array_filter( $styles ) ) ); }, - 'class' => function ( $new_attribute, $extra_attribute ) { + 'class' => static function ( $new_attribute, $extra_attribute ) { $classes = array_merge( wp_parse_list( $extra_attribute ), wp_parse_list( $new_attribute ) From d68e980ebc0a5942a41af604e161c4969981464d Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Thu, 12 Mar 2026 16:23:33 +0900 Subject: [PATCH 14/17] Add static modifier for id callback function Co-authored-by: Weston Ruter --- src/wp-includes/class-wp-block-supports.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-block-supports.php b/src/wp-includes/class-wp-block-supports.php index 94f83f990dedc..3292ff12ede5e 100644 --- a/src/wp-includes/class-wp-block-supports.php +++ b/src/wp-includes/class-wp-block-supports.php @@ -199,7 +199,7 @@ function get_block_wrapper_attributes( $extra_attributes = array() ) { $classes = array_unique( array_filter( array_map( 'sanitize_html_class', $classes ) ) ); return implode( ' ', $classes ); }, - 'id' => function ( $new_attribute, $extra_attribute ) { + 'id' => static function ( $new_attribute, $extra_attribute ) { return '' !== $extra_attribute ? $extra_attribute : $new_attribute; }, 'aria-label' => function ( $new_attribute, $extra_attribute ) { From 810d5acebbdc30abf0208ee0148be9424afbba5d Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Thu, 12 Mar 2026 16:23:46 +0900 Subject: [PATCH 15/17] Add static modifier for aria-label callback function Co-authored-by: Weston Ruter --- src/wp-includes/class-wp-block-supports.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-block-supports.php b/src/wp-includes/class-wp-block-supports.php index 3292ff12ede5e..2e881390442ae 100644 --- a/src/wp-includes/class-wp-block-supports.php +++ b/src/wp-includes/class-wp-block-supports.php @@ -202,7 +202,7 @@ function get_block_wrapper_attributes( $extra_attributes = array() ) { 'id' => static function ( $new_attribute, $extra_attribute ) { return '' !== $extra_attribute ? $extra_attribute : $new_attribute; }, - 'aria-label' => function ( $new_attribute, $extra_attribute ) { + 'aria-label' => static function ( $new_attribute, $extra_attribute ) { return '' !== $extra_attribute ? $extra_attribute : $new_attribute; }, ); From eff534ec86304ea40f139f091facef2cd1505533 Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Thu, 12 Mar 2026 16:25:01 +0900 Subject: [PATCH 16/17] Use null coalescing operator Co-authored-by: Weston Ruter --- src/wp-includes/class-wp-block-supports.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/class-wp-block-supports.php b/src/wp-includes/class-wp-block-supports.php index 2e881390442ae..c39f6c55b7926 100644 --- a/src/wp-includes/class-wp-block-supports.php +++ b/src/wp-includes/class-wp-block-supports.php @@ -209,8 +209,8 @@ function get_block_wrapper_attributes( $extra_attributes = array() ) { $attributes = array(); foreach ( $attribute_merge_callbacks as $attribute_name => $merge_callback ) { - $new_attribute = isset( $new_attributes[ $attribute_name ] ) ? $new_attributes[ $attribute_name ] : ''; - $extra_attribute = isset( $extra_attributes[ $attribute_name ] ) ? $extra_attributes[ $attribute_name ] : ''; + $new_attribute = $new_attributes[ $attribute_name ] ?? ''; + $extra_attribute = $extra_attributes[ $attribute_name ] ?? ''; $new_attribute = is_string( $new_attribute ) ? $new_attribute : ''; $extra_attribute = is_string( $extra_attribute ) ? $extra_attribute : ''; From 66a916949d098c96bafab3263102be2fce89d961 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Fri, 13 Mar 2026 09:51:58 +0900 Subject: [PATCH 17/17] Don't split on commas --- src/wp-includes/class-wp-block-supports.php | 6 +++--- tests/phpunit/tests/blocks/supportedStyles.php | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/wp-includes/class-wp-block-supports.php b/src/wp-includes/class-wp-block-supports.php index c39f6c55b7926..c5df0b9fbd241 100644 --- a/src/wp-includes/class-wp-block-supports.php +++ b/src/wp-includes/class-wp-block-supports.php @@ -193,10 +193,10 @@ function get_block_wrapper_attributes( $extra_attributes = array() ) { }, 'class' => static function ( $new_attribute, $extra_attribute ) { $classes = array_merge( - wp_parse_list( $extra_attribute ), - wp_parse_list( $new_attribute ) + preg_split( '/\s+/', $extra_attribute, -1, PREG_SPLIT_NO_EMPTY ), + preg_split( '/\s+/', $new_attribute, -1, PREG_SPLIT_NO_EMPTY ) ); - $classes = array_unique( array_filter( array_map( 'sanitize_html_class', $classes ) ) ); + $classes = array_unique( array_filter( $classes ) ); return implode( ' ', $classes ); }, 'id' => static function ( $new_attribute, $extra_attribute ) { diff --git a/tests/phpunit/tests/blocks/supportedStyles.php b/tests/phpunit/tests/blocks/supportedStyles.php index 7e341ea279713..771c8f6089d15 100644 --- a/tests/phpunit/tests/blocks/supportedStyles.php +++ b/tests/phpunit/tests/blocks/supportedStyles.php @@ -837,10 +837,10 @@ public function data_get_block_wrapper_attributes_merge_or_override() { ), ), 'extra_attributes' => array( - // Duplicate class names should be merged - 'class' => 'extra-class has-text-color', + // Duplicate class names should be merged, and commas should be preserved. + 'class' => 'extra-class extra,class has-text-color', ), - 'expected_attribute' => 'class="extra-class has-text-color wp-block-example"', + 'expected_attribute' => 'class="extra-class extra,class has-text-color wp-block-example"', ), ), 'extra attributes override block-generated id' => array(