agentleFS
ehsanenalooehsanenaloo/wordpress-devkit/skills/wp-devkit-phpstan-review/SKILL.md

wp-devkit-phpstan-review

Skill0 starsChanged 34 days agoMITView on GitHub

Configure, debug or review PHPStan for WordPress plugins and themes: NEON config and levels, szepeviktor/phpstan-wordpress and WordPress/WooCommerce stubs, undefined symbols, WP_Error and hook typing, baselines, ignores and CI gate coverage that actually fails on type errors.

The file

We split this skill into the rules it gives an agent

6 rules. About 0 are common, 3 are distinctive, and 3 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Check the level and strictness: numeric level (0 to 10) rather than max, a reason for the level, and treatPhpDocTypesAsCertain, phpVersion …

    line 25
  2. Very specific:

    Verify the gate: CI runs the same command, fails the job on a nonzero exit, is not continue-on-error, does not regenerate the baseline, and …

    line 28
  3. Very specific:

    Read references/phpstan-review-workbook.md for severity, the finding template, false positives and acceptance checks.

    line 30
  4. Distinctive:

    Run the current command first and keep the output as the baseline of evidence (version, level, error count, exit status).

    line 34
  5. Distinctive:

    Create a baseline only for a reviewed, bounded set of pre-existing errors, once, in its own commit, after coverage is meaningful.

    line 37
  6. Distinctive:

    Read-only leads from the first-party root.

    line 43

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Static analysis with meaningful coverage

Read references/engineering-contract.md first. A review request is read-only: resolve and explain the configuration and its coverage; do not edit config, regenerate a baseline, install packages or bootstrap the project. Run PHPStan only on an inspected target inside the authorized scope, otherwise record it as unexecuted. Implement only when the user authorizes changes.

Hand off: PHPCS/WordPress Coding Standards, PHPUnit and browser tests to wp-devkit-test-strategy; CI workflow design and release gates to wp-devkit-ci-cd-and-release-engineering; plugin architecture changes to wp-devkit-plugin-development; security conclusions to wp-devkit-security-review (types do not model permissions).

Applicability

Confirm that a PHPStan setup exists: phpstan.neon, phpstan.neon.dist or phpstan.dist.neon, a phpstan/phpstan Composer dependency, or a CI step. If none exists, report Not used in this project with the one INFO coverage gap (no static-analysis gate) and stop. Create a configuration only when the request authorizes implementation.

Inputs

composer.lock (PHPStan, extension, stubs versions), PHP version(s) the code supports and the CI PHP, the exact local and CI commands, the effective config file, first-party source inventory, baseline and ignore policy, and whether WooCommerce, WP-CLI, ACF or other plugin APIs are used. Use vendor/bin/phpstan diagnose and --version output when execution is allowed.

Code Review Workflow

  1. Resolve the configuration the real command uses. Precedence: -c/--configuration, then phpstan.neon, phpstan.neon.dist, phpstan.dist.neon in the working directory. Command-line paths replace paths. Follow every includes:.
  2. Compare analyzed paths and excludePaths with the first-party inventory (plugin root files, src/, inc/, templates, uninstall.php, mu-plugin loaders, CLI classes). Exclusions of failing production files are the first thing to look for.
  3. Distinguish analysis from discovery: paths are analyzed; scanFiles/scanDirectories only make symbols known; bootstrapFiles are executed by PHP. Confirm the WordPress extension and stubs load once (extension-installer or one explicit include), and that WooCommerce/WP-CLI stubs are present if their symbols are used.
  4. Check the level and strictness: numeric level (0 to 10) rather than max, a reason for the level, and treatPhpDocTypesAsCertain, phpVersion and tmpDir set deliberately. See references/config-and-discovery.md.
  5. Triage diagnostics by class: undefined symbol (discovery), real type error, missing PHPDoc, WordPress dynamic types (WP_Error|T, hooks, mixed options). Correct the real contract; do not add a cast or ignore to silence a true defect. See references/wordpress-type-patterns.md.
  6. Review suppressions and the baseline: identifiers, paths, counts, reportUnmatchedIgnoredErrors, comments, and whether new errors remain visible. See references/baseline-ignores-and-ci.md.
  7. Verify the gate: CI runs the same command, fails the job on a nonzero exit, is not continue-on-error, does not regenerate the baseline, and a deliberate type error would fail it.

