Generate a complete, enterprise-grade WordPress plugin from scratch. Output is a full directory tree with production-ready PHP, JavaScript, CSS, and metadata files. No placeholders, no TODO comments, no missing security measures.
The skill takes seven inputs (five multiple-choice, two free-text), infers the plugin slug and architecture from those inputs, and produces every file required to install, activate, configure, and uninstall the plugin on a real WordPress site.
Scope: this skill only generates a brand-new plugin tree from scratch. For changes to an already-existing plugin (add a feature, settings page, endpoint, hook, or fix), defer to wp-builder-pro.
Workflow
Run the multiple-choice intake. Use AskUserQuestion to ask all seven questions. Two are free-text (plugin name, feature detail). Five are multiple-choice - four multiSelect: true, one single-select.
Derive the slug and constants. From the plugin name, derive kebab-case slug, snake_case text domain (same as slug), SCREAMING_SNAKE constant prefix, and PascalCase namespace.
Resolve scope. From the multiple-choice answers, decide which classes to generate (Admin, Frontend, Database, AJAX, REST), which assets to enqueue, and which integration scaffolds to include.
Generate the full plugin tree. Every file must be fully filled in. Forbidden-sentinel list (canonical): no TODO, TBD, FIXME, or generic {placeholder} / "coming soon" text anywhere. This is distinct from the legitimate template tokens this skill derives and substitutes - {plugin-slug}, {Namespace}, {Plugin Name}, {slug} - which MUST be replaced with real values, not left literal. The "no placeholders" checks below refer to the forbidden list, not these template tokens.
Write to disk. Default root: ./{plugin-slug}/ in the current working directory. If that directory already exists, write to ./{plugin-slug}-new/ instead and tell the user.
Verify, then report back. Do not report completion until every item in the Quality checklist below is confirmed against the generated files. Then report the directory path, file count, and a one-line summary. Do not paste full file contents into chat - they are on disk.
Intake
Collect all seven inputs before generating. AskUserQuestion allows at most 4 options per question and at most 4 questions per call, so the intake cannot be a single call:
Free-text (Q1 plugin name, Q3 feature detail): ask as plain chat prompts - AskUserQuestion cannot take free text.
Multiple-choice (Q2, Q4, Q5, Q6, Q7): each option list below exceeds the 4-option cap. Present each as a plain-text "select all that apply" numbered checklist (Q4 is single-select) and let the user reply with the numbers or names. Use AskUserQuestion only for a narrowing sub-decision that genuinely fits within 4 options.
Every multi-select MUST offer an Other (specify) escape so the user can name an unlisted mechanism, surface, or integration; route that free text into the relevant component scope.
If a plugin name arrived via $ARGUMENTS, pre-fill Q1 and confirm.
Q1 - Plugin name (free text)
What is the plugin called? (e.g. "Acme Bookings", "Smart Redirects Pro", "Membership Tiers")
Use this exact name in the plugin header, Plugin Name: field, and main display labels.
Q2 - Functionality (multi-select MC)
Which WordPress mechanisms does the plugin use? Select all that apply.
Option
What it generates
Custom Post Types & Taxonomies
register_post_type() + register_taxonomy() with capability mapping
Settings / Options Page
Full Settings API implementation with tabs and sanitization callbacks
add_role() + add_cap() with proper cleanup on uninstall
Email Notifications
wp_mail() wrapper with templates and HTML headers
Frontend Forms
Nonced AJAX form with server-side validation
Dashboard Widget
wp_add_dashboard_widget() with cached data fetch
Import / Export
JSON/CSV export endpoint and import handler with file validation
Analytics / Activity Logging
Custom log table + admin viewer with filters
Custom User Meta
register_meta() + profile field rendering with sanitization
Other (specify)
Generate scaffolding for the mechanism the user names
Q3 - Specific feature detail (free text)
In 2-4 sentences, describe what the plugin actually DOES at the user level.
What problem does it solve? What is the happy-path user flow?
(Example: "Lets shop owners offer time-slot bookings on any WooCommerce product.
Customers pick a date and slot at checkout; staff see all bookings in a calendar
view in WP admin and receive an email when one is made.")
This drives the domain logic, naming of classes, and copy in the README.txt.
Q4 - Target users (single-select MC)
Who is the primary audience using this plugin? Pick one.
Generate full surface (admin + frontend + extensibility)
Other (specify)
Adapt the surface to the audience the user names
Q5 - Admin interface components (multi-select MC)
Which admin UI components does the plugin need? Select all that apply.
Option
What it generates
Top-level admin menu
add_menu_page() with custom icon (dashicons)
Submenu under Settings
add_options_page()
Submenu under Tools
add_management_page()
Meta boxes on post types
add_meta_box() with nonce + capability check on save
Custom post type list-table screens
WP_List_Table subclass with sortable columns and bulk actions
Dashboard widget
wp_add_dashboard_widget()
Admin notices
Dismissible notices with user-meta persistence
Help tabs on plugin screens
get_current_screen()->add_help_tab()
None (frontend-only plugin)
Skip all admin UI scaffolding
Other (specify)
Generate the admin component the user names
Q6 - Frontend display surfaces (multi-select MC)
How does the plugin render on the public site? Select all that apply.
Option
What it generates
Shortcodes
add_shortcode() handlers
Gutenberg blocks
block.json + React edit component + save function + frontend render_callback
Classic widgets
WP_Widget subclass
Template tags / functions
Public acme_render_*() functions for themes to call
Auto-injected via the_content filter
Filter-based injection with opt-out via post meta
REST-driven SPA / headless
REST endpoints + minimal client-side fetch demo
Custom page templates
page-*.php templates registered via theme_page_templates filter
None (admin-only plugin)
Skip all frontend scaffolding
Other (specify)
Generate the frontend surface the user names
Q7 - Third-party integrations (multi-select MC)
Which external services or plugins does this integrate with? Select all that apply.
Option
What it generates
None
Skip integration scaffolding
WooCommerce
Hooks into WC actions/filters; checks class_exists( 'WooCommerce' ) before booting integration
BuddyPress / bbPress
Hooks into BP/bbP actions with function_exists() guards
Advanced Custom Fields (ACF)
Registers field groups via PHP; gracefully degrades if ACF inactive
Elementor
Custom widget class extending Widget_Base
External REST API
HTTP client wrapper using wp_remote_get() / wp_remote_post() with retries and error handling
Stripe or PayPal
Server-side payment intent / order creation with webhook handler
Mailchimp / ConvertKit / SendGrid
Newsletter signup handler; read the API key from a wp-config.php constant (recommended) or store it in an option, documented as plaintext - WordPress has no built-in option encryption, so never claim it is encrypted
Google Analytics / Tag Manager
Frontend tracking snippet enqueue with cookie-consent gate
OAuth providers (Google, GitHub, etc.)
OAuth callback handler + state nonce + user linking
Webhooks (incoming)
REST endpoint with HMAC signature verification
Webhooks (outgoing)
Async dispatcher using Action Scheduler if available, falls back to wp-cron
Other (specify)
Generate an integration scaffold for the service the user names
PHP namespace - PascalCase of slug. Example: AcmeBookings.
Main file name - {slug}.php.
Singleton class name - {Namespace}\\Plugin.
Minimum WordPress version - 6.0.
Minimum PHP version - 7.4 (8.0+ recommended).
License - GPL-2.0-or-later with License URI: https://www.gnu.org/licenses/gpl-2.0.html.
Required file structure
Always produce this baseline tree. Skip files that correspond to unselected features (e.g. no includes/class-rest-controller.php if REST endpoints not picked).
These rules are non-negotiable. Every generated file is held to them.
Security
Direct access guard on every PHP file: defined( 'ABSPATH' ) || exit; immediately after the docblock.
Nonces on every form, AJAX request, and REST mutation. wp_create_nonce() + check_admin_referer() / wp_verify_nonce() / permission_callback.
Capability checks before any privileged action: current_user_can( 'manage_options' ) (or stricter mapped capability for CPTs).
Sanitization on input - sanitize_text_field(), sanitize_email(), absint(), wp_kses_post(), esc_url_raw() matched to the data type. Never store raw $_POST/$_GET values.
Escaping on output - esc_html(), esc_attr(), esc_url(), wp_kses_post(). No echo $var; - only escaped variables reach the page.
Prepared statements - every $wpdb query uses $wpdb->prepare() with %s/%d/%f placeholders. Never interpolate into SQL.
REST permission_callback - never __return_true unless the route is intentionally public; document why if so.
Forbidden constructs - no dynamic code execution helpers, no extract(), no create_function(), no remote includes, no unsafe deserialization.
Standards & Style
WordPress Coding Standards (WPCS) compliant. Spaces around array brackets [ 'foo' ], Yoda conditions where applicable, elseif not else if.
PHPDoc block on every class, every public method, every filter/action. @since, @param, @return, @throws where relevant.
Class file naming: class-{kebab-case}.php.
PHP open tag only - no ?> at end of pure PHP files.
Architecture
Singleton main plugin class with get_instance() and a private __construct() that wires sub-components.
Composition over inheritance for components - each class accepts its dependencies in the constructor.
Hooks registered in dedicated register_hooks() methods on each component, called once from the bootstrapper.
No business logic in the main plugin file beyond constants and the bootstrap call.
Performance
Object-cache-aware: wp_cache_get() / wp_cache_set() around expensive queries with the plugin slug as cache group.
Transients for cross-request caching with sensible expirations.
Asset enqueueing is conditional - never load admin assets on the frontend, never load on screens that don't need them. Use get_current_screen() checks.
Versioned asset URLs (filemtime() or plugin version constant) for cache busting.
Dependency arrays passed to wp_enqueue_*() - never assume globals.
Database
Custom tables created via dbDelta() (not raw CREATE TABLE) with charset/collation from $wpdb->get_charset_collate().
Indexes on every foreign key and every WHERE/ORDER BY column the plugin actually queries.
Schema version stored in an option; activation hook compares it and runs migrations.
uninstall.php drops all custom tables, options, user meta, post meta, and scheduled events the plugin created. No orphaned data.
Internationalization
Every user-facing string wrapped in __(), _e(), esc_html__(), esc_html_e(), _n(), _x(), etc. - with the plugin's text domain (matches slug).
Text domain loaded on plugins_loaded via load_plugin_textdomain().
.pot file shipped in languages/ with all extracted strings and full header (Project-Id-Version, Last-Translator, Language-Team, etc.).
Translator comments where placeholders are non-obvious: /* translators: %s is the user display name */.
Documentation
File-level docblocks with @package, @since, @license.
Class-level docblocks describing responsibility and dependencies.
readme.txt in WordPress.org format with all required sections: === Plugin Name ===, Contributors, Tags, Requires at least, Tested up to, Stable tag, License, License URI, then == Description ==, == Installation ==, == Frequently Asked Questions ==, == Screenshots ==, == Changelog ==, == Upgrade Notice ==.
readme.md mirrors the same content in GitHub-friendly markdown.
Uninstall
uninstall.php runs only when invoked by WordPress - guard with if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) { exit; }.
Removes: all options (delete_option()), transients, user meta, post meta, custom tables (DROP TABLE IF EXISTS), scheduled cron events, registered roles, registered capabilities.
Multisite-aware: loops over get_sites() and runs cleanup per site, plus network options cleanup.
Main file header template
Every plugin's {slug}.php opens with this header. Fill in real values - never leave placeholders. For Plugin URI / Author / Author URI: use the author's real details if known; otherwise omit those lines entirely rather than shipping literal example.com.
Root directory: ./{plugin-slug}/ by default. Fall back to ./{plugin-slug}-new/ if the first exists; report the chosen path to the user.
Every PHP file ends with a newline and no trailing ?>.
Encoding UTF-8, LF line endings throughout.
After writing, print one line to chat: Wrote {N} files to {path}. Activate via the WordPress admin → Plugins → {Plugin Name}.
Do NOT paste full source into chat - the user opens the files directly.
Quality checklist
Before declaring done, verify every item:
All seven intake answers captured (5 multi-choice, 2 free-text).
Plugin slug, text domain, namespace, and constant prefix all derived consistently from the plugin name.
Main plugin file has a complete header with no {placeholder} text.
defined( 'ABSPATH' ) || exit; guard at the top of every PHP file.
Every form/AJAX/REST mutation has nonce verification.
Every privileged action has a capability check.
Every user input passes through a sanitizer matched to its type.
Every echoed variable passes through an escaping function matched to its context.
Every $wpdb query uses $wpdb->prepare() with placeholders - no string interpolation into SQL.
Every user-facing string is wrapped in an i18n function with the correct text domain.
readme.txt in WordPress.org format with all required headers populated.
uninstall.php removes every artefact the plugin creates (options, tables, meta, cron, roles, caps).
Asset enqueueing is conditional - no admin assets on frontend, no public assets on every admin screen.
Custom tables (if any) use dbDelta() with charset/collation and have indexes on queried columns.
Multisite-aware activation, deactivation, and uninstall when "Multisite network administrators" was selected.
No forbidden sentinel (TODO, TBD, FIXME, {placeholder}, "coming soon") remains in any file, and no template token ({plugin-slug}, {Namespace}, {Plugin Name}, {slug}) is left unsubstituted.
No literal example.com shipped - real author URLs or those header lines omitted.
Zero filler comments. PHPDoc only where required by standards; no narrative commentary.
1---2name: wordpress-plugin3description: WordPress Plugin Generator4---5# WordPress Plugin Generator67Generate a complete, enterprise-grade WordPress plugin from scratch. Output is a full directory tree with production-ready PHP, JavaScript, CSS, and metadata files. No placeholders, no `TODO` comments, no missing security measures.89The skill takes seven inputs (five multiple-choice, two free-text), infers the plugin slug and architecture from those inputs, and produces every file required to install, activate, configure, and uninstall the plugin on a real WordPress site.1011**Scope:** this skill only generates a brand-new plugin tree from scratch. For changes to an already-existing plugin (add a feature, settings page, endpoint, hook, or fix), defer to wp-builder-pro.1213## Workflow14151. **Run the multiple-choice intake.** Use `AskUserQuestion` to ask all seven questions. Two are free-text (plugin name, feature detail). Five are multiple-choice - four `multiSelect: true`, one single-select.162. **Derive the slug and constants.** From the plugin name, derive `kebab-case` slug, `snake_case` text domain (same as slug), `SCREAMING_SNAKE` constant prefix, and `PascalCase` namespace.173. **Resolve scope.** From the multiple-choice answers, decide which classes to generate (Admin, Frontend, Database, AJAX, REST), which assets to enqueue, and which integration scaffolds to include.184. **Generate the full plugin tree.** Every file must be fully filled in. **Forbidden-sentinel list (canonical):** no `TODO`, `TBD`, `FIXME`, or generic `{placeholder}` / "coming soon" text anywhere. This is distinct from the legitimate template tokens this skill derives and substitutes - `{plugin-slug}`, `{Namespace}`, `{Plugin Name}`, `{slug}` - which MUST be replaced with real values, not left literal. The "no placeholders" checks below refer to the forbidden list, not these template tokens.195. **Write to disk.** Default root: `./{plugin-slug}/` in the current working directory. If that directory already exists, write to `./{plugin-slug}-new/` instead and tell the user.206. **Verify, then report back.** Do not report completion until every item in the Quality checklist below is confirmed against the generated files. Then report the directory path, file count, and a one-line summary. Do not paste full file contents into chat - they are on disk.2122## Intake2324Collect all seven inputs before generating. `AskUserQuestion` allows at most 4 options per question and at most 4 questions per call, so the intake cannot be a single call:2526- **Free-text (Q1 plugin name, Q3 feature detail):** ask as plain chat prompts - `AskUserQuestion` cannot take free text.27- **Multiple-choice (Q2, Q4, Q5, Q6, Q7):** each option list below exceeds the 4-option cap. Present each as a plain-text **"select all that apply"** numbered checklist (Q4 is single-select) and let the user reply with the numbers or names. Use `AskUserQuestion` only for a narrowing sub-decision that genuinely fits within 4 options.28- **Every multi-select MUST offer an `Other (specify)` escape** so the user can name an unlisted mechanism, surface, or integration; route that free text into the relevant component scope.2930If a plugin name arrived via `$ARGUMENTS`, pre-fill Q1 and confirm.3132### Q1 - Plugin name (free text)3334```35What is the plugin called? (e.g. "Acme Bookings", "Smart Redirects Pro", "Membership Tiers")36```3738Use this exact name in the plugin header, `Plugin Name:` field, and main display labels.3940### Q2 - Functionality (multi-select MC)4142> Which WordPress mechanisms does the plugin use? Select all that apply.4344| Option | What it generates |45|--------|-------------------|46| Custom Post Types & Taxonomies | `register_post_type()` + `register_taxonomy()` with capability mapping |47| Settings / Options Page | Full Settings API implementation with tabs and sanitization callbacks |48| Gutenberg Blocks | `block.json` + `register_block_type()` + edit.js + save.js + style.scss |49| Shortcodes | `add_shortcode()` with attribute sanitization and output escaping |50| REST API endpoints | `register_rest_route()` with `permission_callback` + schema |51| WP-CLI commands | `WP_CLI::add_command()` with subcommands and synopsis |52| Cron / Scheduled tasks | `wp_schedule_event()` + activation hook registration + cleanup on deactivate |53| Custom Database Tables | `dbDelta()` schema, charset/collation, indexes, version-bump migrations |54| User Roles / Capabilities | `add_role()` + `add_cap()` with proper cleanup on uninstall |55| Email Notifications | `wp_mail()` wrapper with templates and HTML headers |56| Frontend Forms | Nonced AJAX form with server-side validation |57| Dashboard Widget | `wp_add_dashboard_widget()` with cached data fetch |58| Import / Export | JSON/CSV export endpoint and import handler with file validation |59| Analytics / Activity Logging | Custom log table + admin viewer with filters |60| Custom User Meta | `register_meta()` + profile field rendering with sanitization |61| Other (specify) | Generate scaffolding for the mechanism the user names |6263### Q3 - Specific feature detail (free text)6465```66In 2-4 sentences, describe what the plugin actually DOES at the user level.67What problem does it solve? What is the happy-path user flow?68(Example: "Lets shop owners offer time-slot bookings on any WooCommerce product.69Customers pick a date and slot at checkout; staff see all bookings in a calendar70view in WP admin and receive an email when one is made.")71```7273This drives the domain logic, naming of classes, and copy in the README.txt.7475### Q4 - Target users (single-select MC)7677> Who is the primary audience using this plugin? Pick one.7879| Option | Implication |80|--------|-------------|81| Site administrators only | Generate admin-side features; minimal/no frontend output |82| Editors and authors | Generate role-aware capability checks; meta boxes on post screens |83| Frontend site visitors | Generate public-facing shortcodes/blocks; minimize admin surface |84| Developers (extending via hooks/API) | Generate documented hooks, filters, and REST endpoints; ship a `docs/` folder |85| Multisite network administrators | Generate network-activation support, `is_multisite()` branches, network settings page |86| Mixed / multiple of the above | Generate full surface (admin + frontend + extensibility) |87| Other (specify) | Adapt the surface to the audience the user names |8889### Q5 - Admin interface components (multi-select MC)9091> Which admin UI components does the plugin need? Select all that apply.9293| Option | What it generates |94|--------|-------------------|95| Top-level admin menu | `add_menu_page()` with custom icon (dashicons) |96| Submenu under Settings | `add_options_page()` |97| Submenu under Tools | `add_management_page()` |98| Meta boxes on post types | `add_meta_box()` with nonce + capability check on save |99| Custom post type list-table screens | `WP_List_Table` subclass with sortable columns and bulk actions |100| Dashboard widget | `wp_add_dashboard_widget()` |101| Admin notices | Dismissible notices with user-meta persistence |102| Help tabs on plugin screens | `get_current_screen()->add_help_tab()` |103| None (frontend-only plugin) | Skip all admin UI scaffolding |104| Other (specify) | Generate the admin component the user names |105106### Q6 - Frontend display surfaces (multi-select MC)107108> How does the plugin render on the public site? Select all that apply.109110| Option | What it generates |111|--------|-------------------|112| Shortcodes | `add_shortcode()` handlers |113| Gutenberg blocks | `block.json` + React edit component + save function + frontend `render_callback` |114| Classic widgets | `WP_Widget` subclass |115| Template tags / functions | Public `acme_render_*()` functions for themes to call |116| Auto-injected via `the_content` filter | Filter-based injection with opt-out via post meta |117| REST-driven SPA / headless | REST endpoints + minimal client-side fetch demo |118| Custom page templates | `page-*.php` templates registered via `theme_page_templates` filter |119| None (admin-only plugin) | Skip all frontend scaffolding |120| Other (specify) | Generate the frontend surface the user names |121122### Q7 - Third-party integrations (multi-select MC)123124> Which external services or plugins does this integrate with? Select all that apply.125126| Option | What it generates |127|--------|-------------------|128| None | Skip integration scaffolding |129| WooCommerce | Hooks into WC actions/filters; checks `class_exists( 'WooCommerce' )` before booting integration |130| BuddyPress / bbPress | Hooks into BP/bbP actions with `function_exists()` guards |131| Advanced Custom Fields (ACF) | Registers field groups via PHP; gracefully degrades if ACF inactive |132| Elementor | Custom widget class extending `Widget_Base` |133| External REST API | HTTP client wrapper using `wp_remote_get()` / `wp_remote_post()` with retries and error handling |134| Stripe or PayPal | Server-side payment intent / order creation with webhook handler |135| Mailchimp / ConvertKit / SendGrid | Newsletter signup handler; read the API key from a `wp-config.php` constant (recommended) or store it in an option, documented as plaintext - WordPress has no built-in option encryption, so never claim it is encrypted |136| Google Analytics / Tag Manager | Frontend tracking snippet enqueue with cookie-consent gate |137| OAuth providers (Google, GitHub, etc.) | OAuth callback handler + state nonce + user linking |138| Webhooks (incoming) | REST endpoint with HMAC signature verification |139| Webhooks (outgoing) | Async dispatcher using Action Scheduler if available, falls back to wp-cron |140| Other (specify) | Generate an integration scaffold for the service the user names |141142## Inference rules143144From the answers, derive without asking:145146- **Slug** - `sanitize_title( plugin_name )`. Example: "Acme Bookings" → `acme-bookings`.147- **Text domain** - same as slug.148- **Constant prefix** - uppercase slug with hyphens → underscores. Example: `ACME_BOOKINGS_`.149- **PHP namespace** - PascalCase of slug. Example: `AcmeBookings`.150- **Main file name** - `{slug}.php`.151- **Singleton class name** - `{Namespace}\\Plugin`.152- **Minimum WordPress version** - `6.0`.153- **Minimum PHP version** - `7.4` (8.0+ recommended).154- **License** - `GPL-2.0-or-later` with `License URI: https://www.gnu.org/licenses/gpl-2.0.html`.155156## Required file structure157158Always produce this baseline tree. Skip files that correspond to unselected features (e.g. no `includes/class-rest-controller.php` if REST endpoints not picked).159160```161{plugin-slug}/162├── {plugin-slug}.php ← main plugin file (header + bootstrap)163├── uninstall.php ← runs on plugin deletion164├── readme.txt ← WordPress.org format165├── readme.md ← GitHub-friendly mirror166├── composer.json ← autoload definition, dev deps optional167├── .gitignore168├── languages/169│ └── {plugin-slug}.pot ← translation template (header populated)170├── includes/171│ ├── class-plugin.php ← singleton, loads other components172│ ├── class-activator.php ← activation hook handler173│ ├── class-deactivator.php ← deactivation hook handler174│ ├── class-i18n.php ← text domain loader175│ ├── class-admin.php ← admin pages, menus, settings (if admin features picked)176│ ├── class-frontend.php ← shortcodes, scripts, public hooks (if frontend picked)177│ ├── class-database.php ← dbDelta schema, migrations (if custom tables picked)178│ ├── class-ajax.php ← admin-ajax handlers (if AJAX picked)179│ ├── class-rest-controller.php ← REST routes (if REST picked)180│ ├── class-cron.php ← scheduled events (if cron picked)181│ ├── class-cli.php ← WP-CLI commands (if CLI picked)182│ ├── class-roles.php ← role/capability management (if roles picked)183│ ├── class-cpt.php ← custom post types/taxonomies (if CPT picked)184│ ├── class-meta-boxes.php ← meta box registration (if meta boxes picked)185│ ├── class-list-table.php ← WP_List_Table subclass (if list tables picked)186│ ├── class-dashboard-widget.php ← dashboard widget (if picked)187│ ├── class-notices.php ← dismissible admin notices (if picked)188│ ├── class-integration-{name}.php ← one per third-party integration picked189│ └── helpers.php ← procedural utilities190├── assets/191│ ├── css/192│ │ ├── admin.css193│ │ └── public.css194│ ├── js/195│ │ ├── admin.js196│ │ └── public.js197│ └── images/198│ └── icon.svg199├── blocks/ ← only if Gutenberg blocks picked200│ └── {block-slug}/201│ ├── block.json202│ ├── edit.js203│ ├── save.js204│ ├── index.js205│ ├── editor.scss206│ └── style.scss207├── templates/ ← user-overridable theme templates (if frontend picked)208│ └── {feature}-display.php209└── tests/210 └── README.md ← brief notes on running PHPUnit/WPCS211```212213## Code-generation rules214215These rules are non-negotiable. Every generated file is held to them.216217### Security218219- **Direct access guard** on every PHP file: `defined( 'ABSPATH' ) || exit;` immediately after the docblock.220- **Nonces** on every form, AJAX request, and REST mutation. `wp_create_nonce()` + `check_admin_referer()` / `wp_verify_nonce()` / `permission_callback`.221- **Capability checks** before any privileged action: `current_user_can( 'manage_options' )` (or stricter mapped capability for CPTs).222- **Sanitization on input** - `sanitize_text_field()`, `sanitize_email()`, `absint()`, `wp_kses_post()`, `esc_url_raw()` matched to the data type. Never store raw `$_POST`/`$_GET` values.223- **Escaping on output** - `esc_html()`, `esc_attr()`, `esc_url()`, `wp_kses_post()`. No `echo $var;` - only escaped variables reach the page.224- **Prepared statements** - every `$wpdb` query uses `$wpdb->prepare()` with `%s`/`%d`/`%f` placeholders. Never interpolate into SQL.225- **REST `permission_callback`** - never `__return_true` unless the route is intentionally public; document why if so.226- **Forbidden constructs** - no dynamic code execution helpers, no `extract()`, no `create_function()`, no remote includes, no unsafe deserialization.227228### Standards & Style229230- WordPress Coding Standards (WPCS) compliant. Spaces around array brackets `[ 'foo' ]`, Yoda conditions where applicable, `elseif` not `else if`.231- PHPDoc block on every class, every public method, every filter/action. `@since`, `@param`, `@return`, `@throws` where relevant.232- Class file naming: `class-{kebab-case}.php`.233- PHP open tag only - no `?>` at end of pure PHP files.234235### Architecture236237- Singleton main plugin class with `get_instance()` and a `private __construct()` that wires sub-components.238- Composition over inheritance for components - each class accepts its dependencies in the constructor.239- Hooks registered in dedicated `register_hooks()` methods on each component, called once from the bootstrapper.240- No business logic in the main plugin file beyond constants and the bootstrap call.241242### Performance243244- Object-cache-aware: `wp_cache_get()` / `wp_cache_set()` around expensive queries with the plugin slug as cache group.245- Transients for cross-request caching with sensible expirations.246- Asset enqueueing is **conditional** - never load admin assets on the frontend, never load on screens that don't need them. Use `get_current_screen()` checks.247- Versioned asset URLs (`filemtime()` or plugin version constant) for cache busting.248- Dependency arrays passed to `wp_enqueue_*()` - never assume globals.249250### Database251252- Custom tables created via `dbDelta()` (not raw `CREATE TABLE`) with charset/collation from `$wpdb->get_charset_collate()`.253- Indexes on every foreign key and every WHERE/ORDER BY column the plugin actually queries.254- Schema version stored in an option; activation hook compares it and runs migrations.255- `uninstall.php` drops all custom tables, options, user meta, post meta, and scheduled events the plugin created. No orphaned data.256257### Internationalization258259- Every user-facing string wrapped in `__()`, `_e()`, `esc_html__()`, `esc_html_e()`, `_n()`, `_x()`, etc. - with the plugin's text domain (matches slug).260- Text domain loaded on `plugins_loaded` via `load_plugin_textdomain()`.261- `.pot` file shipped in `languages/` with all extracted strings and full header (Project-Id-Version, Last-Translator, Language-Team, etc.).262- Translator comments where placeholders are non-obvious: `/* translators: %s is the user display name */`.263264### Documentation265266- File-level docblocks with `@package`, `@since`, `@license`.267- Class-level docblocks describing responsibility and dependencies.268- `readme.txt` in WordPress.org format with all required sections: `=== Plugin Name ===`, `Contributors`, `Tags`, `Requires at least`, `Tested up to`, `Stable tag`, `License`, `License URI`, then `== Description ==`, `== Installation ==`, `== Frequently Asked Questions ==`, `== Screenshots ==`, `== Changelog ==`, `== Upgrade Notice ==`.269- `readme.md` mirrors the same content in GitHub-friendly markdown.270271### Uninstall272273- `uninstall.php` runs only when invoked by WordPress - guard with `if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) { exit; }`.274- Removes: all options (`delete_option()`), transients, user meta, post meta, custom tables (`DROP TABLE IF EXISTS`), scheduled cron events, registered roles, registered capabilities.275- Multisite-aware: loops over `get_sites()` and runs cleanup per site, plus network options cleanup.276277## Main file header template278279Every plugin's `{slug}.php` opens with this header. Fill in real values - never leave placeholders. For `Plugin URI` / `Author` / `Author URI`: use the author's real details if known; otherwise omit those lines entirely rather than shipping literal `example.com`.280281```php282<?php283/**284 * Plugin Name: {Plugin Name}285 * Plugin URI: https://example.com/{slug}286 * Description: {One-line description derived from Q3.}287 * Version: 1.0.0288 * Requires at least: 6.0289 * Requires PHP: 7.4290 * Author: {Author Name}291 * Author URI: https://example.com292 * License: GPL-2.0-or-later293 * License URI: https://www.gnu.org/licenses/gpl-2.0.html294 * Text Domain: {plugin-slug}295 * Domain Path: /languages296 *297 * @package {Namespace}298 */299300defined( 'ABSPATH' ) || exit;301```302303## Output rules304305- Root directory: `./{plugin-slug}/` by default. Fall back to `./{plugin-slug}-new/` if the first exists; report the chosen path to the user.306- Every PHP file ends with a newline and no trailing `?>`.307- Encoding UTF-8, LF line endings throughout.308- After writing, print one line to chat: `Wrote {N} files to {path}. Activate via the WordPress admin → Plugins → {Plugin Name}.`309- Do NOT paste full source into chat - the user opens the files directly.310311## Quality checklist312313Before declaring done, verify every item:314315- [ ] All seven intake answers captured (5 multi-choice, 2 free-text).316- [ ] Plugin slug, text domain, namespace, and constant prefix all derived consistently from the plugin name.317- [ ] Main plugin file has a complete header with no `{placeholder}` text.318- [ ] `defined( 'ABSPATH' ) || exit;` guard at the top of every PHP file.319- [ ] Every form/AJAX/REST mutation has nonce verification.320- [ ] Every privileged action has a capability check.321- [ ] Every user input passes through a sanitizer matched to its type.322- [ ] Every echoed variable passes through an escaping function matched to its context.323- [ ] Every `$wpdb` query uses `$wpdb->prepare()` with placeholders - no string interpolation into SQL.324- [ ] Every user-facing string is wrapped in an i18n function with the correct text domain.325- [ ] `readme.txt` in WordPress.org format with all required headers populated.326- [ ] `uninstall.php` removes every artefact the plugin creates (options, tables, meta, cron, roles, caps).327- [ ] Asset enqueueing is conditional - no admin assets on frontend, no public assets on every admin screen.328- [ ] Custom tables (if any) use `dbDelta()` with charset/collation and have indexes on queried columns.329- [ ] Multisite-aware activation, deactivation, and uninstall when "Multisite network administrators" was selected.330- [ ] No forbidden sentinel (`TODO`, `TBD`, `FIXME`, `{placeholder}`, "coming soon") remains in any file, and no template token (`{plugin-slug}`, `{Namespace}`, `{Plugin Name}`, `{slug}`) is left unsubstituted.331- [ ] No literal `example.com` shipped - real author URLs or those header lines omitted.332- [ ] Zero filler comments. PHPDoc only where required by standards; no narrative commentary.
Run npx skillmds@latest add chrismccoy/wordpress-plugin in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
WordPress Plugin Generator It is listed under Coding & Dev Tools on SkillMD.
SkillMD's automated safety review verdict for this skill is PASS. Independent scanners report: SkillSpector: CAUTION, Skill Scanner: PASS. Capability flags: makes network calls, reads secrets. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
chrismccoy (@chrismccoy) published this skill. Their other Agent Skills are listed on their SkillMD profile.