Repository navigation
Theme JSON, Duotone: Fix return types and docblocks reported by PHPStan - #86103
Conversation
- Return `null` explicitly from `WP_Theme_JSON_Gutenberg::get_block_name_from_metadata_path()` when there is no path, as in Core. - Document that `get_block_selectors()` returns an array, as in Core. - Document the `$css` parameter of the deprecated, Gutenberg-only `get_block_custom_css()` as a string, which is what it passes on to `process_blocks_custom_css()`. - Document that `WP_Duotone_Gutenberg::get_all_global_style_block_names()` returns `string[]`, as in Core. Remove the 4 resolved entries from the PHPStan baseline. See WordPress#86088.
🤖 PR meta 🤖🎉 PropsIf you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. 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:
Updated as activity occurs, without notifying anyone named here. Add the |
…green # Conflicts: # tools/phpstan/baseline.neon
…ix/phpstan-lib-evergreen
…ck names `WP_Duotone_Gutenberg::get_all_global_style_block_names()` returns a map of block names to duotone preset slugs, matching the `$global_styles_block_names` property type. The method never returns `null`, since it initializes the property to an empty array before populating it, so only the property keeps the nullable type. Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com> Claude-Code-Session-Id: 7a12dabb-d901-4983-86e2-a9cbfedc1158
`WP_Theme_JSON_Gutenberg::get_block_selectors()` is only called with block types from `WP_Block_Type_Registry::get_all_registered()`, and it passes the value on to `wp_get_block_css_selector()`, which expects a `WP_Block_Type`. Replace the generic `object` type accordingly. Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com> Claude-Code-Session-Id: 7a12dabb-d901-4983-86e2-a9cbfedc1158
Mirror the array shape that core defines for `WP_Block_Type::$selectors`: an optional `root` selector string, plus selectors for block support features (such as `color` or `typography`), each either a selector string or an array of selectors keyed by subfeature. Document it as `array<string, string|array<string, string>>`, with the more specific `array{ root?: string, ...<string, string|array<string, string>> }` in `@phpstan-` tags, on:
- The return value of `WP_Theme_JSON_Gutenberg::get_block_selectors()`.
- The `selectors` key of the `$metadata` parameter of `WP_Theme_JSON_Gutenberg::get_feature_declarations_for_node()`.
- The `$feature_selectors` parameter of `WP_Theme_JSON_Gutenberg::get_state_declarations_with_text_clip_escapes()`.
- The `$block_selectors` parameter of `gutenberg_get_state_style_groups()`.
In `WP_Theme_JSON_Gutenberg::get_block_selectors()`, the default selectors are now built by prepending the `root` selector to the feature selectors, rather than adding the feature selectors after it. The keys and their order are unchanged, but a feature named `root` in a subclass's `BLOCK_SUPPORT_FEATURE_LEVEL_SELECTORS` can no longer replace the root selector string with an array.
At level 10, this resolves 4 PHPStan errors once the WordPress stubs include the core change. With the current stubs, `WP_Block_Type::$selectors` is still a plain `array`, so 2 errors remain where it is returned from `get_block_selectors()` and passed to `gutenberg_get_state_style_groups()`.
Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com>
Claude-Code-Session-Id: 7a12dabb-d901-4983-86e2-a9cbfedc1158
…green # Conflicts: # tools/phpstan/baseline.neon
…tors core PR Generate the stubs from the head of the wordpress-develop pull request that defines the array shape for `WP_Block_Type::$selectors`, which the selector types in `WP_Theme_JSON_Gutenberg` and `gutenberg_get_state_style_groups()` depend on. With these stubs, the two level 10 PHPStan errors where the property is returned from `get_block_selectors()` and passed to `gutenberg_get_state_style_groups()` are resolved. The level 5 baseline is unchanged. Regenerate the stubs with `--commit=trunk` once the core change is committed. Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com> Claude-Code-Session-Id: 7a12dabb-d901-4983-86e2-a9cbfedc1158
…aalmesbah/gutenberg into fix/phpstan-lib-evergreen Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com> Claude-Code-Session-Id: 7a12dabb-d901-4983-86e2-a9cbfedc1158
…le_groups()` Mirror the core change to `wp_get_state_style_groups()`. The `$state_style` parameter is a theme.json style object, keyed by style feature (such as `color` or `typography`), and each key is looked up in `$block_selectors`. Its values come from theme.json and are checked by the function itself, so they stay `mixed`. This resolves the `missingType.iterableValue` PHPStan error on the parameter. The caller, `gutenberg_get_block_state_style_rules()`, narrows each state style from `mixed` only with `is_array()`, so at level 10 it now reports an `argument.type` error for passing `array<mixed, mixed>`, which is a more accurate account of the untyped theme.json data. Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com> Claude-Code-Session-Id: 7a12dabb-d901-4983-86e2-a9cbfedc1158
Give `WP_Theme_JSON_Gutenberg::get_state_declarations_with_text_clip_escapes()` the same docblock layout as its core counterpart: plain `@param` types aligned in one column, with the precise types in `@phpstan-param` and `@phpstan-return` tags. This moves the selectors shape out of the `@param` for `$feature_selectors`, where it misaligned the column, and adds the declaration list shapes that core already documents for `$declarations` and the return value. Those shapes need the `name` of each escape declaration to be a `non-falsy-string`, so `gutenberg_get_state_text_clip_escape()` and `gutenberg_get_state_text_fill_reset()` now also have the `@phpstan-return array<non-falsy-string, non-falsy-string>` tags of their core counterparts. At level 10, this resolves the 2 `missingType.iterableValue` PHPStan errors on the method and introduces none. Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com> Claude-Code-Session-Id: 7a12dabb-d901-4983-86e2-a9cbfedc1158
The core change that defines the array shape for `WP_Block_Type::$selectors` was committed in r65318, so generate the stubs from that trunk commit instead of the pull request it was developed in. The level 5 baseline is unchanged. Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com> Claude-Code-Session-Id: 7a12dabb-d901-4983-86e2-a9cbfedc1158
…ct shapes `gutenberg_get_state_text_clip_escape()` only ever returns `background-image: unset` or nothing, and `gutenberg_get_state_text_fill_reset()` only ever returns `-webkit-text-fill-color: currentColor` or nothing, so document their return values with those exact shapes rather than as maps of non-empty strings. Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com> Claude-Code-Session-Id: 7a12dabb-d901-4983-86e2-a9cbfedc1158
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues remain, with the documented annotation, stub, and baseline updates addressing the identified changes.
No open issues 🎉
What changed in this PR
This pull request aligns Gutenberg’s Theme JSON, duotone, and block-state PHPStan annotations with WordPress Core, updates the generated stubs to revision r65318, and removes four resolved baseline suppressions.
Changes:
- Corrects return types and parameter documentation in Theme JSON and duotone code.
- Applies precise block-selector and state-declaration array shapes.
- Preserves root-selector precedence when constructing default selectors.
- Updates WordPress stubs and removes resolved PHPStan baseline entries.
- Review note: add focused tests covering root-first selector construction and subclass selector-key collisions.
| File | Description |
|---|---|
tools/phpstan/wordpress-stubs/composer.json |
Updates the generated WordPress stubs source revision to r65318. |
tools/phpstan/baseline.neon |
Removes the four resolved PHPStan suppressions while retaining unrelated ignores. |
lib/class-wp-theme-json-gutenberg.php |
Corrects Theme JSON documentation, return handling, selector shapes, and root-selector handling. |
lib/class-wp-duotone-gutenberg.php |
Corrects the global style block names return documentation. |
lib/block-supports/states.php |
Adds precise selector and state-declaration annotations. |
Review effort: Lite
What?
See #86088
Fixes return types and docblocks in
WP_Theme_JSON_GutenbergandWP_Duotone_Gutenbergreported by PHPStan, and removes the resolved entries from the PHPStan baseline. It also applies the array shape for block type selectors that was added to WordPress Core in r65318 (Core-65817, WordPress/wordpress-develop#15644).Why?
Three of these are already fixed in WordPress Core, so the Gutenberg classes were out of sync. The fourth is in a deprecated, Gutenberg-only method. This resolves 4 of the 226 errors initially baselined in #66693.
How?
WP_Theme_JSON_Gutenberg::get_block_name_from_metadata_path()fell off the end without a return value when there was no path. It now returns$block_metadata['path'][2] ?? null, matching Core. (return.missing)WP_Theme_JSON_Gutenberg::get_block_selectors()documented its$block_typeparameter asobject, but it is only called with block types from the registry and passes them towp_get_block_css_selector(), so it is now documented asWP_Block_Type, matching Core.WP_Theme_JSON_Gutenberg::get_block_custom_css()documented$cssasarray, but passes it toprocess_blocks_custom_css(), which expects a string. It is now documented asstring. (argument.type)WP_Duotone_Gutenberg::get_all_global_style_block_names()never returnsnull, so its@returnis nowarray<string, string>, keyed by block name. (return.unusedType) This is more precise than Core'sstring[], so it can be synced to Core later.tools/phpstan/baseline.neon.The block type selectors shape from Core is applied wherever Gutenberg passes the selectors along, matching Core's docblocks: the return value of
WP_Theme_JSON_Gutenberg::get_block_selectors(), theselectorskey ofget_feature_declarations_for_node()'s$metadata, and the parameters ofgutenberg_get_state_style_groups(). As in Core,get_block_selectors()now prepends the root selector to the default feature selectors, so that a feature namedrootcannot replace the root selector string with an array.The docblock of the Gutenberg-only
$feature_selectorsand$feature_declarationsparameters ofWP_Theme_JSON_Gutenberg::get_state_declarations_with_text_clip_escapes()now follows Core's layout, with the declaration list shapes that Core documents. Those need the names of the escape declarations to be non-empty strings, sogutenberg_get_state_text_clip_escape()andgutenberg_get_state_text_fill_reset()now document the exact declaration each returns, such asarray{ 'background-image'?: 'unset' }. This is more precise than thearray<non-falsy-string, non-falsy-string>that Core has on them, so it can be synced to Core later.The WordPress stubs for PHPStan are generated from Core trunk at r65318, so that the analysis knows the type of
WP_Block_Type::$selectors.The
method.childParameterTypeerror forWP_REST_Global_Styles_Controller_Gutenberg::prepare_links()is left as it is: Core has the same code and keeps the same entry in its baseline, and fixing it would change the method signature.There is no change in behavior.
Testing Instructions
composer phpstanand confirm it passes with no unmatched ignored errors.composer phpstan:baselinesand confirmtools/phpstan/baseline.neonhas no further changes.npm run test:unit:php -- -- --filter "WP_Theme_JSON|States|Duotone".Testing Instructions for Keyboard
Not applicable. There are no UI changes.
Screenshots or screencast
Not applicable.
Use of AI Tools
I used Claude Code to identify the affected occurrences and draft the change. I reviewed the diff and take responsibility for it.
Additional changes were made by @westonruter using Claude Code with Claude Opus 5.5 (medium effort): the block type selectors shape, the matching Core docblocks, and the stubs update.