Repository navigation
Docs: Add class-level PHPStan annotations - #13891
swissspidy wants to merge 7 commits into
Conversation
Documents the magic properties of `WP_Theme` and `WP_Query` with `@phpstan-property-read`, along with `WP_Query::init_query_flags()` with `@phpstan-method`, and the element type of `WP_Block_List` with `@phpstan-implements ArrayAccess<int, WP_Block>`. The `WP_Theme` properties that come from `WP_Theme::get()`, `::display()` or `::get_screenshot()` include `false`, as those methods do. Marks `WP_Widget::update_callback()` and `::form_callback()` as `@final`, as their documentation says they are not to be overridden. See #65817. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VieGtSQtUoVfHiGwTmkvtc
|
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:
|
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The annotations match the documented runtime behavior, and the related baseline removals are consistent.
Review effort: Balanced
Findings: None
What changed in this PR
Adds accurate PHPStan metadata for magic APIs, block array access, and non-overridable widget callbacks while removing obsolete baseline suppressions.
Changes:
- Documents magic
WP_ThemeandWP_Querymembers. - Types
WP_Block_Listarray access. - Marks widget callbacks final for static analysis.
| File | Description |
|---|---|
src/wp-includes/class-wp-block-list.php |
Adds generic ArrayAccess types. |
src/wp-includes/class-wp-query.php |
Documents magic private members. |
src/wp-includes/class-wp-theme.php |
Types magic read-only properties. |
src/wp-includes/class-wp-widget.php |
Marks non-overridable callbacks. |
tests/phpstan/baselines/property.notFound.neon |
Removes resolved property suppressions. |
tests/phpstan/baselines/property.private.neon |
Removes resolved visibility suppressions. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
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. |
|
🤖 Comment by Claude Opus 5.5 Props for this subset, gathered from the full history of
Props for this PR (swissspidy for the split, westonruter for the review that shaped it): Generated by Claude Code |
Type WP_Theme::$parent_theme as string|false, since it comes from the parent theme's Name header, the same source as $name. Drop the @phpstan tags in WP_Block_List that repeat the canonical tags, and document the null offset of offsetSet() in the canonical @PARAM instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015BuoHZQvJMvPEYp4Sfjgvd
Use `@property-read` for the `WP_Theme` magic properties, as `WP_Comment` does, and align the property names. Type `WP_Query::$query_vars_hash` as `false|(lowercase-string&non-falsy-string)`. See #65817. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T3XYNUvB9sQNDXA14uJQeH
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`WP_Block_List` implements both `Iterator` and `ArrayAccess`, but only `ArrayAccess` was given its key and value types, so PHPStan still reported the generic `Iterator` as missing them, and iterating over a block list yielded untyped values. The iterator yields the same `WP_Block` instances as offset access, since `valid()` stops it before `current()` could return null. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The plain `@property-read` tags are published in the developer docs, so they now come first, separated by a blank line from the `@phpstan-type` alias, which only PHPStan reads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Members that `WP_Theme` and `WP_Query` serve through their magic methods were unknown to static analysis, so every access to one was reported as an undefined or private property and recorded in the PHPStan baselines. These are now declared at the class level: the `WP_Theme` properties with `@property-read`, since they are public back-compat API that belongs in the developer docs, and the private `WP_Query` members that its `$compat_fields` and `$compat_methods` expose with PHPStan-only tags. Where a `WP_Theme` property comes from a method that can return `false`, its type includes `false`, which surfaces a few existing cases in `WP_Debug_Data` that pass such a value on as a string. `WP_Block_List` declares the key and value types of the `Iterator` and `ArrayAccess` interfaces it implements, so that iterating over or indexing a block list yields `WP_Block` instances. The `WP_Widget::update_callback()` and `WP_Widget::form_callback()` methods are marked `@final`, as their documentation already says not to override them. The same note on `WP_Widget::display_callback()` is not enforced, since at least one popular plugin overrides it. The annotations are adopted from the function map of the php-stubs/wordpress-stubs package. Developed in #13891. Follow-up to r31151, r48159, r63020. Props swissspidy, marian1, westonruter. See #65817. git-svn-id: https://develop.svn.wordpress.org/trunk@64794 602fd350-edb4-49c9-b593-d223f7449a82
Members that `WP_Theme` and `WP_Query` serve through their magic methods were unknown to static analysis, so every access to one was reported as an undefined or private property and recorded in the PHPStan baselines. These are now declared at the class level: the `WP_Theme` properties with `@property-read`, since they are public back-compat API that belongs in the developer docs, and the private `WP_Query` members that its `$compat_fields` and `$compat_methods` expose with PHPStan-only tags. Where a `WP_Theme` property comes from a method that can return `false`, its type includes `false`, which surfaces a few existing cases in `WP_Debug_Data` that pass such a value on as a string. `WP_Block_List` declares the key and value types of the `Iterator` and `ArrayAccess` interfaces it implements, so that iterating over or indexing a block list yields `WP_Block` instances. The `WP_Widget::update_callback()` and `WP_Widget::form_callback()` methods are marked `@final`, as their documentation already says not to override them. The same note on `WP_Widget::display_callback()` is not enforced, since at least one popular plugin overrides it. The annotations are adopted from the function map of the php-stubs/wordpress-stubs package. Developed in WordPress/wordpress-develop#13891. Follow-up to r31151, r48159, r63020. Props swissspidy, marian1, westonruter. See #65817. Built from https://develop.svn.wordpress.org/trunk@64794 git-svn-id: http://core.svn.wordpress.org/trunk@63944 1a063a9b-81f0-0310-95a4-ce76da25c4cd
✅ Committed in r64794 (5eb7060).
Split out of #13530, as proposed in this comment (subset 4).
WP_Theme:@property-readfor the 14 magic properties that__get()serves. These are public back-compat API, so they use the plain tag, which is published in the developer docs.WP_Query:@phpstan-property-readfor$query_vars_changedand$query_vars_hash, and@phpstan-methodforinit_query_flags(). All three are private and are reached through the magic methods.WP_Block_List:@phpstan-implements Iterator<int, WP_Block>and@phpstan-implements ArrayAccess<int, WP_Block>.offsetSet()'s canonical@paramnow documents thenulloffset it handles for appending.WP_Widget::update_callback()and::form_callback():@final. Their documentation already says they are not to be overridden.Changes from #13530
These follow the review analysis:
WP_Themeproperties now includefalsewherever the underlying method can return it:name,title,version,descriptionandauthorcome fromWP_Theme::get()or::display().parent_themecomes from the parent theme'sget( 'Name' ).screenshotcomes from::get_screenshot().tagsisstring[]|falserather thanlist<string>, becausearray_filter()keeps the keys.@finalis dropped fromdisplay_callback(). Although its documentation also says "(Do NOT override)", at least one popular plugin overrides it.@phpstan-return voidtags onWP_Block_List::offsetSet()and::offsetUnset()are dropped.Changes after review
WP_Theme::$parent_themeisstring|false, like$name, which has the same source.@phpstan-param int $offsetand@phpstan-return WP_Block|nulltags on theWP_Block_Listoffset methods are dropped, since they repeated the canonical tags. ForoffsetSet(), the canonical@paramis corrected toint|nullinstead.WP_Block_Listalso declares the types of the genericIteratorit implements, which were otherwise still reported as missing.WP_Theme@property-readtags are placed before the@phpstan-type Theme_Keyalias.Effect on the analysis
composer run phpstanpasses. Theproperty.notFoundandproperty.privatebaselines lose theirWP_ThemeandWP_Queryentries. At level 10, compared against trunk, 27 errors are fixed and 4 are introduced. The 4 are inWP_Debug_Data, which passes the theme's name, version and author, now typedstring|false, to functions that expect a string.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
Used for: Splitting #13530 by tag kind, applying the corrections from the review analysis on #13530 and from review on this PR, checking each subset with
composer run phpstan(also at level 10, compared against trunk) andphpcs, and drafting the commit messages and this description. Reviewed 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.
🤖 Generated with Claude Code
https://claude.ai/code/session_015BuoHZQvJMvPEYp4Sfjgvd