Commit 3739c054f8 for wordpress.org
commit 3739c054f8ffa9e201e114a81c48533f33d49da2
Author: westonruter <westonruter@git.wordpress.org>
Date: Thu Nov 12 17:08:01 2026 +0000
Editor: Improve Style Engine types and avoid a fatal error.
A selector made only of whitespace passed the empty check in `WP_Style_Engine::store_css_rule()`, but the rules store trims it and returns no rule, so `add_declarations()` was called on null. This fatal error is reachable from `wp_style_engine_get_stylesheet_from_css_rules()` when a `context` is passed, and the rule is now skipped instead.
Raw style values are documented as `mixed`, since `parse_block_styles()` passes whatever is found at a definition's path to every definition, so spacing values arrive as arrays and settings such as `textColumns` as integers. A `Style_Definition` type alias describes each entry of `BLOCK_STYLE_DEFINITIONS_METADATA`. Non-string values are now left out of the returned declarations so the documented `string[]` return type holds; they were already dropped from the compiled CSS, which is unchanged.
These changes are synced from the Style Engine package in Gutenberg.
Developed in https://github.com/WordPress/wordpress-develop/pull/15823.
Follow-up to r54156, r56614, r58089.
Props westonruter, ramonopoly.
See #65817.
Built from https://develop.svn.wordpress.org/trunk@65438
git-svn-id: http://core.svn.wordpress.org/trunk@64577 1a063a9b-81f0-0310-95a4-ce76da25c4cd
diff --git a/wp-includes/style-engine/class-wp-style-engine.php b/wp-includes/style-engine/class-wp-style-engine.php
index 81499d15e5..2ccfdefa95 100644
--- a/wp-includes/style-engine/class-wp-style-engine.php
+++ b/wp-includes/style-engine/class-wp-style-engine.php
@@ -28,6 +28,14 @@
* @since 6.7.0 Added support for typography.writingMode.
* @since 7.0.0 Added support for typography.textIndent.
* @since 7.2.0 Added support for typography.textShadow.
+ *
+ * @phpstan-type Style_Definition array{
+ * property_keys?: array{ default: string, individual?: string },
+ * path: non-empty-list<string>,
+ * css_vars?: array<string, string>,
+ * classnames?: array<string, string|true>,
+ * value_func?: callable( mixed, array<string, mixed>, array<mixed> ): array<string, string>,
+ * }
*/
#[AllowDynamicProperties]
final class WP_Style_Engine {
@@ -59,7 +67,8 @@ final class WP_Style_Engine {
* @since 6.1.0
* @since 7.1.0 Added `background.gradient` property.
* @since 7.2.0 Added `background.backgroundClip` property.
- * @var array
+ * @var array<string, array<string, array>>
+ * @phpstan-var array<string, array<string, Style_Definition>>
*/
const BLOCK_STYLE_DEFINITIONS_METADATA = array(
'background' => array(
@@ -403,7 +412,7 @@ final class WP_Style_Engine {
*
* @since 6.1.0
*
- * @param string $style_value A single CSS preset value.
+ * @param mixed $style_value A single CSS preset value.
* @param string $property_key The CSS property that is the second element of the preset string.
* Used for matching.
* @return string The slug, or empty string if not found.
@@ -448,7 +457,7 @@ final class WP_Style_Engine {
*
* @since 6.1.0
*
- * @param string $style_value A single CSS preset value.
+ * @param mixed $style_value A single raw style value.
* @return bool
*/
protected static function is_valid_style_value( $style_value ) {
@@ -473,11 +482,21 @@ final class WP_Style_Engine {
* or a CSS nested @rule, such as `@media (min-width: 80rem)`
* or `@layer module`.
*/
- public static function store_css_rule( $store_name, $css_selector, $css_declarations, $rules_group = '' ) {
+ public static function store_css_rule( $store_name, $css_selector, $css_declarations, $rules_group = '' ): void {
if ( empty( $store_name ) || empty( $css_selector ) || empty( $css_declarations ) ) {
return;
}
- static::get_store( $store_name )->add_rule( $css_selector, $rules_group )->add_declarations( $css_declarations );
+
+ $store = static::get_store( $store_name );
+ if ( ! $store ) {
+ return;
+ }
+
+ // The rule is null when the selector is only whitespace.
+ $rule = $store->add_rule( $css_selector, $rules_group );
+ if ( $rule ) {
+ $rule->add_declarations( $css_declarations );
+ }
}
/**
@@ -495,12 +514,12 @@ final class WP_Style_Engine {
/**
* Returns classnames and CSS based on the values in a styles object.
*
- * Return values are parsed based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA.
+ * Return values are parsed based on the instructions in {@see self::BLOCK_STYLE_DEFINITIONS_METADATA}.
*
* @since 6.1.0
*
- * @param array $block_styles The style object.
- * @param array $options {
+ * @param array<string, mixed> $block_styles The style object.
+ * @param array $options {
* Optional. An array of options. Default empty array.
*
* @type bool $convert_vars_to_classnames Whether to skip converting incoming CSS var patterns,
@@ -567,10 +586,13 @@ final class WP_Style_Engine {
*
* @since 6.1.0
*
- * @param string $style_value A single raw style value or CSS preset property
+ * @param mixed $style_value A single raw style value or CSS preset property
* from the `$block_styles` array.
- * @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
+ * @param array $style_definition A single style definition from {@see self::BLOCK_STYLE_DEFINITIONS_METADATA}.
* @return string[] An array of CSS classnames, or empty array if there are none.
+ *
+ * @phpstan-param Style_Definition $style_definition
+ * @phpstan-return list<string>
*/
protected static function get_classnames( $style_value, $style_definition ) {
if ( empty( $style_value ) ) {
@@ -589,7 +611,7 @@ final class WP_Style_Engine {
if ( $slug ) {
/*
- * Right now we expect a classname pattern to be stored in BLOCK_STYLE_DEFINITIONS_METADATA.
+ * Right now we expect a classname pattern to be stored in self::BLOCK_STYLE_DEFINITIONS_METADATA.
* One day, if there are no stored schemata, we could allow custom patterns or
* generate classnames based on other properties
* such as a path or a value or a prefix passed in options.
@@ -608,7 +630,7 @@ final class WP_Style_Engine {
* @since 6.1.0
*
* @param mixed $style_value A single raw style value from $block_styles array.
- * @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
+ * @param array $style_definition A single style definition from {@see self::BLOCK_STYLE_DEFINITIONS_METADATA}.
* @param array $options {
* Optional. An array of options. Default empty array.
*
@@ -617,12 +639,18 @@ final class WP_Style_Engine {
* to `var( --wp--preset--* )` values. Default false.
* }
* @return string[] An associative array of CSS definitions, e.g. `array( "$property" => "$value", "$property" => "$value" )`.
+ *
+ * @phpstan-param Style_Definition $style_definition
*/
protected static function get_css_declarations( $style_value, $style_definition, $options = array() ) {
if ( isset( $style_definition['value_func'] ) && is_callable( $style_definition['value_func'] ) ) {
return call_user_func( $style_definition['value_func'], $style_value, $style_definition, $options );
}
+ if ( ! isset( $style_definition['property_keys'] ) ) {
+ return array();
+ }
+
$css_declarations = array();
$style_property_keys = $style_definition['property_keys'];
$should_skip_css_vars = isset( $options['convert_vars_to_classnames'] ) && true === $options['convert_vars_to_classnames'];
@@ -659,7 +687,7 @@ final class WP_Style_Engine {
$individual_property = sprintf( $style_property_keys['individual'], _wp_to_kebab_case( $key ) );
- if ( $individual_property && static::is_valid_style_value( $value ) ) {
+ if ( $individual_property && is_string( $value ) && static::is_valid_style_value( $value ) ) {
$css_declarations[ $individual_property ] = $value;
}
}
@@ -667,7 +695,10 @@ final class WP_Style_Engine {
return $css_declarations;
}
- $css_declarations[ $style_property_keys['default'] ] = $style_value;
+ // CSS declarations only accept string values.
+ if ( is_string( $style_value ) ) {
+ $css_declarations[ $style_property_keys['default'] ] = $style_value;
+ }
return $css_declarations;
}
@@ -689,8 +720,8 @@ final class WP_Style_Engine {
*
* @since 6.1.0
*
- * @param array $style_value A single raw style value from `$block_styles` array.
- * @param array $individual_property_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA
+ * @param mixed $style_value A single raw style value from `$block_styles` array.
+ * @param array $individual_property_definition A single style definition from {@see self::BLOCK_STYLE_DEFINITIONS_METADATA}
* representing an individual property of a CSS property,
* e.g. 'top' in 'border-top'.
* @param array $options {
@@ -701,6 +732,8 @@ final class WP_Style_Engine {
* to `var( --wp--preset--* )` values. Default false.
* }
* @return string[] An associative array of CSS definitions, e.g. `array( "$property" => "$value", "$property" => "$value" )`.
+ *
+ * @phpstan-param Style_Definition $individual_property_definition
*/
protected static function get_individual_property_css_declarations( $style_value, $individual_property_definition, $options = array() ) {
if ( ! is_array( $style_value ) || empty( $style_value ) || empty( $individual_property_definition['path'] ) ) {
@@ -721,17 +754,17 @@ final class WP_Style_Engine {
$css_declarations = array();
foreach ( $style_value as $css_property => $value ) {
- if ( empty( $value ) ) {
+ // CSS declarations only accept string values.
+ if ( empty( $value ) || ! is_string( $value ) ) {
continue;
}
- // Build a path to the individual rules in definitions.
- $style_definition_path = array( $definition_group_key, $css_property );
- $style_definition = _wp_array_get( static::BLOCK_STYLE_DEFINITIONS_METADATA, $style_definition_path, null );
+ // Get the corresponding style definition from the same group, e.g. `border.color`.
+ $style_definition = static::BLOCK_STYLE_DEFINITIONS_METADATA[ $definition_group_key ][ $css_property ] ?? null;
if ( $style_definition && isset( $style_definition['property_keys']['individual'] ) ) {
// Set a CSS var if there is a valid preset value.
- if ( is_string( $value ) && str_contains( $value, 'var:' )
+ if ( str_contains( $value, 'var:' )
&& ! $should_skip_css_vars && ! empty( $individual_property_definition['css_vars'] )
) {
$value = static::get_css_var_value( $value, $individual_property_definition['css_vars'] );
@@ -753,9 +786,12 @@ final class WP_Style_Engine {
*
* @since 6.4.0
*
- * @param array $style_value A single raw style value from $block_styles array.
- * @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
+ * @param mixed $style_value A single raw style value from $block_styles array.
+ * @param array $style_definition A single style definition from {@see self::BLOCK_STYLE_DEFINITIONS_METADATA}.
* @return string[] An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ).
+ *
+ * @phpstan-param Style_Definition $style_definition
+ * @phpstan-return array<string, string>
*/
protected static function get_url_or_value_css_declaration( $style_value, $style_definition ) {
if ( empty( $style_value ) ) {
@@ -767,7 +803,7 @@ final class WP_Style_Engine {
if ( isset( $style_definition['property_keys']['default'] ) ) {
$value = null;
- if ( ! empty( $style_value['url'] ) ) {
+ if ( is_array( $style_value ) && ! empty( $style_value['url'] ) && is_string( $style_value['url'] ) ) {
$value = "url('" . $style_value['url'] . "')";
} elseif ( is_string( $style_value ) ) {
$value = $style_value;
@@ -789,10 +825,11 @@ final class WP_Style_Engine {
*
* @since 7.2.0
*
- * @param string $style_value A single raw style value from $block_styles array.
- * @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
+ * @param mixed $style_value A single raw style value from $block_styles array.
+ * @param array $style_definition A single style definition from {@see self::BLOCK_STYLE_DEFINITIONS_METADATA}.
* @return array<string, string> An associative array of CSS definitions, mapping properties to values.
*
+ * @phpstan-param Style_Definition $style_definition
* @phpstan-return array<non-falsy-string, non-falsy-string>
*/
protected static function get_background_clip_css_declarations( $style_value, $style_definition ) {
diff --git a/wp-includes/version.php b/wp-includes/version.php
index a2799374f4..8cb5de9d60 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
-$wp_version = '7.2-beta5-65437';
+$wp_version = '7.2-beta5-65438';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.