Read references/phpstan-review-workbook.md for severity, the finding template, false positives and acceptance checks.

Implementation workflow

  1. Run the current command first and keep the output as the baseline of evidence (version, level, error count, exit status).
  2. Fix coverage before strictness: include all first-party paths, load stubs, remove blanket excludes; then triage errors by class.
  3. Fix real defects and PHPDoc contracts at the source. Prefer precise types (list<int>, array shapes, non-empty-string, positive-int) over mixed and casts.
  4. Create a baseline only for a reviewed, bounded set of pre-existing errors, once, in its own commit, after coverage is meaningful. Do not refresh it to make CI pass.
  5. Prove the gate: a known-valid file passes, a deliberate type error in a first-party file produces a nonzero exit, and the baseline does not hide it.
  6. Record versions, level, config, analyzed paths, baseline policy, command and exit code.

Search Patterns for Quick Detection

Read-only leads from the first-party root; candidates, not findings. They do not run PHPStan. Exit codes: 0 match, 1 none, 2 error.

scan() { rg -n -g '!**/{vendor,node_modules,build,dist,coverage,backups}/**' -e "$1" "${2:-.}"; }
scan 'level:|paths:|excludePaths|excludes_analyse|includes:|bootstrapFiles:|scanFiles:|scanDirectories:|tmpDir:|treatPhpDocTypesAsCertain|phpVersion:'   # config and coverage
scan 'phpstan-wordpress|wordpress-stubs|woocommerce-stubs|wp-cli-stubs|extension-installer|extension\.neon|stubFiles:'   # extension and stubs
scan 'ignoreErrors:|reportUnmatchedIgnoredErrors|reportIgnoresWithoutComments|baseline|count:|identifier:|rawMessage'   # suppressions
scan '@phpstan-ignore|@phpstan-ignore-(next-)?line|@var\b|@psalm-suppress|\bmixed\b'   # inline escapes
scan 'phpstan\s+(analy[sz]e|clear-result-cache|diagnose)|vendor/bin/phpstan|--configuration|--level|--memory-limit|--generate-baseline|continue-on-error|\|\|\s*true'   # command and CI parity
scan 'apply_filters|do_action|is_wp_error|WP_Error|get_option\(|get_post_meta\(|\$wpdb->get_(row|results)'   # dynamic WordPress boundaries

Typical benign hits: a baseline with documented counts in a bounded legacy area, scanDirectories for a vendored dependency not meant to be analyzed, @var that narrows a mixed return from get_option() after validation, || true in an unrelated shell step.

Task-selected resources

  • references/config-and-discovery.md: levels, config keys, precedence, symbol discovery, extension and stubs, PHP version, cache. Read for configuration and undefined-symbol problems.
  • references/wordpress-type-patterns.md: how to type WordPress return unions, hooks, options, meta, requests, $wpdb and WooCommerce objects without hiding bugs. Read when triaging real diagnostics.
  • references/baseline-ignores-and-ci.md: baselines, ignore forms, identifiers, CI wiring, adoption strategy, upgrades of PHPStan. Read for suppressions and gates.
  • references/analysis-coverage-fixture.neon.dist: a minimal disposable config for proving that paths are analyzed; adapt paths, never copy blindly.

Output Format

Lead with the verdict and reviewed scope. Record PHPStan, extension and stubs versions, PHP version, level, config, analyzed paths, excluded paths, baseline policy, command and exit status. Per finding: severity, file:line (config or code), what is uncovered or wrong, impact (what class of defect can now slip through), confidence, minimal fix, and a regression (positive and negative check). Separate resolved findings from excluded or unexecuted code. State whether each change corrects the type contract or the runtime behavior. A green run proves only that the analyzed code satisfies the rules at that level; it says nothing about code outside paths, runtime behavior or security.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.