claude-plugin-wordpress-manager 1.4.0 → 1.7.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 (81) hide show
  1. package/.claude-plugin/plugin.json +7 -3
  2. package/CHANGELOG.md +111 -0
  3. package/README.md +10 -3
  4. package/agents/wp-accessibility-auditor.md +206 -0
  5. package/agents/wp-content-strategist.md +18 -0
  6. package/agents/wp-deployment-engineer.md +34 -2
  7. package/agents/wp-performance-optimizer.md +12 -0
  8. package/agents/wp-security-auditor.md +20 -0
  9. package/agents/wp-security-hardener.md +266 -0
  10. package/agents/wp-site-manager.md +14 -0
  11. package/agents/wp-test-engineer.md +207 -0
  12. package/docs/GUIDE.md +68 -15
  13. package/docs/guides/INDEX.md +46 -0
  14. package/docs/guides/wp-blog.md +590 -0
  15. package/docs/guides/wp-design-system.md +976 -0
  16. package/docs/guides/wp-ecommerce.md +786 -0
  17. package/docs/guides/wp-landing-page.md +762 -0
  18. package/docs/guides/wp-portfolio.md +713 -0
  19. package/docs/plans/2026-02-27-design-system-guide-design.md +30 -0
  20. package/docs/plans/2026-02-27-local-dev-tools-assessment.md +332 -0
  21. package/docs/plans/2026-02-27-local-env-design.md +179 -0
  22. package/docs/plans/2026-02-27-site-type-guides-design.md +44 -0
  23. package/package.json +7 -3
  24. package/skills/wordpress-router/SKILL.md +25 -5
  25. package/skills/wordpress-router/references/decision-tree.md +59 -3
  26. package/skills/wp-accessibility/SKILL.md +170 -0
  27. package/skills/wp-accessibility/references/a11y-audit-tools.md +248 -0
  28. package/skills/wp-accessibility/references/a11y-testing.md +222 -0
  29. package/skills/wp-accessibility/references/block-a11y.md +247 -0
  30. package/skills/wp-accessibility/references/interactive-a11y.md +272 -0
  31. package/skills/wp-accessibility/references/media-a11y.md +254 -0
  32. package/skills/wp-accessibility/references/theme-a11y.md +309 -0
  33. package/skills/wp-audit/SKILL.md +4 -0
  34. package/skills/wp-block-development/SKILL.md +5 -0
  35. package/skills/wp-block-themes/SKILL.md +4 -0
  36. package/skills/wp-deploy/SKILL.md +12 -0
  37. package/skills/wp-e2e-testing/SKILL.md +186 -0
  38. package/skills/wp-e2e-testing/references/ci-integration.md +174 -0
  39. package/skills/wp-e2e-testing/references/jest-wordpress.md +114 -0
  40. package/skills/wp-e2e-testing/references/phpunit-wordpress.md +141 -0
  41. package/skills/wp-e2e-testing/references/playwright-wordpress.md +108 -0
  42. package/skills/wp-e2e-testing/references/test-data-generation.md +127 -0
  43. package/skills/wp-e2e-testing/references/visual-regression.md +107 -0
  44. package/skills/wp-e2e-testing/references/wp-env-setup.md +97 -0
  45. package/skills/wp-e2e-testing/scripts/test_inspect.mjs +375 -0
  46. package/skills/wp-headless/SKILL.md +168 -0
  47. package/skills/wp-headless/references/api-layer-choice.md +160 -0
  48. package/skills/wp-headless/references/cors-config.md +245 -0
  49. package/skills/wp-headless/references/frontend-integration.md +331 -0
  50. package/skills/wp-headless/references/headless-auth.md +286 -0
  51. package/skills/wp-headless/references/webhooks.md +277 -0
  52. package/skills/wp-headless/references/wpgraphql.md +331 -0
  53. package/skills/wp-headless/scripts/headless_inspect.mjs +321 -0
  54. package/skills/wp-i18n/SKILL.md +170 -0
  55. package/skills/wp-i18n/references/js-i18n.md +201 -0
  56. package/skills/wp-i18n/references/multilingual-setup.md +219 -0
  57. package/skills/wp-i18n/references/php-i18n.md +196 -0
  58. package/skills/wp-i18n/references/rtl-support.md +206 -0
  59. package/skills/wp-i18n/references/translation-workflow.md +178 -0
  60. package/skills/wp-i18n/references/wpcli-i18n.md +177 -0
  61. package/skills/wp-i18n/scripts/i18n_inspect.mjs +330 -0
  62. package/skills/wp-interactivity-api/SKILL.md +4 -0
  63. package/skills/wp-local-env/SKILL.md +233 -0
  64. package/skills/wp-local-env/references/localwp-adapter.md +156 -0
  65. package/skills/wp-local-env/references/mcp-adapter-setup.md +153 -0
  66. package/skills/wp-local-env/references/studio-adapter.md +127 -0
  67. package/skills/wp-local-env/references/wpenv-adapter.md +121 -0
  68. package/skills/wp-local-env/scripts/detect_local_env.mjs +404 -0
  69. package/skills/wp-playground/SKILL.md +13 -1
  70. package/skills/wp-plugin-development/SKILL.md +6 -0
  71. package/skills/wp-rest-api/SKILL.md +4 -0
  72. package/skills/wp-security/SKILL.md +179 -0
  73. package/skills/wp-security/references/api-restriction.md +147 -0
  74. package/skills/wp-security/references/authentication-hardening.md +105 -0
  75. package/skills/wp-security/references/filesystem-hardening.md +105 -0
  76. package/skills/wp-security/references/http-headers.md +105 -0
  77. package/skills/wp-security/references/incident-response.md +144 -0
  78. package/skills/wp-security/references/user-capabilities.md +115 -0
  79. package/skills/wp-security/references/wp-config-security.md +129 -0
  80. package/skills/wp-security/scripts/security_inspect.mjs +393 -0
  81. package/skills/wp-wpcli-and-ops/SKILL.md +6 -0
