wordpress-agent-kit 0.3.2 → 0.5.1
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.
- package/.agents/skills/blueprint/SKILL.md +418 -0
- package/.agents/skills/wordpress-router/SKILL.md +52 -0
- package/.agents/skills/wordpress-router/references/decision-tree.md +55 -0
- package/.agents/skills/wp-abilities-api/SKILL.md +108 -0
- package/.agents/skills/wp-abilities-api/references/delegate-helper-pattern.md +241 -0
- package/.agents/skills/wp-abilities-api/references/domain-vs-projection.md +113 -0
- package/.agents/skills/wp-abilities-api/references/error-code-vocabulary.md +123 -0
- package/.agents/skills/wp-abilities-api/references/grouping-heuristic.md +89 -0
- package/.agents/skills/wp-abilities-api/references/input-schema-gotchas.md +265 -0
- package/.agents/skills/wp-abilities-api/references/php-registration.md +94 -0
- package/.agents/skills/wp-abilities-api/references/plugin-family-patterns.md +233 -0
- package/.agents/skills/wp-abilities-api/references/rest-api.md +13 -0
- package/.agents/skills/wp-abilities-api/references/shared-core-service.md +184 -0
- package/.agents/skills/wp-abilities-audit/SKILL.md +199 -0
- package/.agents/skills/wp-abilities-audit/references/audit-schema.md +300 -0
- package/.agents/skills/wp-abilities-audit/references/capability-gate-tracing.md +197 -0
- package/.agents/skills/wp-abilities-audit/references/controller-enumeration.md +116 -0
- package/.agents/skills/wp-abilities-verify/SKILL.md +215 -0
- package/.agents/skills/wp-abilities-verify/references/annotation-correctness.md +154 -0
- package/.agents/skills/wp-abilities-verify/references/audit-schema-validation.md +131 -0
- package/.agents/skills/wp-abilities-verify/references/permission-roundtrip.md +190 -0
- package/.agents/skills/wp-abilities-verify/references/runtime-harness.md +462 -0
- package/.agents/skills/wp-abilities-verify/references/schema-lints.md +118 -0
- package/.agents/skills/wp-abilities-verify/references/static-enumeration.md +126 -0
- package/.agents/skills/wp-block-development/SKILL.md +175 -0
- package/.agents/skills/wp-block-development/references/attributes-and-serialization.md +22 -0
- package/.agents/skills/wp-block-development/references/block-json.md +49 -0
- package/.agents/skills/wp-block-development/references/creating-new-blocks.md +46 -0
- package/.agents/skills/wp-block-development/references/debugging.md +36 -0
- package/.agents/skills/wp-block-development/references/deprecations.md +24 -0
- package/.agents/skills/wp-block-development/references/dynamic-rendering.md +23 -0
- package/.agents/skills/wp-block-development/references/inner-blocks.md +25 -0
- package/.agents/skills/wp-block-development/references/registration.md +30 -0
- package/.agents/skills/wp-block-development/references/supports-and-wrappers.md +18 -0
- package/.agents/skills/wp-block-development/references/tooling-and-testing.md +21 -0
- package/.agents/skills/wp-block-development/scripts/list_blocks.mjs +121 -0
- package/.agents/skills/wp-block-themes/SKILL.md +117 -0
- package/.agents/skills/wp-block-themes/references/creating-new-block-theme.md +37 -0
- package/.agents/skills/wp-block-themes/references/debugging.md +24 -0
- package/.agents/skills/wp-block-themes/references/patterns.md +18 -0
- package/.agents/skills/wp-block-themes/references/style-variations.md +14 -0
- package/.agents/skills/wp-block-themes/references/templates-and-parts.md +16 -0
- package/.agents/skills/wp-block-themes/references/theme-json.md +59 -0
- package/.agents/skills/wp-block-themes/scripts/detect_block_themes.mjs +117 -0
- package/.agents/skills/wp-interactivity-api/SKILL.md +180 -0
- package/.agents/skills/wp-interactivity-api/references/debugging.md +29 -0
- package/.agents/skills/wp-interactivity-api/references/directives-quickref.md +30 -0
- package/.agents/skills/wp-interactivity-api/references/server-side-rendering.md +310 -0
- package/.agents/skills/wp-performance/SKILL.md +147 -0
- package/.agents/skills/wp-performance/references/autoload-options.md +24 -0
- package/.agents/skills/wp-performance/references/cron.md +20 -0
- package/.agents/skills/wp-performance/references/database.md +20 -0
- package/.agents/skills/wp-performance/references/http-api.md +15 -0
- package/.agents/skills/wp-performance/references/measurement.md +21 -0
- package/.agents/skills/wp-performance/references/object-cache.md +24 -0
- package/.agents/skills/wp-performance/references/query-monitor-headless.md +38 -0
- package/.agents/skills/wp-performance/references/server-timing.md +22 -0
- package/.agents/skills/wp-performance/references/wp-cli-doctor.md +24 -0
- package/.agents/skills/wp-performance/references/wp-cli-profile.md +32 -0
- package/.agents/skills/wp-performance/scripts/perf_inspect.mjs +128 -0
- package/.agents/skills/wp-phpstan/SKILL.md +98 -0
- package/.agents/skills/wp-phpstan/references/configuration.md +52 -0
- package/.agents/skills/wp-phpstan/references/third-party-classes.md +76 -0
- package/.agents/skills/wp-phpstan/references/wordpress-annotations.md +124 -0
- package/.agents/skills/wp-phpstan/scripts/phpstan_inspect.mjs +263 -0
- package/.agents/skills/wp-playground/SKILL.md +233 -0
- package/.agents/skills/wp-playground/references/blueprints.md +36 -0
- package/.agents/skills/wp-playground/references/cli-commands.md +39 -0
- package/.agents/skills/wp-playground/references/debugging.md +16 -0
- package/.agents/skills/wp-playground/references/e2e-playwright.md +115 -0
- package/.agents/skills/wp-plugin-development/SKILL.md +113 -0
- package/.agents/skills/wp-plugin-development/references/data-and-cron.md +19 -0
- package/.agents/skills/wp-plugin-development/references/debugging.md +19 -0
- package/.agents/skills/wp-plugin-development/references/lifecycle.md +33 -0
- package/.agents/skills/wp-plugin-development/references/security.md +29 -0
- package/.agents/skills/wp-plugin-development/references/settings-api.md +22 -0
- package/.agents/skills/wp-plugin-development/references/structure.md +16 -0
- package/.agents/skills/wp-plugin-development/scripts/detect_plugins.mjs +122 -0
- package/.agents/skills/wp-plugin-directory-guidelines/SKILL.md +133 -0
- package/.agents/skills/wp-plugin-directory-guidelines/references/gpl-compliance.md +217 -0
- package/.agents/skills/wp-plugin-directory-guidelines/references/guideline-review-checklist.md +592 -0
- package/.agents/skills/wp-plugin-directory-guidelines/references/naming-rules.md +121 -0
- package/.agents/skills/wp-project-triage/SKILL.md +39 -0
- package/.agents/skills/wp-project-triage/references/triage.schema.json +143 -0
- package/.agents/skills/wp-project-triage/scripts/detect_wp_project.mjs +610 -0
- package/.agents/skills/wp-rest-api/SKILL.md +115 -0
- package/.agents/skills/wp-rest-api/references/authentication.md +18 -0
- package/.agents/skills/wp-rest-api/references/custom-content-types.md +20 -0
- package/.agents/skills/wp-rest-api/references/discovery-and-params.md +20 -0
- package/.agents/skills/wp-rest-api/references/responses-and-fields.md +30 -0
- package/.agents/skills/wp-rest-api/references/routes-and-endpoints.md +36 -0
- package/.agents/skills/wp-rest-api/references/schema.md +22 -0
- package/.agents/skills/wp-wpcli-and-ops/SKILL.md +126 -0
- package/.agents/skills/wp-wpcli-and-ops/references/automation.md +30 -0
- package/.agents/skills/wp-wpcli-and-ops/references/cron-and-cache.md +23 -0
- package/.agents/skills/wp-wpcli-and-ops/references/debugging.md +17 -0
- package/.agents/skills/wp-wpcli-and-ops/references/multisite.md +22 -0
- package/.agents/skills/wp-wpcli-and-ops/references/packages-and-updates.md +22 -0
- package/.agents/skills/wp-wpcli-and-ops/references/safety.md +30 -0
- package/.agents/skills/wp-wpcli-and-ops/references/search-replace.md +40 -0
- package/.agents/skills/wp-wpcli-and-ops/scripts/wpcli_inspect.mjs +90 -0
- package/.agents/skills/wp-wpengine/SKILL.md +398 -0
- package/.agents/skills/wp-wpengine/references/ci-gate.md +469 -0
- package/.agents/skills/wp-wpengine/references/github-actions-deploy.md +736 -0
- package/.agents/skills/wp-wpengine/scripts/ci-gate.sh +118 -0
- package/.agents/skills/wp-wpengine/scripts/wpe-check.sh +89 -0
- package/.agents/skills/wp-wpengine/scripts/wpe-preflight.sh +104 -0
- package/.agents/skills/wpds/SKILL.md +59 -0
- package/.github/agents/wp-architect.agent.md +1 -2
- package/.github/copilot-instructions.md +1 -1
- package/.github/instructions/wordpress-workflow.instructions.md +3 -3
- package/.github/skills/wp-playground/SKILL.md +132 -1
- package/.github/skills/wp-playground/references/e2e-playwright.md +115 -0
- package/.github/skills/wp-wpengine/SKILL.md +127 -0
- package/AGENTS.md +22 -10
- package/AGENTS.template.md +20 -10
- package/README.md +93 -86
- package/dist/cli.js +5 -1
- package/dist/commands/clean-skills.js +64 -0
- package/dist/commands/setup.js +6 -2
- package/dist/commands/sync-skills.js +3 -0
- package/dist/lib/api.js +176 -4
- package/dist/lib/installer.js +166 -2
- package/extensions/wp-agent-kit/index.ts +185 -10
- package/package.json +10 -14
- package/skills-custom/wp-wpengine/SKILL.md +398 -0
- package/skills-custom/wp-wpengine/references/ci-gate.md +469 -0
- package/skills-custom/wp-wpengine/references/github-actions-deploy.md +736 -0
- package/skills-custom/wp-wpengine/scripts/ci-gate.sh +118 -0
- package/skills-custom/wp-wpengine/scripts/wpe-check.sh +89 -0
- package/skills-custom/wp-wpengine/scripts/wpe-preflight.sh +104 -0
- package/.github/workflows/ci.yml +0 -44
- package/.husky/pre-commit +0 -7
- package/CLI_REVIEW.md +0 -250
- package/biome.json +0 -39
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
## Debugging WordPress Playground
|
|
2
|
+
|
|
3
|
+
- Start CLI with Xdebug: `server --auto-mount --xdebug` (or `--enable-xdebug` depending on release). The CLI prints host/port and IDE key to configure your debugger.
|
|
4
|
+
- If breakpoints are not hit, confirm:
|
|
5
|
+
- IDE listens on the port shown by CLI.
|
|
6
|
+
- Path mappings include the mounted VFS path used by Playground.
|
|
7
|
+
- For slow or stuck runs:
|
|
8
|
+
- Add `--verbosity=debug` to see step-level logs.
|
|
9
|
+
- Disable `--experimental-multi-worker` if it was enabled.
|
|
10
|
+
- For mount issues:
|
|
11
|
+
- Prefer absolute paths in `--mount`.
|
|
12
|
+
- Use `--mount-before-install` when installer steps need files present early.
|
|
13
|
+
- To inspect runtime state:
|
|
14
|
+
- Open the Playground browser console; the Service Worker logs network/FS events.
|
|
15
|
+
- Use the “Terminal” tab (if available) to run WP-CLI inside the instance.
|
|
16
|
+
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# E2E Testing with Playwright + WordPress Playground
|
|
2
|
+
|
|
3
|
+
## Install
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install --save-dev @playwright/test @wp-playground/cli
|
|
7
|
+
npx playwright install chromium
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## playwright.config.ts
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { defineConfig } from '@playwright/test';
|
|
14
|
+
export default defineConfig({
|
|
15
|
+
testDir: './tests/e2e',
|
|
16
|
+
fullyParallel: false,
|
|
17
|
+
forbidOnly: !!process.env.CI,
|
|
18
|
+
retries: process.env.CI ? 2 : 0,
|
|
19
|
+
workers: 1,
|
|
20
|
+
reporter: 'html',
|
|
21
|
+
timeout: 120_000,
|
|
22
|
+
expect: { timeout: 30_000 },
|
|
23
|
+
use: { screenshot: 'only-on-failure', trace: 'on-first-retry' },
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Server lifecycle
|
|
28
|
+
|
|
29
|
+
**Shared** (faster, tests can affect each other — use for read-only tests):
|
|
30
|
+
```ts
|
|
31
|
+
test.beforeAll(async () => { cli = await runCLI({ command: 'server', blueprint }); });
|
|
32
|
+
test.afterAll(async () => { await cli?.server?.close(); });
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Per-test** (isolated, slower — use when tests modify state):
|
|
36
|
+
```ts
|
|
37
|
+
test.beforeEach(async () => { cli = await runCLI({ command: 'server', blueprint }); });
|
|
38
|
+
test.afterEach(async () => { await cli?.server?.close(); });
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Blueprint fixtures
|
|
42
|
+
|
|
43
|
+
Installing from wordpress.org:
|
|
44
|
+
```ts
|
|
45
|
+
steps: [{ step: 'installPlugin', pluginData: { resource: 'wordpress.org/plugins', slug: 'contact-form-7' } }]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Creating content:
|
|
49
|
+
```ts
|
|
50
|
+
steps: [{ step: 'runPHP', code: `<?php require '/wordpress/wp-load.php'; wp_insert_post([...]);` }]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## WordPress-specific locator guidance
|
|
54
|
+
|
|
55
|
+
- `page.getByRole('button', { name: 'Save Changes' })` — works for standard WP buttons
|
|
56
|
+
- `page.getByLabel('API Key')` — works for labeled form fields
|
|
57
|
+
- `page.locator('#wpadminbar')` — CSS required for WP core layout elements (no ARIA)
|
|
58
|
+
- Add `data-testid` to your own plugin markup for stable selectors
|
|
59
|
+
- Run `npx playwright codegen localhost:9400/wp-admin/` to auto-generate locators
|
|
60
|
+
|
|
61
|
+
## Page Object Model
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
// tests/e2e/pages/plugin-settings.ts
|
|
65
|
+
export class PluginSettingsPage {
|
|
66
|
+
constructor(readonly page: Page) {}
|
|
67
|
+
async goto(baseUrl: string) { await this.page.goto(`${baseUrl}/wp-admin/options-general.php?page=my-plugin`); }
|
|
68
|
+
async setApiKey(key: string) {
|
|
69
|
+
await this.page.getByLabel('API Key').fill(key);
|
|
70
|
+
await this.page.getByRole('button', { name: 'Save Changes' }).click();
|
|
71
|
+
}
|
|
72
|
+
async expectSaved() { await expect(this.page.getByText('Settings saved')).toBeVisible(); }
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## GitHub Actions CI
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
name: E2E Tests
|
|
80
|
+
on:
|
|
81
|
+
push: { branches: [main] }
|
|
82
|
+
pull_request: { branches: [main] }
|
|
83
|
+
jobs:
|
|
84
|
+
e2e:
|
|
85
|
+
runs-on: ubuntu-latest
|
|
86
|
+
steps:
|
|
87
|
+
- uses: actions/checkout@v4
|
|
88
|
+
- uses: actions/setup-node@v4
|
|
89
|
+
with: { node-version: 20, cache: 'npm' }
|
|
90
|
+
- run: npm ci
|
|
91
|
+
- uses: actions/cache@v4
|
|
92
|
+
id: playwright-cache
|
|
93
|
+
with:
|
|
94
|
+
path: ~/.cache/ms-playwright
|
|
95
|
+
key: playwright-${{ hashFiles('package-lock.json') }}
|
|
96
|
+
- if: steps.playwright-cache.outputs.cache-hit != 'true'
|
|
97
|
+
run: npx playwright install chromium --with-deps
|
|
98
|
+
- run: npx playwright test
|
|
99
|
+
- uses: actions/upload-artifact@v4
|
|
100
|
+
if: ${{ !cancelled() }}
|
|
101
|
+
with: { name: playwright-report, path: playwright-report/, retention-days: 30 }
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Troubleshooting
|
|
105
|
+
|
|
106
|
+
- **Timeout errors** — increase `timeout` in config; CI needs 120–180s
|
|
107
|
+
- **Port conflicts** — don't hardcode ports; use `cli.serverUrl`
|
|
108
|
+
- **Browser not found** — run `npx playwright install chromium`
|
|
109
|
+
- **Passes locally, fails CI** — increase timeouts, ensure `workers: 1`
|
|
110
|
+
- **Debug** — `npx playwright test --debug` or `--ui` for interactive mode
|
|
111
|
+
|
|
112
|
+
## Docs
|
|
113
|
+
|
|
114
|
+
- https://wordpress.github.io/wordpress-playground/guides/e2e-testing-with-playwright
|
|
115
|
+
- https://wordpress.github.io/wordpress-playground/guides/programmatic-playground-cli
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wp-plugin-development
|
|
3
|
+
description: "Use when developing WordPress plugins: architecture and hooks, activation/deactivation/uninstall, admin UI and Settings API, data storage, cron/tasks, security (nonces/capabilities/sanitization/escaping), and release packaging."
|
|
4
|
+
license: GPL-2.0-or-later
|
|
5
|
+
compatibility: "Targets WordPress 6.9+ (PHP 7.2.24+). Filesystem-based agent with bash + node. Some workflows require WP-CLI."
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# WP Plugin Development
|
|
9
|
+
|
|
10
|
+
## When to use
|
|
11
|
+
|
|
12
|
+
Use this skill for plugin work such as:
|
|
13
|
+
|
|
14
|
+
- creating or refactoring plugin structure (bootstrap, includes, namespaces/classes)
|
|
15
|
+
- adding hooks/actions/filters
|
|
16
|
+
- activation/deactivation/uninstall behavior and migrations
|
|
17
|
+
- adding settings pages / options / admin UI (Settings API)
|
|
18
|
+
- security fixes (nonces, capabilities, sanitization/escaping, SQL safety)
|
|
19
|
+
- packaging a release (build artifacts, readme, assets)
|
|
20
|
+
|
|
21
|
+
## Inputs required
|
|
22
|
+
|
|
23
|
+
- Repo root + target plugin(s) (path to plugin main file if known).
|
|
24
|
+
- Where this plugin runs: single site vs multisite; WP.com conventions if applicable.
|
|
25
|
+
- Target WordPress + PHP versions (affects available APIs and placeholder support in `$wpdb->prepare()`).
|
|
26
|
+
|
|
27
|
+
## Procedure
|
|
28
|
+
|
|
29
|
+
### 0) Triage and locate plugin entrypoints
|
|
30
|
+
|
|
31
|
+
1. Run triage:
|
|
32
|
+
- `node skills/wp-project-triage/scripts/detect_wp_project.mjs`
|
|
33
|
+
2. Detect plugin headers (deterministic scan):
|
|
34
|
+
- `node skills/wp-plugin-development/scripts/detect_plugins.mjs`
|
|
35
|
+
|
|
36
|
+
If this is a full site repo, pick the specific plugin under `wp-content/plugins/` or `mu-plugins/` before changing code.
|
|
37
|
+
|
|
38
|
+
### 1) Follow a predictable architecture
|
|
39
|
+
|
|
40
|
+
Guidelines:
|
|
41
|
+
|
|
42
|
+
- Keep a single bootstrap (main plugin file with header).
|
|
43
|
+
- Avoid heavy side effects at file load time; load on hooks.
|
|
44
|
+
- Prefer a dedicated loader/class to register hooks.
|
|
45
|
+
- Keep admin-only code behind `is_admin()` (or admin hooks) to reduce frontend overhead.
|
|
46
|
+
|
|
47
|
+
See:
|
|
48
|
+
- `references/structure.md`
|
|
49
|
+
|
|
50
|
+
### 2) Hooks and lifecycle (activation/deactivation/uninstall)
|
|
51
|
+
|
|
52
|
+
Activation hooks are fragile; follow guardrails:
|
|
53
|
+
|
|
54
|
+
- register activation/deactivation hooks at top-level, not inside other hooks
|
|
55
|
+
- flush rewrite rules only when needed and only after registering CPTs/rules
|
|
56
|
+
- uninstall should be explicit and safe (`uninstall.php` or `register_uninstall_hook`)
|
|
57
|
+
|
|
58
|
+
See:
|
|
59
|
+
- `references/lifecycle.md`
|
|
60
|
+
|
|
61
|
+
### 3) Settings and admin UI (Settings API)
|
|
62
|
+
|
|
63
|
+
Prefer Settings API for options:
|
|
64
|
+
|
|
65
|
+
- `register_setting()`, `add_settings_section()`, `add_settings_field()`
|
|
66
|
+
- sanitize via `sanitize_callback`
|
|
67
|
+
|
|
68
|
+
See:
|
|
69
|
+
- `references/settings-api.md`
|
|
70
|
+
|
|
71
|
+
### 4) Security baseline (always)
|
|
72
|
+
|
|
73
|
+
Before shipping:
|
|
74
|
+
|
|
75
|
+
- Validate/sanitize input early; escape output late.
|
|
76
|
+
- Use nonces to prevent CSRF *and* capability checks for authorization.
|
|
77
|
+
- Avoid directly trusting `$_POST` / `$_GET`; use `wp_unslash()` and specific keys.
|
|
78
|
+
- Use `$wpdb->prepare()` for SQL; avoid building SQL with string concatenation.
|
|
79
|
+
|
|
80
|
+
See:
|
|
81
|
+
- `references/security.md`
|
|
82
|
+
|
|
83
|
+
### 5) Data storage, cron, migrations (if needed)
|
|
84
|
+
|
|
85
|
+
- Prefer options for small config; custom tables only if necessary.
|
|
86
|
+
- For cron tasks, ensure idempotency and provide manual run paths (WP-CLI or admin).
|
|
87
|
+
- For schema changes, write upgrade routines and store schema version.
|
|
88
|
+
|
|
89
|
+
See:
|
|
90
|
+
- `references/data-and-cron.md`
|
|
91
|
+
|
|
92
|
+
## Verification
|
|
93
|
+
|
|
94
|
+
- Plugin activates with no fatals/notices.
|
|
95
|
+
- Settings save and read correctly (capability + nonce enforced).
|
|
96
|
+
- Uninstall removes intended data (and nothing else).
|
|
97
|
+
- Run repo lint/tests (PHPUnit/PHPCS if present) and any JS build steps if the plugin ships assets.
|
|
98
|
+
|
|
99
|
+
## Failure modes / debugging
|
|
100
|
+
|
|
101
|
+
- Activation hook not firing:
|
|
102
|
+
- hook registered incorrectly (not in main file scope), wrong main file path, or plugin is network-activated
|
|
103
|
+
- Settings not saving:
|
|
104
|
+
- settings not registered, wrong option group, missing capability, nonce failure
|
|
105
|
+
- Security regressions:
|
|
106
|
+
- nonce present but missing capability checks; or sanitized input not escaped on output
|
|
107
|
+
|
|
108
|
+
See:
|
|
109
|
+
- `references/debugging.md`
|
|
110
|
+
|
|
111
|
+
## Escalation
|
|
112
|
+
|
|
113
|
+
For canonical detail, consult the Plugin Handbook and security guidelines before inventing patterns.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Data storage, cron, and upgrades
|
|
2
|
+
|
|
3
|
+
Use this file when adding persistent storage, background jobs, or upgrade routines.
|
|
4
|
+
|
|
5
|
+
## Data storage
|
|
6
|
+
|
|
7
|
+
- Prefer Options API for small config/state.
|
|
8
|
+
- Use custom tables only when needed; store schema version and provide upgrade paths.
|
|
9
|
+
|
|
10
|
+
## Cron
|
|
11
|
+
|
|
12
|
+
- Ensure tasks are idempotent (may run late or multiple times).
|
|
13
|
+
- Provide a manual trigger path for debugging (WP-CLI or admin-only action).
|
|
14
|
+
|
|
15
|
+
## Database safety note
|
|
16
|
+
|
|
17
|
+
If using `$wpdb->prepare()`, avoid building queries with concatenated user input.
|
|
18
|
+
Recent WordPress versions support identifier placeholders (`%i`) but you must not assume it exists without checking capabilities or target versions.
|
|
19
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Debugging quick routes
|
|
2
|
+
|
|
3
|
+
## Plugin doesn’t load / fatal errors
|
|
4
|
+
|
|
5
|
+
- Confirm correct plugin main file and header.
|
|
6
|
+
- Check PHP error logs and `WP_DEBUG_LOG`.
|
|
7
|
+
- If the repo is a site repo, confirm you edited the correct plugin under `wp-content/plugins/`.
|
|
8
|
+
|
|
9
|
+
## Activation hook surprises
|
|
10
|
+
|
|
11
|
+
- Hooks must be registered at top-level.
|
|
12
|
+
- Activation runs in a special context; avoid assuming other hooks already ran.
|
|
13
|
+
|
|
14
|
+
## Settings not saving
|
|
15
|
+
|
|
16
|
+
- Confirm `register_setting()` is called.
|
|
17
|
+
- Confirm the option group matches the form.
|
|
18
|
+
- Confirm capability checks and nonces.
|
|
19
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Activation, deactivation, uninstall
|
|
2
|
+
|
|
3
|
+
Use this file for lifecycle changes and data cleanup.
|
|
4
|
+
|
|
5
|
+
## Activation / deactivation hooks
|
|
6
|
+
|
|
7
|
+
- `register_activation_hook( __FILE__, 'callback' )`
|
|
8
|
+
- `register_deactivation_hook( __FILE__, 'callback' )`
|
|
9
|
+
|
|
10
|
+
Guardrails:
|
|
11
|
+
|
|
12
|
+
- These hooks must be registered at top-level (not inside other hooks).
|
|
13
|
+
- If you flush rewrite rules, ensure rules are registered first (often via a shared function called both on `init` and activation).
|
|
14
|
+
|
|
15
|
+
Upstream reference:
|
|
16
|
+
|
|
17
|
+
- https://developer.wordpress.org/plugins/plugin-basics/activation-deactivation-hooks/
|
|
18
|
+
|
|
19
|
+
## Uninstall
|
|
20
|
+
|
|
21
|
+
Preferred approaches:
|
|
22
|
+
|
|
23
|
+
- `uninstall.php` (runs only on uninstall)
|
|
24
|
+
- `register_uninstall_hook()`
|
|
25
|
+
|
|
26
|
+
Guardrails:
|
|
27
|
+
|
|
28
|
+
- Check `WP_UNINSTALL_PLUGIN` before running destructive cleanup.
|
|
29
|
+
|
|
30
|
+
Upstream reference:
|
|
31
|
+
|
|
32
|
+
- https://developer.wordpress.org/plugins/plugin-basics/uninstall-methods/
|
|
33
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Security guardrails (plugin work)
|
|
2
|
+
|
|
3
|
+
Use this file when making security fixes or when handling any input/output.
|
|
4
|
+
|
|
5
|
+
## Nonces + permissions
|
|
6
|
+
|
|
7
|
+
- Nonces help prevent CSRF, not authorization.
|
|
8
|
+
- Always pair nonces with capability checks (`current_user_can()` or a more specific capability).
|
|
9
|
+
|
|
10
|
+
Upstream reference:
|
|
11
|
+
|
|
12
|
+
- https://developer.wordpress.org/apis/security/nonces/
|
|
13
|
+
|
|
14
|
+
## Sanitization and escaping
|
|
15
|
+
|
|
16
|
+
Golden rule:
|
|
17
|
+
|
|
18
|
+
- sanitize/validate on input, escape on output.
|
|
19
|
+
|
|
20
|
+
Practical rules:
|
|
21
|
+
|
|
22
|
+
- never process the entire `$_POST` / `$_GET` array; read explicit keys
|
|
23
|
+
- use `wp_unslash()` before sanitizing when needed
|
|
24
|
+
- use prepared statements for SQL; avoid interpolating user input into queries
|
|
25
|
+
|
|
26
|
+
Common review guidance:
|
|
27
|
+
|
|
28
|
+
- https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/
|
|
29
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Settings API (admin options)
|
|
2
|
+
|
|
3
|
+
Use this file when adding settings pages or storing user-configurable options.
|
|
4
|
+
|
|
5
|
+
Core APIs:
|
|
6
|
+
|
|
7
|
+
- `register_setting()`
|
|
8
|
+
- `add_settings_section()`
|
|
9
|
+
- `add_settings_field()`
|
|
10
|
+
|
|
11
|
+
Upstream references:
|
|
12
|
+
|
|
13
|
+
- Settings API overview: https://developer.wordpress.org/plugins/settings/settings-api/
|
|
14
|
+
- Register settings: https://developer.wordpress.org/plugins/settings/registration/
|
|
15
|
+
- Add settings fields: https://developer.wordpress.org/plugins/settings/settings-fields/
|
|
16
|
+
|
|
17
|
+
Practical guardrails:
|
|
18
|
+
|
|
19
|
+
- Use `sanitize_callback` to validate/sanitize data.
|
|
20
|
+
- Use capability checks (commonly `manage_options`) for settings screens and saves.
|
|
21
|
+
- Escape values on output (`esc_attr`, `esc_html`, etc.).
|
|
22
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Plugin structure and loading
|
|
2
|
+
|
|
3
|
+
Use this file when introducing or refactoring a plugin architecture.
|
|
4
|
+
|
|
5
|
+
## Core concepts
|
|
6
|
+
|
|
7
|
+
- Main plugin file contains the plugin header and bootstraps the plugin.
|
|
8
|
+
- Prefer predictable init:
|
|
9
|
+
- minimal boot file
|
|
10
|
+
- a loader/class that registers hooks
|
|
11
|
+
- admin-only code behind admin hooks
|
|
12
|
+
|
|
13
|
+
Upstream reference:
|
|
14
|
+
|
|
15
|
+
- https://developer.wordpress.org/plugins/plugin-basics/
|
|
16
|
+
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
const DEFAULT_IGNORES = new Set([
|
|
5
|
+
".git",
|
|
6
|
+
"node_modules",
|
|
7
|
+
"vendor",
|
|
8
|
+
"dist",
|
|
9
|
+
"build",
|
|
10
|
+
"coverage",
|
|
11
|
+
".next",
|
|
12
|
+
".turbo",
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
function statSafe(p) {
|
|
16
|
+
try {
|
|
17
|
+
return fs.statSync(p);
|
|
18
|
+
} catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function readFileSafe(p, maxBytes = 128 * 1024) {
|
|
24
|
+
try {
|
|
25
|
+
const buf = fs.readFileSync(p);
|
|
26
|
+
if (buf.byteLength > maxBytes) return buf.subarray(0, maxBytes).toString("utf8");
|
|
27
|
+
return buf.toString("utf8");
|
|
28
|
+
} catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function findFilesRecursive(repoRoot, predicate, { maxFiles = 6000, maxDepth = 10 } = {}) {
|
|
34
|
+
const results = [];
|
|
35
|
+
const queue = [{ dir: repoRoot, depth: 0 }];
|
|
36
|
+
let visited = 0;
|
|
37
|
+
|
|
38
|
+
while (queue.length > 0) {
|
|
39
|
+
const { dir, depth } = queue.shift();
|
|
40
|
+
if (depth > maxDepth) continue;
|
|
41
|
+
|
|
42
|
+
let entries;
|
|
43
|
+
try {
|
|
44
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
45
|
+
} catch {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (const ent of entries) {
|
|
50
|
+
const fullPath = path.join(dir, ent.name);
|
|
51
|
+
if (ent.isDirectory()) {
|
|
52
|
+
if (DEFAULT_IGNORES.has(ent.name)) continue;
|
|
53
|
+
queue.push({ dir: fullPath, depth: depth + 1 });
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (!ent.isFile()) continue;
|
|
57
|
+
|
|
58
|
+
visited += 1;
|
|
59
|
+
if (visited > maxFiles) return { results, truncated: true };
|
|
60
|
+
if (predicate(fullPath)) results.push(fullPath);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return { results, truncated: false };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function parsePluginHeader(contents) {
|
|
68
|
+
// WordPress reads plugin headers from the top of the file. We only need key fields.
|
|
69
|
+
const header = {};
|
|
70
|
+
const pairs = [
|
|
71
|
+
["Plugin Name", "name"],
|
|
72
|
+
["Plugin URI", "uri"],
|
|
73
|
+
["Description", "description"],
|
|
74
|
+
["Version", "version"],
|
|
75
|
+
["Author", "author"],
|
|
76
|
+
["Author URI", "authorUri"],
|
|
77
|
+
["Text Domain", "textDomain"],
|
|
78
|
+
["Domain Path", "domainPath"],
|
|
79
|
+
];
|
|
80
|
+
for (const [label, key] of pairs) {
|
|
81
|
+
const m = contents.match(new RegExp(`^\\s*${label}:\\s*(.+)\\s*$`, "im"));
|
|
82
|
+
if (m) header[key] = m[1].trim();
|
|
83
|
+
}
|
|
84
|
+
if (!header.name) return null;
|
|
85
|
+
return header;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function main() {
|
|
89
|
+
const repoRoot = process.cwd();
|
|
90
|
+
|
|
91
|
+
const { results: phpFiles, truncated } = findFilesRecursive(repoRoot, (p) => p.toLowerCase().endsWith(".php"), {
|
|
92
|
+
maxFiles: 5000,
|
|
93
|
+
maxDepth: 10,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const plugins = [];
|
|
97
|
+
|
|
98
|
+
for (const phpPath of phpFiles) {
|
|
99
|
+
const txt = readFileSafe(phpPath);
|
|
100
|
+
if (!txt) continue;
|
|
101
|
+
if (!/Plugin Name:/i.test(txt)) continue;
|
|
102
|
+
const header = parsePluginHeader(txt);
|
|
103
|
+
if (!header) continue;
|
|
104
|
+
plugins.push({
|
|
105
|
+
pluginFile: path.relative(repoRoot, phpPath),
|
|
106
|
+
...header,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const report = {
|
|
111
|
+
tool: { name: "detect_plugins", version: "0.1.0" },
|
|
112
|
+
repoRoot,
|
|
113
|
+
truncated,
|
|
114
|
+
count: plugins.length,
|
|
115
|
+
plugins,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
main();
|
|
122
|
+
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wp-plugin-directory-guidelines
|
|
3
|
+
description: "Use when reviewing WordPress plugins for GPL compliance, checking license headers or compatibility, evaluating upsell/freemium/trialware patterns, validating plugin naming or trademark rules, checking plugin slugs, understanding why a plugin was rejected from WordPress.org, or answering any question about the 18 WordPress.org Plugin Directory guidelines — even if the user doesn't mention 'guidelines' explicitly."
|
|
4
|
+
license: GPL-2.0-or-later
|
|
5
|
+
compatibility: "Targets WordPress 6.9+ (PHP 7.2.24+)."
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Authoritative reference for the 18 WordPress.org Plugin Directory guidelines. Covers GPL licensing, plugin naming/trademark rules, trialware restrictions, and all other submission requirements.
|
|
11
|
+
|
|
12
|
+
## When to use
|
|
13
|
+
|
|
14
|
+
Use this skill when you need to:
|
|
15
|
+
- Review a WordPress plugin for compliance with the WordPress.org Plugin Directory guidelines
|
|
16
|
+
- Check GPL license compatibility for a plugin or its bundled libraries
|
|
17
|
+
- Verify license headers in plugin files
|
|
18
|
+
- Identify common guideline violations before submission
|
|
19
|
+
- Answer questions about what is or is not allowed on WordPress.org
|
|
20
|
+
- Evaluate premium/upsell flows, license checks, or freemium positioning
|
|
21
|
+
- Review "teaser" or "preview" UI for trialware violations
|
|
22
|
+
|
|
23
|
+
## Inputs required
|
|
24
|
+
|
|
25
|
+
- Plugin source code (or specific files to review)
|
|
26
|
+
- Optional: plugin readme and plugin header metadata for naming and license checks
|
|
27
|
+
|
|
28
|
+
## Procedure
|
|
29
|
+
|
|
30
|
+
1. Check the plugin's license header against the **Valid License Headers** section below.
|
|
31
|
+
2. Walk through the **18 Guidelines** checklist, paying special attention to Guidelines 1, 4, 5, 7, 8, and 17.
|
|
32
|
+
3. Confirm trialware/freemium compliance using the checklist in [guideline-review-checklist.md](references/guideline-review-checklist.md) (Guideline 5 section).
|
|
33
|
+
4. For bundled third-party code, verify license compatibility against **GPL-Compatible Licenses (Quick)** below.
|
|
34
|
+
5. Flag matches from **Common GPL Violations (Quick)** below.
|
|
35
|
+
6. For edge cases, consult the detailed references and the [GNU GPL FAQ](https://www.gnu.org/licenses/gpl-faq.html).
|
|
36
|
+
|
|
37
|
+
## 18-Guideline Review Checklist
|
|
38
|
+
|
|
39
|
+
Use the detailed, per-guideline checklist in [guideline-review-checklist.md](references/guideline-review-checklist.md). Load this reference file only when a full guideline audit is requested.
|
|
40
|
+
|
|
41
|
+
## GPL Compliance (Guideline 1 in Detail)
|
|
42
|
+
|
|
43
|
+
Use [gpl-compliance.md](references/gpl-compliance.md) for full license tables, compatibility nuances, and examples. Keep this inline section as a quick decision aid.
|
|
44
|
+
|
|
45
|
+
### Verification (Licensing)
|
|
46
|
+
|
|
47
|
+
- Every licensing-related issue must cite **Guideline 1** and include the file path and exact license string.
|
|
48
|
+
- Confirm compatibility claims against **GPL-Compatible Licenses (Quick)** and escalate ambiguous licenses.
|
|
49
|
+
|
|
50
|
+
### Failure modes (Licensing)
|
|
51
|
+
|
|
52
|
+
- If a license is not clearly GPL-compatible, do not guess. Check the [GNU license list](https://www.gnu.org/licenses/license-list.html).
|
|
53
|
+
- For dual-license packages, verify both licenses and redistribution terms.
|
|
54
|
+
|
|
55
|
+
### Quick Reference: WordPress GPL Requirements
|
|
56
|
+
|
|
57
|
+
- WordPress is **GPLv2 or later**.
|
|
58
|
+
- Plugins distributed on WordPress.org must be 100% GPL-compatible (code and assets).
|
|
59
|
+
- Include a valid `License:` header and `License URI:` in the main plugin file.
|
|
60
|
+
- Do not add restrictions that conflict with GPL freedoms.
|
|
61
|
+
|
|
62
|
+
### Valid License Headers
|
|
63
|
+
|
|
64
|
+
## GPL Versions Summary
|
|
65
|
+
|
|
66
|
+
| Version | Year | Key Addition |
|
|
67
|
+
|---------|------|--------------|
|
|
68
|
+
| GPLv1 | 1989 | Base copyleft: share-alike for modifications |
|
|
69
|
+
| GPLv2 | 1991 | "Liberty or death" clause (Section 7), clearer distribution terms |
|
|
70
|
+
| GPLv3 | 2007 | Anti-tivoization, explicit patent grants, compatibility provisions |
|
|
71
|
+
|
|
72
|
+
WordPress uses **GPLv2 or later**, meaning plugins can use GPLv2, GPLv3, or "GPLv2 or later".
|
|
73
|
+
|
|
74
|
+
For full license texts, see:
|
|
75
|
+
- [GNU General Public License v1](https://www.gnu.org/licenses/gpl-1.0.html)
|
|
76
|
+
- [GNU General Public License v2](https://www.gnu.org/licenses/gpl-2.0.html)
|
|
77
|
+
- [GNU General Public License v3](https://www.gnu.org/licenses/gpl-3.0.html)
|
|
78
|
+
|
|
79
|
+
## License Compliance Checklist
|
|
80
|
+
|
|
81
|
+
When reviewing a plugin, verify:
|
|
82
|
+
|
|
83
|
+
- [ ] Main plugin file has a valid `License:` header (e.g., `GPL-2.0-or-later`, `GPL-2.0+`, `GPLv2 or later`)
|
|
84
|
+
- [ ] Main plugin file has a `License URI:` header pointing to the GPL text
|
|
85
|
+
- [ ] If bundled libraries exist, each has a GPL-compatible license
|
|
86
|
+
- [ ] No "split licensing" (e.g., code GPL but premium features proprietary)
|
|
87
|
+
- [ ] No additional restrictions beyond what GPL allows
|
|
88
|
+
- [ ] No clauses restricting commercial use, modification, or redistribution
|
|
89
|
+
- [ ] No obfuscated code (violates the spirit of source code availability)
|
|
90
|
+
|
|
91
|
+
## Valid License Headers for WordPress Plugins
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
License: GPL-2.0-or-later
|
|
95
|
+
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
License: GPL-3.0-or-later
|
|
100
|
+
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```text
|
|
104
|
+
License: GPLv2 or later
|
|
105
|
+
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### GPL-Compatible Licenses (Quick)
|
|
109
|
+
|
|
110
|
+
- Safe defaults: GPL-2.0-or-later, GPL-3.0-or-later.
|
|
111
|
+
- Commonly accepted permissive families: MIT/Expat, BSD, ISC, zlib, Boost.
|
|
112
|
+
- Conditional compatibility requires care: Apache-2.0 and MPL-2.0 (verify usage context).
|
|
113
|
+
- For full accepted and rejected identifiers, use [gpl-compliance.md](references/gpl-compliance.md).
|
|
114
|
+
|
|
115
|
+
### Common GPL Violations (Quick)
|
|
116
|
+
|
|
117
|
+
- Split licensing that restricts distributed code.
|
|
118
|
+
- Obfuscated or non-corresponding source distribution.
|
|
119
|
+
- Restrictive clauses (non-commercial, no-resale, forced backlink).
|
|
120
|
+
- Bundling GPL-incompatible libraries or assets.
|
|
121
|
+
|
|
122
|
+
## Plugin Naming Rules (Guideline 17)
|
|
123
|
+
|
|
124
|
+
Use [naming-rules.md](references/naming-rules.md) for full trademark lists, slug blocks, and naming examples. Keep this inline checklist for quick screening.
|
|
125
|
+
|
|
126
|
+
### Naming Checklist (Quick)
|
|
127
|
+
|
|
128
|
+
- Name is not a placeholder and has at least 5 alphanumeric characters.
|
|
129
|
+
- Header name and readme name match.
|
|
130
|
+
- Name is specific and function-related; avoid keyword stuffing.
|
|
131
|
+
- Trademark/project names appear only after connectors like `for`, `with`, `using`, `and`.
|
|
132
|
+
- No banned/discouraged terms or trademark portmanteaus.
|
|
133
|
+
- Slug is lowercase, hyphenated, <= 50 chars, and avoids blocked terms.
|