wp-plugin-dev
WordPress Plugin Development
Overview
Create production-ready WordPress plugins that follow official WordPress coding standards, the WordPress.org plugin directory guidelines, and security best practices. Every plugin produced by this skill is modular, secure, translatable, and ready for WordPress.org submission.
Quick Start Workflow
- Read references — Before writing any code, read the relevant reference files:
references/architecture.md— Plugin structure, boilerplate patterns for all plugin typesreferences/security.md— Sanitization, escaping, prepared statements, nonces, cachingreferences/wp-org-guidelines.md— WordPress.org directory rules (18 guidelines)
- Gather requirements — Ask the user what the plugin should do, then determine which modules are needed
- Scaffold — Generate the directory structure and bootstrap file
- Build features — Create each feature as a separate modular class
- Generate readme.txt — Always include a WordPress.org-compliant readme.txt
- Deliver — Ask user if they want files in
/mnt/user-data/outputs/for download or a custom path
Core Principles — ALWAYS Follow These
1. Clean Bootstrap File
The main plugin file (plugin-name.php) is ONLY a bootstrap loader. It contains:
- Plugin header comment (with all required headers)
- Constants (
VERSION,PLUGIN_DIR,PLUGIN_URL,PLUGIN_BASENAME) register_activation_hook()/register_deactivation_hook()- Autoloader or
require_oncestatements - A single init function that instantiates the main class
NEVER put settings registration, shortcode handlers, AJAX callbacks, CPT registration, hook callbacks, template rendering, or ANY feature logic in the main plugin file.
2. Modular Architecture
Every distinct feature gets its own class file in the appropriate directory:
includes/— Core classes, shared utilities, data modelsadmin/— Admin-only functionality (settings pages, meta boxes, admin notices)public/— Public-facing functionality (shortcodes, frontend rendering)blocks/— Gutenberg blocks (each block gets its own subdirectory)api/— REST API endpoints
Each class follows the single-responsibility principle. When a feature grows beyond ~200 lines, split it into sub-components.
3. Security — Non-Negotiable
Apply ALL of the following on EVERY piece of code:
Input: Sanitize ALL user input immediately upon receipt.
$title = sanitize_text_field( wp_unslash( $_POST['title'] ) );
Output: Escape ALL output at the point of rendering (late escaping).
echo esc_html( $title );
Database: Use $wpdb->prepare() for ALL custom SQL queries. No exceptions.
$wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table} WHERE id = %d", $id ) );
Auth: Check nonces for ALL form submissions and AJAX requests. Check capabilities before ALL privileged operations.
Caching: Use Transients API or wp_cache_* for expensive queries and external API calls.
Read references/security.md for the complete function reference.
4. WordPress Coding Standards
- Use WordPress naming conventions:
snake_casefor functions/variables,Upper_Snake_Casefor classes - Prefix ALL functions, classes, hooks, options, transients, and database tables with the plugin prefix
- Use proper PHPDoc blocks on all classes, methods, and functions
- All user-facing strings must be translatable using
__(),_e(),esc_html__(), etc. - Set the text domain to match the plugin slug
- Use
wp_enqueue_script()/wp_enqueue_style()— never hardcode<script>or<link>tags - Use WordPress bundled libraries (jQuery, etc.) — never bundle your own copies
- Enqueue admin assets only on plugin pages (check
$hookparameter) - Enqueue public assets conditionally (only when the plugin's output is on the page)
5. WordPress.org Compliance
Every plugin MUST:
- Use GPLv2 or later license
- Include a complete
readme.txtfollowing the WordPress.org format - Include
uninstall.phpfor clean removal - Not include obfuscated code
- Not include tracking without opt-in consent
- Not bundle WordPress default libraries
- Have human-readable code with meaningful names
- Not embed credit links without explicit user opt-in
Read references/wp-org-guidelines.md for all 18 guidelines.
Plugin Type Reference
When the user's requirements include any of these, read references/architecture.md and use the corresponding patterns:
| User Wants | Module Pattern | Key File |
|---|---|---|
| Settings page | Settings class with Settings API | admin/class-*-settings.php |
| Custom post type | CPT registration class | includes/class-*-post-types.php |
| Custom taxonomy | Taxonomy registration (in CPT class or separate) | includes/class-*-taxonomies.php |
| Shortcodes | Shortcode handler class | public/class-*-shortcodes.php |
| REST API endpoints | REST controller class | api/class-*-rest-controller.php |
| Gutenberg blocks | Block with block.json + JS/React |
blocks/{block-name}/ |
| WooCommerce extension | WooCommerce integration class (with dependency check) | includes/class-*-woocommerce.php |
| AJAX handlers | AJAX handler class | includes/class-*-ajax.php |
| Custom database table | Database class with dbDelta() |
includes/class-*-database.php |
| Admin notices | Notices class | admin/class-*-notices.php |
| Cron jobs | Cron scheduler class | includes/class-*-cron.php |
| Meta boxes | Meta box class | admin/class-*-meta-boxes.php |
| Widgets | Widget class extending WP_Widget |
includes/class-*-widget.php |
Naming Conventions
When scaffolding, derive all names from the plugin name the user provides:
| Element | Convention | Example (plugin: "Smart Bookmarks") |
|---|---|---|
| Plugin slug | lowercase-hyphenated | smart-bookmarks |
| Text domain | same as slug | smart-bookmarks |
| Function prefix | lowercase underscore | smb_ |
| Class prefix | Upper_Snake | Smart_Bookmarks_ |
| Constant prefix | UPPER_SNAKE | SMB_ |
| Option names | prefix + name | smb_settings |
| Transient names | prefix + name | smb_cache_items |
| DB table prefix | prefix + name | smb_items |
| Hook names | prefix/name | smb_after_save |
| REST namespace | slug/v1 | smart-bookmarks/v1 |
| Block namespace | slug/block | smart-bookmarks/featured-list |
Choose a short prefix (2-4 characters) derived from the plugin name initials.
Delivery
After building the plugin:
- Ask the user where they want the files:
- Download: Copy to
/mnt/user-data/outputs/{plugin-slug}/and present as downloadable - Custom path: Write to the path the user specifies
- Download: Copy to
- Always include
readme.txtin the plugin root - Provide a brief summary of the generated files and what each module does
- If the plugin includes Gutenberg blocks, note that
npm install && npm run buildis needed for the block assets
Checklist Before Delivery
Run through this before presenting the final plugin:
- Main plugin file contains ONLY bootstrap code
- Every feature is in its own class file
- ALL user input is sanitized
- ALL output is escaped
- ALL custom SQL uses
$wpdb->prepare() - ALL forms use nonces
- ALL privileged actions check capabilities
- ALL strings are translatable with correct text domain
- ALL functions/classes/hooks are prefixed
- Assets are properly enqueued (not hardcoded)
- Admin assets only load on plugin pages
-
readme.txtis present and complete -
uninstall.phphandles clean removal - License header is GPLv2 or later
- No bundled WP default libraries
- Caching is used for expensive operations
- Activation hook creates any needed DB tables
- Deactivation hook cleans up scheduled events