@@ -0,0 +1,121 @@
1
+ # wp-env Adapter
2
+
3
+ ## Prerequisites
4
+
5
+ - **Docker** installed and running (`docker info`)
6
+ - **Node.js** 18+ and npm
7
+ - `.wp-env.json` in the project root
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm -g install @wordpress/env
13
+ # or use npx (no install):
14
+ npx @wordpress/env start
15
+ ```
16
+
17
+ ## Configuration (.wp-env.json)
18
+
19
+ Minimal:
20
+ ```json
21
+ {
22
+ "core": null,
23
+ "plugins": ["./my-plugin"],
24
+ "themes": ["./my-theme"]
25
+ }
26
+ ```
27
+
28
+ Full example:
29
+ ```json
30
+ {
31
+ "core": "WordPress/WordPress#6.9",
32
+ "phpVersion": "8.2",
33
+ "plugins": [
34
+ "./my-plugin",
35
+ "https://downloads.wordpress.org/plugin/woocommerce.latest-stable.zip"
36
+ ],
37
+ "themes": ["./my-theme"],
38
+ "port": 8888,
39
+ "testsPort": 8889,
40
+ "config": {
41
+ "WP_DEBUG": true,
42
+ "WP_DEBUG_LOG": true,
43
+ "SCRIPT_DEBUG": true
44
+ },
45
+ "mappings": {
46
+ "wp-content/mu-plugins": "./mu-plugins"
47
+ }
48
+ }
49
+ ```
50
+
51
+ Override per-developer settings in `.wp-env.override.json` (gitignored).
52
+
53
+ ## Commands
54
+
55
+ ```bash
56
+ # Start development and test environments
57
+ npx wp-env start
58
+ npx wp-env start --update # Also pull latest images
59
+
60
+ # Stop environments
61
+ npx wp-env stop
62
+
63
+ # Destroy (remove containers and data)
64
+ npx wp-env destroy
65
+
66
+ # Run WP-CLI commands
67
+ npx wp-env run cli wp <command>
68
+ npx wp-env run cli wp plugin list
69
+ npx wp-env run cli wp scaffold block my-block --plugin=my-plugin
70
+ npx wp-env run cli wp db export /tmp/backup.sql
71
+
72
+ # Run arbitrary commands in containers
73
+ npx wp-env run cli bash
74
+ npx wp-env run tests-cli wp test
75
+ ```
76
+
77
+ ## Ports
78
+
79
+ | Environment | Default port |
80
+ |-------------|-------------|
81
+ | Development | `http://localhost:8888` |
82
+ | Tests | `http://localhost:8889` |
83
+
84
+ Configurable via `port` and `testsPort` in `.wp-env.json`.
85
+
86
+ ## Default credentials
87
+
88
+ - **User**: `admin`
89
+ - **Password**: `password`
90
+ - **Database**: Inside Docker container (not directly accessible from host)
91
+
92
+ ## REST API
93
+
94
+ ```bash
95
+ curl http://localhost:8888/wp-json/wp/v2/posts
96
+ curl -u "admin:password" http://localhost:8888/wp-json/wp/v2/posts
97
+ ```
98
+
99
+ ## When to use wp-env
100
+
101
+ - **WordPress core contribution** — standard for Gutenberg development
102
+ - **CI/CD pipelines** — Docker-based, reproducible
103
+ - **Plugin/theme testing** — isolated, disposable
104
+ - **PHPUnit tests** — `npx wp-env run tests-cli --env-cwd=wp-content/plugins/my-plugin phpunit`
105
+
106
+ ## When NOT to use wp-env
107
+
108
+ - Quick theme previews → use WordPress Studio instead
109
+ - Production-parity with specific hosting → use LocalWP
110
+ - No Docker available → use WordPress Studio (WASM-based)
111
+
112
+ ## Comparison with Studio and LocalWP
113
+
114
+ | Feature | wp-env | Studio | LocalWP |
115
+ |---------|--------|--------|---------|
116
+ | Requires Docker | Yes | No | No |
117
+ | Config as code | `.wp-env.json` | CLI flags | GUI |
118
+ | CI/CD friendly | Excellent | Limited | No |
119
+ | Setup speed | Medium (Docker pull) | Fast (WASM) | Slow (native) |
120
+ | Multiple sites | 2 (dev + test) | Unlimited | Unlimited |
121
+ | Multisite | Yes | No | Yes |
@@ -0,0 +1,404 @@
1
+ /**
2
+ * detect_local_env.mjs — Detect local WordPress development environments.
3
+ *
4
+ * Scans for WordPress Studio, LocalWP, and wp-env installations.
5
+ * Outputs a JSON report to stdout with discovered environments, sites,
6
+ * recommended tool, and WP-CLI invocation paths.
7
+ *
8
+ * Usage:
9
+ * node detect_local_env.mjs [--cwd=/path/to/check]
10
+ *
11
+ * Exit codes:
12
+ * 0 — at least one environment found
13
+ * 1 — no environments found
14
+ */
15
+
16
+ import fs from "node:fs";
17
+ import path from "node:path";
18
+ import process from "node:process";
19
+ import { execSync } from "node:child_process";
20
+ import os from "node:os";
21
+
22
+ const TOOL_VERSION = "1.0.0";
23
+
24
+ // ---------------------------------------------------------------------------
25
+ // Helpers
26
+ // ---------------------------------------------------------------------------
27
+
28
+ function statSafe(p) {
29
+ try {
30
+ return fs.statSync(p);
31
+ } catch {
32
+ return null;
33
+ }
34
+ }
35
+
36
+ function readFileSafe(p) {
37
+ try {
38
+ return fs.readFileSync(p, "utf8");
39
+ } catch {
40
+ return null;
41
+ }
42
+ }
43
+
44
+ function readJsonSafe(p) {
45
+ const raw = readFileSafe(p);
46
+ if (!raw) return null;
47
+ try {
48
+ return JSON.parse(raw);
49
+ } catch {
50
+ return null;
51
+ }
52
+ }
53
+
54
+ function execSafe(cmd, timeoutMs = 5000) {
55
+ try {
56
+ return execSync(cmd, { encoding: "utf8", timeout: timeoutMs, stdio: ["pipe", "pipe", "pipe"] }).trim();
57
+ } catch {
58
+ return null;
59
+ }
60
+ }
61
+
62
+ function whichSafe(bin) {
63
+ const cmd = process.platform === "win32" ? `where ${bin}` : `command -v ${bin}`;
64
+ return execSafe(cmd);
65
+ }
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // Platform paths
69
+ // ---------------------------------------------------------------------------
70
+
71
+ function getPlatformPaths() {
72
+ const home = os.homedir();
73
+ const platform = process.platform;
74
+
75
+ if (platform === "darwin") {
76
+ return {
77
+ studio: {
78
+ sites: path.join(home, "Studio"),
79
+ config: path.join(home, "Library", "Application Support", "WordPressStudio"),
80
+ },
81
+ localwp: {
82
+ sites: path.join(home, "Local Sites"),
83
+ config: path.join(home, "Library", "Application Support", "Local"),
84
+ json: path.join(home, "Library", "Application Support", "Local", "sites.json"),
85
+ lightning: path.join(home, "Library", "Application Support", "Local", "lightning-services"),
86
+ run: path.join(home, "Library", "Application Support", "Local", "run"),
87
+ },
88
+ };
89
+ }
90
+
91
+ if (platform === "win32") {
92
+ const appData = process.env.APPDATA || path.join(home, "AppData", "Roaming");
93
+ const localAppData = process.env.LOCALAPPDATA || path.join(home, "AppData", "Local");
94
+ return {
95
+ studio: {
96
+ sites: path.join(home, "Studio"),
97
+ config: path.join(localAppData, "WordPressStudio"),
98
+ },
99
+ localwp: {
100
+ sites: path.join(home, "Local Sites"),
101
+ config: path.join(appData, "Local"),
102
+ json: path.join(appData, "Local", "sites.json"),
103
+ lightning: path.join(appData, "Local", "lightning-services"),
104
+ run: path.join(appData, "Local", "run"),
105
+ },
106
+ };
107
+ }
108
+
109
+ // Linux (default)
110
+ return {
111
+ studio: {
112
+ sites: path.join(home, "Studio"),
113
+ config: path.join(home, ".config", "WordPressStudio"),
114
+ },
115
+ localwp: {
116
+ sites: path.join(home, "Local Sites"),
117
+ config: path.join(home, ".config", "Local"),
118
+ json: path.join(home, ".config", "Local", "sites.json"),
119
+ lightning: path.join(home, ".config", "Local", "lightning-services"),
120
+ run: path.join(home, ".config", "Local", "run"),
121
+ },
122
+ };
123
+ }
124
+
125
+ // ---------------------------------------------------------------------------
126
+ // WordPress Studio detection
127
+ // ---------------------------------------------------------------------------
128
+
129
+ function detectStudio(paths) {
130
+ const cli = whichSafe("studio");
131
+ const sitesDir = paths.studio.sites;
132
+ const hasSitesDir = statSafe(sitesDir)?.isDirectory();
133
+
134
+ if (!cli && !hasSitesDir) return null;
135
+
136
+ // Get version from CLI
137
+ let version = null;
138
+ if (cli) {
139
+ const vOut = execSafe("studio --version");
140
+ if (vOut) version = vOut.replace(/[^0-9.]/g, "") || vOut;
141
+ }
142
+
143
+ // Discover sites
144
+ const sites = [];
145
+ if (hasSitesDir) {
146
+ try {
147
+ const entries = fs.readdirSync(sitesDir, { withFileTypes: true });
148
+ for (const entry of entries) {
149
+ if (!entry.isDirectory()) continue;
150
+ const sitePath = path.join(sitesDir, entry.name);
151
+ const wpConfig = path.join(sitePath, "wp-config.php");
152
+ if (!statSafe(wpConfig)) continue;
153
+
154
+ const site = {
155
+ name: entry.name,
156
+ path: sitePath,
157
+ url: null,
158
+ status: "unknown",
159
+ php: null,
160
+ wp: null,
161
+ db: "sqlite",
162
+ };
163
+
164
+ // Check if SQLite db exists
165
+ const sqliteDb = path.join(sitePath, "wp-content", "database", ".ht.sqlite");
166
+ if (statSafe(sqliteDb)) {
167
+ site.db = "sqlite";
168
+ }
169
+
170
+ // Try to get site info via CLI
171
+ if (cli) {
172
+ const statusOut = execSafe(`studio site status --path="${sitePath}"`);
173
+ if (statusOut) {
174
+ const urlMatch = statusOut.match(/URL:\s*(https?:\/\/\S+)/i);
175
+ if (urlMatch) site.url = urlMatch[1];
176
+ const phpMatch = statusOut.match(/PHP:\s*(\d+\.\d+)/i);
177
+ if (phpMatch) site.php = phpMatch[1];
178
+ const wpMatch = statusOut.match(/WordPress:\s*(\d+\.\d+(?:\.\d+)?)/i);
179
+ if (wpMatch) site.wp = wpMatch[1];
180
+ if (/running/i.test(statusOut)) site.status = "running";
181
+ else if (/stopped/i.test(statusOut)) site.status = "stopped";
182
+ }
183
+ }
184
+
185
+ sites.push(site);
186
+ }
187
+ } catch {
188
+ // Permission or read error — skip
189
+ }
190
+ }
191
+
192
+ return {
193
+ tool: "studio",
194
+ version,
195
+ cli: cli || null,
196
+ sites,
197
+ };
198
+ }
199
+
200
+ // ---------------------------------------------------------------------------
201
+ // LocalWP detection
202
+ // ---------------------------------------------------------------------------
203
+
204
+ function detectLocalWP(paths) {
205
+ const sitesJson = paths.localwp.json;
206
+ const sitesData = readJsonSafe(sitesJson);
207
+ const hasSitesDir = statSafe(paths.localwp.sites)?.isDirectory();
208
+
209
+ if (!sitesData && !hasSitesDir) return null;
210
+
211
+ // Find wp-cli binary
212
+ let wpCliBin = null;
213
+ const lightningDir = paths.localwp.lightning;
214
+ if (statSafe(lightningDir)?.isDirectory()) {
215
+ try {
216
+ const entries = fs.readdirSync(lightningDir);
217
+ const wcliDir = entries.find((e) => e.startsWith("wp-cli"));
218
+ if (wcliDir) {
219
+ const candidate = path.join(lightningDir, wcliDir, "bin", "wp");
220
+ if (statSafe(candidate)) wpCliBin = candidate;
221
+ }
222
+ } catch {
223
+ // Skip
224
+ }
225
+ }
226
+
227
+ // Parse sites from sites.json
228
+ const sites = [];
229
+ if (sitesData && typeof sitesData === "object") {
230
+ const siteEntries = Array.isArray(sitesData) ? sitesData : Object.values(sitesData);
231
+ for (const s of siteEntries) {
232
+ if (!s || typeof s !== "object") continue;
233
+
234
+ const sitePath = s.path
235
+ ? path.join(s.path, "app", "public")
236
+ : s.name
237
+ ? path.join(paths.localwp.sites, s.name, "app", "public")
238
+ : null;
239
+
240
+ const site = {
241
+ name: s.name || s.domain || "unknown",
242
+ path: sitePath,
243
+ url: s.url || (s.domain ? `http://${s.domain}` : null),
244
+ port: s.services?.nginx?.port || s.services?.apache?.port || null,
245
+ status: "unknown",
246
+ php: s.services?.php?.version || null,
247
+ wp: null,
248
+ db: "mysql",
249
+ webServer: s.services?.nginx ? "nginx" : s.services?.apache ? "apache" : null,
250
+ };
251
+
252
+ // Check if site directory exists
253
+ if (sitePath && statSafe(sitePath)?.isDirectory()) {
254
+ site.status = "stopped"; // Directory exists but we can't confirm running
255
+ }
256
+
257
+ // Check MySQL socket to determine if running
258
+ if (s.id && paths.localwp.run) {
259
+ const socketPath = path.join(paths.localwp.run, s.id, "mysql", "mysqld.sock");
260
+ if (statSafe(socketPath)) {
261
+ site.status = "running";
262
+ }
263
+ }
264
+
265
+ sites.push(site);
266
+ }
267
+ }
268
+
269
+ // Get LocalWP version
270
+ let version = null;
271
+ const pkgJson = readJsonSafe(path.join(paths.localwp.config, "package.json"));
272
+ if (pkgJson?.version) version = pkgJson.version;
273
+
274
+ return {
275
+ tool: "localwp",
276
+ version,
277
+ configPath: sitesJson,
278
+ wpCliBin,
279
+ sites,
280
+ };
281
+ }
282
+
283
+ // ---------------------------------------------------------------------------
284
+ // wp-env detection
285
+ // ---------------------------------------------------------------------------
286
+
287
+ function detectWpEnv(cwd) {
288
+ const wpEnvJson = path.join(cwd, ".wp-env.json");
289
+ const wpEnvOverride = path.join(cwd, ".wp-env.override.json");
290
+
291
+ const config = readJsonSafe(wpEnvJson);
292
+ if (!config) return null;
293
+
294
+ const overrides = readJsonSafe(wpEnvOverride);
295
+ const merged = overrides ? { ...config, ...overrides } : config;
296
+
297
+ const devPort = merged.port || 8888;
298
+ const testPort = merged.testsPort || 8889;
299
+
300
+ return {
301
+ tool: "wpenv",
302
+ version: null,
303
+ configPath: wpEnvJson,
304
+ sites: [
305
+ {
306
+ name: "development",
307
+ path: cwd,
308
+ url: `http://localhost:${devPort}`,
309
+ port: devPort,
310
+ status: "unknown",
311
+ php: merged.phpVersion || null,
312
+ wp: merged.core || null,
313
+ db: "mysql",
314
+ },
315
+ {
316
+ name: "tests",
317
+ path: cwd,
318
+ url: `http://localhost:${testPort}`,
319
+ port: testPort,
320
+ status: "unknown",
321
+ php: merged.phpVersion || null,
322
+ wp: merged.core || null,
323
+ db: "mysql",
324
+ },
325
+ ],
326
+ };
327
+ }
328
+
329
+ // ---------------------------------------------------------------------------
330
+ // Recommendation logic
331
+ // ---------------------------------------------------------------------------
332
+
333
+ function recommend(environments) {
334
+ if (environments.length === 0) return null;
335
+ if (environments.length === 1) return environments[0].tool;
336
+
337
+ // Prefer Studio if CLI is available (best automation surface)
338
+ const studio = environments.find((e) => e.tool === "studio" && e.cli);
339
+ if (studio) return "studio";
340
+
341
+ // Then LocalWP if it has sites
342
+ const localwp = environments.find((e) => e.tool === "localwp" && e.sites.length > 0);
343
+ if (localwp) return "localwp";
344
+
345
+ // Then wp-env
346
+ const wpenv = environments.find((e) => e.tool === "wpenv");
347
+ if (wpenv) return "wpenv";
348
+
349
+ return environments[0].tool;
350
+ }
351
+
352
+ function buildWpCliMap(environments) {
353
+ const map = {};
354
+ for (const env of environments) {
355
+ if (env.tool === "studio" && env.cli) {
356
+ map.studio = "studio wp --path=<site>";
357
+ }
358
+ if (env.tool === "localwp" && env.wpCliBin) {
359
+ map.localwp = `${env.wpCliBin} --path=<site>`;
360
+ }
361
+ if (env.tool === "wpenv") {
362
+ map.wpenv = "npx wp-env run cli wp";
363
+ }
364
+ }
365
+ return map;
366
+ }
367
+
368
+ // ---------------------------------------------------------------------------
369
+ // Main
370
+ // ---------------------------------------------------------------------------
371
+
372
+ function main() {
373
+ const args = process.argv.slice(2);
374
+ let cwd = process.cwd();
375
+ for (const arg of args) {
376
+ if (arg.startsWith("--cwd=")) cwd = arg.slice(6);
377
+ }
378
+
379
+ const paths = getPlatformPaths();
380
+ const environments = [];
381
+
382
+ const studio = detectStudio(paths);
383
+ if (studio) environments.push(studio);
384
+
385
+ const localwp = detectLocalWP(paths);
386
+ if (localwp) environments.push(localwp);
387
+
388
+ const wpenv = detectWpEnv(cwd);
389
+ if (wpenv) environments.push(wpenv);
390
+
391
+ const report = {
392
+ version: TOOL_VERSION,
393
+ timestamp: new Date().toISOString(),
394
+ platform: process.platform,
395
+ environments,
396
+ recommended: recommend(environments),
397
+ wpCli: buildWpCliMap(environments),
398
+ };
399
+
400
+ process.stdout.write(JSON.stringify(report, null, 2) + "\n");
401
+ process.exit(environments.length > 0 ? 0 : 1);
402
+ }
403
+
404
+ main();
@@ -99,5 +99,17 @@ npx @wp-playground/cli@latest build-snapshot --blueprint=<file> --outfile=./site
99
99
 
