Run PHPStan static analysis on a WordPress plugin or theme using `szepeviktor/phpstan-wordpress`. Covers the composer dev-dependencies and what is pulled transitively (`phpstan/phpstan` ^2.0, `php-stubs/wordpress-stubs`), the optional `phpstan/extension-installer` that auto-registers the extension, the `phpstan.neon.dist` config (level 0-10 / `max`, `paths`, the `vendor/szepeviktor/phpstan-wordpress/extension.neon` include when not using the installer), why WordPress needs stubs, adding WooCo...
Scanned 9/5/2026
Install to Claude Code
npx -y skills add Lonsdale201/wp-agent-skills --skill wp-phpstan-static-analysis --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Wp Phpstan Static Analysis?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/lonsdale201-wp-phpstan-static-analysis)More formats (shields.io, HTML) on the badges page.
---
name: wp-phpstan-static-analysis
description: >
Run PHPStan static analysis on a WordPress plugin or theme using
`szepeviktor/phpstan-wordpress`. Covers the composer dev-dependencies and what
is pulled transitively (`phpstan/phpstan` ^2.0, `php-stubs/wordpress-stubs`),
the optional `phpstan/extension-installer` that auto-registers the extension,
the `phpstan.neon.dist` config (level 0-10 / `max`, `paths`, the
`vendor/szepeviktor/phpstan-wordpress/extension.neon` include when not using
the installer), why WordPress needs stubs, adding WooCommerce stubs
(`php-stubs/woocommerce-stubs`) for cross-plugin analysis, the
`--generate-baseline` workflow for legacy code, common WP false positives the
extension fixes (apply_filters arg counts, is_wp_error narrowing, hook
callbacks, dynamic constants), and running with `--level` / `--memory-limit`.
Use when adding static analysis, writing phpstan.neon, raising the level, or
taming WP-specific PHPStan errors.
license: GPLv2-or-later
metadata:
wp-skills-author: "Soczó Kristóf"
wp-skills-contact: "mailto:lonsdale201@hotmail.com"
wp-skills-plugin: "wordpress"
wp-skills-plugin-version-tested: "7.1"
wp-skills-wp-version-tested: "7.1"
wp-skills-toolchain-tested: "PHPStan 2.2.5; phpstan-wordpress 2.0.3; wordpress-stubs 7.0.1"
wp-skills-php-min: "7.4"
wp-skills-last-updated: "2026-08-20"
---
# PHPStan static analysis for WordPress
PHPStan catches type errors, dead code, and bad calls without running anything. It doesn't load WordPress, so it needs **stubs** for core's functions/classes — `szepeviktor/phpstan-wordpress` provides those plus WP-aware rules. This skill wires it up and tames the WP-specific noise. PHPCS (`wp-phpcs-coding-standards`) covers style; PHPStan covers types/logic — run both.
## When to use this skill
- Adding static analysis to a plugin/theme.
- Writing or reviewing `phpstan.neon` / `phpstan.neon.dist`.
- Raising the analysis level on existing code (and baselining the backlog).
- Killing WP-specific false positives (`apply_filters` arg counts, `is_wp_error()`, `$wpdb`, conditional constants).
## Install
```bash
composer require --dev szepeviktor/phpstan-wordpress
composer require --dev phpstan/extension-installer # recommended: auto-registers the extension
```
`szepeviktor/phpstan-wordpress` (2.0.3) pulls in **`phpstan/phpstan` `^2.0`** and **`php-stubs/wordpress-stubs` `^6.6.2`** transitively — you don't normally add those yourself. It requires PHPStan 2.0+.
At the WordPress 7.1 audit date, the newest tagged `wordpress-stubs` release is
7.0.1. Composer can therefore analyze ordinary plugin code, but new 7.1-only
symbols may still be reported as unknown. Do not silence those errors broadly.
Feature-detect the API for older WordPress support and add a small reviewed
project stub for the missing 7.1 declaration, then remove it when an official
7.1 stubs package is available.
`phpstan/extension-installer` is a Composer plugin that auto-includes any installed `phpstan-extension` package's config, so you don't hand-wire the include. Composer 2.2+ needs it in `allow-plugins`:
```json
{
"config": {
"allow-plugins": {
"phpstan/extension-installer": true
}
}
}
```
## Configure (`phpstan.neon.dist`)
**With `extension-installer`**, the config is minimal — the extension auto-registers:
```neon
parameters:
level: 5
paths:
- my-plugin.php
- includes/
```
**Without `extension-installer`**, include the extension manually (exact path, verified):
```neon
includes:
- vendor/szepeviktor/phpstan-wordpress/extension.neon
parameters:
level: max
paths:
- my-plugin.php
- includes/
ignoreErrors:
# WP filter functions use func_get_args(); calling with extra args is fine.
- '#^Function apply_filters(_ref_array)? invoked with [34567] parameters, 2 required\.$#'
```
You normally do **not** set `bootstrapFiles` for WP core — the extension already loads `php-stubs/wordpress-stubs`. Add `bootstrapFiles` only for extra stubs (see WooCommerce below) or your own define-shims.
### Levels
PHPStan has **levels 0–10** (0 loosest, 10 strictest; level 10 was added in PHPStan 2.0). `max` is an alias for the highest. Start where the code passes (often 5), commit that, then raise one level at a time. Don't jump to `max` on a legacy plugin — baseline instead (below).
## Stubs, and cross-plugin analysis
PHPStan can't see WordPress, so `wordpress-stubs` supplies typed, implementation-free declarations of core functions/classes. The package is versioned to the WordPress version it was generated from.
To analyze code that calls **another plugin's** API (e.g. WooCommerce), add that plugin's stubs and register them:
```bash
composer require --dev php-stubs/woocommerce-stubs
```
```neon
parameters:
bootstrapFiles:
- vendor/php-stubs/woocommerce-stubs/woocommerce-stubs.php
```
`php-stubs/woocommerce-stubs` depends on `wordpress-stubs`, so WP stubs come along. Without the right stubs, PHPStan reports "unknown function/class" for every external call.
## The baseline workflow (legacy code)
Don't fight thousands of pre-existing errors. Snapshot them and only gate new/changed code:
```bash
vendor/bin/phpstan analyse --generate-baseline
```
This writes `phpstan-baseline.neon` (every current error). Include it:
```neon
includes:
- phpstan-baseline.neon
```
Now CI is green, but any **new** error fails the build. Over time, fix entries and regenerate a smaller baseline, or raise the level behind the baseline. This is how you adopt PHPStan (or a higher level) on an existing plugin without a giant rewrite.
## WP-specific false positives the extension handles
`phpstan-wordpress` fixes much of the usual WordPress noise:
- **`apply_filters()` "invoked with N parameters, 2 required"** — WP filters use `func_get_args()`. The extension's official example supplies the narrow `ignoreErrors` regex shown above; the installed `extension.neon` itself does not contain that ignore.
- **Loose return types** — dynamic return-type extensions narrow `apply_filters()`, `esc_sql()`, `wp_parse_url()`, `shortcode_atts()`, `wp_slash()`, and more.
- **`is_wp_error()` narrowing** — after `if ( is_wp_error( $x ) )`, PHPStan knows `$x` is a `WP_Error` (vs the success type) in each branch.
- **Hook callbacks** — `HookCallbackRule` validates `add_action()`/`add_filter()` callback signatures; `HookDocsRule` validates the docblocks on `apply_filters()`/`do_action()` calls.
- **WordPress constants** — the extension's `dynamicConstantNames` list (`WP_DEBUG`, `WP_DEBUG_LOG`, `WP_DEBUG_DISPLAY`, `SCRIPT_DEBUG`, `ABSPATH`, `WP_CONTENT_DIR`, `WP_PLUGIN_DIR`, …) plus its `WpConstantFetchRule` tell PHPStan those WordPress constants may be conditionally (re)defined, so it won't wrongly narrow `if ( WP_DEBUG )`-style checks.
- **Early-terminating functions** — `wp_send_json*` and `wp_nonce_ays` are known to end execution, so PHPStan won't flag "undefined variable after" them.
One it can't infer for you: **`global $wpdb;`**. Annotate it where used:
```php
global $wpdb;
/** @var \wpdb $wpdb */
```
## Run it
```bash
vendor/bin/phpstan analyse # uses phpstan.neon(.dist)
vendor/bin/phpstan analyse -l 8 includes/ # override level + path
vendor/bin/phpstan analyse --memory-limit 1G # large plugins + stubs eat RAM
```
Add a composer script so it joins the QA entry point alongside `phpcs`/`phpunit`:
```json
"scripts": {
"analyze": "phpstan analyse"
}
```
## Critical rules
- **Install `szepeviktor/phpstan-wordpress`** (it brings PHPStan 2.0 + WP stubs) — don't hand-assemble stubs.
- **Use `phpstan/extension-installer`** (and `allow-plugins`) so the extension auto-registers; otherwise add the `extension.neon` include manually.
- **Pick a level the code passes, commit, raise gradually.** `max` on legacy code without a baseline is noise, not signal.
- **Baseline legacy errors** with `--generate-baseline` so only new/changed code is gated.
- **Add the right stubs for cross-plugin calls** (e.g. `php-stubs/woocommerce-stubs`) or every external symbol is "unknown".
- **Use only the extension's documented narrow suppression** for the extra-argument `apply_filters()` pattern; do not generalize it to unrelated calls. The extension handles return narrowing, hooks, constants, and `is_wp_error()` separately. Annotate `global $wpdb` with `/** @var \wpdb $wpdb */`.
- **Check stub freshness against the target core.** For WordPress 7.1, tagged 7.0.1 stubs do not describe every new symbol; a green run alone is not a complete 7.1 API audit.
## Cross-references
- Run **`wp-phpcs-coding-standards`** for the complementary style/standards gate (PHPCS = style, PHPStan = types/logic).
- Run **`wp-phpunit-test-setup`** to add PHPStan to the same composer scripts and CI matrix.
- Run **`wp-plugin-architecture`** when PHPStan findings point at structural issues (untyped boundaries, god objects).
- Run **`wp-security-audit`** — PHPStan catches type bugs, not security ones; pair them.
## References
- phpstan-wordpress: <https://github.com/szepeviktor/phpstan-wordpress>
- Rule levels: <https://phpstan.org/user-guide/rule-levels>
- The baseline: <https://phpstan.org/user-guide/baseline>
- WordPress stubs: <https://github.com/php-stubs/wordpress-stubs>
- WooCommerce stubs: <https://github.com/php-stubs/woocommerce-stubs>
- Extension installer: <https://github.com/phpstan/extension-installer>
- Related documentation: <https://github.com/szepeviktor/phpstan-wordpress/blob/master/extension.neon>
- Related documentation: <https://github.com/szepeviktor/phpstan-wordpress/blob/master/examples/phpstan.neon.dist>
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!