wp-skills 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/LICENSE +16 -0
  2. package/README.md +157 -0
  3. package/docs/ai-authorship.md +60 -0
  4. package/docs/authoring-guide.md +56 -0
  5. package/docs/compatibility-policy.md +18 -0
  6. package/docs/packaging.md +35 -0
  7. package/docs/principles.md +7 -0
  8. package/docs/skill-set-v1.md +21 -0
  9. package/docs/upstream-sync.md +52 -0
  10. package/package.json +21 -0
  11. package/shared/scripts/ai-generate-updates.mjs +458 -0
  12. package/shared/scripts/scaffold-skill.mjs +62 -0
  13. package/shared/scripts/skillpack-build.mjs +168 -0
  14. package/shared/scripts/skillpack-cli.mjs +77 -0
  15. package/shared/scripts/skillpack-install.mjs +338 -0
  16. package/shared/scripts/update-upstream-indices.mjs +173 -0
  17. package/skills/wordpress-router/SKILL.md +51 -0
  18. package/skills/wordpress-router/references/decision-tree.md +55 -0
  19. package/skills/wp-abilities-api/SKILL.md +95 -0
  20. package/skills/wp-abilities-api/references/php-registration.md +67 -0
  21. package/skills/wp-abilities-api/references/rest-api.md +13 -0
  22. package/skills/wp-block-development/SKILL.md +174 -0
  23. package/skills/wp-block-development/references/attributes-and-serialization.md +22 -0
  24. package/skills/wp-block-development/references/block-json.md +49 -0
  25. package/skills/wp-block-development/references/creating-new-blocks.md +46 -0
  26. package/skills/wp-block-development/references/debugging.md +36 -0
  27. package/skills/wp-block-development/references/deprecations.md +24 -0
  28. package/skills/wp-block-development/references/dynamic-rendering.md +23 -0
  29. package/skills/wp-block-development/references/inner-blocks.md +25 -0
  30. package/skills/wp-block-development/references/registration.md +30 -0
  31. package/skills/wp-block-development/references/supports-and-wrappers.md +18 -0
  32. package/skills/wp-block-development/references/tooling-and-testing.md +21 -0
  33. package/skills/wp-block-development/scripts/list_blocks.mjs +121 -0
  34. package/skills/wp-block-themes/SKILL.md +116 -0
  35. package/skills/wp-block-themes/references/creating-new-block-theme.md +37 -0
  36. package/skills/wp-block-themes/references/debugging.md +24 -0
  37. package/skills/wp-block-themes/references/patterns.md +18 -0
  38. package/skills/wp-block-themes/references/style-variations.md +14 -0
  39. package/skills/wp-block-themes/references/templates-and-parts.md +16 -0
  40. package/skills/wp-block-themes/references/theme-json.md +59 -0
  41. package/skills/wp-block-themes/scripts/detect_block_themes.mjs +117 -0
  42. package/skills/wp-interactivity-api/SKILL.md +179 -0
  43. package/skills/wp-interactivity-api/references/debugging.md +29 -0
  44. package/skills/wp-interactivity-api/references/directives-quickref.md +30 -0
  45. package/skills/wp-interactivity-api/references/server-side-rendering.md +310 -0
  46. package/skills/wp-performance/SKILL.md +146 -0
  47. package/skills/wp-performance/references/autoload-options.md +24 -0
  48. package/skills/wp-performance/references/cron.md +20 -0
  49. package/skills/wp-performance/references/database.md +20 -0
  50. package/skills/wp-performance/references/http-api.md +15 -0
  51. package/skills/wp-performance/references/measurement.md +21 -0
  52. package/skills/wp-performance/references/object-cache.md +24 -0
  53. package/skills/wp-performance/references/query-monitor-headless.md +38 -0
  54. package/skills/wp-performance/references/server-timing.md +22 -0
  55. package/skills/wp-performance/references/wp-cli-doctor.md +24 -0
  56. package/skills/wp-performance/references/wp-cli-profile.md +32 -0
  57. package/skills/wp-performance/scripts/perf_inspect.mjs +128 -0
  58. package/skills/wp-phpstan/SKILL.md +97 -0
  59. package/skills/wp-phpstan/references/configuration.md +52 -0
  60. package/skills/wp-phpstan/references/third-party-classes.md +76 -0
  61. package/skills/wp-phpstan/references/wordpress-annotations.md +124 -0
  62. package/skills/wp-phpstan/scripts/phpstan_inspect.mjs +263 -0
  63. package/skills/wp-playground/SKILL.md +101 -0
  64. package/skills/wp-playground/references/blueprints.md +36 -0
  65. package/skills/wp-playground/references/cli-commands.md +39 -0
  66. package/skills/wp-playground/references/debugging.md +16 -0
  67. package/skills/wp-plugin-development/SKILL.md +112 -0
  68. package/skills/wp-plugin-development/references/data-and-cron.md +19 -0
  69. package/skills/wp-plugin-development/references/debugging.md +19 -0
  70. package/skills/wp-plugin-development/references/lifecycle.md +33 -0
  71. package/skills/wp-plugin-development/references/security.md +29 -0
  72. package/skills/wp-plugin-development/references/settings-api.md +22 -0
  73. package/skills/wp-plugin-development/references/structure.md +16 -0
  74. package/skills/wp-plugin-development/scripts/detect_plugins.mjs +122 -0
  75. package/skills/wp-project-triage/SKILL.md +38 -0
  76. package/skills/wp-project-triage/references/triage.schema.json +143 -0
  77. package/skills/wp-project-triage/scripts/detect_wp_project.mjs +592 -0
  78. package/skills/wp-rest-api/SKILL.md +114 -0
  79. package/skills/wp-rest-api/references/authentication.md +18 -0
  80. package/skills/wp-rest-api/references/custom-content-types.md +20 -0
  81. package/skills/wp-rest-api/references/discovery-and-params.md +20 -0
  82. package/skills/wp-rest-api/references/responses-and-fields.md +30 -0
  83. package/skills/wp-rest-api/references/routes-and-endpoints.md +36 -0
  84. package/skills/wp-rest-api/references/schema.md +22 -0
  85. package/skills/wp-wpcli-and-ops/SKILL.md +123 -0
  86. package/skills/wp-wpcli-and-ops/references/automation.md +30 -0
  87. package/skills/wp-wpcli-and-ops/references/cron-and-cache.md +23 -0
  88. package/skills/wp-wpcli-and-ops/references/debugging.md +17 -0
  89. package/skills/wp-wpcli-and-ops/references/multisite.md +22 -0
  90. package/skills/wp-wpcli-and-ops/references/packages-and-updates.md +22 -0
  91. package/skills/wp-wpcli-and-ops/references/safety.md +30 -0
  92. package/skills/wp-wpcli-and-ops/references/search-replace.md +40 -0
  93. package/skills/wp-wpcli-and-ops/scripts/wpcli_inspect.mjs +90 -0
  94. package/skills/wpds/SKILL.md +58 -0
