From superpowers-sage
Configures PHPStan static analysis for Sage/Acorn projects: installs phpstan, larastan, and wordpress stubs, creates phpstan.neon, generates baselines, and handles common type errors.
How this skill is triggered — by the user, by Claude, or both
Slash command
/superpowers-sage:wp-phpstanThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
- Setting up static analysis on a Sage theme for the first time
lando theme-composer require --dev phpstan/phpstan larastan/larastan szepeviktor/phpstan-wordpress
This installs:
phpstan.neonCreate or update phpstan.neon in the theme root:
includes:
- vendor/larastan/larastan/extension.neon
- vendor/szepeviktor/phpstan-wordpress/extension.neon
parameters:
paths:
- app/
level: 0
# WordPress dynamic functions that PHPStan cannot resolve
ignoreErrors:
- '#Function apply_filters invoked with#'
- '#Function do_action invoked with#'
- '#Function add_filter expects#'
- '#Function add_action expects#'
# Scan files for WordPress global function definitions
scanDirectories:
- vendor/szepeviktor/phpstan-wordpress/bootstrap.php
# Treat Acorn facades correctly via Larastan
checkGenericClassInNonGenericObjectType: false
lando theme-composer exec phpstan -- analyse
At level 0, this should produce few or no errors. If errors exist, fix them or generate a baseline.
A baseline captures all existing errors so they can be addressed incrementally without blocking development.
lando theme-composer exec phpstan -- analyse --generate-baseline
This creates phpstan-baseline.neon. Include it in the main config:
includes:
- vendor/larastan/larastan/extension.neon
- vendor/szepeviktor/phpstan-wordpress/extension.neon
- phpstan-baseline.neon
New code must pass analysis; baseline errors are addressed over time.
// PHPStan complains about callable types
// Fix: use explicit Closure or typed callable
add_filter('the_content', function (string $content): string {
return $content . '<p>Appended</p>';
});
// get_field() returns mixed — PHPStan cannot infer the type
// Fix: assert or cast the return value
/** @var string|null $subtitle */
$subtitle = get_field('subtitle');
// Or use a wrapper with PHPDoc
/**
* @return array<string, mixed>
*/
function get_hero_fields(): array
{
return (array) get_field('hero_section') ?: [];
}
get_field// Bad — PHPStan reports "Cannot access property on mixed"
$image = get_field('image');
echo $image['url']; // Error
// Good — type-narrow first
$image = get_field('image');
if (is_array($image) && isset($image['url'])) {
echo $image['url'];
}
Larastan handles most Eloquent patterns automatically. For custom model attributes, add PHPDoc:
/**
* @property int $id
* @property string $title
* @property \Carbon\Carbon $created_at
*/
class Event extends Model
{
// ...
}
| Level | Catches | Effort | Recommendation |
|---|---|---|---|
| 0 | Basic errors, unknown classes | Minimal | Start here |
| 1 | Possibly undefined variables | Low | Move to quickly |
| 2 | Unknown methods on mixed | Low | Move to quickly |
| 3 | Return types checked | Moderate | First real milestone |
| 4 | Basic dead code detection | Moderate | Good target for most projects |
| 5 | Argument types checked | High | Requires disciplined typing |
| 6+ | Strict union/intersection types | Very high | For projects committed to strict typing |
Recommended progression:
After raising the level, regenerate the baseline:
lando theme-composer exec phpstan -- analyse --generate-baseline
Run PHPStan in CI without progress output:
lando theme-composer exec phpstan -- analyse --no-progress --error-format=github
- name: Run PHPStan
run: |
cd web/app/themes/<theme-name>
composer exec phpstan -- analyse --no-progress --error-format=github
The --error-format=github flag produces annotations that appear inline on pull requests.
In CI, verify the baseline has not grown:
# Regenerate baseline and check for changes
lando theme-composer exec phpstan -- analyse --generate-baseline
git diff --exit-code phpstan-baseline.neon
If the diff is non-empty, the PR introduces new errors that must be fixed.
Larastan provides analysis support for Laravel patterns used in Acorn:
app()->make() and dependency injection are type-awareconfig() and view() calls are understoodNo additional configuration is needed beyond including larastan/extension.neon.
lando theme-composer exec phpstan -- analyse runs without errors (or only baseline errors)phpstan.neon includes both Larastan and WordPress stubs extensions| Symptom | Likely cause | Fix |
|---|---|---|
| "Class not found" for WordPress functions | WordPress stubs not installed or not included | Verify szepeviktor/phpstan-wordpress is installed and included in phpstan.neon |
| "Class not found" for Acorn facades | Larastan not included | Verify larastan/larastan is installed and extension.neon is included |
| Hundreds of errors on first run | Level set too high for current codebase | Start at level 0, generate baseline, increment gradually |
| Baseline keeps growing | New code introducing type errors | Enforce CI check that baseline does not grow |
| Memory exhaustion during analysis | Large codebase or too many paths scanned | Limit paths to app/, increase PHP memory limit in phpstan.neon: parameters.memoryLimit: 512M |
| False positives on WordPress hooks | Dynamic invocation patterns | Add specific patterns to ignoreErrors in phpstan.neon |
| Larastan conflicts with PHPStan version | Version mismatch | Check Larastan compatibility matrix, pin compatible versions in composer.json |
szepeviktor/phpstan-wordpress and larastan/larastan before suppressingnpx claudepluginhub hekivo/superpowers-sageReviews WordPress PHP/JS/CSS/HTML code against WPCS standards, static analysis with PHPCS/PHPStan/ESLint, architecture patterns, error handling, and deprecated functions. Use for custom themes/plugins.
Guides PHPStan error resolution prioritizing refactoring over phpDoc and ignoring, with Nette patterns, baseline management, and type tests. Use before running PHPStan or fixing errors.
Analyzes unfamiliar Sage/Acorn/Lando projects — discovers CPTs, routes, ACF field groups, Livewire components, Service Providers, packages, and produces a structured overview with health status and next steps.