$npx -y skills add amElnagdy/guard-skills --skill wp-guardReview generated or changed WordPress code — plugins, themes, and blocks — before it ships. Best used reactively after an agent writes, edits, or reviews code touching WordPress APIs: add_action/add_filter, shortcodes, meta boxes, AJAX handlers, REST routes, WP_Query or $wpdb, wi
| 1 | # WP Guard |
| 2 | |
| 3 | 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. |
| 4 | |
| 5 | These rules exist because AI agents produce WordPress code with systematic failures: raw `echo` of request data, AJAX handlers with neither nonce nor capability check, SQL built by string interpolation, English hardcoded into user-facing strings, `posts_per_page => -1` 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. |
| 6 | |
| 7 | ## How to use this skill |
| 8 | |
| 9 | **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. |
| 10 | |
| 11 | **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. |
| 12 | |
| 13 | **Review mode** (the user asks you to review, audit, or rate WordPress code): walk [references/review-checklist.md](references/review-checklist.md) against the target files and produce a structured findings report. Do not edit code in review mode unless asked. |
| 14 | |
| 15 | Pair this skill with clean-code-guard when both are installed: clean-code-guard owns generic code quality; wp-guard owns the WordPress layer. |
| 16 | |
| 17 | ## Adapt to the project first |
| 18 | |
| 19 | 1. Read the project's agent instructions (CLAUDE.md, AGENTS.md), `phpcs.xml`/WPCS config, and `composer.json`. Project conventions win on conflict. |
| 20 | 2. Identify the established prefix (functions, options, meta keys, handles) and the minimum supported WP/PHP versions. Match both. |
| 21 | 3. 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. |
| 22 | 4. 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. |
| 23 | |
| 24 | ## The Rules |
| 25 | |
| 26 | ### Security — must fix, no exceptions |
| 27 | |
| 28 | 1. **Escape late, escape everything.** Every variable crossing into HTML output goes through the context-correct function: `esc_html()`, `esc_attr()`, `esc_url()`, or `wp_kses()`/`wp_kses_post()` for rich content. Data passed to inline JS goes through `wp_json_encode()` + `wp_add_inline_script()` — `esc_js()` is legacy, for single-quoted strings in inline attributes only. Escaping happens at output, not at storage. `echo $anything;` without an `esc_*` wrapper fails review. |
| 29 | |
| 30 | 2. **Sanitize early, and unslash first.** Request data (`$_POST`, `$_GET`, `$_REQUEST`, `$_SERVER`) never touches logic raw: `wp_unslash()` first, then the type-correct sanitizer (`sanitize_text_field()`, `sanitize_key()`, `absint()`, `sanitize_email()`, …). Sanitization is not escaping; doing one never excuses the other. |
| 31 | |
| 32 | 3. **Every state change proves identity and intent.** Form handlers, AJAX endpoints, and REST routes that change anything require BOTH a capability check (`current_user_can()`) AND a nonce (`check_admin_referer()`, `check_ajax_referer()`, or REST nonce handling). A nonce is not authorization. A REST `permission_callback` of `__return_true` on a writing route fails review. |
| 33 | |
| 34 | 4. **`$wpdb->prepare()` for every query containing a variable.** Placeholders (`%s`, `%d`, `%f`, and `%i` for identifiers on WP ≥ 6.2), never interpolation or concatenation. Prefer `WP_Query`, the meta and options APIs over raw SQL when they can express the query. |
| 35 | |
| 36 | ### Core API discipline |
| 37 | |
| 38 | 5. **Use the platform; don't reinvent it.** Outbound HTTP via `wp_remote_get()`/`wp_remote_post()`, never curl. Assets via `wp_enqueue_script()`/`wp_enqueue_style |