WP Guard
You are reviewing generated or changed WordPress code before it ships. Apply the rules below as a guard pass after the first implementation pass. Be a sharp reviewer, not a pedantic one: flag what creates vulnerabilities, breaks translations, or melts servers — ignore cosmetic preferences WPCS tooling already handles.
These rules exist because AI agents produce WordPress code with systematic failures: raw
of request data, AJAX handlers with neither nonce nor capability check, SQL built by string interpolation, English hardcoded into user-facing strings,
on sites with a million posts, and hand-rolled replacements for APIs core already ships. Each one looks fine in a demo and fails in production.
How to use this skill
Guard-pass mode (recommended): after WordPress code has been generated or edited, apply the rules to the diff or target files, then run the self-check before delivery. Fix violations before showing the user.
Live mode (explicit): when the user invokes this skill before writing WordPress code, apply the same rules while writing, then run the self-check before delivery.
Review mode (the user asks you to review, audit, or rate WordPress code): walk references/review-checklist.md against the target files and produce a structured findings report. Do not edit code in review mode unless asked.
Pair this skill with clean-code-guard when both are installed: clean-code-guard owns generic code quality; wp-guard owns the WordPress layer.
Adapt to the project first
- Read the project's agent instructions (CLAUDE.md, AGENTS.md), /WPCS config, and . Project conventions win on conflict.
- Identify the established prefix (functions, options, meta keys, handles) and the minimum supported WP/PHP versions. Match both.
- Detect context: WooCommerce APIs in play → apply woo-guard alongside this skill when it is installed; otherwise apply WooCommerce's HPOS, CRUD, and checkout rules from its developer documentation. Multilingual site (WPML/Polylang/multisite) → i18n rules are blocking, not advisory.
- Read one neighboring file before writing. Mirror its error handling, hook registration style, and escaping habits — unless they violate the security rules below, which are non-negotiable.
The Rules
Security — must fix, no exceptions
-
Escape late, escape everything. Every variable crossing into HTML output goes through the context-correct function:
,
,
, or
/
for rich content. Data passed to inline JS goes through
+
—
is legacy, for single-quoted strings in inline attributes only. Escaping happens at output, not at storage.
without an
wrapper fails review.
-
Sanitize early, and unslash first. Request data (
,
,
,
) never touches logic raw:
first, then the type-correct sanitizer (
,
,
,
, …). Sanitization is not escaping; doing one never excuses the other.
-
Every state change proves identity and intent. Form handlers, AJAX endpoints, and REST routes that change anything require BOTH a capability check (
) AND a nonce (
,
, or REST nonce handling). A nonce is not authorization. A REST
of
on a writing route fails review.
-
for every query containing a variable. Placeholders (
,
,
, and
for identifiers on WP ≥ 6.2), never interpolation or concatenation. Prefer
, the meta and options APIs over raw SQL when they can express the query.
Core API discipline
-
Use the platform; don't reinvent it. Outbound HTTP via
/
, never curl. Assets via
/
, never echoed
/
tags. Scheduling via WP-Cron or Action Scheduler. Redirects via
followed by
. File writes via
. Simple persistent data via options/transients, not a custom table.
-
Verify every hook and function exists. Before
,
, or calling a core/plugin function, confirm it exists in the supported versions — read the source or the project's installed code. Hallucinated hooks fail silently in WordPress: no error, no behavior. Also match the hook to the moment — front-end code does not load on
, queries do not run before
expects them.
-
Prefix or namespace everything public. Functions, classes, options, transients, meta keys, script handles, AJAX actions, REST namespaces — all carry the project prefix. Generic names (
,
,
) are collisions waiting for the next active plugin.
-
Guard direct access. Every PHP file that does work starts with the
check (or equivalent project convention).
Internationalization
- Every user-facing string is translation-ready. The correct wrapper for the context (, , , , or the escaping combos , ), a literal text domain matching the plugin slug — never a variable or constant — translator comments on every placeholder, for plurals (never with a hardcoded singular/plural choice), and no sentence assembly by concatenation. Dates and numbers through / and . Details and JS i18n: references/i18n.md.
Performance
-
Query discipline. No
and no
, ever. Use
when only IDs are needed,
when not paginating, and never query inside a loop what could be primed once (meta/term caches). Details:
references/performance.md.
-
Cache expensive work, load assets where used. Remote calls and heavy computations go behind transients or the object cache with a deliberate TTL. Options that are large or rarely read register with
. Scripts and styles enqueue only on the screens that use them.
Self-check before delivery
- Grep your diff for , , : is every variable output escaped with the context-correct function?
- Grep for , , : unslashed? sanitized? nonce-verified? capability-checked?
- Grep for : every variable behind a placeholder?
- Any user-facing string outside an i18n wrapper? Any non-literal text domain?
- Any hook or function you did not verify exists?
- Any unbounded query, uncached remote call, or unconditional enqueue?
- Does every new public name carry the project prefix?
- Would this survive WPCS ( + ) without warnings you cannot justify?
If any answer is wrong, fix it before showing the user.
Reporting format (review mode)
**Rule N violation** in `path/file.php:<line or function>`
- What: <one sentence>
- Risk: <XSS / SQLi / CSRF / broken i18n / scaling — one phrase>
- Fix: <one sentence>
Group by file, lead with security findings. If a file is clean, don't mention it.
Severity guide
- Must fix: Rules 1–4 — these are exploitable (XSS, SQLi, CSRF, privilege escalation)
- Should fix: Rules 5–9 — conflicts, silent failures, untranslatable releases
- Worth noting: Rules 10–11 — they decide whether the code survives traffic; block on them for code that runs on every request
References
- references/security.md — escaping/sanitization function tables, nonce lifecycle, REST permissions, details, file uploads
- references/i18n.md — wrapper selection, text domain rules, plurals, translator comments, JS translations, RTL, multilingual-plugin gotchas
- references/performance.md — WP_Query flags, transients vs object cache, autoload hygiene, asset loading, cron, scaling traps
- references/review-checklist.md — structured walk-through for review mode
- references/sources.md — handbook and research URLs; read only when citing a source
What this skill does not do
- Run PHPCS, PHPStan, or Plugin Check — use the project's tooling for mechanical verification; this skill is the judgment layer above it.
- Decide plugin architecture or business logic — it guards how WordPress code ships, not what it does.
- Replace clean-code-guard or test-guard — generic code quality and test quality remain their jurisdiction.