
Wp Plugin Development
- 4.7k installs
- 1.9k repo stars
- Updated July 27, 2026
- wordpress/agent-skills
wp-plugin-development is an agent skill: Use when developing WordPress plugins: architecture and hooks, activation/deactivation/uninstall, admin UI and Settings API, data storage, c
About
The wp-plugin-development skill 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.. WP Plugin Development When to use Use this skill for plugin work such as: - creating or refactoring plugin structure (bootstrap, includes, namespaces/classes) - adding hooks/actions/filters - activation/deactivation/uninstall behavior and migrations - adding settings pages / options / admin UI (Settings API) - security fixes (nonces, capabilities, sanitization/escaping, SQL safety) - packaging a release (build artifacts, readme, assets) Inputs required - Repo root + target plugin(s) (path to plugin main file if known). - Where this plugin runs: single site vs multisite; WP.com conventions if applicable. - Target WordPress + Agents should read SKILL.md quick start steps, verify required binaries and environment variables, and follow reference files for exact parameters before calling tools.
- Covers wp-plugin-development quick start, workflow steps, and reference pointers from SKILL.md.
- Tagged for stage build and subphase backend in the closed Skillselion taxonomy.
- Documents prerequisites, permissions shell, filesystem, git, and compatible agents.
- Includes AEO tagMeta with task queries, keywords, and evidence quotes for discovery.
- Cross-links related skills and generated REFERENCE.md tables where the repo provides them.
Wp Plugin Development by the numbers
- 4,655 all-time installs (skills.sh)
- +242 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #4 of 65 PHP & Laravel skills by installs in the Skillselion catalog
- Security screen: HIGH risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
wp-plugin-development capabilities & compatibility
- Capabilities
- wp plugin development documented workflow · quick start examples · reference parameter lookup · taxonomy aligned metadata · aeo discovery fields
- Use cases
- api development · security audit
What wp-plugin-development says it does
Use when developing WordPress plugins: architecture and hooks, activation/deactivation/uninstall, ad
npx skills add https://github.com/wordpress/agent-skills --skill wp-plugin-developmentAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 4.7k |
|---|---|
| repo stars | ★ 1.9k |
| Security audit | 2 / 3 scanners passed |
| Last updated | July 27, 2026 |
| Repository | wordpress/agent-skills ↗ |
How do I run wp-plugin-development correctly without guessing steps, tools, or parameters?
Use when developing WordPress plugins: architecture and hooks, activation/deactivation/uninstall, admin UI and Settings API, data storage, cron/tasks, security (nonces/capabilities/sanitization/e
Who is it for?
Teams using wp-plugin-development when SKILL.md triggers match the user request.
Skip if: Skip when the task is outside wp-plugin-development documented triggers or sibling skill scope.
When should I use this skill?
User mentions wp-plugin-development, related trigger phrases, or asks to follow this SKILL.md workflow.
What you get
Completed wp-plugin-development workflow with outputs and checks defined in SKILL.md.
- wp-plugin-development output per SKILL.md
By the numbers
- Stage build/backend
- Category PHP & Laravel
- Complexity intermediate
Files
WP Plugin Development
When to use
Use this skill for plugin work such as:
- creating or refactoring plugin structure (bootstrap, includes, namespaces/classes)
- adding hooks/actions/filters
- activation/deactivation/uninstall behavior and migrations
- adding settings pages / options / admin UI (Settings API)
- security fixes (nonces, capabilities, sanitization/escaping, SQL safety)
- packaging a release (build artifacts, readme, assets)
Inputs required
- Repo root + target plugin(s) (path to plugin main file if known).
- Where this plugin runs: single site vs multisite; WP.com conventions if applicable.
- Target WordPress + PHP versions (affects available APIs and placeholder support in
$wpdb->prepare()).
Procedure
0) Triage and locate plugin entrypoints
1. Run triage:
node skills/wp-project-triage/scripts/detect_wp_project.mjs
2. Detect plugin headers (deterministic scan):
node skills/wp-plugin-development/scripts/detect_plugins.mjs
If this is a full site repo, pick the specific plugin under wp-content/plugins/ or mu-plugins/ before changing code.
1) Follow a predictable architecture
Guidelines:
- Keep a single bootstrap (main plugin file with header).
- Avoid heavy side effects at file load time; load on hooks.
- Prefer a dedicated loader/class to register hooks.
- Keep admin-only code behind
is_admin()(or admin hooks) to reduce frontend overhead.
See:
references/structure.md
2) Hooks and lifecycle (activation/deactivation/uninstall)
Activation hooks are fragile; follow guardrails:
- register activation/deactivation hooks at top-level, not inside other hooks
- flush rewrite rules only when needed and only after registering CPTs/rules
- uninstall should be explicit and safe (
uninstall.phporregister_uninstall_hook)
See:
references/lifecycle.md
3) Settings and admin UI (Settings API)
Prefer Settings API for options:
register_setting(),add_settings_section(),add_settings_field()- sanitize via
sanitize_callback
See:
references/settings-api.md
4) Security baseline (always)
Before shipping:
- Validate/sanitize input early; escape output late.
- Use nonces to prevent CSRF and capability checks for authorization.
- Avoid directly trusting
$_POST/$_GET; usewp_unslash()and specific keys. - Use
$wpdb->prepare()for SQL; avoid building SQL with string concatenation.
See:
references/security.md
5) Data storage, cron, migrations (if needed)
- Prefer options for small config; custom tables only if necessary.
- For cron tasks, ensure idempotency and provide manual run paths (WP-CLI or admin).
- For schema changes, write upgrade routines and store schema version.
See:
references/data-and-cron.md
Verification
- Plugin activates with no fatals/notices.
- Settings save and read correctly (capability + nonce enforced).
- Uninstall removes intended data (and nothing else).
- Run repo lint/tests (PHPUnit/PHPCS if present) and any JS build steps if the plugin ships assets.
Failure modes / debugging
- Activation hook not firing:
- hook registered incorrectly (not in main file scope), wrong main file path, or plugin is network-activated
- Settings not saving:
- settings not registered, wrong option group, missing capability, nonce failure
- Security regressions:
- nonce present but missing capability checks; or sanitized input not escaped on output
See:
references/debugging.md
Escalation
For canonical detail, consult the Plugin Handbook and security guidelines before inventing patterns.
Data storage, cron, and upgrades
Use this file when adding persistent storage, background jobs, or upgrade routines.
Data storage
- Prefer Options API for small config/state.
- Use custom tables only when needed; store schema version and provide upgrade paths.
Cron
- Ensure tasks are idempotent (may run late or multiple times).
- Provide a manual trigger path for debugging (WP-CLI or admin-only action).
Database safety note
If using $wpdb->prepare(), avoid building queries with concatenated user input. Recent WordPress versions support identifier placeholders (%i) but you must not assume it exists without checking capabilities or target versions.
Debugging quick routes
Plugin doesn’t load / fatal errors
- Confirm correct plugin main file and header.
- Check PHP error logs and
WP_DEBUG_LOG. - If the repo is a site repo, confirm you edited the correct plugin under
wp-content/plugins/.
Activation hook surprises
- Hooks must be registered at top-level.
- Activation runs in a special context; avoid assuming other hooks already ran.
Settings not saving
- Confirm
register_setting()is called. - Confirm the option group matches the form.
- Confirm capability checks and nonces.
Activation, deactivation, uninstall
Use this file for lifecycle changes and data cleanup.
Activation / deactivation hooks
register_activation_hook( __FILE__, 'callback' )register_deactivation_hook( __FILE__, 'callback' )
Guardrails:
- These hooks must be registered at top-level (not inside other hooks).
- If you flush rewrite rules, ensure rules are registered first (often via a shared function called both on
initand activation).
Upstream reference:
- https://developer.wordpress.org/plugins/plugin-basics/activation-deactivation-hooks/
Uninstall
Preferred approaches:
uninstall.php(runs only on uninstall)register_uninstall_hook()
Guardrails:
- Check
WP_UNINSTALL_PLUGINbefore running destructive cleanup.
Upstream reference:
- https://developer.wordpress.org/plugins/plugin-basics/uninstall-methods/
Security guardrails (plugin work)
Use this file when making security fixes or when handling any input/output.
Nonces + permissions
- Nonces help prevent CSRF, not authorization.
- Always pair nonces with capability checks (
current_user_can()or a more specific capability).
Upstream reference:
- https://developer.wordpress.org/apis/security/nonces/
Sanitization and escaping
Golden rule:
- sanitize/validate on input, escape on output.
Practical rules:
- never process the entire
$_POST/$_GETarray; read explicit keys - use
wp_unslash()before sanitizing when needed - use prepared statements for SQL; avoid interpolating user input into queries
Common review guidance:
- https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/
Settings API (admin options)
Use this file when adding settings pages or storing user-configurable options.
Core APIs:
register_setting()add_settings_section()add_settings_field()
Upstream references:
- Settings API overview: https://developer.wordpress.org/plugins/settings/settings-api/
- Register settings: https://developer.wordpress.org/plugins/settings/registration/
- Add settings fields: https://developer.wordpress.org/plugins/settings/settings-fields/
Practical guardrails:
- Use
sanitize_callbackto validate/sanitize data. - Use capability checks (commonly
manage_options) for settings screens and saves. - Escape values on output (
esc_attr,esc_html, etc.).
Plugin structure and loading
Use this file when introducing or refactoring a plugin architecture.
Core concepts
- Main plugin file contains the plugin header and bootstraps the plugin.
- Prefer predictable init:
- minimal boot file
- a loader/class that registers hooks
- admin-only code behind admin hooks
Upstream reference:
- https://developer.wordpress.org/plugins/plugin-basics/
import fs from "node:fs";
import path from "node:path";
const DEFAULT_IGNORES = new Set([
".git",
"node_modules",
"vendor",
"dist",
"build",
"coverage",
".next",
".turbo",
]);
function statSafe(p) {
try {
return fs.statSync(p);
} catch {
return null;
}
}
function readFileSafe(p, maxBytes = 128 * 1024) {
try {
const buf = fs.readFileSync(p);
if (buf.byteLength > maxBytes) return buf.subarray(0, maxBytes).toString("utf8");
return buf.toString("utf8");
} catch {
return null;
}
}
function findFilesRecursive(repoRoot, predicate, { maxFiles = 6000, maxDepth = 10 } = {}) {
const results = [];
const queue = [{ dir: repoRoot, depth: 0 }];
let visited = 0;
while (queue.length > 0) {
const { dir, depth } = queue.shift();
if (depth > maxDepth) continue;
let entries;
try {
entries = fs.readdirSync(dir, { withFileTypes: true });
} catch {
continue;
}
for (const ent of entries) {
const fullPath = path.join(dir, ent.name);
if (ent.isDirectory()) {
if (DEFAULT_IGNORES.has(ent.name)) continue;
queue.push({ dir: fullPath, depth: depth + 1 });
continue;
}
if (!ent.isFile()) continue;
visited += 1;
if (visited > maxFiles) return { results, truncated: true };
if (predicate(fullPath)) results.push(fullPath);
}
}
return { results, truncated: false };
}
function parsePluginHeader(contents) {
// WordPress reads plugin headers from the top of the file. We only need key fields.
const header = {};
const pairs = [
["Plugin Name", "name"],
["Plugin URI", "uri"],
["Description", "description"],
["Version", "version"],
["Author", "author"],
["Author URI", "authorUri"],
["Text Domain", "textDomain"],
["Domain Path", "domainPath"],
];
for (const [label, key] of pairs) {
const m = contents.match(new RegExp(`^\\s*${label}:\\s*(.+)\\s*$`, "im"));
if (m) header[key] = m[1].trim();
}
if (!header.name) return null;
return header;
}
function main() {
const repoRoot = process.cwd();
const { results: phpFiles, truncated } = findFilesRecursive(repoRoot, (p) => p.toLowerCase().endsWith(".php"), {
maxFiles: 5000,
maxDepth: 10,
});
const plugins = [];
for (const phpPath of phpFiles) {
const txt = readFileSafe(phpPath);
if (!txt) continue;
if (!/Plugin Name:/i.test(txt)) continue;
const header = parsePluginHeader(txt);
if (!header) continue;
plugins.push({
pluginFile: path.relative(repoRoot, phpPath),
...header,
});
}
const report = {
tool: { name: "detect_plugins", version: "0.1.0" },
repoRoot,
truncated,
count: plugins.length,
plugins,
};
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
}
main();
Related skills
How it compares
wp-plugin-development implements its own SKILL.md workflow rather than a generic substitute skill.
FAQ
Who is wp-plugin-development for?
Agents and developers following the wp-plugin-development SKILL.md guidance.
When should I use wp-plugin-development?
When user intent matches description triggers and quick start scenarios.
Is wp-plugin-development safe to install?
Review the Security Audits panel before production shell or network use.