Repository navigation
Style Engine: Improve PHPStan types and avoid fatal errors when storing rules - #15823
westonruter wants to merge 6 commits into
Conversation
`WP_Style_Engine::parse_block_styles()` passes the value found at each definition's `path` to `is_valid_style_value()` and `get_classnames()` for every definition, not just those with classnames. Those values are often not strings: spacing and border radius values are arrays, font weights and text columns can be numbers, and block attributes are unvalidated. `get_slug_from_preset_value()` receives the same value and already guards it with `is_string()`. Document `$style_value` as `mixed` on all three methods instead of `string`, matching `get_css_declarations()`. Also add PHPStan types to `get_classnames()`: a shape for the `classnames` key it reads from `$style_definition`, and a `list<string>` return type. Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com> Claude-Code-Session-Id: 1064defd-b2b0-40d4-bfca-0c5b60899c05
…ADATA
Wrap the docblock mentions of the constant in
`{@see self::BLOCK_STYLE_DEFINITIONS_METADATA}` so the developer docs
link to it, and qualify the mention in the inline comment in
`WP_Style_Engine::get_classnames()`.
Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com>
Claude-Code-Session-Id: 1064defd-b2b0-40d4-bfca-0c5b60899c05
Add a `Style_Definition` PHPStan type alias to `WP_Style_Engine`, describing one entry of `BLOCK_STYLE_DEFINITIONS_METADATA`, and use it for the constant and for every method that receives a definition. This gives PHPStan the shapes of `property_keys`, `path`, `css_vars`, `classnames`, and `value_func`. Document the remaining raw style value parameters as `mixed`, since `parse_block_styles()` passes whatever is found at the definition's `path`, and the parsers already check its type. With the types in place, a few small code changes keep the analysis sound without changing behavior for valid definitions: * Read the sibling definition in `get_individual_property_css_declarations()` from the constant directly, instead of through `_wp_array_get()`, which loses its type. * Return early from `get_css_declarations()` when a definition has neither a callable `value_func` nor `property_keys`, rather than reading an undefined index. * Only build a `url()` value in `get_url_or_value_css_declaration()` when the value is an array with a string `url`. Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com> Claude-Code-Session-Id: 1064defd-b2b0-40d4-bfca-0c5b60899c05
`WP_Style_Engine::store_css_rule()` rejects an empty selector, but `WP_Style_Engine_CSS_Rules_Store::add_rule()` trims the selector and returns nothing when the result is empty. A selector made only of whitespace therefore passed the first check and then called `add_declarations()` on null, which is a fatal error. It is reachable from `wp_style_engine_get_stylesheet_from_css_rules()` when a `context` is passed. Skip storing the rule when no store or rule is returned, and declare the method's `void` return type. Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com> Claude-Code-Session-Id: 1064defd-b2b0-40d4-bfca-0c5b60899c05
`get_css_declarations()` and `get_individual_property_css_declarations()` are documented to return `string[]`, but they passed raw block style values through unchanged, so a numeric value such as `textColumns: 2` or a padding side of `5` ended up in the declarations as an integer. `WP_Style_Engine_CSS_Declarations::add_declaration()` already drops non-string values, so they never reached the compiled CSS; they only leaked into the `declarations` array returned by `wp_style_engine_get_styles()`. Skip non-string values in both methods, so the return type holds. The compiled CSS is unchanged. Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com> Claude-Code-Session-Id: 1064defd-b2b0-40d4-bfca-0c5b60899c05
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. Props Bot commandsYou can trigger Props Bot actions by commenting on this PR:
|
ramonjd
left a comment
There was a problem hiding this comment.
Thanks for taking care of these improvements.
| 'top' => 5, | ||
| 'left' => '1em', | ||
| ), | ||
| ), |
There was a problem hiding this comment.
Optional: Maybe add border.top.width: 5 to cover the individual properties for that style?
There was a problem hiding this comment.
Could you amend the PR with what you have in mind?
| /** | ||
| * Tests that non-string style values are left out of the returned declarations, | ||
| * since {@see WP_Style_Engine_CSS_Declarations::add_declaration()} would drop them from the CSS anyway. | ||
| * |
There was a problem hiding this comment.
Not sure if this and above needs @ticket
There was a problem hiding this comment.
Since the only ticket is the catch-all Core-65817 for PHPStan fixes, I don't think it would be helpful.
Improves the PHPStan types in
WP_Style_Engine, bringingsrc/wp-includes/style-engine/class-wp-style-engine.phpfrom 36 errors to none at level 10, and fixes a fatal error found along the way. This syncs the Style Engine changes from WordPress/gutenberg#86105 and WordPress/gutenberg#86468.Types
Style_DefinitionPHPStan type alias for one entry ofWP_Style_Engine::BLOCK_STYLE_DEFINITIONS_METADATA, and use it for the constant and for every method that receives a definition.$style_valueparameters asmixedrather thanstringorarray.parse_block_styles()passes whatever is found at a definition'spathto every definition, so spacing and border radius values arrive as arrays, and numeric settings such astextColumnscan be integers. The methods already check the type themselves.get_classnames()alist<string>return type, and link the docblock references to{@see self::BLOCK_STYLE_DEFINITIONS_METADATA}.Behavior
WP_Style_Engine::store_css_rule()rejected an empty selector, butWP_Style_Engine_CSS_Rules_Store::add_rule()trims it and returns nothing when the result is empty. A selector of only whitespace therefore calledadd_declarations()on null, a fatal error reachable fromwp_style_engine_get_stylesheet_from_css_rules()when acontextis passed. It now skips storing the rule. A non-string store name fataled the same way, since the store lookup returned null.get_css_declarations()andget_individual_property_css_declarations()now skip non-string values, so their documentedstring[]return type holds.WP_Style_Engine_CSS_Declarations::add_declaration()already dropped those values, so the compiled CSS is unchanged; they only leaked into thedeclarationsarray returned bywp_style_engine_get_styles()._wp_array_get(), a definition withoutproperty_keysreturns no declarations instead of reading an undefined index, andurl()is only built from a stringurl.New tests cover the whitespace selector and the non-string values.
The Navigation block change in the Gutenberg PR is not included here, since
src/wp-includes/blocks/navigation.phpis updated through the Gutenberg package bump.Trac ticket: https://core.trac.wordpress.org/ticket/65817
Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5.5 (medium effort)
Used for: Investigating the PHPStan errors, drafting the type changes, fixes, and tests, and syncing them between Gutenberg and Core; reviewed and directed by me.
This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.