diff --git a/src/wp-includes/block-supports/layout.php b/src/wp-includes/block-supports/layout.php index dc3b56c0171c5..3036c581fd67b 100644 --- a/src/wp-includes/block-supports/layout.php +++ b/src/wp-includes/block-supports/layout.php @@ -237,7 +237,7 @@ function wp_get_child_layout_style_rules( $selector, $child_layout, $parent_layo $column_start_number = floatval( $column_start ); $parent_column_width = $minimum_column_width ? $minimum_column_width : '12rem'; $parent_column_value = floatval( $parent_column_width ); - $parent_column_unit = explode( $parent_column_value, $parent_column_width ); + $parent_column_unit = explode( (string) $parent_column_value, $parent_column_width ); $num_cols_to_break_at = 2; if ( $column_span_number && $column_start_number ) { diff --git a/src/wp-includes/block-supports/shadow.php b/src/wp-includes/block-supports/shadow.php index 4c09ce9d08f0f..272eb87407099 100644 --- a/src/wp-includes/block-supports/shadow.php +++ b/src/wp-includes/block-supports/shadow.php @@ -25,13 +25,13 @@ function wp_register_shadow_support( $block_type ) { $block_type->attributes = array(); } - if ( array_key_exists( 'style', $block_type->attributes ) ) { + if ( ! array_key_exists( 'style', $block_type->attributes ) ) { $block_type->attributes['style'] = array( 'type' => 'object', ); } - if ( array_key_exists( 'shadow', $block_type->attributes ) ) { + if ( ! array_key_exists( 'shadow', $block_type->attributes ) ) { $block_type->attributes['shadow'] = array( 'type' => 'string', ); diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 08beac3cd4923..b254e3c95b0a0 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -496,7 +496,7 @@ private static function colord_parse_hsla_string( $input ) { $hsla = self::colord_clamp_hsla( array( - 'h' => self::colord_parse_hue( $match[1], $match[2] ), + 'h' => self::colord_parse_hue( (float) $match[1], $match[2] ), 's' => (float) $match[3], 'l' => (float) $match[4], 'a' => '' === $match[5] ? 1 : (float) $match[5] / ( $match[6] ? 100 : 1 ), diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 34c737bb0d1a7..e3f0721343205 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -24,6 +24,7 @@ class WP_Theme_JSON { * * @since 5.8.0 * @var array + * @phpstan-var array{ version?: int, settings?: array, styles?: array, ... } */ protected $theme_json = null; @@ -3187,6 +3188,8 @@ protected static function flatten_tree( $tree, $prefix = '', $token = '--' ) { * @param string $selector The style block selector. * @param bool $use_root_padding Whether to add custom properties at root level. * @return array Returns the modified $declarations. + * + * @phpstan-return list */ protected static function compute_style_properties( $styles, $settings = array(), $properties = null, $theme_json = null, $selector = null, $use_root_padding = null ) { if ( empty( $styles ) ) { @@ -6052,11 +6055,14 @@ protected static function get_block_element_selectors( $root_selector ) { * * @since 6.3.0 * - * @param array $metadata The related block metadata containing selectors. - * @param array $node A merged theme.json node for block or variation. Features - * promoted to their own selector are removed from it. - * @return array The style declarations for the node's features with custom - * selectors. + * @param array $metadata The related block metadata containing selectors. + * @param array $node A merged theme.json node for block or variation. Features + * promoted to their own selector are removed from it. + * @return array The style declarations for the node's features with custom + * selectors, keyed by selector. + * + * @phpstan-param array{ selectors?: array> } $metadata + * @phpstan-return array> */ protected function get_feature_declarations_for_node( $metadata, &$node ) { $declarations = array(); @@ -6076,9 +6082,10 @@ protected function get_feature_declarations_for_node( $metadata, &$node ) { continue; } - if ( is_array( $feature_selectors ) ) { + if ( is_array( $feature_selectors ) && is_array( $node[ $feature ] ) ) { + $feature_styles = $node[ $feature ]; foreach ( $feature_selectors as $subfeature => $subfeature_selector ) { - if ( 'root' === $subfeature || empty( $node[ $feature ][ $subfeature ] ) ) { + if ( 'root' === $subfeature || empty( $feature_styles[ $subfeature ] ) ) { continue; } @@ -6088,7 +6095,7 @@ protected function get_feature_declarations_for_node( $metadata, &$node ) { */ $subfeature_node = array( $feature => array( - $subfeature => $node[ $feature ][ $subfeature ], + $subfeature => $feature_styles[ $subfeature ], ), ); @@ -6109,8 +6116,9 @@ protected function get_feature_declarations_for_node( $metadata, &$node ) { * styles will be included under its own selector not the * block's. */ - unset( $node[ $feature ][ $subfeature ] ); + unset( $feature_styles[ $subfeature ] ); } + $node[ $feature ] = $feature_styles; } /* diff --git a/tests/phpstan/baselines/argument.type.neon b/tests/phpstan/baselines/argument.type.neon index 5438195438f19..a8beb0366a515 100644 --- a/tests/phpstan/baselines/argument.type.neon +++ b/tests/phpstan/baselines/argument.type.neon @@ -653,11 +653,6 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-includes/author-template.php - - - message: '#^Parameter \#1 \$separator of function explode expects string, float given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/block-supports/layout.php - message: '#^Parameter \#1 \$block of function filter_block_kses expects WP_Block_Parser_Block, array given\.$#' identifier: argument.type @@ -733,11 +728,6 @@ parameters: identifier: argument.type count: 3 path: ../../../src/wp-includes/class-wp-date-query.php - - - message: '#^Parameter \#1 \$value of static method WP_Duotone\:\:colord_parse_hue\(\) expects float, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/class-wp-duotone.php - message: '#^Parameter \#1 \$postarr of function wp_insert_post expects array\{ID\?\: int, post_author\?\: int, post_date\?\: string, post_date_gmt\?\: string, post_content\?\: string, post_content_filtered\?\: string, post_title\?\: string, post_excerpt\?\: string, \.\.\., \.\.\.\}, array\ given\.$#' identifier: argument.type diff --git a/tests/phpunit/tests/block-supports/shadow.php b/tests/phpunit/tests/block-supports/shadow.php index bc2bb53b10ea4..5376d3f6be78a 100644 --- a/tests/phpunit/tests/block-supports/shadow.php +++ b/tests/phpunit/tests/block-supports/shadow.php @@ -3,6 +3,11 @@ * @group block-supports * * @covers ::wp_apply_shadow_support + * + * @phpstan-type Shadow_Attributes array{ + * style?: array{ type: 'object', default?: array{ shadow: non-empty-string } }, + * shadow?: array{ type: 'string', default?: non-empty-string }, + * } */ class Tests_Block_Supports_Shadow extends WP_UnitTestCase { /** @@ -47,6 +52,94 @@ private function register_shadow_block_with_support( $block_name, $supports = ar return $registry->get_registered( $this->test_block_name ); } + /** + * Tests that shadow block support attribute registration works as expected. + * + * @ticket 65817 + * + * @covers ::wp_register_shadow_support + * + * @dataProvider data_wp_register_shadow_support + * + * @param bool $support Shadow block support configuration. + * @param Shadow_Attributes|null $value Attributes array for the block. + * @param Shadow_Attributes $expected Expected attributes for the block. + */ + public function test_wp_register_shadow_support( bool $support, ?array $value, array $expected ) { + $this->test_block_name = 'test/shadow-attributes'; + register_block_type( + $this->test_block_name, + array( + 'api_version' => 3, + 'supports' => array( 'shadow' => $support ), + 'attributes' => $value, + ) + ); + $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $this->test_block_name ); + $this->assertInstanceOf( WP_Block_Type::class, $block_type ); + + wp_register_shadow_support( $block_type ); + + $actual = $block_type->attributes; + $this->assertIsArray( $actual ); + $expected = array_merge( WP_Block_Type::GLOBAL_ATTRIBUTES, $expected ); + $this->assertSameSetsWithIndex( $expected, $actual ); + } + + /** + * Data provider for {@see self::test_wp_register_shadow_support()}. + * + * @return array + */ + public static function data_wp_register_shadow_support(): array { + return array( + 'style and shadow attributes are registered when block supports shadow' => array( + 'support' => true, + 'value' => null, + 'expected' => array( + 'style' => array( + 'type' => 'object', + ), + 'shadow' => array( + 'type' => 'string', + ), + ), + ), + 'no attributes are registered when block does not support shadow' => array( + 'support' => false, + 'value' => null, + 'expected' => array(), + ), + 'existing style and shadow attributes are not overwritten' => array( + 'support' => true, + 'value' => array( + 'style' => array( + 'type' => 'object', + 'default' => array( + 'shadow' => 'var:preset|shadow|natural', + ), + ), + 'shadow' => array( + 'type' => 'string', + 'default' => 'natural', + ), + ), + 'expected' => array( + 'style' => array( + 'type' => 'object', + 'default' => array( + 'shadow' => 'var:preset|shadow|natural', + ), + ), + 'shadow' => array( + 'type' => 'string', + 'default' => 'natural', + ), + ), + ), + ); + } + /** * Tests the generation of shadow block support styles. *