100
100
  ## Escalation
101
101
 
102
- - If PHP extensions or native DB access are required, Playground may be unsuitable; fall back to full WP stack or wp-env/Docker.
102
+ - If PHP extensions or native DB access are required, Playground may be unsuitable; fall back to a local dev environment.
103
+ - For persistent local development, use the `wp-local-env` skill which supports WordPress Studio (WASM-based, lightweight), LocalWP (native MySQL, production-parity), and wp-env (Docker, CI-friendly).
103
104
  - For browser-only embedding or VS Code extension specifics, consult the upstream docs: https://wordpress.github.io/wordpress-playground/
105
+
106
+ ## Relationship with wp-local-env
107
+
108
+ | Need | Use |
109
+ |------|-----|
110
+ | Quick disposable test | wp-playground (this skill) |
111
+ | Persistent local dev with DB | `wp-local-env` (Studio/LocalWP/wp-env) |
112
+ | CI/CD testing | wp-playground (blueprints) or wp-env |
113
+ | Plugin/theme development | `wp-local-env` (symlink workflow) |
114
+ | Version switching (ephemeral) | wp-playground (`--wp=` / `--php=`) |
115
+ | Version switching (persistent) | `wp-local-env` (tool-specific settings) |
@@ -112,3 +112,9 @@ See:
112
112
  ## Escalation
113
113
 
114
114
  For canonical detail, consult the Plugin Handbook and security guidelines before inventing patterns.
115
+
116
+ ## Related skills
117
+
118
+ - `wp-e2e-testing` — PHPUnit for plugin unit tests, Playwright for E2E, CI integration
119
+ - `wp-i18n` — Text domain setup, translation workflow, WP-CLI i18n commands
120
+ - `wp-security` — Filesystem hardening, wp-config constants, authentication security
@@ -114,3 +114,7 @@ Read `references/discovery-and-params.md`.
114
114
  ## Escalation
115
115
 
116
116
  If version support or behavior is unclear, consult the REST API Handbook and core docs before inventing patterns.
117
+
118
+ ## Related skills
119
+
120
+ - `wp-headless` — Decoupled architecture, WPGraphQL, CORS configuration, frontend framework integration, webhooks