Repository navigation
Narrow types and sync WP_Theme_JSON_Gutenberg::get_feature_declarations_for_node() with core - #68407
Conversation
|
This file also needs updating: https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-includes/class-wp-theme-json.php#L4328 |
…e_declarations_for_node()
2f799a2 to
dd4f7d3
Compare
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both parameters of `get_feature_declarations_for_node()` only ever receive arrays. This syncs the `@param` tags with `WP_Theme_JSON` in WordPress core as of r63426, which corrected both from `object` and noted that the by-reference `$node` has its promoted features removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Describe the shapes `WP_Theme_JSON_Gutenberg::get_feature_declarations_for_node()` works with: the `selectors` it reads from the block metadata map each feature to a selector string or to a map of subfeature selectors, the node is a theme.json node keyed by feature, and the returned declarations are keyed by selector. Each declaration list uses the same shape that `get_state_declarations_with_text_clip_escapes()` already documents. This resolves the PHPStan errors on mixed offsets and iteration inside the method at the higher rule levels. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The block metadata passed to `get_feature_declarations_for_node()` is a string-keyed array, just like the node, so say so in the plain `@param` tag as well. The `@phpstan-param` shape still describes the `selectors` key the method reads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fix is being brought to core in WordPress/wordpress-develop#14862, along with the related PHPStan fixes from three other Gutenberg PRs, which share this entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`get_feature_declarations_for_node()` only checked that the feature's selectors were an array before reading `$node[ $feature ][ $subfeature ]`, but the node comes from theme.json data, where the feature value may be a string or another non-array value. Such a value has no subfeatures, and `empty()` already treated every lookup on it as empty, so skipping the subfeature loop for it keeps the behavior the same while making the check explicit. This resolves the PHPStan error for accessing an offset on `mixed`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Checking `is_array( $node[ $feature ] )` was not enough for PHPStan, since unsetting `$node[ $feature ][ $subfeature ]` inside the loop made it forget the narrowed type on the next iteration. Copy the feature styles to a local variable, read and unset the subfeatures there, and write the copy back to the node after the loop, which leaves the node exactly as before. This resolves the PHPStan error for accessing an offset on `mixed`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the theme.json data has no `settings`, `get_styles_for_block()` and `get_feature_declarations_for_node()` fell back to `null`, which was then passed on as the settings to `compute_style_properties()` and the other style helpers, all of which expect an array. Core has always fallen back to an empty array here, so do the same. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Give the `$theme_json` property a `@phpstan-var` shape for its top-level `version`, `settings`, and `styles` keys, leaving it open to the others. Reading `$this->theme_json['settings']` or `['styles']` then yields an array rather than `mixed`, which resolves the PHPStan errors at the higher rule levels where these are passed to `compute_style_properties()` and the other style helpers, or have offsets read from them. The methods that build the data still return a plain `array`, so the assignments to the property are now reported instead, until those return types are narrowed as well. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Give `compute_style_properties()` a `@phpstan-return` with the same declaration shape that `get_state_declarations_with_text_clip_escapes()` documents. Its callers, including `get_feature_declarations_for_node()`, then see a list of declarations rather than a plain array, which resolves their PHPStan errors at the higher rule levels. This moves some errors elsewhere at those levels: to the method's own body, whose property names come from the untyped `$properties` parameter and whose font size value may be `null` as far as PHPStan can tell, and to the callers that pass a declaration value to `is_safe_css_declaration()`, which expects a string. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Now that `get_styles_for_block()` falls back to an empty settings array, `$settings` is never `null`, so the `?? array()` when passing it to `get_state_base_styles()` is redundant. Drop it, as core does. This resolves the PHPStan error that the variable on the left side of `??` always exists and is not nullable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bring over the documentation differences from `WP_Theme_JSON::get_feature_declarations_for_node()` in core: the punctuation in the summary, the `@since` tag, no blank line between the `@param` and `@return` tags, and multi-line comments in the `/* */` style instead of consecutive `//` lines. The method is now identical to core's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The `@since 6.3.0` tag brought over from core refers to the WordPress release that added the method, which is meaningless for the plugin's copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
🤖 Comment by Claude Opus 5.5
At PHPStan level 5 this fixes 12 errors and introduces none. At level 10 the total drops from 3183 to 3136. The last two commits move some errors to the boundaries: assignments to Since this goes beyond r63426, it is being brought to core in WordPress/wordpress-develop#14862, along with three related PHPStan fixes, under Core-65817; the backport changelog entry was added for it. |
🤖 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 |
WP_Theme_JSON_Gutenberg::get_feature_declarations_for_node() with core
|
Difference between core and gutenberg's implementations of --- gutenberg.txt 2026-10-25 15:29:04
+++ core.txt 2026-10-25 15:29:20
@@ -3,6 +3,8 @@
* typography etc. that have custom selectors in their related block's
* metadata.
*
+ * @since 6.3.0
+ *
* @param array<string, mixed> $metadata The related block metadata containing selectors.
* @param array<string, mixed> $node A merged theme.json node for block or variation. Features
* promoted to their own selector are removed from it. |
|
🤖 Comment by Claude Opus 5.5 A clarification on the
So both originally fell back to |
| $use_root_padding = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments']; | ||
| $selector = $block_metadata['selector']; | ||
| $settings = $this->theme_json['settings'] ?? null; | ||
| $settings = $this->theme_json['settings'] ?? array(); |
There was a problem hiding this comment.
🤖 Comment by Claude Opus 5.5
Core has used an array() fallback here since r56709, while Gutenberg kept null from #51116. See #68407 (comment) for the full history.
|
🤖 Comment by Claude Opus 5.5 Similarly, the history of the
The So the call-site |
| * Otherwise just compute the styles for the default selector as normal. | ||
| */ | ||
| $base_styles = self::get_state_base_styles( $block_metadata['path'] ?? array(), $this->theme_json, $settings ?? array() ); | ||
| $base_styles = self::get_state_base_styles( $block_metadata['path'] ?? array(), $this->theme_json, $settings ); |
There was a problem hiding this comment.
🤖 Comment by Claude Opus 5.5
The ?? array() here was added in #85057 to work around $settings possibly being null; core passes $settings as is. See #68407 (comment) for the full history.
| } | ||
|
|
||
| $settings = $this->theme_json['settings'] ?? null; | ||
| $settings = $this->theme_json['settings'] ?? array(); |
There was a problem hiding this comment.
🤖 Comment by Claude Opus 5.5
Same as in get_styles_for_block(): core has used an array() fallback here since r56709, while Gutenberg kept null from #51116. See #68407 (comment) for the full history.
Initially fixed in WordPress/wordpress-develop@b915feb and then fix further applied in WordPress/wordpress-develop#14862 |
These fixes were made in Gutenberg while resolving the PHPStan errors in the plugin, ahead of adding PHPStan to its CI, and are brought to core to keep the two codebases in sync. They were developed in: * WordPress/gutenberg#68398 * WordPress/gutenberg#68404 * WordPress/gutenberg#68405 * WordPress/gutenberg#68407 The first one fixes a bug in core. Since r56046 the `array_key_exists()` checks in `wp_register_shadow_support()` have lacked their negation, so a block type with shadow support but no `style` or `shadow` attribute never had them registered, while one that already defined them had its definitions replaced, dropping any `default`. Gutenberg already had the negation. Tests are added for the attribute registration. The others make implicit type conversions explicit in the layout and duotone code, and narrow the types used by `WP_Theme_JSON::get_feature_declarations_for_node()` so that it reports no errors even at PHPStan rule level 10. Since the node comes from `theme.json` data, that method now also checks that a feature is an array before reading its subfeatures. This fixes a fatal error ("Cannot unset string offsets") when a feature's value is a string, such as a `shadow`, and the block's selectors for that feature are a list rather than keyed by subfeature name, since each numeric key then reads a character of the string instead of a subfeature. The baseline entries for the resolved errors are removed. Developed in #14862. Follow-up to r56046, r56058, r56101, r62478, r63426. Props justlevine, westonruter, poena, ramonopoly. See #65817. git-svn-id: https://develop.svn.wordpress.org/trunk@64727 602fd350-edb4-49c9-b593-d223f7449a82
These fixes were made in Gutenberg while resolving the PHPStan errors in the plugin, ahead of adding PHPStan to its CI, and are brought to core to keep the two codebases in sync. They were developed in: * WordPress/gutenberg#68398 * WordPress/gutenberg#68404 * WordPress/gutenberg#68405 * WordPress/gutenberg#68407 The first one fixes a bug in core. Since r56046 the `array_key_exists()` checks in `wp_register_shadow_support()` have lacked their negation, so a block type with shadow support but no `style` or `shadow` attribute never had them registered, while one that already defined them had its definitions replaced, dropping any `default`. Gutenberg already had the negation. Tests are added for the attribute registration. The others make implicit type conversions explicit in the layout and duotone code, and narrow the types used by `WP_Theme_JSON::get_feature_declarations_for_node()` so that it reports no errors even at PHPStan rule level 10. Since the node comes from `theme.json` data, that method now also checks that a feature is an array before reading its subfeatures. This fixes a fatal error ("Cannot unset string offsets") when a feature's value is a string, such as a `shadow`, and the block's selectors for that feature are a list rather than keyed by subfeature name, since each numeric key then reads a character of the string instead of a subfeature. The baseline entries for the resolved errors are removed. Developed in WordPress/wordpress-develop#14862. Follow-up to r56046, r56058, r56101, r62478, r63426. Props justlevine, westonruter, poena, ramonopoly. See #65817. Built from https://develop.svn.wordpress.org/trunk@64727 git-svn-id: http://core.svn.wordpress.org/trunk@63877 1a063a9b-81f0-0310-95a4-ce76da25c4cd
What?
This PR fixes the
$metadataparam type forWP_Theme_JSON_Gutenberg::get_feature_declarations_for_node()so it correctly expects anarraytype instead of aobject.Why?
While this issue was surfaced by PHPStan (via #66693) it can be remediated independently as part of #66598
How?
Testing Instructions
Testing Instructions for Keyboard
Screenshots or screencast