# WordPress Best Practices Guide ## Overview This guide documents WordPress best practices as implemented in the HVAC Community Events plugin. Following these practices ensures maintainability, security, and compatibility with WordPress core and other plugins. ## JavaScript and jQuery ### ✅ DO: Use WordPress jQuery Patterns ```javascript // CORRECT - WordPress standard pattern jQuery(document).ready(function($) { 'use strict'; // $ is now available within this scope $('.my-element').addClass('active'); }); ``` ### ❌ DON'T: Create Complex Compatibility Layers ```javascript // WRONG - Unnecessary complexity (function($) { if (typeof $ === 'undefined' && typeof window.jQuery !== 'undefined') { $ = window.jQuery; } // Complex error handling for basic jQuery operations })(jQuery); ``` ### Key Principles 1. WordPress loads jQuery in no-conflict mode by default 2. Use `jQuery` globally, `$` within document ready callbacks 3. Don't create compatibility shims - they add complexity without value 4. Trust WordPress's jQuery implementation ## Security Best Practices ### Always Escape Output ```php // ✅ CORRECT echo esc_html($user_input); echo esc_url($link); echo esc_attr($attribute); echo wp_kses_post($content_with_html); // ❌ WRONG echo $user_input; ``` ### Always Sanitize Input ```php // ✅ CORRECT $clean_text = sanitize_text_field($_POST['field']); $clean_email = sanitize_email($_POST['email']); $clean_url = esc_url_raw($_POST['url']); // ❌ WRONG $data = $_POST['field']; ``` ### Always Verify Nonces ```php // ✅ CORRECT if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'action_name')) { wp_die('Security check failed'); } // ❌ WRONG - No nonce verification if (isset($_POST['submit'])) { // Process form } ``` ### Always Check Capabilities ```php // ✅ CORRECT if (!current_user_can('edit_posts')) { wp_die('Insufficient permissions'); } // Check custom roles properly $user = wp_get_current_user(); if (!in_array('hvac_trainer', $user->roles)) { wp_die('Access denied'); } // ❌ WRONG if (!current_user_can('hvac_trainer')) { // Custom roles aren't capabilities! wp_die('Access denied'); } ``` ## Plugin Development Standards ### File Organization ``` hvac-community-events/ ├── hvac-community-events.php # Main plugin file ├── includes/ # PHP classes and functions │ ├── class-*.php # One class per file │ └── functions.php # Helper functions ├── assets/ # Frontend resources │ ├── css/ # Stylesheets │ ├── js/ # JavaScript files │ └── images/ # Images ├── templates/ # Page templates └── docs/ # Documentation ``` ### Class Structure ```php /** * HVAC Example Class * * @package HVAC_Community_Events * @since 1.0.0 */ class HVAC_Example { /** * Instance * @var HVAC_Example */ private static $instance = null; /** * Get instance (Singleton pattern) */ public static function instance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } /** * Constructor */ private function __construct() { $this->init_hooks(); } /** * Initialize hooks */ private function init_hooks() { add_action('init', array($this, 'init')); } } ``` ### Naming Conventions - **PHP Classes**: `HVAC_Class_Name` (prefix + PascalCase) - **Functions**: `hvac_function_name` (prefix + snake_case) - **Hooks**: `hvac_hook_name` (prefix + snake_case) - **Constants**: `HVAC_CONSTANT_NAME` (prefix + UPPER_SNAKE_CASE) - **Database**: `hvac_table_name` (prefix + snake_case) ## Asset Management ### Conditional Loading ```php /** * Only load assets on plugin pages */ public function enqueue_scripts() { // Check if we're on a plugin page if (!$this->is_plugin_page()) { return; } wp_enqueue_script( 'hvac-dashboard', HVAC_PLUGIN_URL . 'assets/js/hvac-dashboard.js', array('jquery'), HVAC_PLUGIN_VERSION, true ); // Localize script for AJAX wp_localize_script('hvac-dashboard', 'hvac_ajax', array( 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('hvac_ajax_nonce') )); } ``` ### CSS Organization ```css /* Use consistent naming and organization */ .hvac-wrapper { max-width: 1200px; margin: 0 auto; padding: 20px; } /* Component-based styling */ .hvac-card { background: #fff; border-radius: 8px; padding: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } /* State modifiers */ .hvac-card--active { border-color: var(--hvac-primary); } ``` ## Database Operations ### Use WordPress Database API ```php global $wpdb; // ✅ CORRECT - Using prepared statements $results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}posts WHERE post_author = %d", $user_id ) ); // ❌ WRONG - Direct query without preparation $results = $wpdb->get_results( "SELECT * FROM wp_posts WHERE post_author = " . $user_id ); ``` ### Cache Expensive Queries ```php $cache_key = 'hvac_trainer_events_' . $user_id; $events = wp_cache_get($cache_key); if (false === $events) { // Expensive query $events = $this->get_trainer_events($user_id); // Cache for 1 hour wp_cache_set($cache_key, $events, '', HOUR_IN_SECONDS); } ``` ## AJAX Best Practices ### Proper AJAX Handler ```php /** * AJAX handler with security checks */ public function ajax_handler() { // Verify nonce if (!check_ajax_referer('hvac_ajax_nonce', 'nonce', false)) { wp_send_json_error('Security check failed'); } // Check capabilities if (!current_user_can('edit_posts')) { wp_send_json_error('Insufficient permissions'); } // Sanitize input $data = sanitize_text_field($_POST['data']); // Process request $result = $this->process_data($data); // Return JSON response if ($result) { wp_send_json_success($result); } else { wp_send_json_error('Processing failed'); } } ``` ## Template Development ### WordPress Template Requirements ```php