Changeset 62068
- Timestamp:
- 03/19/2026 02:39:42 PM (9 days ago)
- Location:
- trunk
- Files:
-
- 2 edited
-
src/wp-includes/class-wp-block-supports.php (modified) (1 diff)
-
tests/phpunit/tests/blocks/supportedStyles.php (modified) (19 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/class-wp-block-supports.php
r59925 r62068 180 180 } 181 181 182 // This is hardcoded on purpose. 183 // We only support a fixed list of attributes. 184 $attributes_to_merge = array( 'style', 'class', 'id', 'aria-label' ); 185 $attributes = array(); 186 foreach ( $attributes_to_merge as $attribute_name ) { 187 if ( empty( $new_attributes[ $attribute_name ] ) && empty( $extra_attributes[ $attribute_name ] ) ) { 182 // Attribute values are concatenated or overridden depending on the attribute type. 183 // This is hardcoded on purpose, as we only support a fixed list of attributes. 184 $attribute_merge_callbacks = array( 185 'style' => static function ( $new_attribute, $extra_attribute ) { 186 $styles = array_filter( 187 array( 188 rtrim( trim( $new_attribute ), ';' ), 189 rtrim( trim( $extra_attribute ), ';' ), 190 ) 191 ); 192 return safecss_filter_attr( implode( ';', array_filter( $styles ) ) ); 193 }, 194 'class' => static function ( $new_attribute, $extra_attribute ) { 195 $classes = array_merge( 196 (array) preg_split( '/\s+/', $extra_attribute, -1, PREG_SPLIT_NO_EMPTY ), 197 (array) preg_split( '/\s+/', $new_attribute, -1, PREG_SPLIT_NO_EMPTY ) 198 ); 199 $classes = array_unique( array_filter( $classes ) ); 200 return implode( ' ', $classes ); 201 }, 202 'id' => static function ( $new_attribute, $extra_attribute ) { 203 return '' !== $extra_attribute ? $extra_attribute : $new_attribute; 204 }, 205 'aria-label' => static function ( $new_attribute, $extra_attribute ) { 206 return '' !== $extra_attribute ? $extra_attribute : $new_attribute; 207 }, 208 ); 209 210 $attributes = array(); 211 foreach ( $attribute_merge_callbacks as $attribute_name => $merge_callback ) { 212 $new_attribute = $new_attributes[ $attribute_name ] ?? ''; 213 $extra_attribute = $extra_attributes[ $attribute_name ] ?? ''; 214 $new_attribute = is_string( $new_attribute ) ? $new_attribute : ''; 215 $extra_attribute = is_string( $extra_attribute ) ? $extra_attribute : ''; 216 217 if ( '' === $new_attribute && '' === $extra_attribute ) { 188 218 continue; 189 219 } 190 220 191 if ( empty( $new_attributes[ $attribute_name ] ) ) { 192 $attributes[ $attribute_name ] = $extra_attributes[ $attribute_name ]; 193 continue; 194 } 195 196 if ( empty( $extra_attributes[ $attribute_name ] ) ) { 197 $attributes[ $attribute_name ] = $new_attributes[ $attribute_name ]; 198 continue; 199 } 200 201 $attributes[ $attribute_name ] = $extra_attributes[ $attribute_name ] . ' ' . $new_attributes[ $attribute_name ]; 221 $attributes[ $attribute_name ] = $merge_callback( $new_attribute, $extra_attribute ); 202 222 } 203 223 204 224 foreach ( $extra_attributes as $attribute_name => $value ) { 205 if ( ! i n_array( $attribute_name, $attributes_to_merge, true) ) {225 if ( ! isset( $attribute_merge_callbacks[ $attribute_name ] ) ) { 206 226 $attributes[ $attribute_name ] = $value; 207 227 } -
trunk/tests/phpunit/tests/blocks/supportedStyles.php
r59925 r62068 100 100 array( 101 101 'class' => 'foo-bar-class', 102 'style' => ' test: style;',102 'style' => 'margin-top: 2px;', 103 103 ) 104 104 ); 105 105 return '<div ' . $wrapper_attributes . '>' . self::BLOCK_CONTENT . '</div>'; 106 }107 108 /**109 * Runs assertions that the rendered output has expected class/style attrs.110 *111 * @param array $block Block to render.112 * @param string $expected_classes Expected output class attr string.113 * @param string $expected_styles Expected output styles attr string.114 */115 private function assert_styles_and_classes_match( $block, $expected_classes, $expected_styles ) {116 $styled_block = $this->render_example_block( $block );117 $class_list = $this->get_attribute_from_block( 'class', $styled_block );118 $style_list = $this->get_attribute_from_block( 'style', $styled_block );119 120 $this->assertSame( $expected_classes, $class_list, 'Class list does not match expected classes' );121 $this->assertSame( $expected_styles, $style_list, 'Style list does not match expected styles' );122 106 } 123 107 … … 197 181 198 182 $expected_classes = 'foo-bar-class wp-block-example has-text-color has-red-color has-background has-black-background-color'; 199 $expected_styles = ' test: style;';183 $expected_styles = 'margin-top: 2px'; 200 184 201 185 $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); … … 233 217 ); 234 218 235 $expected_styles = ' test: style;color:#000;background-color:#fff;';219 $expected_styles = 'color:#000;background-color:#fff;margin-top: 2px'; 236 220 $expected_classes = 'foo-bar-class wp-block-example has-text-color has-background'; 237 221 … … 265 249 266 250 $expected_classes = 'foo-bar-class wp-block-example has-background has-red-gradient-background'; 267 $expected_styles = ' test: style;';251 $expected_styles = 'margin-top: 2px'; 268 252 269 253 $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); … … 296 280 297 281 $expected_classes = 'foo-bar-class wp-block-example has-background'; 298 $expected_styles = ' test: style; background:some-gradient-style;';282 $expected_styles = 'background:some-gradient-style;margin-top: 2px'; 299 283 300 284 $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); … … 332 316 333 317 $expected_classes = 'foo-bar-class wp-block-example'; 334 $expected_styles = ' test: style;';318 $expected_styles = 'margin-top: 2px'; 335 319 336 320 $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); … … 362 346 363 347 $expected_classes = 'foo-bar-class wp-block-example has-large-font-size'; 364 $expected_styles = ' test: style;';348 $expected_styles = 'margin-top: 2px'; 365 349 366 350 $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); … … 392 376 393 377 $expected_classes = 'foo-bar-class wp-block-example'; 394 $expected_styles = ' test: style; font-size:10px;';378 $expected_styles = 'font-size:10px;margin-top: 2px'; 395 379 396 380 $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); … … 419 403 420 404 $expected_classes = 'foo-bar-class wp-block-example'; 421 $expected_styles = ' test: style;';405 $expected_styles = 'margin-top: 2px'; 422 406 423 407 $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); … … 449 433 450 434 $expected_classes = 'foo-bar-class wp-block-example'; 451 $expected_styles = ' test: style; line-height:10;';435 $expected_styles = 'line-height:10;margin-top: 2px'; 452 436 453 437 $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); … … 475 459 476 460 $expected_classes = 'foo-bar-class wp-block-example'; 477 $expected_styles = ' test: style;';461 $expected_styles = 'margin-top: 2px'; 478 462 479 463 $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); … … 503 487 504 488 $expected_classes = 'foo-bar-class wp-block-example alignwide'; 505 $expected_styles = ' test: style;';489 $expected_styles = 'margin-top: 2px'; 506 490 507 491 $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); … … 529 513 530 514 $expected_classes = 'foo-bar-class wp-block-example'; 531 $expected_styles = ' test: style;';515 $expected_styles = 'margin-top: 2px'; 532 516 533 517 $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); … … 576 560 577 561 $expected_classes = 'foo-bar-class wp-block-example has-text-color has-background alignwide'; 578 $expected_styles = ' test: style; color:#000; background-color:#fff; font-size:10px; line-height:20;';562 $expected_styles = 'color:#000;background-color:#fff;font-size:10px;line-height:20;margin-top: 2px'; 579 563 580 564 $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); … … 619 603 620 604 $expected_classes = 'foo-bar-class wp-block-example'; 621 $expected_styles = ' test: style; font-size:10px;';605 $expected_styles = 'font-size:10px;margin-top: 2px'; 622 606 623 607 $this->assert_content_and_styles_and_classes_match( $block, $expected_classes, $expected_styles ); … … 644 628 ); 645 629 646 $expected_styles = ' test: style;';630 $expected_styles = 'margin-top: 2px'; 647 631 $expected_classes = 'foo-bar-class wp-block-example my-custom-classname'; 648 632 … … 672 656 ); 673 657 674 $expected_styles = ' test: style;';658 $expected_styles = 'margin-top: 2px'; 675 659 $expected_classes = 'foo-bar-class wp-block-example'; 676 660 … … 698 682 ); 699 683 700 $expected_styles = ' test: style;';684 $expected_styles = 'margin-top: 2px'; 701 685 $expected_classes = 'foo-bar-class'; 702 686 … … 765 749 $this->assertEmpty( $errors, 'Libxml errors should be dropped.' ); 766 750 } 751 752 /** 753 * Ensures that style, class, id, and aria-label attributes are correctly merged or overridden 754 * in get_block_wrapper_attributes(). 755 * 756 * @ticket 64603 757 * @covers ::get_block_wrapper_attributes 758 * 759 * @dataProvider data_get_block_wrapper_attributes_merge_or_override 760 * 761 * @param array<string, mixed> $block_type_settings 762 * @param array<string, mixed> $block_attrs 763 * @param array<string, string> $extra_attributes 764 * @param string $expected_attribute 765 */ 766 public function test_get_block_wrapper_attributes_merge_and_override( array $block_type_settings, array $block_attrs, array $extra_attributes, string $expected_attribute ): void { 767 $block_name = 'core/example'; 768 $block_type_settings = array_merge( 769 array( 770 'attributes' => array(), 771 'render_callback' => true, 772 ), 773 $block_type_settings 774 ); 775 $this->register_block_type( $block_name, $block_type_settings ); 776 777 $block = array( 778 'blockName' => $block_name, 779 'attrs' => $block_attrs, 780 'innerBlock' => array(), 781 'innerContent' => array(), 782 'innerHTML' => array(), 783 ); 784 785 WP_Block_Supports::init(); 786 WP_Block_Supports::$block_to_render = $block; 787 788 $wrapper_attributes = get_block_wrapper_attributes( $extra_attributes ); 789 790 $this->assertSame( $expected_attribute, $wrapper_attributes ); 791 } 792 793 /** 794 * Data provider for test_get_block_wrapper_attributes_merge_and_override. 795 * 796 * @return array<string, array{ 797 * block_type_settings: array<string, mixed>, 798 * block_attrs: array<string, mixed>, 799 * extra_attributes: array<string, string>, 800 * expected_attribute: string 801 * }> Array of test cases. 802 */ 803 public function data_get_block_wrapper_attributes_merge_or_override(): array { 804 return array( 805 'extra style attributes are merged with block values' => array( 806 'block_type_settings' => array( 807 'supports' => array( 808 'color' => true, 809 ), 810 ), 811 'block_attrs' => array( 812 'style' => array( 813 'color' => array( 814 'text' => '#000', 815 ), 816 ), 817 ), 818 'extra_attributes' => array( 819 // Redundant trailing semicolons should be stripped 820 'style' => 'margin-top: 2px;;;', 821 ), 822 'expected_attribute' => 'style="color:#000;margin-top: 2px" class="wp-block-example has-text-color"', 823 ), 824 'extra class attributes are merged with block values' => array( 825 'block_type_settings' => array( 826 'supports' => array( 827 'color' => true, 828 ), 829 ), 830 'block_attrs' => array( 831 'style' => array( 832 'color' => array( 833 'text' => '#000', 834 ), 835 ), 836 ), 837 'extra_attributes' => array( 838 // Duplicate class names should be merged, and commas should be preserved. 839 'class' => 'extra-class extra,class has-text-color', 840 ), 841 'expected_attribute' => 'style="color:#000" class="extra-class extra,class has-text-color wp-block-example"', 842 ), 843 'extra attributes override block-generated id' => array( 844 'block_type_settings' => array( 845 'supports' => array( 846 'anchor' => true, 847 ), 848 ), 849 'block_attrs' => array( 850 'anchor' => 'block-id', 851 ), 852 'extra_attributes' => array( 853 'id' => 'user-id', 854 ), 855 'expected_attribute' => 'class="wp-block-example" id="user-id"', 856 ), 857 'block-generated id is used when no extra provided' => array( 858 'block_type_settings' => array( 859 'supports' => array( 860 'anchor' => true, 861 ), 862 ), 863 'block_attrs' => array( 864 'anchor' => 'block-id', 865 ), 866 'extra_attributes' => array(), 867 'expected_attribute' => 'class="wp-block-example" id="block-id"', 868 ), 869 'extra attributes override block-generated aria-label' => array( 870 'block_type_settings' => array( 871 'supports' => array( 872 'ariaLabel' => true, 873 ), 874 ), 875 'block_attrs' => array( 876 'ariaLabel' => 'Block aria-label', 877 ), 878 'extra_attributes' => array( 879 'aria-label' => 'User aria-label', 880 ), 881 'expected_attribute' => 'class="wp-block-example" aria-label="User aria-label"', 882 ), 883 'block-generated aria-label is used when no extra provided' => array( 884 'block_type_settings' => array( 885 'supports' => array( 886 'ariaLabel' => true, 887 ), 888 ), 889 'block_attrs' => array( 890 'ariaLabel' => 'Block aria-label', 891 ), 892 'extra_attributes' => array(), 893 'expected_attribute' => 'class="wp-block-example" aria-label="Block aria-label"', 894 ), 895 ); 896 } 767 897 }
Note: See TracChangeset
for help on using the changeset viewer.