@@ -0,0 +1,24 @@
1
+ # Autoloaded options
2
+
3
+ Autoloaded options are loaded on *every request*, so large autoload payloads can hurt performance site-wide.
4
+
5
+ ## Quick checks
6
+
7
+ - Total autoload bytes:
8
+ - `wp option list --autoload=on --format=total_bytes`
9
+ - Find biggest autoloaded options:
10
+ - `wp option list --autoload=on --fields=option_name,size_bytes | sort -n -k 2 | tail`
11
+
12
+ Docs:
13
+
14
+ - `wp option list`: https://wpcli.dev/docs/option/list
15
+ - `wp doctor` includes an `autoload-options-size` check:
16
+ - https://make.wordpress.org/cli/handbook/doctor-default-checks/
17
+
18
+ ## Fix patterns
19
+
20
+ - Stop autoloading large blobs:
21
+ - store large data in non-autoload options (autoload=off)
22
+ - move large computed data to transients/object cache
23
+ - Remove stale options left behind by removed plugins/themes (careful: confirm usage before deleting).
24
+
@@ -0,0 +1,20 @@
1
+ # WP-Cron performance
2
+
3
+ Use this file when cron causes spikes or request-time slowness.
4
+
5
+ Backend-only tools:
6
+
7
+ - `wp cron test` (spawning health)
8
+ - `wp cron event list`
9
+ - `wp cron event run --due-now`
10
+
11
+ Reference:
12
+
13
+ - WP-CLI cron command package: https://github.com/wp-cli/cron-command
14
+
15
+ Fix patterns:
16
+
17
+ - De-duplicate scheduled events and reduce frequency where possible.
18
+ - Ensure tasks are idempotent and short.
19
+ - Move heavy work off-request; cron that runs on page load can hurt TTFB.
20
+
@@ -0,0 +1,20 @@
1
+ # Database / query performance
2
+
3
+ Use this file when profiling points to DB time or high query counts.
4
+
5
+ Common fixes:
6
+
7
+ - Avoid N+1 query patterns (batch queries, prime caches, avoid per-row lookups).
8
+ - Prefer `fields => 'ids'` when you only need IDs.
9
+ - Avoid expensive meta queries where possible; consider indexing or schema changes.
10
+ - Use object caching for repeated reads.
11
+
12
+ Tools (backend-only):
13
+
14
+ - Query Monitor (REST headers/envelope) for query lists and stack traces.
15
+ - `wp db query` for targeted SQL/explain (be careful in prod).
16
+
17
+ References:
18
+
19
+ - Query Monitor plugin: https://wordpress.org/plugins/query-monitor/
20
+
@@ -0,0 +1,15 @@
1
+ # HTTP API (remote requests)
2
+
3
+ Use this file when profiling shows slow external requests (`wp_remote_get`, etc.).
4
+
5
+ Fix patterns:
6
+
7
+ - Add timeouts and fail-fast behavior.
8
+ - Cache responses where appropriate (transients/object cache).
9
+ - Batch requests and avoid calling remote APIs on every page load.
10
+ - Move heavy remote work to async (cron/queue) where possible.
11
+
12
+ Tooling:
13
+
14
+ - Query Monitor can report HTTP API calls (including timing) via REST envelope info.
15
+
@@ -0,0 +1,21 @@
1
+ # Measurement (profiling vs benchmarking)
2
+
3
+ Backend-only measurement options:
4
+
5
+ - **WP-CLI profiling** (`wp profile`): best for pinpointing slow hooks/stages without a browser.
6
+ - **WP-CLI doctor** (`wp doctor`): best for quick diagnostics (autoload bloat, debug constants, updates).
7
+ - **Query Monitor via REST**: use authenticated REST requests and inspect `x-qm-*` headers / `qm` envelope data.
8
+ - **Server-Timing** (Performance Lab): inspect `Server-Timing` headers via `curl -I` (when enabled).
9
+ - **APM/profilers**: New Relic, Datadog, Blackfire, Tideways, XHProf/Xdebug (requires server support).
10
+
11
+ Best practices:
12
+
13
+ - Always capture a baseline first.
14
+ - Keep the test scenario fixed (same URL/route, same user state, same data).
15
+ - Prefer multiple samples and medians over single runs.
16
+
17
+ References:
18
+
19
+ - Measuring performance handbook: https://make.wordpress.org/performance/handbook/measuring-performance/
20
+ - Benchmarking with Server-Timing: https://make.wordpress.org/performance/handbook/measuring-performance/benchmarking-server-timing/
21
+
@@ -0,0 +1,24 @@
1
+ # Object caching
2
+
3
+ Use this file when profiling indicates repeated queries or low cache hit rate.
4
+
5
+ ## Concepts
6
+
7
+ - Default WP object cache is per-request memory only.
8
+ - A persistent object cache “drop-in” (`wp-content/object-cache.php`) can persist cache across requests.
9
+
10
+ WP-CLI cache commands:
11
+
12
+ - https://wpcli.dev/docs/cache
13
+
14
+ Guardrails:
15
+
16
+ - `wp cache flush` can impact all sites in multisite and cause load spikes:
17
+ - https://wpcli.dev/docs/cache/flush
18
+
19
+ ## Fix patterns
20
+
21
+ - Cache expensive computed results (transients or object cache) with explicit invalidation.
22
+ - Avoid unbounded caches (set expirations or implement invalidation hooks).
23
+ - If adding a persistent object cache, coordinate with infra (Redis/Memcached) and test cache flush behavior.
24
+
@@ -0,0 +1,38 @@
1
+ # Query Monitor (headless / backend-only)
2
+
3
+ Query Monitor is UI-first, but it can expose useful data to backend-only tooling.
4
+
5
+ ## What it can show
6
+
7
+ Query Monitor can help debug:
8
+
9
+ - DB queries (slow/dupes/errors), hooks/actions, HTTP API calls, PHP errors
10
+
11
+ Plugin page:
12
+
13
+ - https://wordpress.org/plugins/query-monitor/
14
+
15
+ Configuration constants:
16
+
17
+ - https://querymonitor.com/help/configuration-constants/
18
+
19
+ ## REST API requests (no browser needed)
20
+
21
+ Query Monitor can add performance/error info to authenticated REST responses.
22
+
23
+ Docs:
24
+
25
+ - https://querymonitor.com/wordpress-debugging/rest-api-requests/
26
+
27
+ High-level approach:
28
+
29
+ 1. Authenticate (nonce or Application Password).
30
+ 2. Make a REST request and inspect response headers like `x-qm-overview-*`.
31
+ 3. If you request an enveloped response (`?_envelope`), you can get a `qm` property with:
32
+ - DB queries details, cache stats, HTTP API request details, etc.
33
+
34
+ ## Guardrails
35
+
36
+ - Query Monitor adds some overhead; don’t enable it in production without approval.
37
+ - If it’s already installed by your platform (e.g. VIP), you may need to grant `view_query_monitor`.
38
+
@@ -0,0 +1,22 @@
1
+ # Server-Timing (Performance Lab)
2
+
3
+ Use this file when you can enable Server-Timing metrics and want backend-only inspection via HTTP headers.
4
+
5
+ Performance Lab plugin:
6
+
7
+ - https://wordpress.org/plugins/performance-lab/
8
+
9
+ Benchmarking guidance:
10
+
11
+ - https://make.wordpress.org/performance/handbook/measuring-performance/benchmarking-server-timing/
12
+
13
+ Backend-only approach:
14
+
15
+ - Enable the relevant module/standalone plugin.
16
+ - Request a URL and inspect the `Server-Timing` header:
17
+ - `curl -sS -D - https://example.test/ -o /dev/null | rg -i \"^server-timing:\"`
18
+
19
+ Guardrails:
20
+
21
+ - Don’t enable experimental modules in production without approval.
22
+
@@ -0,0 +1,24 @@
1
+ # WP-CLI doctor (`wp doctor`)
2
+
3
+ Use this for quick “production readiness” checks.
4
+
5
+ ## Install (if missing)
6
+
7
+ - `wp package install wp-cli/doctor-command`
8
+
9
+ Docs:
10
+
11
+ - Default checks: https://make.wordpress.org/cli/handbook/doctor-default-checks/
12
+ - Customize checks: https://make.wordpress.org/cli/handbook/guides/doctor/doctor-customize-config/
13
+
14
+ ## Recommended usage
15
+
16
+ - `wp doctor check`
17
+ - `wp doctor list` (to see available checks)
18
+
19
+ Especially relevant to performance:
20
+
21
+ - `autoload-options-size` (autoloaded options threshold)
22
+ - `constant-savequeries-falsy` / `constant-wp-debug-falsy` (avoid perf-costly debug flags in prod)
23
+ - cron checks (count/duplicates)
24
+
@@ -0,0 +1,32 @@
1
+ # WP-CLI profiling (`wp profile`)
2
+
3
+ Use this when you need actionable profiling without a browser.
4
+
5
+ ## Install (if missing)
6
+
7
+ `wp profile` comes from a WP-CLI package:
8
+
9
+ - `wp package install wp-cli/profile-command`
10
+
11
+ Docs:
12
+
13
+ - https://wpcli.dev/docs/profile/stage
14
+ - https://wpcli.dev/docs/profile/hook
15
+ - https://wpcli.dev/docs/profile/eval
16
+
17
+ ## Recommended sequence
18
+
19
+ 1. Stage overview:
20
+ - `wp profile stage --fields=stage,time,cache_ratio [--url=<url>]`
21
+ 2. Hooks hotspot:
22
+ - `wp profile hook --spotlight [--url=<url>]`
23
+ - then drill into a specific hook:
24
+ - `wp profile hook init --spotlight [--url=<url>]`
25
+ 3. Targeted evaluation:
26
+ - `wp profile eval 'do_action(\"init\");' --hook=init`
27
+
28
+ Tips:
29
+
30
+ - Use `--url` to profile specific site/route behavior.
31
+ - Use `--skip-plugins` / `--skip-themes` to isolate culprit components (careful: behavior changes).
32
+
@@ -0,0 +1,128 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { spawnSync } from "node:child_process";
4
+
5
+ const TOOL_VERSION = "0.1.0";
6
+
7
+ function parseArgs(argv) {
8
+ const args = { path: null, url: null, allowRoot: false };
9
+ for (const a of argv) {
10
+ if (a === "--allow-root") args.allowRoot = true;
11
+ if (a.startsWith("--path=")) args.path = a.slice("--path=".length);
12
+ if (a.startsWith("--url=")) args.url = a.slice("--url=".length);
13
+ }
14
+ return args;
15
+ }
16
+
17
+ function existsFile(p) {
18
+ try {
19
+ return fs.statSync(p).isFile();
20
+ } catch {
21
+ return false;
22
+ }
23
+ }
24
+
25
+ function runWp(cmdArgs, { pathArg, urlArg, allowRoot }) {
26
+ const args = [];
27
+ if (allowRoot) args.push("--allow-root");
28
+ if (pathArg) args.push(`--path=${pathArg}`);
29
+ if (urlArg) args.push(`--url=${urlArg}`);
30
+ args.push(...cmdArgs);
31
+
32
+ const out = spawnSync("wp", args, { encoding: "utf8" });
33
+ return {
34
+ ok: out.status === 0,
35
+ status: out.status,
36
+ error: out.error ? { message: out.error.message, code: out.error.code } : null,
37
+ stdout: (out.stdout || "").trim(),
38
+ stderr: (out.stderr || "").trim(),
39
+ args,
40
+ };
41
+ }
42
+
43
+ function canRun(report, result, noteIfNotOk) {
44
+ report._runs.push({ cmd: result.args.join(" "), ok: result.ok, status: result.status, error: result.error });
45
+ if (!result.ok && noteIfNotOk) report.notes.push(noteIfNotOk);
46
+ return result.ok;
47
+ }
48
+
49
+ function main() {
50
+ const opts = parseArgs(process.argv.slice(2));
51
+ const report = {
52
+ tool: { name: "perf_inspect", version: TOOL_VERSION },
53
+ target: { path: opts.path, url: opts.url },
54
+ wpCli: { available: false },
55
+ wp: {
56
+ isInstalled: null,
57
+ coreVersion: null,
58
+ },
59
+ commands: {
60
+ doctor: { available: false },
61
+ profile: { available: false },
62
+ },
63
+ perfSignals: {
64
+ autoloadTotalBytes: null,
65
+ hasObjectCacheDropin: null,
66
+ hasAdvancedCacheDropin: null,
67
+ hasQueryMonitorPlugin: null,
68
+ hasPerformanceLabPlugin: null,
69
+ },
70
+ notes: [],
71
+ _runs: [],
72
+ };
73
+
74
+ const info = runWp(["--info"], { pathArg: null, urlArg: null, allowRoot: opts.allowRoot });
75
+ report.wpCli.available = info.ok;
76
+ report.wpCli.info = info;
77
+ if (!info.ok) {
78
+ report.notes.push("WP-CLI not available on PATH. Run in the intended environment (container/ssh) or install WP-CLI.");
79
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
80
+ return;
81
+ }
82
+
83
+ const isInstalled = runWp(["core", "is-installed"], { pathArg: opts.path, urlArg: opts.url, allowRoot: opts.allowRoot });
84
+ report.wp.isInstalled = isInstalled.ok;
85
+ canRun(report, isInstalled, "WordPress not detected at the given --path/--url (check wp-config.php and targeting).");
86
+ if (!isInstalled.ok) {
87
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
88
+ return;
89
+ }
90
+
91
+ const coreVersion = runWp(["core", "version"], { pathArg: opts.path, urlArg: opts.url, allowRoot: opts.allowRoot });
92
+ report.wp.coreVersion = coreVersion.ok ? coreVersion.stdout : null;
93
+ canRun(report, coreVersion);
94
+
95
+ const doctorHelp = runWp(["doctor", "--help"], { pathArg: opts.path, urlArg: opts.url, allowRoot: opts.allowRoot });
96
+ report.commands.doctor.available = doctorHelp.ok;
97
+ canRun(report, doctorHelp);
98
+
99
+ const profileHelp = runWp(["profile", "--help"], { pathArg: opts.path, urlArg: opts.url, allowRoot: opts.allowRoot });
100
+ report.commands.profile.available = profileHelp.ok;
101
+ canRun(report, profileHelp);
102
+
103
+ const autoloadBytes = runWp(["option", "list", "--autoload=on", "--format=total_bytes"], {
104
+ pathArg: opts.path,
105
+ urlArg: opts.url,
106
+ allowRoot: opts.allowRoot,
107
+ });
108
+ if (autoloadBytes.ok && /^\d+$/.test(autoloadBytes.stdout)) {
109
+ report.perfSignals.autoloadTotalBytes = Number(autoloadBytes.stdout);
110
+ }
111
+ canRun(report, autoloadBytes);
112
+
113
+ if (opts.path) {
114
+ const wpContent = path.join(opts.path, "wp-content");
115
+ report.perfSignals.hasObjectCacheDropin = existsFile(path.join(wpContent, "object-cache.php"));
116
+ report.perfSignals.hasAdvancedCacheDropin = existsFile(path.join(wpContent, "advanced-cache.php"));
117
+ report.perfSignals.hasQueryMonitorPlugin = existsFile(path.join(wpContent, "plugins", "query-monitor", "query-monitor.php"));
118
+ report.perfSignals.hasPerformanceLabPlugin = existsFile(path.join(wpContent, "plugins", "performance-lab", "load.php"));
119
+ }
120
+
121
+ if (!report.commands.doctor.available) report.notes.push("Tip: install WP-CLI doctor: `wp package install wp-cli/doctor-command`.");
122
+ if (!report.commands.profile.available) report.notes.push("Tip: install WP-CLI profile: `wp package install wp-cli/profile-command`.");
123
+
124
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
125
+ }
126
+
127
+ main();
128
+
@@ -0,0 +1,97 @@
1
+ ---
2
+ name: wp-phpstan
3
+ description: "Use when configuring, running, or fixing PHPStan static analysis in WordPress projects (plugins/themes/sites): phpstan.neon setup, baselines, WordPress-specific typing, and handling third-party plugin classes."
4
+ compatibility: "Targets WordPress 6.9+ (PHP 7.2.24+). Requires Composer-based PHPStan."
5
+ ---
6
+
7
+ # WP PHPStan
8
+
9
+ ## When to use
10
+
11
+ Use this skill when working on PHPStan in a WordPress codebase, for example:
12
+
13
+ - setting up or updating `phpstan.neon` / `phpstan.neon.dist`
14
+ - generating or updating `phpstan-baseline.neon`
15
+ - fixing PHPStan errors via WordPress-friendly PHPDoc (REST requests, hooks, query results)
16
+ - handling third-party plugin/theme classes safely (stubs/autoload/targeted ignores)
17
+
18
+ ## Inputs required
19
+
20
+ - `wp-project-triage` output (run first if you haven't)
21
+ - Whether adding/updating Composer dev dependencies is allowed (stubs).
22
+ - Whether changing the baseline is allowed for this task.
23
+
24
+ ## Procedure
25
+
26
+ ### 0) Discover PHPStan entrypoints (deterministic)
27
+ 1. Inspect PHPStan setup (config, baseline, scripts):
28
+ - `node skills/wp-phpstan/scripts/phpstan_inspect.mjs`
29
+
30
+ Prefer the repo’s existing `composer` script (e.g. `composer run phpstan`) when present.
31
+
32
+ ### 1) Ensure WordPress core stubs are loaded
33
+
34
+ `szepeviktor/phpstan-wordpress` or `php-stubs/wordpress-stubs` are effectively required for most WordPress plugin/theme repos. Without it, expect a high volume of errors about unknown WordPress core functions.
35
+
36
+ - Confirm the package is installed (see `composer.dependencies` in the inspect report).
37
+ - Ensure the PHPStan config references the stubs (see `references/third-party-classes.md`).
38
+
39
+ ### 2) Ensure a sane `phpstan.neon` for WordPress projects
40
+
41
+ - Keep `paths` focused on first-party code (plugin/theme directories).
42
+ - Exclude generated and vendored code (`vendor/`, `node_modules/`, build artifacts, tests unless explicitly analyzed).
43
+ - Keep `ignoreErrors` entries narrow and documented.
44
+
45
+ See:
46
+ - `references/configuration.md`
47
+
48
+ ### 3) Fix errors with WordPress-specific typing (preferred)
49
+
50
+ Prefer correcting types over ignoring errors. Common WP patterns that need help:
51
+
52
+ - REST endpoints: type request parameters using `WP_REST_Request<...>`
53
+ - Hook callbacks: add accurate `@param` types for callback args
54
+ - Database results and iterables: use array shapes or object shapes for query results
55
+ - Action Scheduler: type `$args` array shapes for job callbacks
56
+
57
+ See:
58
+ - `references/wordpress-annotations.md`
59
+
60
+ ### 4) Handle third-party plugin/theme classes (only when needed)
61
+
62
+ When integrating with plugins/themes not present in the analysis environment:
63
+
64
+ - First, confirm the dependency is real (installed/required).
65
+ - Prefer plugin-specific stubs already used in the repo (common examples: `php-stubs/woocommerce-stubs`, `php-stubs/acf-pro-stubs`).
66
+ - If PHPStan still cannot resolve classes, add targeted `ignoreErrors` patterns for the specific vendor prefix.
67
+
68
+ See:
69
+ - `references/third-party-classes.md`
70
+
71
+ ### 5) Baseline management (use as a migration tool, not a trash bin)
72
+
73
+ - Generate a baseline once for legacy code, then reduce it over time.
74
+ - Do not “baseline” newly introduced errors.
75
+
76
+ See:
77
+ - `references/configuration.md`
78
+
79
+ ## Verification
80
+
81
+ - Run PHPStan using the discovered command (`composer run ...` or `vendor/bin/phpstan analyse`).
82
+ - Confirm the baseline file (if used) is included and didn’t grow unexpectedly.
83
+ - Re-run after changing `ignoreErrors` to ensure patterns are not masking unrelated issues.
84
+
85
+ ## Failure modes / debugging
86
+
87
+ - “Class not found”:
88
+ - confirm autoloading/stubs, or add a narrow ignore pattern
89
+ - Huge error counts after enabling PHPStan:
90
+ - reduce `paths`, add `excludePaths`, start at a lower level, then ratchet up
91
+ - Inconsistent types around hooks / REST params:
92
+ - add explicit PHPDoc (see references) rather than runtime guards
93
+
94
+ ## Escalation
95
+
96
+ - If a type depends on a third-party plugin API you can’t confirm, ask for the dependency version or source before inventing types.
97
+ - If fixing requires adding new Composer dependencies (stubs/extensions), confirm it with the user first.
@@ -0,0 +1,52 @@
1
+ # PHPStan configuration (WordPress)
2
+
3
+ This reference documents a minimal, WordPress-friendly PHPStan setup and baseline workflow.
4
+
5
+ ## Minimal `phpstan.neon` template
6
+
7
+ Use the repo’s existing layout. The example below is intentionally conservative and should be adapted to the project’s actual directories.
8
+
9
+ ```neon
10
+ # Include the baseline only if the file exists.
11
+ includes:
12
+ - phpstan-baseline.neon
13
+
14
+ parameters:
15
+ level: 5
16
+ paths:
17
+ - src/
18
+ - includes/
19
+
20
+ excludePaths:
21
+ - vendor/
22
+ - vendor-prefixed/
23
+ - node_modules/
24
+ - tests/
25
+
26
+ ignoreErrors:
27
+ # Add targeted exceptions only when necessary.
28
+ ```
29
+
30
+ Guidelines:
31
+
32
+ - Prefer analyzing first-party code only.
33
+ - Exclude anything generated or vendored.
34
+ - Keep `ignoreErrors` patterns narrow and grouped by dependency.
35
+
36
+ ## Baseline workflow
37
+
38
+ Baselines help you adopt PHPStan in legacy code without accepting new regressions.
39
+
40
+ ```bash
41
+ # Generate a baseline (explicit filename)
42
+ vendor/bin/phpstan analyse --generate-baseline phpstan-baseline.neon
43
+
44
+ # Update an existing baseline (defaults)
45
+ vendor/bin/phpstan analyse --generate-baseline
46
+ ```
47
+
48
+ Best practices:
49
+
50
+ - Avoid adding new errors to the baseline; fix the new code instead.
51
+ - Treat baseline changes like code changes: review in PRs.
52
+ - Chip away at the baseline gradually (remove entries as you fix root causes).
@@ -0,0 +1,76 @@
1
+ # Third-party classes and ignore patterns
2
+
3
+ When PHPStan reports legitimate classes as missing (e.g. because WordPress or a plugin is not installed in the analysis environment), prefer fixing discovery first and only then add targeted ignores.
4
+
5
+ ## Before adding `ignoreErrors`
6
+
7
+ - Confirm the dependency is real (installed/required in this environment).
8
+ - Prefer stubs/extensions already used by the repo.
9
+ - Prefer a narrow ignore for the vendor prefix over a broad ignore.
10
+
11
+ ## Recommended stub packages
12
+
13
+ Stubs are useful when the analysis environment does not include WordPress (or a plugin API) but you still want real type checking (instead of blanket ignores).
14
+
15
+ Common packages:
16
+
17
+ ```bash
18
+ composer require --dev szepeviktor/phpstan-wordpress
19
+ composer require --dev php-stubs/wordpress-stubs
20
+ composer require --dev php-stubs/woocommerce-stubs
21
+ composer require --dev php-stubs/acf-pro-stubs
22
+ ```
23
+
24
+ When stubs are useful (and sometimes necessary):
25
+
26
+ - Running PHPStan in a plugin/theme repo without a full WordPress checkout.
27
+ - PHPStan reports unknown WordPress core functions (e.g. `add_action()`, `get_option()`).
28
+ - Integrations with optional plugins (WooCommerce, ACF Pro) that are not installed during analysis.
29
+ - You want method/property existence checks and accurate return types instead of `ignoreErrors`.
30
+
31
+ Notes:
32
+
33
+ - Prefer stubs that match the runtime versions; mismatches can cause false positives.
34
+ - Adding Composer dependencies changes the repo; confirm it is acceptable for the task.
35
+
36
+ ## Ensure stubs are loaded
37
+
38
+ Installing stubs is not enough if PHPStan does not scan them. Add stub paths in `phpstan.neon`.
39
+
40
+ ```neon
41
+ parameters:
42
+ bootstrapFiles:
43
+ - %rootDir%/../../php-stubs/woocommerce-stubs/woocommerce-stubs.php
44
+ scanFiles:
45
+ - %rootDir%/../../php-stubs/wordpress-stubs/wordpress-stubs.php
46
+ - %rootDir%/../../php-stubs/acf-pro-stubs/acf-pro-stubs.php
47
+ - %rootDir%/../../woocommerce/action-scheduler/functions.php
48
+ ```
49
+
50
+ ## Targeted ignore patterns (examples)
51
+
52
+ ```neon
53
+ parameters:
54
+ ignoreErrors:
55
+ # Admin Columns Pro
56
+ - '#.*(unknown class|invalid type|call to method .* on an unknown class) AC\\ListScreen.*#'
57
+
58
+ # Elementor
59
+ - '#.*(unknown class|invalid type|call to method .* on an unknown class) Elementor\\.*#'
60
+
61
+ # Yoast SEO
62
+ - '#.*(unknown class|invalid type|call to method .* on an unknown class) WPSEO_.*#'
63
+ ```
64
+
65
+ Pattern creation rules:
66
+
67
+ - Cover error variations: `unknown class`, `invalid type`, `call to method .* on an unknown class`.
68
+ - Keep patterns specific enough to target only intended classes.
69
+ - Add a short comment naming the plugin/theme.
70
+ - Group related patterns for the same dependency.
71
+
72
+ When to add exceptions:
73
+
74
+ - Only for legitimate third-party dependencies your code integrates with.
75
+ - Document each pattern with a comment.
76
+ - Re-run PHPStan to ensure the ignore does not hide unrelated issues.