Rules: 4-5 chars minimum, apply to functions, classes, constants, options, transients, meta keys. Avoid wp_, __, .
_
// GOOD
function mypl_init() {}
class MyPL_Settings {}
add_option( 'mypl_option', 'value' );
// BAD - Will conflict
function init() {}
class Settings {}
CRITICAL: Always use $wpdb->prepare() for user input.
// WRONG - SQL Injection
$wpdb->get_results( "SELECT * FROM {$wpdb->prefix}table WHERE id = {$_GET['id']}" );
// CORRECT
$wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}table WHERE id = %d", $_GET['id'] ) );
LIKE Queries: Use $wpdb->esc_like() before adding wildcards:
$search = '%' . $wpdb->esc_like( $term ) . '%';
$wpdb->get_results( $wpdb->prepare( "... WHERE title LIKE %s", $search ) );
Critical Rules
Always Do
✅ Use unique prefix (4-5 chars) for all global code (functions, classes, options, transients)
✅ Add ABSPATH check to every PHP file: if ( ! defined( 'ABSPATH' ) ) exit;
✅ Check capabilities (current_user_can()) not just is_admin()
✅ Verify nonces for all forms and AJAX requests
✅ Use $wpdb->prepare() for all database queries with user input
✅ Sanitize input with sanitize_*() functions before saving
✅ Escape output with esc_*() functions before displaying
✅ Flush rewrite rules on activation when registering custom post types
✅ Use uninstall.php for permanent cleanup (not deactivation hook)
✅ Follow WordPress Coding Standards (tabs for indentation, Yoda conditions)
Never Do
❌ Never use extract() - Creates security vulnerabilities
❌ Never trust $_POST/$_GET without sanitization
❌ Never concatenate user input into SQL - Always use prepare()
❌ Never use is_admin() alone for permission checks
❌ Never output unsanitized data - Always escape
❌ Never use generic function/class names - Always prefix
❌ Never use short PHP tags<? or <?= - Use <?php only
❌ Never delete user data on deactivation - Only on uninstall
❌ Never register uninstall hook repeatedly - Only once on activation
❌ Never use register_uninstall_hook() in main flow - Use uninstall.php instead
Known Issues Prevention
This skill prevents 20 documented issues:
Issue #1: SQL Injection
Error: Database compromised via unescaped user input
Source: https://patchstack.com/articles/sql-injection/ (15% of all vulnerabilities)
Why It Happens: Direct concatenation of user input into SQL queries
Prevention: Always use $wpdb->prepare() with placeholders
// VULNERABLE
$wpdb->query( "DELETE FROM {$wpdb->prefix}table WHERE id = {$_GET['id']}" );
// SECURE
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}table WHERE id = %d", $_GET['id'] ) );
Issue #2: XSS (Cross-Site Scripting)
Error: Malicious JavaScript executed in user browsers
Source: https://patchstack.com (35% of all vulnerabilities)
Why It Happens: Outputting unsanitized user data to HTML
Prevention: Always escape output with context-appropriate function
Error: Regular users can access admin functions
Source: WordPress Security Review Guidelines
Why It Happens: Using is_admin() instead of current_user_can()Prevention: Always check capabilities, not just admin context
// VULNERABLE
if ( is_admin() ) {
// Any logged-in user can trigger this
}
// SECURE
if ( current_user_can( 'manage_options' ) ) {
// Only administrators can trigger this
}
Issue #5: Direct File Access
Error: PHP files executed outside WordPress context
Source: WordPress Plugin Handbook
Why It Happens: No ABSPATH check at top of file
Prevention: Add ABSPATH check to every PHP file
// Add to top of EVERY PHP file
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
Additional Issues (#6-20)
For comprehensive error coverage beyond the Top 5, load references/error-catalog.md which includes:
Functionality: Prefix collision, rewrite rules not flushed, deprecated functions, text domain mismatch, plugin dependencies, autosave triggers
Performance: Scripts loaded everywhere, transients not cleaned, admin-ajax.php performance
Security: Missing sanitization on save, incorrect LIKE queries, using extract(), missing REST API permission callbacks, uninstall hook issues
Data Integrity: Data deleted on deactivation
Each issue includes: error description, source, why it happens, prevention code, impact severity, and frequency.
Plugin Architecture Patterns
Choose the right architecture for your plugin size and complexity:
Decision Guide
Simple (Functions Only)
When: Small plugins (<5 functions), single feature
Pros: Easy to start, minimal boilerplate
Cons: Doesn't scale, hard to organize beyond ~5 functions
Example: Simple shortcode plugin, basic widget
OOP (Singleton Pattern)
When: Medium plugins (5-20 functions), related functionality
HTML Stripped: Use wp_kses_post() instead of sanitize_text_field()
DB Queries Fail: Always use $wpdb->prepare(), include $wpdb->prefix, verify syntax
When to Load References
This skill uses progressive disclosure - main file contains essentials, reference files have detailed implementation. Load references based on your current task:
references/common-patterns.md (465 lines)
Load when: Implementing specific WordPress features
Contains:
Custom Post Types (registration, Gutenberg support, rewrite rules)
Custom Taxonomies (hierarchical vs flat, REST API)
Meta Boxes (security requirements, save hooks, autosave checks)
Settings API (register_setting, sections, fields hierarchy)
REST API Endpoints (permission callbacks, validation, responses)
Data integrity issues (deactivation vs uninstall)
Each issue includes: Error description, source/reference, why it happens, prevention code, impact severity, frequency