diff --git a/docs/MONITORING-SYSTEMS.md b/docs/MONITORING-SYSTEMS.md
new file mode 100644
index 00000000..96f2cab4
--- /dev/null
+++ b/docs/MONITORING-SYSTEMS.md
@@ -0,0 +1,412 @@
+# HVAC Plugin Monitoring Systems
+
+This document describes the comprehensive enterprise-level monitoring and reliability systems implemented in the HVAC Community Events plugin.
+
+## Overview
+
+The plugin includes four integrated monitoring systems:
+
+1. **Health Monitor** - Automated health checks and system validation
+2. **Error Recovery** - Automatic error recovery and graceful degradation
+3. **Security Monitor** - Real-time threat detection and response
+4. **Performance Monitor** - Performance tracking and optimization alerts
+
+## Health Monitor
+
+### Features
+- 8 different health check types
+- Automated hourly checks with email alerts
+- Admin dashboard integration
+- REST API endpoints for external monitoring
+- WP-CLI integration
+
+### Health Check Types
+- **Database Connectivity** - Tests database connection and table integrity
+- **Cache System** - Validates WordPress object cache functionality
+- **User Authentication** - Verifies role system and user capabilities
+- **Event Management** - Checks The Events Calendar integration
+- **Certificate System** - Validates certificate page existence and permissions
+- **Background Jobs** - Monitors background job queue health
+- **File Permissions** - Checks critical directory permissions
+- **Third Party Integrations** - Validates external plugin dependencies
+
+### Usage
+
+#### Admin Interface
+Navigate to `Tools > HVAC Health` to view comprehensive health status.
+
+#### WP-CLI
+```bash
+wp hvac health
+```
+
+#### REST API
+```
+GET /wp-json/hvac/v1/health
+```
+
+### Configuration
+Health checks run automatically every hour. Critical issues trigger immediate email alerts to the admin email address.
+
+## Error Recovery System
+
+### Features
+- 4 recovery strategies for different failure scenarios
+- Circuit breaker pattern for external services
+- Emergency mode activation for critical failures
+- Comprehensive error tracking and statistics
+
+### Recovery Strategies
+
+#### 1. Retry with Exponential Backoff
+Used for: Database queries, temporary failures
+- Max attempts: 3
+- Backoff multiplier: 2
+
+#### 2. Fallback Operations
+Used for: Cache operations, non-critical services
+- Falls back to safe alternatives
+- Skips functionality gracefully
+
+#### 3. Circuit Breaker
+Used for: External APIs, third-party services
+- Opens after 5 failures
+- 5-minute timeout period
+- Uses cached data when available
+
+#### 4. Graceful Failure
+Used for: File operations, optional features
+- Logs errors and continues operation
+- Returns safe default values
+
+### Usage
+
+#### Programmatic Usage
+```php
+$result = HVAC_Error_Recovery::execute_with_recovery(
+ 'database_query',
+ function() {
+ // Your database operation
+ return $wpdb->get_results("SELECT * FROM table");
+ }
+);
+```
+
+#### Admin Interface
+Navigate to `Tools > HVAC Error Recovery` to view error statistics and manage emergency mode.
+
+### Emergency Mode
+Automatically activated on fatal errors. Disables problematic functionality and sends immediate email alerts.
+
+## Security Monitor
+
+### Features
+- Real-time threat detection
+- Automatic IP blocking for malicious activity
+- Comprehensive security event logging
+- File integrity monitoring
+- Database query analysis
+
+### Monitored Threats
+- **Failed Login Attempts** - Brute force attack detection
+- **SQL Injection** - Pattern detection in requests and queries
+- **XSS Attempts** - Cross-site scripting pattern detection
+- **File Modification** - Critical plugin file integrity checks
+- **Privilege Escalation** - Unauthorized admin actions
+- **Suspicious Activity** - Plugin/theme installation monitoring
+
+### Security Settings
+```php
+$settings = [
+ 'max_failed_logins' => 5,
+ 'lockout_duration' => 900, // 15 minutes
+ 'monitor_file_changes' => true,
+ 'scan_requests' => true,
+ 'alert_threshold' => 3,
+ 'auto_block_ips' => true
+];
+```
+
+### Usage
+
+#### Admin Interface
+Navigate to `Tools > HVAC Security` to view security events, blocked IPs, and threat statistics.
+
+#### WP-CLI
+```bash
+wp hvac security stats
+wp hvac security events
+```
+
+#### REST API
+```
+GET /wp-json/hvac/v1/security/stats
+```
+
+### IP Blocking
+Automatic IP blocking triggers on:
+- 5+ failed login attempts in 1 hour
+- SQL injection attempts
+- Critical threat patterns
+
+## Performance Monitor
+
+### Features
+- Real-time performance tracking
+- Automated performance benchmarks
+- Memory usage monitoring
+- Database query analysis
+- Cache performance tracking
+
+### Performance Metrics
+- **Page Load Time** - Full request processing time
+- **Memory Usage** - Peak memory consumption
+- **Database Queries** - Query count and slow query detection
+- **Cache Hit Rate** - Object cache effectiveness
+- **File I/O Performance** - Disk operation speed
+
+### Thresholds
+```php
+const THRESHOLDS = [
+ 'slow_query_time' => 2.0, // 2 seconds
+ 'memory_usage_mb' => 128, // 128 MB
+ 'page_load_time' => 3.0, // 3 seconds
+ 'db_query_count' => 100, // 100 queries per request
+ 'cache_hit_rate' => 70 // 70% cache hit rate
+];
+```
+
+### Usage
+
+#### Admin Interface
+Navigate to `Tools > HVAC Performance` to view performance statistics and run benchmarks.
+
+#### Admin Bar Integration
+Performance stats appear in the admin bar for logged-in administrators.
+
+#### WP-CLI
+```bash
+wp hvac performance stats
+wp hvac performance benchmark
+```
+
+#### REST API
+```
+GET /wp-json/hvac/v1/performance/stats
+```
+
+### Benchmarking
+Automated daily benchmarks test:
+- Database query performance
+- Memory allocation speed
+- Cache read/write operations
+- File I/O performance
+
+Performance degradation detection compares current benchmarks with previous results and alerts on 50%+ degradation.
+
+## Deployment Validation
+
+### Features
+- 8 critical deployment tests
+- Pre-deployment validation
+- Performance benchmarks during validation
+- Security configuration checks
+
+### Validation Tests
+1. **Plugin Activation** - Verifies plugin is active with correct version
+2. **Database Connectivity** - Tests database connection and queries
+3. **Required Pages** - Checks all plugin pages exist with templates
+4. **User Roles** - Validates HVAC trainer roles and capabilities
+5. **Essential Functionality** - Tests shortcodes, background jobs, health monitoring
+6. **Third Party Integrations** - Verifies The Events Calendar and theme integration
+7. **Performance Benchmarks** - Runs performance tests during deployment
+8. **Security Configurations** - Checks file permissions, nonce system, debug settings
+
+### Usage
+
+#### Command Line
+```bash
+php /path/to/plugin/scripts/deployment-validator.php
+```
+
+#### WP-CLI
+```bash
+wp hvac deployment
+```
+
+### Integration with Deployment Scripts
+Add to your deployment scripts:
+```bash
+# Run deployment validation
+if ! wp hvac deployment; then
+ echo "Deployment validation failed!"
+ exit 1
+fi
+```
+
+## Integration and Architecture
+
+### Singleton Pattern
+All monitoring classes use the singleton pattern to prevent duplicate initialization:
+```php
+HVAC_Health_Monitor::init();
+HVAC_Error_Recovery::init();
+HVAC_Security_Monitor::init();
+HVAC_Performance_Monitor::init();
+```
+
+### WordPress Integration
+- **Cron Jobs** - Automated scheduling for health checks and benchmarks
+- **Admin Menus** - Integrated admin interfaces under Tools menu
+- **REST API** - RESTful endpoints for external monitoring
+- **WP-CLI** - Command-line interface for automation
+- **Admin Bar** - Real-time performance stats
+
+### Database Storage
+- Uses WordPress options table for configuration and metrics
+- Automatic cleanup prevents database bloat
+- Transient caching for frequently accessed data
+
+### Error Handling
+- Comprehensive error logging through HVAC_Logger
+- Fail-safe mechanisms prevent monitoring from breaking site
+- Graceful degradation when monitoring systems fail
+
+## Configuration
+
+### Health Monitor Settings
+```php
+update_option('hvac_health_settings', [
+ 'check_frequency' => 'hourly',
+ 'alert_email' => 'admin@example.com',
+ 'cache_duration' => 300
+]);
+```
+
+### Security Monitor Settings
+```php
+update_option('hvac_security_settings', [
+ 'max_failed_logins' => 5,
+ 'lockout_duration' => 900,
+ 'monitor_file_changes' => true,
+ 'auto_block_ips' => true
+]);
+```
+
+### Performance Monitor Settings
+```php
+update_option('hvac_performance_settings', [
+ 'email_alerts' => true,
+ 'alert_threshold' => 3,
+ 'benchmark_frequency' => 'daily'
+]);
+```
+
+## Troubleshooting
+
+### Common Issues
+
+#### Health Checks Failing
+1. Check database connectivity
+2. Verify file permissions
+3. Ensure The Events Calendar is active
+4. Check WordPress cron system
+
+#### Security Alerts Not Working
+1. Verify admin email setting
+2. Check email delivery system
+3. Review security event logs
+4. Test manual alert trigger
+
+#### Performance Monitoring Inactive
+1. Ensure monitoring conditions are met
+2. Check if request should be monitored
+3. Verify performance thresholds
+4. Review performance event logs
+
+### Debug Mode
+Enable debug logging for detailed monitoring information:
+```php
+define('HVAC_DEBUG_MONITORING', true);
+```
+
+### Log Files
+Monitor logs for system health:
+- WordPress debug.log
+- HVAC_Logger entries
+- Server error logs
+
+## Best Practices
+
+### Production Deployment
+1. Always run deployment validation before going live
+2. Monitor health checks for first 24 hours post-deployment
+3. Review security events regularly
+4. Set up external monitoring for REST API endpoints
+
+### Performance Optimization
+1. Enable object caching for better cache hit rates
+2. Monitor slow query logs and optimize problematic queries
+3. Use performance benchmarks to identify degradation trends
+4. Configure appropriate performance thresholds
+
+### Security Hardening
+1. Enable automatic IP blocking
+2. Monitor file integrity checks
+3. Review security events weekly
+4. Configure security alert thresholds appropriately
+
+### Maintenance
+1. Review and clean old monitoring data monthly
+2. Update performance thresholds based on site growth
+3. Test emergency recovery procedures quarterly
+4. Document any custom monitoring configurations
+
+## API Reference
+
+### Health Monitor API
+```php
+// Run all health checks
+$results = HVAC_Health_Monitor::run_all_checks($force_refresh = false);
+
+// Check overall health status
+$status = $results['overall_status']; // 'healthy', 'warning', 'critical'
+```
+
+### Error Recovery API
+```php
+// Execute with recovery
+$result = HVAC_Error_Recovery::execute_with_recovery($type, $callback, $args);
+
+// Check emergency mode
+$is_emergency = HVAC_Error_Recovery::is_emergency_mode();
+```
+
+### Security Monitor API
+```php
+// Get security statistics
+$stats = HVAC_Security_Monitor::get_security_stats();
+
+// Trigger emergency lockdown
+HVAC_Security_Monitor::emergency_lockdown();
+```
+
+### Performance Monitor API
+```php
+// Get performance statistics
+$stats = HVAC_Performance_Monitor::get_performance_stats();
+
+// Run benchmark
+HVAC_Performance_Monitor::run_performance_benchmark();
+```
+
+## Support and Maintenance
+
+This monitoring system is designed to be self-maintaining with automatic cleanup and intelligent alerting. For issues or questions:
+
+1. Check the admin interfaces for immediate insights
+2. Review log files for detailed error information
+3. Use WP-CLI commands for automation and testing
+4. Consult this documentation for configuration options
+
+The system is designed to fail gracefully - if monitoring systems encounter issues, they will not impact the main plugin functionality.
\ No newline at end of file
diff --git a/includes/class-hvac-backup-manager.php b/includes/class-hvac-backup-manager.php
new file mode 100644
index 00000000..27209660
--- /dev/null
+++ b/includes/class-hvac-backup-manager.php
@@ -0,0 +1,1413 @@
+ true,
+ 'backup_frequency' => 'daily',
+ 'retention_days' => 30,
+ 'backup_location' => 'local', // local, s3, ftp
+ 'compression_enabled' => true,
+ 'encryption_enabled' => true,
+ 'max_backup_size_mb' => 500,
+ 'backup_critical_only' => false
+ ];
+
+ /**
+ * Critical data tables and options
+ */
+ private static $critical_data = [
+ 'tables' => [
+ 'posts',
+ 'postmeta',
+ 'users',
+ 'usermeta',
+ 'options'
+ ],
+ 'options' => [
+ 'hvac_*',
+ 'tribe_events_*',
+ 'astra_*'
+ ],
+ 'files' => [
+ 'uploads/hvac-*',
+ 'plugins/hvac-community-events'
+ ]
+ ];
+
+ /**
+ * Initialize backup manager
+ */
+ public static function init() {
+ // Load settings
+ self::$settings = array_merge(
+ self::$settings,
+ get_option('hvac_backup_settings', [])
+ );
+
+ // Schedule automatic backups
+ if (self::$settings['auto_backup_enabled']) {
+ self::schedule_automatic_backups();
+ }
+
+ // Hook backup actions
+ add_action('hvac_run_backup', [__CLASS__, 'run_scheduled_backup']);
+ add_action('hvac_cleanup_old_backups', [__CLASS__, 'cleanup_old_backups']);
+
+ // Emergency backup triggers
+ add_action('hvac_before_critical_operation', [__CLASS__, 'create_emergency_backup']);
+ add_action('wp_upgrade', [__CLASS__, 'create_pre_update_backup']);
+ add_action('upgrader_process_complete', [__CLASS__, 'create_post_update_backup'], 10, 2);
+
+ // Admin interface
+ if (is_admin()) {
+ add_action('admin_menu', [__CLASS__, 'add_admin_menu']);
+ add_action('wp_ajax_hvac_backup_action', [__CLASS__, 'handle_backup_action']);
+ add_action('admin_notices', [__CLASS__, 'show_backup_notices']);
+ }
+
+ // REST API endpoints
+ add_action('rest_api_init', [__CLASS__, 'register_rest_endpoints']);
+
+ // WP-CLI integration
+ if (defined('WP_CLI') && WP_CLI) {
+ WP_CLI::add_command('hvac backup', [__CLASS__, 'wp_cli_backup']);
+ }
+
+ // Disaster recovery detection
+ add_action('init', [__CLASS__, 'check_disaster_recovery_mode']);
+ }
+
+ /**
+ * Schedule automatic backups
+ */
+ private static function schedule_automatic_backups() {
+ $frequency = self::$settings['backup_frequency'];
+
+ if (!wp_next_scheduled('hvac_run_backup')) {
+ wp_schedule_event(time(), $frequency, 'hvac_run_backup');
+ }
+
+ // Schedule cleanup
+ if (!wp_next_scheduled('hvac_cleanup_old_backups')) {
+ wp_schedule_event(time(), 'daily', 'hvac_cleanup_old_backups');
+ }
+ }
+
+ /**
+ * Create backup
+ *
+ * @param string $type Backup type
+ * @param array $options Backup options
+ * @return array Backup result
+ */
+ public static function create_backup($type = self::BACKUP_FULL, $options = []) {
+ $backup_id = uniqid('hvac_backup_');
+ $timestamp = time();
+
+ // Default options
+ $options = array_merge([
+ 'compress' => self::$settings['compression_enabled'],
+ 'encrypt' => self::$settings['encryption_enabled'],
+ 'description' => '',
+ 'triggered_by' => 'manual'
+ ], $options);
+
+ // Create backup record
+ $backup_record = [
+ 'id' => $backup_id,
+ 'type' => $type,
+ 'status' => self::STATUS_RUNNING,
+ 'created_at' => $timestamp,
+ 'size' => 0,
+ 'file_path' => '',
+ 'options' => $options,
+ 'progress' => 0
+ ];
+
+ self::update_backup_record($backup_id, $backup_record);
+
+ try {
+ // Create backup directory
+ $backup_dir = self::get_backup_directory();
+ if (!wp_mkdir_p($backup_dir)) {
+ throw new Exception('Failed to create backup directory');
+ }
+
+ $backup_file = $backup_dir . "/{$backup_id}.sql";
+
+ // Perform backup based on type
+ switch ($type) {
+ case self::BACKUP_FULL:
+ $result = self::create_full_backup($backup_file, $backup_id);
+ break;
+
+ case self::BACKUP_CRITICAL_DATA:
+ $result = self::create_critical_data_backup($backup_file, $backup_id);
+ break;
+
+ case self::BACKUP_INCREMENTAL:
+ $result = self::create_incremental_backup($backup_file, $backup_id);
+ break;
+
+ default:
+ throw new Exception('Invalid backup type');
+ }
+
+ // Post-processing
+ if ($result['success']) {
+ $final_file = $result['file_path'];
+
+ // Compress if enabled
+ if ($options['compress']) {
+ $final_file = self::compress_backup($final_file);
+ }
+
+ // Encrypt if enabled
+ if ($options['encrypt']) {
+ $final_file = self::encrypt_backup($final_file);
+ }
+
+ $file_size = file_exists($final_file) ? filesize($final_file) : 0;
+
+ // Update backup record
+ $backup_record['status'] = self::STATUS_COMPLETED;
+ $backup_record['file_path'] = $final_file;
+ $backup_record['size'] = $file_size;
+ $backup_record['progress'] = 100;
+ $backup_record['completed_at'] = time();
+
+ self::update_backup_record($backup_id, $backup_record);
+
+ // Log success
+ HVAC_Logger::info(
+ "Backup completed successfully: $backup_id ($type)",
+ 'Backup Manager'
+ );
+
+ return [
+ 'success' => true,
+ 'backup_id' => $backup_id,
+ 'file_path' => $final_file,
+ 'size' => $file_size
+ ];
+ } else {
+ throw new Exception($result['error']);
+ }
+
+ } catch (Exception $e) {
+ // Update backup record with failure
+ $backup_record['status'] = self::STATUS_FAILED;
+ $backup_record['error'] = $e->getMessage();
+ self::update_backup_record($backup_id, $backup_record);
+
+ HVAC_Logger::error(
+ "Backup failed: $backup_id - " . $e->getMessage(),
+ 'Backup Manager'
+ );
+
+ return [
+ 'success' => false,
+ 'error' => $e->getMessage(),
+ 'backup_id' => $backup_id
+ ];
+ }
+ }
+
+ /**
+ * Create full backup
+ */
+ private static function create_full_backup($backup_file, $backup_id) {
+ global $wpdb;
+
+ try {
+ // Get all tables
+ $tables = $wpdb->get_results('SHOW TABLES', ARRAY_N);
+ $total_tables = count($tables);
+ $current_table = 0;
+
+ $sql_content = "-- HVAC Plugin Full Backup\n";
+ $sql_content .= "-- Created: " . date('Y-m-d H:i:s') . "\n";
+ $sql_content .= "-- Backup ID: $backup_id\n\n";
+
+ foreach ($tables as $table) {
+ $table_name = $table[0];
+ $current_table++;
+
+ // Update progress
+ $progress = ($current_table / $total_tables) * 90; // 90% for database, 10% for files
+ self::update_backup_progress($backup_id, $progress);
+
+ // Export table structure
+ $create_table = $wpdb->get_row("SHOW CREATE TABLE `$table_name`", ARRAY_N);
+ $sql_content .= "\n-- Table structure for `$table_name`\n";
+ $sql_content .= "DROP TABLE IF EXISTS `$table_name`;\n";
+ $sql_content .= $create_table[1] . ";\n\n";
+
+ // Export table data
+ $rows = $wpdb->get_results("SELECT * FROM `$table_name`", ARRAY_A);
+ if (!empty($rows)) {
+ $sql_content .= "-- Data for table `$table_name`\n";
+
+ foreach ($rows as $row) {
+ $values = array_map(function($value) {
+ return is_null($value) ? 'NULL' : "'" . esc_sql($value) . "'";
+ }, array_values($row));
+
+ $sql_content .= "INSERT INTO `$table_name` VALUES (" .
+ implode(', ', $values) . ");\n";
+ }
+ $sql_content .= "\n";
+ }
+ }
+
+ // Write SQL file
+ $bytes_written = file_put_contents($backup_file, $sql_content);
+ if ($bytes_written === false) {
+ throw new Exception('Failed to write backup file');
+ }
+
+ // Update progress to 100%
+ self::update_backup_progress($backup_id, 100);
+
+ return [
+ 'success' => true,
+ 'file_path' => $backup_file,
+ 'tables_exported' => $total_tables,
+ 'size' => $bytes_written
+ ];
+
+ } catch (Exception $e) {
+ return [
+ 'success' => false,
+ 'error' => $e->getMessage()
+ ];
+ }
+ }
+
+ /**
+ * Create critical data backup
+ */
+ private static function create_critical_data_backup($backup_file, $backup_id) {
+ global $wpdb;
+
+ try {
+ $sql_content = "-- HVAC Plugin Critical Data Backup\n";
+ $sql_content .= "-- Created: " . date('Y-m-d H:i:s') . "\n";
+ $sql_content .= "-- Backup ID: $backup_id\n\n";
+
+ $critical_tables = self::$critical_data['tables'];
+ $total_tables = count($critical_tables);
+ $current_table = 0;
+
+ foreach ($critical_tables as $table_suffix) {
+ $table_name = $wpdb->prefix . $table_suffix;
+ $current_table++;
+
+ // Update progress
+ $progress = ($current_table / $total_tables) * 100;
+ self::update_backup_progress($backup_id, $progress);
+
+ // Check if table exists
+ $table_exists = $wpdb->get_var($wpdb->prepare(
+ "SHOW TABLES LIKE %s",
+ $table_name
+ ));
+
+ if (!$table_exists) {
+ continue;
+ }
+
+ // Export critical data from this table
+ if ($table_suffix === 'options') {
+ // Export critical options only
+ $sql_content .= self::export_critical_options($table_name);
+ } elseif ($table_suffix === 'posts') {
+ // Export HVAC-related posts only
+ $sql_content .= self::export_hvac_posts($table_name);
+ } else {
+ // Export full table for other critical tables
+ $sql_content .= self::export_full_table($table_name);
+ }
+ }
+
+ // Write SQL file
+ $bytes_written = file_put_contents($backup_file, $sql_content);
+ if ($bytes_written === false) {
+ throw new Exception('Failed to write critical data backup file');
+ }
+
+ return [
+ 'success' => true,
+ 'file_path' => $backup_file,
+ 'tables_exported' => count($critical_tables),
+ 'size' => $bytes_written
+ ];
+
+ } catch (Exception $e) {
+ return [
+ 'success' => false,
+ 'error' => $e->getMessage()
+ ];
+ }
+ }
+
+ /**
+ * Export critical options
+ */
+ private static function export_critical_options($table_name) {
+ global $wpdb;
+
+ $sql = "\n-- Critical Options from $table_name\n";
+
+ foreach (self::$critical_data['options'] as $option_pattern) {
+ $like_pattern = str_replace('*', '%', $option_pattern);
+
+ $options = $wpdb->get_results($wpdb->prepare(
+ "SELECT * FROM `$table_name` WHERE option_name LIKE %s",
+ $like_pattern
+ ), ARRAY_A);
+
+ foreach ($options as $option) {
+ $name = esc_sql($option['option_name']);
+ $value = esc_sql($option['option_value']);
+ $autoload = esc_sql($option['autoload']);
+
+ $sql .= "INSERT INTO `$table_name` (option_name, option_value, autoload) VALUES ";
+ $sql .= "('$name', '$value', '$autoload') ON DUPLICATE KEY UPDATE ";
+ $sql .= "option_value = VALUES(option_value), autoload = VALUES(autoload);\n";
+ }
+ }
+
+ return $sql . "\n";
+ }
+
+ /**
+ * Export HVAC-related posts
+ */
+ private static function export_hvac_posts($table_name) {
+ global $wpdb;
+
+ $sql = "\n-- HVAC-related Posts from $table_name\n";
+
+ // Export tribe_events and HVAC pages
+ $post_types = ['tribe_events', 'page'];
+
+ foreach ($post_types as $post_type) {
+ $posts = $wpdb->get_results($wpdb->prepare(
+ "SELECT * FROM `$table_name` WHERE post_type = %s AND (post_title LIKE %s OR post_name LIKE %s)",
+ $post_type,
+ '%trainer%',
+ '%hvac%'
+ ), ARRAY_A);
+
+ foreach ($posts as $post) {
+ $values = array_map(function($value) {
+ return is_null($value) ? 'NULL' : "'" . esc_sql($value) . "'";
+ }, array_values($post));
+
+ $sql .= "INSERT INTO `$table_name` VALUES (" . implode(', ', $values) . ");\n";
+ }
+ }
+
+ return $sql . "\n";
+ }
+
+ /**
+ * Export full table
+ */
+ private static function export_full_table($table_name) {
+ global $wpdb;
+
+ $sql = "\n-- Full export of $table_name\n";
+
+ // Get table structure
+ $create_table = $wpdb->get_row("SHOW CREATE TABLE `$table_name`", ARRAY_N);
+ $sql .= "DROP TABLE IF EXISTS `$table_name`;\n";
+ $sql .= $create_table[1] . ";\n\n";
+
+ // Get table data
+ $rows = $wpdb->get_results("SELECT * FROM `$table_name`", ARRAY_A);
+
+ foreach ($rows as $row) {
+ $values = array_map(function($value) {
+ return is_null($value) ? 'NULL' : "'" . esc_sql($value) . "'";
+ }, array_values($row));
+
+ $sql .= "INSERT INTO `$table_name` VALUES (" . implode(', ', $values) . ");\n";
+ }
+
+ return $sql . "\n";
+ }
+
+ /**
+ * Create incremental backup
+ */
+ private static function create_incremental_backup($backup_file, $backup_id) {
+ // Get last backup timestamp
+ $last_backup_time = get_option('hvac_last_backup_timestamp', 0);
+ $current_time = time();
+
+ // Find changes since last backup
+ global $wpdb;
+
+ $sql_content = "-- HVAC Plugin Incremental Backup\n";
+ $sql_content .= "-- Created: " . date('Y-m-d H:i:s') . "\n";
+ $sql_content .= "-- Since: " . date('Y-m-d H:i:s', $last_backup_time) . "\n";
+ $sql_content .= "-- Backup ID: $backup_id\n\n";
+
+ // Get modified posts
+ $modified_posts = $wpdb->get_results($wpdb->prepare(
+ "SELECT * FROM {$wpdb->posts} WHERE post_modified_gmt > %s",
+ date('Y-m-d H:i:s', $last_backup_time)
+ ), ARRAY_A);
+
+ if (!empty($modified_posts)) {
+ $sql_content .= "-- Modified Posts\n";
+ foreach ($modified_posts as $post) {
+ $values = array_map(function($value) {
+ return is_null($value) ? 'NULL' : "'" . esc_sql($value) . "'";
+ }, array_values($post));
+
+ $sql_content .= "REPLACE INTO {$wpdb->posts} VALUES (" .
+ implode(', ', $values) . ");\n";
+ }
+ }
+
+ // Get modified options
+ $modified_options = $wpdb->get_results($wpdb->prepare(
+ "SELECT * FROM {$wpdb->options} WHERE option_name LIKE %s",
+ 'hvac_%'
+ ), ARRAY_A);
+
+ if (!empty($modified_options)) {
+ $sql_content .= "\n-- HVAC Options\n";
+ foreach ($modified_options as $option) {
+ $name = esc_sql($option['option_name']);
+ $value = esc_sql($option['option_value']);
+ $autoload = esc_sql($option['autoload']);
+
+ $sql_content .= "REPLACE INTO {$wpdb->options} (option_name, option_value, autoload) ";
+ $sql_content .= "VALUES ('$name', '$value', '$autoload');\n";
+ }
+ }
+
+ // Write incremental backup
+ $bytes_written = file_put_contents($backup_file, $sql_content);
+ if ($bytes_written === false) {
+ throw new Exception('Failed to write incremental backup file');
+ }
+
+ // Update last backup timestamp
+ update_option('hvac_last_backup_timestamp', $current_time);
+
+ return [
+ 'success' => true,
+ 'file_path' => $backup_file,
+ 'modified_posts' => count($modified_posts),
+ 'modified_options' => count($modified_options),
+ 'size' => $bytes_written
+ ];
+ }
+
+ /**
+ * Compress backup file
+ */
+ private static function compress_backup($file_path) {
+ if (!function_exists('gzopen')) {
+ HVAC_Logger::warning('GZ compression not available', 'Backup Manager');
+ return $file_path;
+ }
+
+ $compressed_file = $file_path . '.gz';
+
+ $file_handle = fopen($file_path, 'rb');
+ $gz_handle = gzopen($compressed_file, 'wb9');
+
+ if ($file_handle && $gz_handle) {
+ while (!feof($file_handle)) {
+ gzwrite($gz_handle, fread($file_handle, 4096));
+ }
+
+ fclose($file_handle);
+ gzclose($gz_handle);
+
+ // Remove original file
+ unlink($file_path);
+
+ return $compressed_file;
+ }
+
+ return $file_path;
+ }
+
+ /**
+ * Encrypt backup file
+ */
+ private static function encrypt_backup($file_path) {
+ if (!function_exists('openssl_encrypt')) {
+ HVAC_Logger::warning('OpenSSL encryption not available', 'Backup Manager');
+ return $file_path;
+ }
+
+ $encryption_key = self::get_encryption_key();
+ $encrypted_file = $file_path . '.enc';
+
+ $data = file_get_contents($file_path);
+ $iv = openssl_random_pseudo_bytes(16);
+
+ $encrypted_data = openssl_encrypt(
+ $data,
+ 'AES-256-CBC',
+ $encryption_key,
+ 0,
+ $iv
+ );
+
+ if ($encrypted_data !== false) {
+ // Store IV + encrypted data
+ file_put_contents($encrypted_file, base64_encode($iv . $encrypted_data));
+
+ // Remove original file
+ unlink($file_path);
+
+ return $encrypted_file;
+ }
+
+ return $file_path;
+ }
+
+ /**
+ * Get or generate encryption key
+ */
+ private static function get_encryption_key() {
+ $key = get_option('hvac_backup_encryption_key');
+
+ if (!$key) {
+ $key = bin2hex(openssl_random_pseudo_bytes(32));
+ update_option('hvac_backup_encryption_key', $key);
+ }
+
+ return $key;
+ }
+
+ /**
+ * Restore from backup
+ *
+ * @param string $backup_id Backup ID to restore
+ * @param array $options Restore options
+ * @return array Restore result
+ */
+ public static function restore_from_backup($backup_id, $options = []) {
+ $backup_record = self::get_backup_record($backup_id);
+
+ if (!$backup_record || $backup_record['status'] !== self::STATUS_COMPLETED) {
+ return [
+ 'success' => false,
+ 'error' => 'Backup not found or incomplete'
+ ];
+ }
+
+ $backup_file = $backup_record['file_path'];
+
+ if (!file_exists($backup_file)) {
+ return [
+ 'success' => false,
+ 'error' => 'Backup file not found'
+ ];
+ }
+
+ try {
+ // Create restoration backup first
+ self::create_backup(self::BACKUP_CRITICAL_DATA, [
+ 'description' => 'Pre-restoration backup',
+ 'triggered_by' => 'restore_operation'
+ ]);
+
+ // Decrypt if needed
+ if (str_ends_with($backup_file, '.enc')) {
+ $backup_file = self::decrypt_backup($backup_file);
+ }
+
+ // Decompress if needed
+ if (str_ends_with($backup_file, '.gz')) {
+ $backup_file = self::decompress_backup($backup_file);
+ }
+
+ // Execute SQL restoration
+ $sql_content = file_get_contents($backup_file);
+
+ if ($sql_content === false) {
+ throw new Exception('Failed to read backup file');
+ }
+
+ // Split SQL into individual statements
+ $statements = array_filter(
+ explode(";\n", $sql_content),
+ function($statement) {
+ return trim($statement) && !str_starts_with(trim($statement), '--');
+ }
+ );
+
+ global $wpdb;
+ $executed_statements = 0;
+ $failed_statements = 0;
+
+ foreach ($statements as $statement) {
+ $statement = trim($statement);
+ if (empty($statement)) continue;
+
+ $result = $wpdb->query($statement);
+
+ if ($result === false) {
+ $failed_statements++;
+ HVAC_Logger::warning(
+ "Failed to execute SQL: " . $wpdb->last_error,
+ 'Backup Manager'
+ );
+ } else {
+ $executed_statements++;
+ }
+ }
+
+ // Clear all caches
+ wp_cache_flush();
+
+ // Log successful restoration
+ HVAC_Logger::info(
+ "Backup restored successfully: $backup_id ($executed_statements statements)",
+ 'Backup Manager'
+ );
+
+ return [
+ 'success' => true,
+ 'executed_statements' => $executed_statements,
+ 'failed_statements' => $failed_statements,
+ 'backup_id' => $backup_id
+ ];
+
+ } catch (Exception $e) {
+ HVAC_Logger::error(
+ "Backup restoration failed: $backup_id - " . $e->getMessage(),
+ 'Backup Manager'
+ );
+
+ return [
+ 'success' => false,
+ 'error' => $e->getMessage(),
+ 'backup_id' => $backup_id
+ ];
+ }
+ }
+
+ /**
+ * Decrypt backup file
+ */
+ private static function decrypt_backup($encrypted_file) {
+ $encryption_key = self::get_encryption_key();
+ $decrypted_file = str_replace('.enc', '', $encrypted_file);
+
+ $encrypted_data = base64_decode(file_get_contents($encrypted_file));
+ $iv = substr($encrypted_data, 0, 16);
+ $data = substr($encrypted_data, 16);
+
+ $decrypted_data = openssl_decrypt(
+ $data,
+ 'AES-256-CBC',
+ $encryption_key,
+ 0,
+ $iv
+ );
+
+ if ($decrypted_data !== false) {
+ file_put_contents($decrypted_file, $decrypted_data);
+ return $decrypted_file;
+ }
+
+ throw new Exception('Failed to decrypt backup file');
+ }
+
+ /**
+ * Decompress backup file
+ */
+ private static function decompress_backup($compressed_file) {
+ $decompressed_file = str_replace('.gz', '', $compressed_file);
+
+ $gz_handle = gzopen($compressed_file, 'rb');
+ $file_handle = fopen($decompressed_file, 'wb');
+
+ if ($gz_handle && $file_handle) {
+ while (!gzeof($gz_handle)) {
+ fwrite($file_handle, gzread($gz_handle, 4096));
+ }
+
+ gzclose($gz_handle);
+ fclose($file_handle);
+
+ return $decompressed_file;
+ }
+
+ throw new Exception('Failed to decompress backup file');
+ }
+
+ /**
+ * Run scheduled backup
+ */
+ public static function run_scheduled_backup() {
+ $backup_type = self::$settings['backup_critical_only'] ?
+ self::BACKUP_CRITICAL_DATA :
+ self::BACKUP_FULL;
+
+ $result = self::create_backup($backup_type, [
+ 'description' => 'Scheduled automatic backup',
+ 'triggered_by' => 'scheduler'
+ ]);
+
+ if ($result['success']) {
+ HVAC_Logger::info(
+ 'Scheduled backup completed: ' . $result['backup_id'],
+ 'Backup Manager'
+ );
+ } else {
+ HVAC_Logger::error(
+ 'Scheduled backup failed: ' . $result['error'],
+ 'Backup Manager'
+ );
+
+ // Send alert email
+ self::send_backup_alert('Scheduled Backup Failed', [
+ 'error' => $result['error'],
+ 'timestamp' => time()
+ ]);
+ }
+ }
+
+ /**
+ * Create emergency backup
+ */
+ public static function create_emergency_backup() {
+ $result = self::create_backup(self::BACKUP_CRITICAL_DATA, [
+ 'description' => 'Emergency backup before critical operation',
+ 'triggered_by' => 'emergency'
+ ]);
+
+ if (!$result['success']) {
+ HVAC_Logger::error(
+ 'Emergency backup failed: ' . $result['error'],
+ 'Backup Manager'
+ );
+ }
+
+ return $result;
+ }
+
+ /**
+ * Create pre-update backup
+ */
+ public static function create_pre_update_backup() {
+ self::create_backup(self::BACKUP_FULL, [
+ 'description' => 'Pre-WordPress update backup',
+ 'triggered_by' => 'wp_update'
+ ]);
+ }
+
+ /**
+ * Create post-update backup
+ */
+ public static function create_post_update_backup($upgrader, $options) {
+ if ($options['type'] === 'plugin' &&
+ isset($options['plugins']) &&
+ in_array('hvac-community-events/hvac-community-events.php', $options['plugins'])) {
+
+ self::create_backup(self::BACKUP_CRITICAL_DATA, [
+ 'description' => 'Post-plugin update backup',
+ 'triggered_by' => 'plugin_update'
+ ]);
+ }
+ }
+
+ /**
+ * Cleanup old backups
+ */
+ public static function cleanup_old_backups() {
+ $retention_days = self::$settings['retention_days'];
+ $cutoff_timestamp = time() - ($retention_days * 86400);
+
+ $backups = self::get_all_backups();
+ $cleaned_count = 0;
+
+ foreach ($backups as $backup_id => $backup) {
+ if ($backup['created_at'] < $cutoff_timestamp) {
+ if (self::delete_backup($backup_id)) {
+ $cleaned_count++;
+ }
+ }
+ }
+
+ if ($cleaned_count > 0) {
+ HVAC_Logger::info(
+ "Cleaned up $cleaned_count old backups",
+ 'Backup Manager'
+ );
+ }
+ }
+
+ /**
+ * Delete backup
+ */
+ public static function delete_backup($backup_id) {
+ $backup_record = self::get_backup_record($backup_id);
+
+ if ($backup_record && !empty($backup_record['file_path'])) {
+ if (file_exists($backup_record['file_path'])) {
+ unlink($backup_record['file_path']);
+ }
+ }
+
+ // Remove from records
+ $backups = get_option('hvac_backups', []);
+ unset($backups[$backup_id]);
+ update_option('hvac_backups', $backups);
+
+ return true;
+ }
+
+ /**
+ * Get backup directory
+ */
+ private static function get_backup_directory() {
+ $upload_dir = wp_upload_dir();
+ return $upload_dir['basedir'] . '/hvac-backups';
+ }
+
+ /**
+ * Update backup record
+ */
+ private static function update_backup_record($backup_id, $record) {
+ $backups = get_option('hvac_backups', []);
+ $backups[$backup_id] = $record;
+ update_option('hvac_backups', $backups);
+ }
+
+ /**
+ * Get backup record
+ */
+ private static function get_backup_record($backup_id) {
+ $backups = get_option('hvac_backups', []);
+ return $backups[$backup_id] ?? null;
+ }
+
+ /**
+ * Get all backups
+ */
+ public static function get_all_backups() {
+ return get_option('hvac_backups', []);
+ }
+
+ /**
+ * Update backup progress
+ */
+ private static function update_backup_progress($backup_id, $progress) {
+ $backup_record = self::get_backup_record($backup_id);
+ if ($backup_record) {
+ $backup_record['progress'] = $progress;
+ self::update_backup_record($backup_id, $backup_record);
+ }
+ }
+
+ /**
+ * Check disaster recovery mode
+ */
+ public static function check_disaster_recovery_mode() {
+ $recovery_mode = get_option('hvac_disaster_recovery_mode', false);
+
+ if ($recovery_mode) {
+ // Display disaster recovery notice
+ add_action('admin_notices', function() use ($recovery_mode) {
+ echo '
';
+ echo '
Disaster Recovery Mode Active
';
+ echo '
Last backup: ' . date('Y-m-d H:i:s', $recovery_mode['timestamp']) . '
';
+ echo '
Issue: ' . esc_html($recovery_mode['issue']) . '
';
+ echo '
';
+ });
+ }
+ }
+
+ /**
+ * Send backup alert
+ */
+ private static function send_backup_alert($subject, $data) {
+ $admin_email = get_option('admin_email');
+ $site_name = get_bloginfo('name');
+
+ $message = "Backup Alert from $site_name\n\n";
+ $message .= "Subject: $subject\n\n";
+
+ foreach ($data as $key => $value) {
+ $message .= ucfirst(str_replace('_', ' ', $key)) . ": $value\n";
+ }
+
+ $message .= "\nTime: " . date('Y-m-d H:i:s') . "\n";
+
+ wp_mail($admin_email, "[$site_name] $subject", $message);
+ }
+
+ /**
+ * Get backup statistics
+ */
+ public static function get_backup_stats() {
+ $backups = self::get_all_backups();
+
+ $stats = [
+ 'total_backups' => count($backups),
+ 'completed_backups' => 0,
+ 'failed_backups' => 0,
+ 'total_size' => 0,
+ 'last_backup' => null,
+ 'next_scheduled' => wp_next_scheduled('hvac_run_backup')
+ ];
+
+ foreach ($backups as $backup) {
+ if ($backup['status'] === self::STATUS_COMPLETED) {
+ $stats['completed_backups']++;
+ $stats['total_size'] += $backup['size'];
+
+ if (!$stats['last_backup'] || $backup['created_at'] > $stats['last_backup']['created_at']) {
+ $stats['last_backup'] = $backup;
+ }
+ } elseif ($backup['status'] === self::STATUS_FAILED) {
+ $stats['failed_backups']++;
+ }
+ }
+
+ return $stats;
+ }
+
+ /**
+ * Add admin menu
+ */
+ public static function add_admin_menu() {
+ if (current_user_can('manage_options')) {
+ add_management_page(
+ 'HVAC Backup Manager',
+ 'HVAC Backups',
+ 'manage_options',
+ 'hvac-backup-manager',
+ [__CLASS__, 'admin_page']
+ );
+ }
+ }
+
+ /**
+ * Admin page
+ */
+ public static function admin_page() {
+ $stats = self::get_backup_stats();
+ $backups = array_slice(self::get_all_backups(), -10, 10, true);
+
+ ?>
+
+
HVAC Backup Manager
+
+
+
+
Backup Overview
+
Total Backups:
+
Completed:
+
Failed:
+
Total Size:
+
+
Last Backup:
+
+
+
Next Scheduled:
+
+
+
+
+
Create New Backup
+
+
+
+
+
+
+
+
+
Recent Backups
+
+
+
+ | Backup ID |
+ Type |
+ Status |
+ Created |
+ Size |
+ Actions |
+
+
+
+
+
+ | No backups found |
+
+
+ $backup): ?>
+
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ 'manual']);
+
+ if ($result['success']) {
+ wp_send_json_success('Backup created successfully: ' . $result['backup_id']);
+ } else {
+ wp_send_json_error($result['error']);
+ }
+ break;
+
+ case 'restore':
+ $backup_id = sanitize_text_field($_POST['backup_id']);
+ $result = self::restore_from_backup($backup_id);
+
+ if ($result['success']) {
+ wp_send_json_success('Backup restored successfully');
+ } else {
+ wp_send_json_error($result['error']);
+ }
+ break;
+
+ case 'delete':
+ $backup_id = sanitize_text_field($_POST['backup_id']);
+ if (self::delete_backup($backup_id)) {
+ wp_send_json_success('Backup deleted successfully');
+ } else {
+ wp_send_json_error('Failed to delete backup');
+ }
+ break;
+
+ default:
+ wp_send_json_error('Unknown action');
+ }
+ }
+
+ /**
+ * Show backup notices
+ */
+ public static function show_backup_notices() {
+ if (!current_user_can('manage_options')) {
+ return;
+ }
+
+ $stats = self::get_backup_stats();
+
+ // Show warning if no recent backups
+ if (!$stats['last_backup'] ||
+ $stats['last_backup']['created_at'] < (time() - 7 * 86400)) {
+
+ echo '';
+ echo '
HVAC Backup Warning: No recent backups found. ';
+ echo 'Create a backup now
';
+ echo '
';
+ }
+
+ // Show error if recent backup failures
+ if ($stats['failed_backups'] > 0) {
+ echo '';
+ echo '
HVAC Backup Error: Recent backup failures detected. ';
+ echo 'Check backup status
';
+ echo '
';
+ }
+ }
+
+ /**
+ * Register REST endpoints
+ */
+ public static function register_rest_endpoints() {
+ register_rest_route('hvac/v1', '/backup/stats', [
+ 'methods' => 'GET',
+ 'callback' => [__CLASS__, 'rest_backup_stats'],
+ 'permission_callback' => function() {
+ return current_user_can('manage_options');
+ }
+ ]);
+
+ register_rest_route('hvac/v1', '/backup/create', [
+ 'methods' => 'POST',
+ 'callback' => [__CLASS__, 'rest_create_backup'],
+ 'permission_callback' => function() {
+ return current_user_can('manage_options');
+ }
+ ]);
+ }
+
+ /**
+ * REST API backup stats
+ */
+ public static function rest_backup_stats() {
+ $stats = self::get_backup_stats();
+
+ return new WP_REST_Response([
+ 'stats' => $stats,
+ 'timestamp' => time()
+ ], 200);
+ }
+
+ /**
+ * REST API create backup
+ */
+ public static function rest_create_backup($request) {
+ $type = $request->get_param('type') ?: self::BACKUP_CRITICAL_DATA;
+
+ $result = self::create_backup($type, [
+ 'triggered_by' => 'api'
+ ]);
+
+ if ($result['success']) {
+ return new WP_REST_Response($result, 200);
+ } else {
+ return new WP_REST_Response($result, 500);
+ }
+ }
+
+ /**
+ * WP-CLI backup command
+ */
+ public static function wp_cli_backup($args, $assoc_args) {
+ $subcommand = $args[0] ?? 'create';
+
+ switch ($subcommand) {
+ case 'create':
+ $type = $assoc_args['type'] ?? self::BACKUP_CRITICAL_DATA;
+ WP_CLI::line("Creating $type backup...");
+
+ $result = self::create_backup($type, ['triggered_by' => 'cli']);
+
+ if ($result['success']) {
+ WP_CLI::success("Backup created: {$result['backup_id']}");
+ WP_CLI::line("Size: " . size_format($result['size']));
+ } else {
+ WP_CLI::error($result['error']);
+ }
+ break;
+
+ case 'list':
+ $backups = self::get_all_backups();
+ WP_CLI::line('Recent backups:');
+ foreach (array_slice($backups, -10, 10, true) as $id => $backup) {
+ WP_CLI::line(sprintf(
+ '%s - %s (%s) - %s',
+ $id,
+ $backup['type'],
+ $backup['status'],
+ date('Y-m-d H:i:s', $backup['created_at'])
+ ));
+ }
+ break;
+
+ case 'restore':
+ $backup_id = $assoc_args['id'] ?? '';
+ if (empty($backup_id)) {
+ WP_CLI::error('Backup ID required. Use --id=');
+ }
+
+ WP_CLI::line("Restoring from backup: $backup_id");
+ $result = self::restore_from_backup($backup_id);
+
+ if ($result['success']) {
+ WP_CLI::success('Backup restored successfully');
+ } else {
+ WP_CLI::error($result['error']);
+ }
+ break;
+
+ case 'stats':
+ $stats = self::get_backup_stats();
+ WP_CLI::line('Backup Statistics:');
+ WP_CLI::line('Total Backups: ' . $stats['total_backups']);
+ WP_CLI::line('Completed: ' . $stats['completed_backups']);
+ WP_CLI::line('Failed: ' . $stats['failed_backups']);
+ WP_CLI::line('Total Size: ' . size_format($stats['total_size']));
+ break;
+
+ default:
+ WP_CLI::error('Unknown subcommand. Use: create, list, restore, stats');
+ }
+ }
+}
\ No newline at end of file
diff --git a/includes/class-hvac-cache-optimizer.php b/includes/class-hvac-cache-optimizer.php
new file mode 100644
index 00000000..7dea963d
--- /dev/null
+++ b/includes/class-hvac-cache-optimizer.php
@@ -0,0 +1,1171 @@
+ self::STRATEGY_BALANCED,
+ 'enable_object_cache' => true,
+ 'enable_database_cache' => true,
+ 'enable_api_cache' => true,
+ 'enable_page_cache' => true,
+ 'cache_warming_enabled' => true,
+ 'preload_critical_data' => true,
+ 'cache_compression' => true,
+ 'cache_ttl_multiplier' => 1.0
+ ];
+
+ /**
+ * Cache TTL configurations by strategy
+ */
+ private static $cache_ttls = [
+ self::STRATEGY_AGGRESSIVE => [
+ 'events_list' => 3600, // 1 hour
+ 'trainer_profile' => 7200, // 2 hours
+ 'dashboard_stats' => 1800, // 30 minutes
+ 'certificate_data' => 86400, // 24 hours
+ 'api_responses' => 900, // 15 minutes
+ 'database_queries' => 600, // 10 minutes
+ ],
+ self::STRATEGY_BALANCED => [
+ 'events_list' => 1800, // 30 minutes
+ 'trainer_profile' => 3600, // 1 hour
+ 'dashboard_stats' => 900, // 15 minutes
+ 'certificate_data' => 43200, // 12 hours
+ 'api_responses' => 300, // 5 minutes
+ 'database_queries' => 300, // 5 minutes
+ ],
+ self::STRATEGY_CONSERVATIVE => [
+ 'events_list' => 600, // 10 minutes
+ 'trainer_profile' => 1800, // 30 minutes
+ 'dashboard_stats' => 300, // 5 minutes
+ 'certificate_data' => 21600, // 6 hours
+ 'api_responses' => 120, // 2 minutes
+ 'database_queries' => 120, // 2 minutes
+ ]
+ ];
+
+ /**
+ * Cache warming tasks
+ */
+ private static $warming_tasks = [];
+
+ /**
+ * Cache statistics
+ */
+ private static $stats = [
+ 'hits' => 0,
+ 'misses' => 0,
+ 'sets' => 0,
+ 'deletes' => 0,
+ 'flushes' => 0
+ ];
+
+ /**
+ * Initialize cache optimizer
+ */
+ public static function init() {
+ // Load settings
+ self::$settings = array_merge(
+ self::$settings,
+ get_option('hvac_cache_settings', [])
+ );
+
+ // Initialize cache groups
+ self::setup_cache_groups();
+
+ // Hook into WordPress cache functions
+ add_action('wp_cache_set', [__CLASS__, 'track_cache_set'], 10, 5);
+ add_action('wp_cache_get', [__CLASS__, 'track_cache_get'], 10, 4);
+ add_action('wp_cache_delete', [__CLASS__, 'track_cache_delete'], 10, 2);
+ add_action('wp_cache_flush', [__CLASS__, 'track_cache_flush']);
+
+ // Database query caching
+ if (self::$settings['enable_database_cache']) {
+ add_filter('query', [__CLASS__, 'maybe_cache_query'], 10, 1);
+ }
+
+ // API response caching
+ if (self::$settings['enable_api_cache']) {
+ add_filter('hvac_api_response', [__CLASS__, 'cache_api_response'], 10, 3);
+ add_filter('hvac_api_request', [__CLASS__, 'get_cached_api_response'], 10, 2);
+ }
+
+ // Cache warming
+ if (self::$settings['cache_warming_enabled']) {
+ self::setup_cache_warming();
+ }
+
+ // Preload critical data
+ if (self::$settings['preload_critical_data']) {
+ add_action('init', [__CLASS__, 'preload_critical_data'], 20);
+ }
+
+ // Cache invalidation hooks
+ self::setup_cache_invalidation();
+
+ // Admin interface
+ if (is_admin()) {
+ add_action('admin_menu', [__CLASS__, 'add_admin_menu']);
+ add_action('wp_ajax_hvac_cache_action', [__CLASS__, 'handle_cache_action']);
+ }
+
+ // REST API endpoints
+ add_action('rest_api_init', [__CLASS__, 'register_rest_endpoints']);
+
+ // WP-CLI integration
+ if (defined('WP_CLI') && WP_CLI) {
+ WP_CLI::add_command('hvac cache', [__CLASS__, 'wp_cli_cache']);
+ }
+
+ // Performance monitoring integration
+ add_action('hvac_performance_check', [__CLASS__, 'analyze_cache_performance']);
+ }
+
+ /**
+ * Setup cache groups
+ */
+ private static function setup_cache_groups() {
+ $cache_groups = [
+ self::CACHE_GROUP_EVENTS,
+ self::CACHE_GROUP_TRAINERS,
+ self::CACHE_GROUP_CERTIFICATES,
+ self::CACHE_GROUP_DASHBOARD,
+ self::CACHE_GROUP_API
+ ];
+
+ // Register cache groups as non-persistent if using object cache
+ if (function_exists('wp_cache_add_non_persistent_groups')) {
+ wp_cache_add_non_persistent_groups($cache_groups);
+ }
+ }
+
+ /**
+ * Get cache TTL for key type
+ */
+ private static function get_cache_ttl($key_type) {
+ $strategy = self::$settings['strategy'];
+ $base_ttl = self::$cache_ttls[$strategy][$key_type] ?? 300;
+
+ // Apply multiplier
+ return intval($base_ttl * self::$settings['cache_ttl_multiplier']);
+ }
+
+ /**
+ * Enhanced cache set with compression and statistics
+ */
+ public static function cache_set($key, $data, $group = '', $expire = 0) {
+ // Compress data if enabled and data is large
+ if (self::$settings['cache_compression'] && is_string($data) && strlen($data) > 1024) {
+ $data = gzcompress($data, 6);
+ $key .= '_compressed';
+ }
+
+ $result = wp_cache_set($key, $data, $group, $expire);
+
+ if ($result) {
+ self::$stats['sets']++;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Enhanced cache get with decompression
+ */
+ public static function cache_get($key, $group = '') {
+ $data = wp_cache_get($key, $group);
+
+ if ($data !== false) {
+ self::$stats['hits']++;
+
+ // Check for compressed data
+ if (str_ends_with($key, '_compressed')) {
+ $data = gzuncompress($data);
+ }
+ } else {
+ self::$stats['misses']++;
+
+ // Try compressed version if original not found
+ if (!str_ends_with($key, '_compressed')) {
+ $compressed_data = wp_cache_get($key . '_compressed', $group);
+ if ($compressed_data !== false) {
+ self::$stats['hits']++;
+ $data = gzuncompress($compressed_data);
+ }
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Smart cache delete
+ */
+ public static function cache_delete($key, $group = '') {
+ $result = wp_cache_delete($key, $group);
+
+ // Also try to delete compressed version
+ wp_cache_delete($key . '_compressed', $group);
+
+ if ($result) {
+ self::$stats['deletes']++;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Cache events list with smart invalidation
+ */
+ public static function cache_events_list($args = [], $force_refresh = false) {
+ $cache_key = 'events_list_' . md5(serialize($args));
+
+ if (!$force_refresh) {
+ $cached_data = self::cache_get($cache_key, self::CACHE_GROUP_EVENTS);
+ if ($cached_data !== false) {
+ return $cached_data;
+ }
+ }
+
+ // Generate fresh data
+ $events_data = self::generate_events_list($args);
+
+ // Cache the results
+ $ttl = self::get_cache_ttl('events_list');
+ self::cache_set($cache_key, $events_data, self::CACHE_GROUP_EVENTS, $ttl);
+
+ return $events_data;
+ }
+
+ /**
+ * Cache trainer profile data
+ */
+ public static function cache_trainer_profile($trainer_id, $force_refresh = false) {
+ $cache_key = "trainer_profile_$trainer_id";
+
+ if (!$force_refresh) {
+ $cached_data = self::cache_get($cache_key, self::CACHE_GROUP_TRAINERS);
+ if ($cached_data !== false) {
+ return $cached_data;
+ }
+ }
+
+ // Generate fresh profile data
+ $profile_data = self::generate_trainer_profile($trainer_id);
+
+ // Cache the results
+ $ttl = self::get_cache_ttl('trainer_profile');
+ self::cache_set($cache_key, $profile_data, self::CACHE_GROUP_TRAINERS, $ttl);
+
+ return $profile_data;
+ }
+
+ /**
+ * Cache dashboard statistics
+ */
+ public static function cache_dashboard_stats($user_id, $force_refresh = false) {
+ $cache_key = "dashboard_stats_$user_id";
+
+ if (!$force_refresh) {
+ $cached_data = self::cache_get($cache_key, self::CACHE_GROUP_DASHBOARD);
+ if ($cached_data !== false) {
+ return $cached_data;
+ }
+ }
+
+ // Generate fresh dashboard data
+ if (class_exists('HVAC_Dashboard_Data')) {
+ $dashboard = new HVAC_Dashboard_Data($user_id);
+ $stats_data = [
+ 'total_events' => $dashboard->get_total_events_count(),
+ 'upcoming_events' => $dashboard->get_upcoming_events_count(),
+ 'completed_events' => $dashboard->get_completed_events_count(),
+ 'total_attendees' => $dashboard->get_total_attendees_count()
+ ];
+ } else {
+ $stats_data = [];
+ }
+
+ // Cache the results
+ $ttl = self::get_cache_ttl('dashboard_stats');
+ self::cache_set($cache_key, $stats_data, self::CACHE_GROUP_DASHBOARD, $ttl);
+
+ return $stats_data;
+ }
+
+ /**
+ * Cache certificate data
+ */
+ public static function cache_certificate_data($event_id, $force_refresh = false) {
+ $cache_key = "certificate_data_$event_id";
+
+ if (!$force_refresh) {
+ $cached_data = self::cache_get($cache_key, self::CACHE_GROUP_CERTIFICATES);
+ if ($cached_data !== false) {
+ return $cached_data;
+ }
+ }
+
+ // Generate fresh certificate data
+ $certificate_data = self::generate_certificate_data($event_id);
+
+ // Cache the results with longer TTL (certificates don't change often)
+ $ttl = self::get_cache_ttl('certificate_data');
+ self::cache_set($cache_key, $certificate_data, self::CACHE_GROUP_CERTIFICATES, $ttl);
+
+ return $certificate_data;
+ }
+
+ /**
+ * Database query caching
+ */
+ public static function maybe_cache_query($query) {
+ // Only cache SELECT queries
+ if (!preg_match('/^\s*SELECT/i', $query)) {
+ return $query;
+ }
+
+ // Skip queries with functions that shouldn't be cached
+ $skip_patterns = [
+ '/NOW\(\)/',
+ '/RAND\(\)/',
+ '/CURRENT_TIMESTAMP/',
+ '/USER\(\)/',
+ '/CONNECTION_ID\(\)/'
+ ];
+
+ foreach ($skip_patterns as $pattern) {
+ if (preg_match($pattern, $query)) {
+ return $query;
+ }
+ }
+
+ $cache_key = 'query_' . md5($query);
+ $cached_result = self::cache_get($cache_key, 'hvac_db_cache');
+
+ if ($cached_result !== false) {
+ return $cached_result;
+ }
+
+ // Execute query and cache result
+ global $wpdb;
+ $result = $wpdb->get_results($query);
+
+ if (!$wpdb->last_error) {
+ $ttl = self::get_cache_ttl('database_queries');
+ self::cache_set($cache_key, $result, 'hvac_db_cache', $ttl);
+ }
+
+ return $query;
+ }
+
+ /**
+ * Cache API responses
+ */
+ public static function cache_api_response($response, $endpoint, $params) {
+ $cache_key = 'api_' . md5($endpoint . serialize($params));
+ $ttl = self::get_cache_ttl('api_responses');
+
+ self::cache_set($cache_key, $response, self::CACHE_GROUP_API, $ttl);
+
+ return $response;
+ }
+
+ /**
+ * Get cached API response
+ */
+ public static function get_cached_api_response($endpoint, $params) {
+ $cache_key = 'api_' . md5($endpoint . serialize($params));
+ return self::cache_get($cache_key, self::CACHE_GROUP_API);
+ }
+
+ /**
+ * Setup cache warming
+ */
+ private static function setup_cache_warming() {
+ // Schedule cache warming
+ if (!wp_next_scheduled('hvac_warm_cache')) {
+ wp_schedule_event(time(), 'hourly', 'hvac_warm_cache');
+ }
+
+ add_action('hvac_warm_cache', [__CLASS__, 'warm_critical_caches']);
+
+ // Warm cache on user login
+ add_action('wp_login', [__CLASS__, 'warm_user_specific_cache'], 10, 2);
+ }
+
+ /**
+ * Warm critical caches
+ */
+ public static function warm_critical_caches() {
+ // Warm events list cache
+ self::cache_events_list();
+ self::cache_events_list(['post_status' => 'publish', 'meta_query' => [
+ ['key' => '_EventStartDate', 'value' => date('Y-m-d'), 'compare' => '>=']
+ ]]);
+
+ // Warm trainer profiles for active trainers
+ $trainers = get_users(['role__in' => ['hvac_trainer', 'hvac_master_trainer'], 'number' => 20]);
+ foreach ($trainers as $trainer) {
+ self::cache_trainer_profile($trainer->ID);
+ }
+
+ // Warm certificate data for recent events
+ $recent_events = get_posts([
+ 'post_type' => 'tribe_events',
+ 'post_status' => 'publish',
+ 'numberposts' => 10,
+ 'meta_query' => [
+ ['key' => '_EventStartDate', 'value' => date('Y-m-d', strtotime('-30 days')), 'compare' => '>=']
+ ]
+ ]);
+
+ foreach ($recent_events as $event) {
+ self::cache_certificate_data($event->ID);
+ }
+
+ HVAC_Logger::info('Critical caches warmed successfully', 'Cache Optimizer');
+ }
+
+ /**
+ * Warm user-specific cache
+ */
+ public static function warm_user_specific_cache($user_login, $user) {
+ if (in_array('hvac_trainer', $user->roles) || in_array('hvac_master_trainer', $user->roles)) {
+ // Warm dashboard stats
+ self::cache_dashboard_stats($user->ID);
+
+ // Warm trainer profile
+ self::cache_trainer_profile($user->ID);
+ }
+ }
+
+ /**
+ * Preload critical data
+ */
+ public static function preload_critical_data() {
+ // Skip if already preloaded in this request
+ if (defined('HVAC_CRITICAL_DATA_PRELOADED')) {
+ return;
+ }
+
+ // Preload plugin options
+ $critical_options = [
+ 'hvac_plugin_settings',
+ 'hvac_cache_settings',
+ 'hvac_performance_settings',
+ 'tribe_events_calendar_options'
+ ];
+
+ foreach ($critical_options as $option) {
+ get_option($option);
+ }
+
+ // Preload active trainer count
+ wp_count_posts('hvac_trainer');
+
+ // Preload recent events count
+ wp_count_posts('tribe_events');
+
+ define('HVAC_CRITICAL_DATA_PRELOADED', true);
+ }
+
+ /**
+ * Setup cache invalidation
+ */
+ private static function setup_cache_invalidation() {
+ // Clear events cache when events are modified
+ add_action('save_post', [__CLASS__, 'invalidate_events_cache']);
+ add_action('delete_post', [__CLASS__, 'invalidate_events_cache']);
+
+ // Clear trainer cache when user profiles are updated
+ add_action('profile_update', [__CLASS__, 'invalidate_trainer_cache']);
+ add_action('user_register', [__CLASS__, 'invalidate_trainer_cache']);
+ add_action('delete_user', [__CLASS__, 'invalidate_trainer_cache']);
+
+ // Clear certificate cache when events are updated
+ add_action('save_post', [__CLASS__, 'invalidate_certificate_cache']);
+
+ // Clear dashboard cache when relevant data changes
+ add_action('save_post', [__CLASS__, 'invalidate_dashboard_cache']);
+ add_action('profile_update', [__CLASS__, 'invalidate_dashboard_cache']);
+ }
+
+ /**
+ * Invalidate events cache
+ */
+ public static function invalidate_events_cache($post_id = null) {
+ if ($post_id && get_post_type($post_id) !== 'tribe_events') {
+ return;
+ }
+
+ wp_cache_flush_group(self::CACHE_GROUP_EVENTS);
+
+ HVAC_Logger::info('Events cache invalidated', 'Cache Optimizer');
+ }
+
+ /**
+ * Invalidate trainer cache
+ */
+ public static function invalidate_trainer_cache($user_id = null) {
+ if ($user_id) {
+ self::cache_delete("trainer_profile_$user_id", self::CACHE_GROUP_TRAINERS);
+ } else {
+ wp_cache_flush_group(self::CACHE_GROUP_TRAINERS);
+ }
+
+ HVAC_Logger::info('Trainer cache invalidated', 'Cache Optimizer');
+ }
+
+ /**
+ * Invalidate certificate cache
+ */
+ public static function invalidate_certificate_cache($post_id = null) {
+ if ($post_id && get_post_type($post_id) === 'tribe_events') {
+ self::cache_delete("certificate_data_$post_id", self::CACHE_GROUP_CERTIFICATES);
+ } else {
+ wp_cache_flush_group(self::CACHE_GROUP_CERTIFICATES);
+ }
+
+ HVAC_Logger::info('Certificate cache invalidated', 'Cache Optimizer');
+ }
+
+ /**
+ * Invalidate dashboard cache
+ */
+ public static function invalidate_dashboard_cache($user_id = null) {
+ if ($user_id) {
+ self::cache_delete("dashboard_stats_$user_id", self::CACHE_GROUP_DASHBOARD);
+ } else {
+ wp_cache_flush_group(self::CACHE_GROUP_DASHBOARD);
+ }
+
+ HVAC_Logger::info('Dashboard cache invalidated', 'Cache Optimizer');
+ }
+
+ /**
+ * Generate events list data
+ */
+ private static function generate_events_list($args = []) {
+ $default_args = [
+ 'post_type' => 'tribe_events',
+ 'post_status' => 'publish',
+ 'numberposts' => 50,
+ 'orderby' => 'meta_value',
+ 'meta_key' => '_EventStartDate',
+ 'order' => 'ASC'
+ ];
+
+ $query_args = array_merge($default_args, $args);
+ $events = get_posts($query_args);
+
+ $events_data = [];
+ foreach ($events as $event) {
+ $events_data[] = [
+ 'id' => $event->ID,
+ 'title' => $event->post_title,
+ 'start_date' => get_post_meta($event->ID, '_EventStartDate', true),
+ 'end_date' => get_post_meta($event->ID, '_EventEndDate', true),
+ 'venue_id' => get_post_meta($event->ID, '_EventVenueID', true),
+ 'organizer_id' => get_post_meta($event->ID, '_EventOrganizerID', true)
+ ];
+ }
+
+ return $events_data;
+ }
+
+ /**
+ * Generate trainer profile data
+ */
+ private static function generate_trainer_profile($trainer_id) {
+ $user = get_user_by('id', $trainer_id);
+
+ if (!$user) {
+ return null;
+ }
+
+ $profile_data = [
+ 'id' => $user->ID,
+ 'display_name' => $user->display_name,
+ 'email' => $user->user_email,
+ 'roles' => $user->roles,
+ 'meta' => []
+ ];
+
+ // Get relevant user meta
+ $meta_keys = [
+ 'hvac_trainer_phone',
+ 'hvac_trainer_company',
+ 'hvac_trainer_location',
+ 'hvac_certification_type',
+ 'hvac_certification_status'
+ ];
+
+ foreach ($meta_keys as $key) {
+ $profile_data['meta'][$key] = get_user_meta($trainer_id, $key, true);
+ }
+
+ return $profile_data;
+ }
+
+ /**
+ * Generate certificate data
+ */
+ private static function generate_certificate_data($event_id) {
+ $event = get_post($event_id);
+
+ if (!$event || $event->post_type !== 'tribe_events') {
+ return null;
+ }
+
+ $certificate_data = [
+ 'event_id' => $event->ID,
+ 'event_title' => $event->post_title,
+ 'start_date' => get_post_meta($event->ID, '_EventStartDate', true),
+ 'venue_id' => get_post_meta($event->ID, '_EventVenueID', true),
+ 'organizer_id' => get_post_meta($event->ID, '_EventOrganizerID', true),
+ 'attendees_count' => 0 // Would be populated by actual attendee system
+ ];
+
+ return $certificate_data;
+ }
+
+ /**
+ * Analyze cache performance
+ */
+ public static function analyze_cache_performance() {
+ $hit_rate = self::get_cache_hit_rate();
+ $memory_usage = self::get_cache_memory_usage();
+
+ $performance_data = [
+ 'hit_rate' => $hit_rate,
+ 'memory_usage' => $memory_usage,
+ 'total_operations' => array_sum(self::$stats),
+ 'stats' => self::$stats
+ ];
+
+ // Log performance issues
+ if ($hit_rate < 70) {
+ HVAC_Logger::warning(
+ "Low cache hit rate detected: {$hit_rate}%",
+ 'Cache Optimizer'
+ );
+ }
+
+ if ($memory_usage > 50 * 1024 * 1024) { // 50MB
+ HVAC_Logger::warning(
+ "High cache memory usage: " . size_format($memory_usage),
+ 'Cache Optimizer'
+ );
+ }
+
+ return $performance_data;
+ }
+
+ /**
+ * Get cache hit rate
+ */
+ public static function get_cache_hit_rate() {
+ $total_gets = self::$stats['hits'] + self::$stats['misses'];
+
+ if ($total_gets == 0) {
+ return 0;
+ }
+
+ return round((self::$stats['hits'] / $total_gets) * 100, 2);
+ }
+
+ /**
+ * Get cache memory usage
+ */
+ public static function get_cache_memory_usage() {
+ // This would require object cache backend specific implementation
+ // For now, return estimated usage based on operations
+ return self::$stats['sets'] * 1024; // Estimate 1KB per cached item
+ }
+
+ /**
+ * Get cache statistics
+ */
+ public static function get_cache_stats() {
+ return [
+ 'hit_rate' => self::get_cache_hit_rate(),
+ 'memory_usage' => self::get_cache_memory_usage(),
+ 'operations' => self::$stats,
+ 'strategy' => self::$settings['strategy'],
+ 'groups' => [
+ self::CACHE_GROUP_EVENTS,
+ self::CACHE_GROUP_TRAINERS,
+ self::CACHE_GROUP_CERTIFICATES,
+ self::CACHE_GROUP_DASHBOARD,
+ self::CACHE_GROUP_API
+ ]
+ ];
+ }
+
+ /**
+ * Flush all HVAC caches
+ */
+ public static function flush_all_caches() {
+ $cache_groups = [
+ self::CACHE_GROUP_EVENTS,
+ self::CACHE_GROUP_TRAINERS,
+ self::CACHE_GROUP_CERTIFICATES,
+ self::CACHE_GROUP_DASHBOARD,
+ self::CACHE_GROUP_API
+ ];
+
+ foreach ($cache_groups as $group) {
+ wp_cache_flush_group($group);
+ }
+
+ // Also flush database cache
+ wp_cache_flush_group('hvac_db_cache');
+
+ self::$stats['flushes']++;
+
+ HVAC_Logger::info('All HVAC caches flushed', 'Cache Optimizer');
+ }
+
+ /**
+ * Track cache operations for statistics
+ */
+ public static function track_cache_set($key, $data, $group, $expire, $result) {
+ if (str_starts_with($group, 'hvac_')) {
+ self::$stats['sets']++;
+ }
+ }
+
+ public static function track_cache_get($key, $group, $force, $found) {
+ if (str_starts_with($group, 'hvac_')) {
+ if ($found) {
+ self::$stats['hits']++;
+ } else {
+ self::$stats['misses']++;
+ }
+ }
+ }
+
+ public static function track_cache_delete($key, $group) {
+ if (str_starts_with($group, 'hvac_')) {
+ self::$stats['deletes']++;
+ }
+ }
+
+ public static function track_cache_flush() {
+ self::$stats['flushes']++;
+ }
+
+ /**
+ * Add admin menu
+ */
+ public static function add_admin_menu() {
+ if (current_user_can('manage_options')) {
+ add_management_page(
+ 'HVAC Cache Optimizer',
+ 'HVAC Cache',
+ 'manage_options',
+ 'hvac-cache-optimizer',
+ [__CLASS__, 'admin_page']
+ );
+ }
+ }
+
+ /**
+ * Admin page
+ */
+ public static function admin_page() {
+ $stats = self::get_cache_stats();
+ $performance = self::analyze_cache_performance();
+
+ ?>
+
+
HVAC Cache Optimizer
+
+
+
+
Cache Performance
+
Hit Rate: %
+
Memory Usage:
+
Strategy:
+
Total Operations:
+
+
+
+
Cache Operations
+
Cache Hits:
+
Cache Misses:
+
Cache Sets:
+
Cache Deletes:
+
Cache Flushes:
+
+
+
+
Cache Management
+
+
+
+
+
+
+
+
+
+
+
+
Cache Groups
+
+
+
+ | Group |
+ Description |
+ Actions |
+
+
+
+ 'Event listings and event data',
+ self::CACHE_GROUP_TRAINERS => 'Trainer profiles and trainer data',
+ self::CACHE_GROUP_CERTIFICATES => 'Certificate data and generation',
+ self::CACHE_GROUP_DASHBOARD => 'Dashboard statistics and metrics',
+ self::CACHE_GROUP_API => 'API responses and external data'
+ ];
+ ?>
+
+
+ |
+ |
+
+
+ |
+
+
+
+
+
+
+
+
Cache Strategy Settings
+
+
+
+
+
+
+
+ 'GET',
+ 'callback' => [__CLASS__, 'rest_cache_stats'],
+ 'permission_callback' => function() {
+ return current_user_can('manage_options');
+ }
+ ]);
+
+ register_rest_route('hvac/v1', '/cache/flush', [
+ 'methods' => 'POST',
+ 'callback' => [__CLASS__, 'rest_flush_cache'],
+ 'permission_callback' => function() {
+ return current_user_can('manage_options');
+ }
+ ]);
+ }
+
+ /**
+ * REST API cache stats
+ */
+ public static function rest_cache_stats() {
+ $stats = self::get_cache_stats();
+
+ return new WP_REST_Response([
+ 'stats' => $stats,
+ 'timestamp' => time()
+ ], 200);
+ }
+
+ /**
+ * REST API flush cache
+ */
+ public static function rest_flush_cache() {
+ self::flush_all_caches();
+
+ return new WP_REST_Response([
+ 'message' => 'All caches flushed successfully',
+ 'timestamp' => time()
+ ], 200);
+ }
+
+ /**
+ * WP-CLI cache command
+ */
+ public static function wp_cli_cache($args, $assoc_args) {
+ $subcommand = $args[0] ?? 'stats';
+
+ switch ($subcommand) {
+ case 'stats':
+ $stats = self::get_cache_stats();
+ WP_CLI::line('HVAC Cache Statistics:');
+ WP_CLI::line('Hit Rate: ' . $stats['hit_rate'] . '%');
+ WP_CLI::line('Memory Usage: ' . size_format($stats['memory_usage']));
+ WP_CLI::line('Strategy: ' . ucfirst($stats['strategy']));
+ WP_CLI::line('Total Operations: ' . array_sum($stats['operations']));
+ break;
+
+ case 'warm':
+ WP_CLI::line('Warming critical caches...');
+ self::warm_critical_caches();
+ WP_CLI::success('Cache warming completed');
+ break;
+
+ case 'flush':
+ $group = $assoc_args['group'] ?? '';
+ if ($group) {
+ wp_cache_flush_group($group);
+ WP_CLI::success("Cache group $group flushed");
+ } else {
+ self::flush_all_caches();
+ WP_CLI::success('All caches flushed');
+ }
+ break;
+
+ case 'analyze':
+ WP_CLI::line('Analyzing cache performance...');
+ $analysis = self::analyze_cache_performance();
+ WP_CLI::line('Hit Rate: ' . $analysis['hit_rate'] . '%');
+ WP_CLI::line('Memory Usage: ' . size_format($analysis['memory_usage']));
+ WP_CLI::success('Performance analysis completed');
+ break;
+
+ default:
+ WP_CLI::error('Unknown subcommand. Use: stats, warm, flush, analyze');
+ }
+ }
+}
\ No newline at end of file
diff --git a/includes/class-hvac-error-recovery.php b/includes/class-hvac-error-recovery.php
new file mode 100644
index 00000000..28976cb0
--- /dev/null
+++ b/includes/class-hvac-error-recovery.php
@@ -0,0 +1,589 @@
+ [
+ 'strategy' => self::STRATEGY_RETRY,
+ 'max_attempts' => 3,
+ 'backoff_multiplier' => 2,
+ 'fallback_callback' => null
+ ],
+ 'cache_operation' => [
+ 'strategy' => self::STRATEGY_FALLBACK,
+ 'max_attempts' => 2,
+ 'fallback_callback' => 'skip_cache'
+ ],
+ 'external_api' => [
+ 'strategy' => self::STRATEGY_CIRCUIT_BREAKER,
+ 'max_failures' => 5,
+ 'timeout' => 300, // 5 minutes
+ 'fallback_callback' => 'use_cached_data'
+ ],
+ 'file_operation' => [
+ 'strategy' => self::STRATEGY_GRACEFUL_FAIL,
+ 'max_attempts' => 2,
+ 'fallback_callback' => 'log_and_continue'
+ ]
+ ];
+
+ /**
+ * Initialize error recovery system
+ */
+ public static function init() {
+ // Set custom error handler for plugin operations
+ add_action('init', [__CLASS__, 'setup_error_handling']);
+
+ // Hook into WordPress error handling
+ add_action('wp_die_handler', [__CLASS__, 'handle_wp_die'], 10, 1);
+
+ // Monitor and recover from specific plugin errors
+ add_action('hvac_operation_failed', [__CLASS__, 'handle_operation_failure'], 10, 3);
+
+ // Admin interface for error recovery stats
+ if (is_admin()) {
+ add_action('admin_menu', [__CLASS__, 'add_admin_menu']);
+ }
+
+ // Cleanup old error data
+ add_action('wp_scheduled_delete', [__CLASS__, 'cleanup_old_errors']);
+ }
+
+ /**
+ * Setup error handling
+ */
+ public static function setup_error_handling() {
+ // Only set error handler for plugin operations
+ if (self::is_plugin_context()) {
+ set_error_handler([__CLASS__, 'handle_php_error'], E_ALL);
+ register_shutdown_function([__CLASS__, 'handle_fatal_error']);
+ }
+ }
+
+ /**
+ * Check if we're in plugin context
+ */
+ private static function is_plugin_context() {
+ $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10);
+
+ foreach ($backtrace as $trace) {
+ $file = $trace['file'] ?? '';
+ if (strpos($file, 'hvac-community-events') !== false) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Execute operation with error recovery
+ *
+ * @param string $operation_type Type of operation
+ * @param callable $callback Operation callback
+ * @param array $args Operation arguments
+ * @return mixed Operation result or fallback
+ */
+ public static function execute_with_recovery($operation_type, $callback, $args = []) {
+ $config = self::$recovery_config[$operation_type] ?? self::$recovery_config['file_operation'];
+ $attempt = 0;
+ $last_error = null;
+
+ // Check circuit breaker
+ if ($config['strategy'] === self::STRATEGY_CIRCUIT_BREAKER) {
+ if (self::is_circuit_open($operation_type)) {
+ return self::execute_fallback($operation_type, $config, $args);
+ }
+ }
+
+ while ($attempt < ($config['max_attempts'] ?? 1)) {
+ $attempt++;
+
+ try {
+ // Execute operation
+ $result = call_user_func_array($callback, $args);
+
+ // Reset error count on success
+ self::reset_error_count($operation_type);
+
+ return $result;
+
+ } catch (Exception $e) {
+ $last_error = $e;
+
+ // Increment error count
+ self::increment_error_count($operation_type);
+
+ // Log error
+ HVAC_Logger::warning(
+ "Operation failed (attempt $attempt): {$e->getMessage()}",
+ 'Error Recovery'
+ );
+
+ // Apply recovery strategy
+ if ($attempt < ($config['max_attempts'] ?? 1)) {
+ switch ($config['strategy']) {
+ case self::STRATEGY_RETRY:
+ $delay = ($config['backoff_multiplier'] ?? 1) * $attempt;
+ sleep($delay);
+ break;
+
+ case self::STRATEGY_CIRCUIT_BREAKER:
+ if (self::should_open_circuit($operation_type)) {
+ self::open_circuit($operation_type, $config['timeout'] ?? 300);
+ return self::execute_fallback($operation_type, $config, $args);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // All attempts failed - execute fallback or fail gracefully
+ return self::handle_final_failure($operation_type, $config, $last_error, $args);
+ }
+
+ /**
+ * Handle final operation failure
+ */
+ private static function handle_final_failure($operation_type, $config, $error, $args) {
+ HVAC_Logger::error(
+ "Operation $operation_type failed after all attempts: " . $error->getMessage(),
+ 'Error Recovery'
+ );
+
+ switch ($config['strategy']) {
+ case self::STRATEGY_FALLBACK:
+ case self::STRATEGY_CIRCUIT_BREAKER:
+ return self::execute_fallback($operation_type, $config, $args);
+
+ case self::STRATEGY_GRACEFUL_FAIL:
+ // Return safe default value
+ return self::get_safe_default($operation_type);
+
+ default:
+ // Re-throw exception for retry strategy
+ throw $error;
+ }
+ }
+
+ /**
+ * Execute fallback operation
+ */
+ private static function execute_fallback($operation_type, $config, $args) {
+ $fallback = $config['fallback_callback'] ?? null;
+
+ if (!$fallback) {
+ return self::get_safe_default($operation_type);
+ }
+
+ try {
+ if (is_string($fallback) && method_exists(__CLASS__, $fallback)) {
+ return call_user_func([__CLASS__, $fallback], $operation_type, $args);
+ } elseif (is_callable($fallback)) {
+ return call_user_func_array($fallback, $args);
+ }
+ } catch (Exception $e) {
+ HVAC_Logger::error(
+ "Fallback also failed for $operation_type: " . $e->getMessage(),
+ 'Error Recovery'
+ );
+ }
+
+ return self::get_safe_default($operation_type);
+ }
+
+ /**
+ * Get safe default value for operation type
+ */
+ private static function get_safe_default($operation_type) {
+ $defaults = [
+ 'database_query' => [],
+ 'cache_operation' => null,
+ 'external_api' => ['error' => 'Service temporarily unavailable'],
+ 'file_operation' => false
+ ];
+
+ return $defaults[$operation_type] ?? null;
+ }
+
+ /**
+ * Circuit breaker management
+ */
+ private static function is_circuit_open($operation_type) {
+ return isset(self::$circuit_breakers[$operation_type]) &&
+ self::$circuit_breakers[$operation_type] > time();
+ }
+
+ private static function should_open_circuit($operation_type) {
+ $error_count = self::get_error_count($operation_type);
+ $config = self::$recovery_config[$operation_type] ?? [];
+
+ return $error_count >= ($config['max_failures'] ?? 5);
+ }
+
+ private static function open_circuit($operation_type, $timeout) {
+ self::$circuit_breakers[$operation_type] = time() + $timeout;
+ update_option('hvac_circuit_breakers', self::$circuit_breakers);
+
+ HVAC_Logger::warning(
+ "Circuit breaker opened for $operation_type (timeout: {$timeout}s)",
+ 'Error Recovery'
+ );
+ }
+
+ /**
+ * Error counting
+ */
+ private static function increment_error_count($operation_type) {
+ if (!isset(self::$error_counts[$operation_type])) {
+ self::$error_counts[$operation_type] = 0;
+ }
+
+ self::$error_counts[$operation_type]++;
+ update_option('hvac_error_counts', self::$error_counts);
+ }
+
+ private static function get_error_count($operation_type) {
+ if (empty(self::$error_counts)) {
+ self::$error_counts = get_option('hvac_error_counts', []);
+ }
+
+ return self::$error_counts[$operation_type] ?? 0;
+ }
+
+ private static function reset_error_count($operation_type) {
+ self::$error_counts[$operation_type] = 0;
+ update_option('hvac_error_counts', self::$error_counts);
+ }
+
+ /**
+ * Fallback implementations
+ */
+ public static function skip_cache($operation_type, $args) {
+ HVAC_Logger::info("Cache operation skipped due to errors", 'Error Recovery');
+ return null;
+ }
+
+ public static function use_cached_data($operation_type, $args) {
+ // Try to get stale cached data
+ $cache_key = 'hvac_fallback_' . md5($operation_type . serialize($args));
+ $cached_data = get_transient($cache_key);
+
+ if ($cached_data !== false) {
+ HVAC_Logger::info("Using stale cached data for $operation_type", 'Error Recovery');
+ return $cached_data;
+ }
+
+ return self::get_safe_default($operation_type);
+ }
+
+ public static function log_and_continue($operation_type, $args) {
+ HVAC_Logger::info("Continuing after failed $operation_type", 'Error Recovery');
+ return true;
+ }
+
+ /**
+ * Handle PHP errors
+ */
+ public static function handle_php_error($severity, $message, $file, $line) {
+ // Only handle errors from plugin files
+ if (strpos($file, 'hvac-community-events') === false) {
+ return false;
+ }
+
+ $error_types = [
+ E_ERROR => 'Error',
+ E_WARNING => 'Warning',
+ E_NOTICE => 'Notice',
+ E_USER_ERROR => 'User Error',
+ E_USER_WARNING => 'User Warning',
+ E_USER_NOTICE => 'User Notice'
+ ];
+
+ $error_type = $error_types[$severity] ?? 'Unknown';
+
+ HVAC_Logger::error(
+ "PHP $error_type: $message in $file:$line",
+ 'Error Recovery'
+ );
+
+ // Don't execute PHP internal error handler
+ return true;
+ }
+
+ /**
+ * Handle fatal errors
+ */
+ public static function handle_fatal_error() {
+ $error = error_get_last();
+
+ if ($error && in_array($error['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE])) {
+ // Only handle fatal errors from plugin files
+ if (strpos($error['file'], 'hvac-community-events') !== false) {
+ HVAC_Logger::error(
+ "Fatal Error: {$error['message']} in {$error['file']}:{$error['line']}",
+ 'Error Recovery'
+ );
+
+ // Attempt to recover by disabling problematic functionality
+ self::emergency_recovery($error);
+ }
+ }
+ }
+
+ /**
+ * Emergency recovery for fatal errors
+ */
+ private static function emergency_recovery($error) {
+ // Create emergency flag to disable problematic functionality
+ update_option('hvac_emergency_mode', [
+ 'enabled' => true,
+ 'error' => $error,
+ 'timestamp' => time()
+ ]);
+
+ // Send emergency notification
+ $admin_email = get_option('admin_email');
+ $site_name = get_bloginfo('name');
+
+ wp_mail(
+ $admin_email,
+ "[$site_name] HVAC Plugin Emergency Mode Activated",
+ "A fatal error occurred in the HVAC plugin and emergency mode has been activated.\n\n" .
+ "Error: {$error['message']}\n" .
+ "File: {$error['file']}:{$error['line']}\n\n" .
+ "Please check the plugin status and contact support if needed."
+ );
+ }
+
+ /**
+ * Check if emergency mode is active
+ */
+ public static function is_emergency_mode() {
+ $emergency = get_option('hvac_emergency_mode', false);
+
+ if (!$emergency || !$emergency['enabled']) {
+ return false;
+ }
+
+ // Auto-disable after 24 hours
+ if (time() - $emergency['timestamp'] > 86400) {
+ delete_option('hvac_emergency_mode');
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Disable emergency mode
+ */
+ public static function disable_emergency_mode() {
+ delete_option('hvac_emergency_mode');
+ HVAC_Logger::info('Emergency mode disabled', 'Error Recovery');
+ }
+
+ /**
+ * Handle operation failure action
+ */
+ public static function handle_operation_failure($operation_type, $error_message, $context = []) {
+ // This can be triggered by other parts of the plugin
+ HVAC_Logger::warning(
+ "Operation failure reported: $operation_type - $error_message",
+ 'Error Recovery'
+ );
+
+ self::increment_error_count($operation_type);
+
+ // Check if circuit breaker should be triggered
+ $config = self::$recovery_config[$operation_type] ?? [];
+ if ($config['strategy'] === self::STRATEGY_CIRCUIT_BREAKER) {
+ if (self::should_open_circuit($operation_type)) {
+ self::open_circuit($operation_type, $config['timeout'] ?? 300);
+ }
+ }
+ }
+
+ /**
+ * Get error recovery statistics
+ */
+ public static function get_recovery_stats() {
+ return [
+ 'error_counts' => get_option('hvac_error_counts', []),
+ 'circuit_breakers' => get_option('hvac_circuit_breakers', []),
+ 'emergency_mode' => get_option('hvac_emergency_mode', false)
+ ];
+ }
+
+ /**
+ * Cleanup old error data
+ */
+ public static function cleanup_old_errors() {
+ // Reset error counts daily
+ $last_reset = get_option('hvac_error_reset_time', 0);
+ if (time() - $last_reset > 86400) { // 24 hours
+ update_option('hvac_error_counts', []);
+ update_option('hvac_error_reset_time', time());
+ }
+
+ // Clean up expired circuit breakers
+ $circuit_breakers = get_option('hvac_circuit_breakers', []);
+ $current_time = time();
+ $updated = false;
+
+ foreach ($circuit_breakers as $operation => $expiry) {
+ if ($expiry < $current_time) {
+ unset($circuit_breakers[$operation]);
+ $updated = true;
+ }
+ }
+
+ if ($updated) {
+ update_option('hvac_circuit_breakers', $circuit_breakers);
+ }
+ }
+
+ /**
+ * Add admin menu
+ */
+ public static function add_admin_menu() {
+ if (current_user_can('manage_options')) {
+ add_submenu_page(
+ 'tools.php',
+ 'HVAC Error Recovery',
+ 'HVAC Error Recovery',
+ 'manage_options',
+ 'hvac-error-recovery',
+ [__CLASS__, 'admin_page']
+ );
+ }
+ }
+
+ /**
+ * Admin page
+ */
+ public static function admin_page() {
+ $stats = self::get_recovery_stats();
+ $emergency_mode = self::is_emergency_mode();
+
+ ?>
+
+
HVAC Error Recovery System
+
+
+
+
Emergency Mode Active - Some plugin functionality may be disabled due to critical errors.
+
+
+
+
+
+
+
+
Error Statistics
+
+
+
+ | Operation Type |
+ Error Count |
+ Circuit Breaker |
+
+
+
+
+
+ | No errors recorded |
+
+
+ $count): ?>
+
+ |
+ |
+
+ time()) {
+ echo 'OPEN (expires: ' . date('H:i:s', $breaker_expiry) . ')';
+ } else {
+ echo 'CLOSED';
+ }
+ ?>
+ |
+
+
+
+
+
+
+
+
+
Recovery Configuration
+
The error recovery system is configured with the following strategies:
+
+ - Database Queries: Retry with exponential backoff (3 attempts)
+ - Cache Operations: Skip and continue without caching
+ - External APIs: Circuit breaker with 5-minute timeout
+ - File Operations: Graceful failure with safe defaults
+
+
+
+
+
+ 'Database Connectivity',
+ 'cache' => 'Cache System',
+ 'authentication' => 'User Authentication',
+ 'events' => 'Event Management',
+ 'certificates' => 'Certificate Generation',
+ 'background_jobs' => 'Background Jobs',
+ 'file_permissions' => 'File Permissions',
+ 'third_party' => 'Third Party Integrations'
+ ];
+
+ /**
+ * Health status constants
+ */
+ const STATUS_HEALTHY = 'healthy';
+ const STATUS_WARNING = 'warning';
+ const STATUS_CRITICAL = 'critical';
+
+ /**
+ * Health check results cache
+ */
+ const CACHE_KEY = 'hvac_health_checks';
+ const CACHE_DURATION = 300; // 5 minutes
+
+ /**
+ * Initialize health monitoring
+ */
+ public static function init() {
+ // Schedule recurring health checks
+ if (!wp_next_scheduled('hvac_health_check')) {
+ wp_schedule_event(time(), 'hourly', 'hvac_health_check');
+ }
+
+ // Hook health check action
+ add_action('hvac_health_check', [__CLASS__, 'run_automated_checks']);
+
+ // Admin integration
+ if (is_admin()) {
+ add_action('admin_menu', [__CLASS__, 'add_admin_menu']);
+ add_action('wp_ajax_hvac_run_health_check', [__CLASS__, 'ajax_run_health_check']);
+ add_action('admin_notices', [__CLASS__, 'show_health_warnings']);
+ }
+
+ // REST API endpoint for external monitoring
+ add_action('rest_api_init', [__CLASS__, 'register_rest_endpoints']);
+
+ // WP-CLI integration
+ if (defined('WP_CLI') && WP_CLI) {
+ WP_CLI::add_command('hvac health', [__CLASS__, 'wp_cli_health_check']);
+ }
+ }
+
+ /**
+ * Run all health checks
+ *
+ * @param bool $force_refresh Force refresh cached results
+ * @return array Health check results
+ */
+ public static function run_all_checks($force_refresh = false) {
+ if (!$force_refresh) {
+ $cached_results = get_transient(self::CACHE_KEY);
+ if ($cached_results !== false) {
+ return $cached_results;
+ }
+ }
+
+ $results = [
+ 'timestamp' => time(),
+ 'overall_status' => self::STATUS_HEALTHY,
+ 'checks' => []
+ ];
+
+ foreach (self::CHECK_TYPES as $type => $name) {
+ $check_result = self::run_health_check($type);
+ $results['checks'][$type] = $check_result;
+
+ // Update overall status based on worst result
+ if ($check_result['status'] === self::STATUS_CRITICAL) {
+ $results['overall_status'] = self::STATUS_CRITICAL;
+ } elseif ($check_result['status'] === self::STATUS_WARNING &&
+ $results['overall_status'] !== self::STATUS_CRITICAL) {
+ $results['overall_status'] = self::STATUS_WARNING;
+ }
+ }
+
+ // Cache results
+ set_transient(self::CACHE_KEY, $results, self::CACHE_DURATION);
+
+ // Log critical issues
+ if ($results['overall_status'] === self::STATUS_CRITICAL) {
+ $critical_checks = array_filter($results['checks'], function($check) {
+ return $check['status'] === self::STATUS_CRITICAL;
+ });
+
+ $critical_names = array_keys($critical_checks);
+ HVAC_Logger::error(
+ 'Critical health check failures: ' . implode(', ', $critical_names),
+ 'Health Monitor'
+ );
+ }
+
+ return $results;
+ }
+
+ /**
+ * Run individual health check
+ *
+ * @param string $type Check type
+ * @return array Check result
+ */
+ private static function run_health_check($type) {
+ $start_time = microtime(true);
+
+ try {
+ switch ($type) {
+ case 'database':
+ $result = self::check_database();
+ break;
+
+ case 'cache':
+ $result = self::check_cache_system();
+ break;
+
+ case 'authentication':
+ $result = self::check_authentication();
+ break;
+
+ case 'events':
+ $result = self::check_event_management();
+ break;
+
+ case 'certificates':
+ $result = self::check_certificate_system();
+ break;
+
+ case 'background_jobs':
+ $result = self::check_background_jobs();
+ break;
+
+ case 'file_permissions':
+ $result = self::check_file_permissions();
+ break;
+
+ case 'third_party':
+ $result = self::check_third_party_integrations();
+ break;
+
+ default:
+ $result = [
+ 'status' => self::STATUS_WARNING,
+ 'message' => 'Unknown check type',
+ 'details' => []
+ ];
+ }
+
+ } catch (Exception $e) {
+ $result = [
+ 'status' => self::STATUS_CRITICAL,
+ 'message' => 'Check failed with exception: ' . $e->getMessage(),
+ 'details' => ['exception' => get_class($e)]
+ ];
+ }
+
+ $result['execution_time'] = round(microtime(true) - $start_time, 4);
+ $result['timestamp'] = time();
+ $result['name'] = self::CHECK_TYPES[$type];
+
+ return $result;
+ }
+
+ /**
+ * Check database connectivity and integrity
+ */
+ private static function check_database() {
+ global $wpdb;
+
+ // Test basic connection
+ $test_query = $wpdb->get_var("SELECT 1");
+ if ($test_query !== '1') {
+ return [
+ 'status' => self::STATUS_CRITICAL,
+ 'message' => 'Database connection failed',
+ 'details' => ['error' => $wpdb->last_error]
+ ];
+ }
+
+ // Check plugin tables exist
+ $required_tables = [
+ $wpdb->prefix . 'posts',
+ $wpdb->prefix . 'postmeta',
+ $wpdb->prefix . 'users',
+ $wpdb->prefix . 'usermeta'
+ ];
+
+ $missing_tables = [];
+ foreach ($required_tables as $table) {
+ $exists = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table));
+ if (!$exists) {
+ $missing_tables[] = $table;
+ }
+ }
+
+ if (!empty($missing_tables)) {
+ return [
+ 'status' => self::STATUS_CRITICAL,
+ 'message' => 'Required tables missing',
+ 'details' => ['missing_tables' => $missing_tables]
+ ];
+ }
+
+ // Check for recent database errors
+ if ($wpdb->last_error) {
+ return [
+ 'status' => self::STATUS_WARNING,
+ 'message' => 'Recent database error detected',
+ 'details' => ['last_error' => $wpdb->last_error]
+ ];
+ }
+
+ return [
+ 'status' => self::STATUS_HEALTHY,
+ 'message' => 'Database connectivity is healthy',
+ 'details' => ['tables_checked' => count($required_tables)]
+ ];
+ }
+
+ /**
+ * Check cache system functionality
+ */
+ private static function check_cache_system() {
+ // Test WordPress object cache
+ $test_key = 'hvac_health_test_' . time();
+ $test_value = 'test_data_' . wp_generate_password(10, false);
+
+ // Set cache
+ $set_result = wp_cache_set($test_key, $test_value, 'hvac_health', 60);
+ if (!$set_result) {
+ return [
+ 'status' => self::STATUS_WARNING,
+ 'message' => 'Cache set operation failed',
+ 'details' => []
+ ];
+ }
+
+ // Get cache
+ $cached_value = wp_cache_get($test_key, 'hvac_health');
+ if ($cached_value !== $test_value) {
+ return [
+ 'status' => self::STATUS_WARNING,
+ 'message' => 'Cache retrieval failed or returned incorrect data',
+ 'details' => ['expected' => $test_value, 'actual' => $cached_value]
+ ];
+ }
+
+ // Test master dashboard cache
+ if (class_exists('HVAC_Master_Dashboard_Data')) {
+ $dashboard_data = new HVAC_Master_Dashboard_Data();
+ $events_count = $dashboard_data->get_total_events_count();
+
+ if (!is_numeric($events_count)) {
+ return [
+ 'status' => self::STATUS_WARNING,
+ 'message' => 'Master dashboard cache returning invalid data',
+ 'details' => ['events_count' => $events_count]
+ ];
+ }
+ }
+
+ // Clean up test cache
+ wp_cache_delete($test_key, 'hvac_health');
+
+ return [
+ 'status' => self::STATUS_HEALTHY,
+ 'message' => 'Cache system is functioning correctly',
+ 'details' => ['test_key' => $test_key]
+ ];
+ }
+
+ /**
+ * Check authentication system
+ */
+ private static function check_authentication() {
+ // Check if trainer roles exist
+ $required_roles = ['hvac_trainer', 'hvac_master_trainer'];
+ $missing_roles = [];
+
+ foreach ($required_roles as $role) {
+ if (!get_role($role)) {
+ $missing_roles[] = $role;
+ }
+ }
+
+ if (!empty($missing_roles)) {
+ return [
+ 'status' => self::STATUS_CRITICAL,
+ 'message' => 'Required user roles are missing',
+ 'details' => ['missing_roles' => $missing_roles]
+ ];
+ }
+
+ // Check for users with trainer roles
+ $trainer_count = count(get_users(['role__in' => $required_roles]));
+ if ($trainer_count === 0) {
+ return [
+ 'status' => self::STATUS_WARNING,
+ 'message' => 'No users found with trainer roles',
+ 'details' => ['trainer_count' => $trainer_count]
+ ];
+ }
+
+ // Test capability system
+ if (!current_user_can('read')) {
+ return [
+ 'status' => self::STATUS_WARNING,
+ 'message' => 'Capability system may have issues',
+ 'details' => []
+ ];
+ }
+
+ return [
+ 'status' => self::STATUS_HEALTHY,
+ 'message' => 'Authentication system is healthy',
+ 'details' => ['trainer_count' => $trainer_count]
+ ];
+ }
+
+ /**
+ * Check event management system
+ */
+ private static function check_event_management() {
+ // Check if The Events Calendar is active
+ if (!class_exists('Tribe__Events__Main')) {
+ return [
+ 'status' => self::STATUS_CRITICAL,
+ 'message' => 'The Events Calendar plugin is not active',
+ 'details' => []
+ ];
+ }
+
+ // Check for events
+ $events_count = wp_count_posts('tribe_events');
+ $total_events = ($events_count->publish ?? 0) + ($events_count->private ?? 0);
+
+ if ($total_events === 0) {
+ return [
+ 'status' => self::STATUS_WARNING,
+ 'message' => 'No events found in the system',
+ 'details' => ['events_count' => $total_events]
+ ];
+ }
+
+ // Check event creation capability
+ $can_create_events = post_type_exists('tribe_events');
+ if (!$can_create_events) {
+ return [
+ 'status' => self::STATUS_CRITICAL,
+ 'message' => 'Event post type is not registered',
+ 'details' => []
+ ];
+ }
+
+ return [
+ 'status' => self::STATUS_HEALTHY,
+ 'message' => 'Event management system is functioning',
+ 'details' => ['total_events' => $total_events]
+ ];
+ }
+
+ /**
+ * Check certificate system
+ */
+ private static function check_certificate_system() {
+ // Check if certificate pages exist
+ $certificate_pages = [
+ 'trainer/certificate-reports',
+ 'trainer/generate-certificates'
+ ];
+
+ $missing_pages = [];
+ foreach ($certificate_pages as $page_slug) {
+ if (!get_page_by_path($page_slug)) {
+ $missing_pages[] = $page_slug;
+ }
+ }
+
+ if (!empty($missing_pages)) {
+ return [
+ 'status' => self::STATUS_WARNING,
+ 'message' => 'Certificate pages are missing',
+ 'details' => ['missing_pages' => $missing_pages]
+ ];
+ }
+
+ // Check uploads directory permissions
+ $upload_dir = wp_upload_dir();
+ if (!wp_is_writable($upload_dir['basedir'])) {
+ return [
+ 'status' => self::STATUS_CRITICAL,
+ 'message' => 'Uploads directory is not writable',
+ 'details' => ['upload_dir' => $upload_dir['basedir']]
+ ];
+ }
+
+ return [
+ 'status' => self::STATUS_HEALTHY,
+ 'message' => 'Certificate system appears functional',
+ 'details' => ['pages_found' => count($certificate_pages) - count($missing_pages)]
+ ];
+ }
+
+ /**
+ * Check background jobs system
+ */
+ private static function check_background_jobs() {
+ if (!class_exists('HVAC_Background_Jobs')) {
+ return [
+ 'status' => self::STATUS_WARNING,
+ 'message' => 'Background jobs system not available',
+ 'details' => []
+ ];
+ }
+
+ // Check if cron is working
+ $cron_test = wp_next_scheduled('hvac_process_background_jobs');
+ if (!$cron_test) {
+ return [
+ 'status' => self::STATUS_WARNING,
+ 'message' => 'Background job processing is not scheduled',
+ 'details' => []
+ ];
+ }
+
+ // Check queue stats
+ $stats = HVAC_Background_Jobs::get_queue_stats();
+ if ($stats['total'] > 100) {
+ return [
+ 'status' => self::STATUS_WARNING,
+ 'message' => 'Background job queue is very large',
+ 'details' => ['queue_size' => $stats['total']]
+ ];
+ }
+
+ return [
+ 'status' => self::STATUS_HEALTHY,
+ 'message' => 'Background jobs system is operational',
+ 'details' => ['queue_size' => $stats['total']]
+ ];
+ }
+
+ /**
+ * Check file permissions
+ */
+ private static function check_file_permissions() {
+ $critical_paths = [
+ WP_CONTENT_DIR,
+ wp_upload_dir()['basedir'],
+ HVAC_PLUGIN_DIR . 'assets'
+ ];
+
+ $permission_issues = [];
+ foreach ($critical_paths as $path) {
+ if (!is_dir($path) || !wp_is_writable($path)) {
+ $permission_issues[] = $path;
+ }
+ }
+
+ if (!empty($permission_issues)) {
+ return [
+ 'status' => self::STATUS_CRITICAL,
+ 'message' => 'Critical directories have permission issues',
+ 'details' => ['problematic_paths' => $permission_issues]
+ ];
+ }
+
+ return [
+ 'status' => self::STATUS_HEALTHY,
+ 'message' => 'File permissions are correct',
+ 'details' => ['paths_checked' => count($critical_paths)]
+ ];
+ }
+
+ /**
+ * Check third-party integrations
+ */
+ private static function check_third_party_integrations() {
+ $integrations = [];
+
+ // Check The Events Calendar
+ if (class_exists('Tribe__Events__Main')) {
+ $integrations['events_calendar'] = 'active';
+ } else {
+ $integrations['events_calendar'] = 'missing';
+ }
+
+ // Check Astra theme integration
+ if (defined('ASTRA_THEME_VERSION')) {
+ $integrations['astra_theme'] = 'active';
+ } else {
+ $integrations['astra_theme'] = 'not_detected';
+ }
+
+ // Check for critical missing integrations
+ if ($integrations['events_calendar'] === 'missing') {
+ return [
+ 'status' => self::STATUS_CRITICAL,
+ 'message' => 'Critical integration missing: The Events Calendar',
+ 'details' => $integrations
+ ];
+ }
+
+ return [
+ 'status' => self::STATUS_HEALTHY,
+ 'message' => 'Third-party integrations are functional',
+ 'details' => $integrations
+ ];
+ }
+
+ /**
+ * Run automated health checks
+ */
+ public static function run_automated_checks() {
+ $results = self::run_all_checks(true);
+
+ // Send alerts for critical issues
+ if ($results['overall_status'] === self::STATUS_CRITICAL) {
+ self::send_health_alert($results);
+ }
+
+ HVAC_Logger::info(
+ "Health check completed: {$results['overall_status']}",
+ 'Health Monitor'
+ );
+ }
+
+ /**
+ * Send health alert
+ *
+ * @param array $results Health check results
+ */
+ private static function send_health_alert($results) {
+ $admin_email = get_option('admin_email');
+ $site_name = get_bloginfo('name');
+
+ $critical_issues = array_filter($results['checks'], function($check) {
+ return $check['status'] === self::STATUS_CRITICAL;
+ });
+
+ $subject = "[$site_name] Critical Health Check Alert";
+ $message = "Critical issues detected in HVAC Community Events plugin:\n\n";
+
+ foreach ($critical_issues as $type => $check) {
+ $message .= "• {$check['name']}: {$check['message']}\n";
+ }
+
+ $message .= "\nPlease check the admin dashboard for more details.";
+
+ wp_mail($admin_email, $subject, $message);
+ }
+
+ /**
+ * Add admin menu
+ */
+ public static function add_admin_menu() {
+ if (current_user_can('manage_options')) {
+ add_management_page(
+ 'HVAC Health Monitor',
+ 'HVAC Health',
+ 'manage_options',
+ 'hvac-health-monitor',
+ [__CLASS__, 'admin_page']
+ );
+ }
+ }
+
+ /**
+ * Admin page
+ */
+ public static function admin_page() {
+ $results = self::run_all_checks();
+
+ ?>
+
+
HVAC Health Monitor
+
+
+
Overall Status:
+
+
+
+
+
Last checked:
+
+
+
+
+
+
+ $check): ?>
+
+
+
Status:
+
+
Checked in: s
+
+
+
+ Details
+
+
+
+
+
+
+
+
+
+
+
+ ';
+ echo 'HVAC Plugin Health Alert: Critical issues detected. ';
+ echo 'View Details';
+ echo '
';
+ }
+ }
+
+ /**
+ * Register REST endpoints
+ */
+ public static function register_rest_endpoints() {
+ register_rest_route('hvac/v1', '/health', [
+ 'methods' => 'GET',
+ 'callback' => [__CLASS__, 'rest_health_check'],
+ 'permission_callback' => function() {
+ return current_user_can('manage_options');
+ }
+ ]);
+ }
+
+ /**
+ * REST API health check
+ */
+ public static function rest_health_check() {
+ $results = self::run_all_checks();
+
+ return new WP_REST_Response([
+ 'status' => $results['overall_status'],
+ 'timestamp' => $results['timestamp'],
+ 'checks' => $results['checks']
+ ], 200);
+ }
+
+ /**
+ * WP-CLI health check command
+ */
+ public static function wp_cli_health_check($args, $assoc_args) {
+ WP_CLI::line('Running HVAC health checks...');
+
+ $results = self::run_all_checks(true);
+
+ WP_CLI::line('Overall Status: ' . strtoupper($results['overall_status']));
+ WP_CLI::line('');
+
+ foreach ($results['checks'] as $type => $check) {
+ $status_color = $check['status'] === self::STATUS_HEALTHY ? '%G' :
+ ($check['status'] === self::STATUS_WARNING ? '%Y' : '%R');
+
+ WP_CLI::line(sprintf(
+ '%s: ' . $status_color . '%s%n - %s',
+ $check['name'],
+ strtoupper($check['status']),
+ $check['message']
+ ));
+ }
+
+ if ($results['overall_status'] !== self::STATUS_HEALTHY) {
+ WP_CLI::error('Health checks failed with issues', false);
+ } else {
+ WP_CLI::success('All health checks passed');
+ }
+ }
+}
\ No newline at end of file
diff --git a/includes/class-hvac-performance-monitor.php b/includes/class-hvac-performance-monitor.php
new file mode 100644
index 00000000..7e5c2ea6
--- /dev/null
+++ b/includes/class-hvac-performance-monitor.php
@@ -0,0 +1,951 @@
+ 2.0, // 2 seconds
+ 'memory_usage_mb' => 128, // 128 MB
+ 'page_load_time' => 3.0, // 3 seconds
+ 'cpu_usage_percent' => 80, // 80%
+ 'db_query_count' => 100, // 100 queries per request
+ 'cache_hit_rate' => 70 // 70% cache hit rate
+ ];
+
+ /**
+ * Performance metrics
+ */
+ private static $metrics = [];
+ private static $query_log = [];
+ private static $memory_checkpoints = [];
+ private static $start_time;
+ private static $start_memory;
+
+ /**
+ * Alert settings
+ */
+ private static $alert_settings = [
+ 'email_alerts' => true,
+ 'slack_webhook' => '',
+ 'alert_threshold' => 3, // Number of incidents before alert
+ 'alert_cooldown' => 1800, // 30 minutes between alerts
+ 'benchmark_frequency' => 'daily'
+ ];
+
+ /**
+ * Initialize performance monitoring
+ */
+ public static function init() {
+ // Load settings
+ self::$alert_settings = array_merge(
+ self::$alert_settings,
+ get_option('hvac_performance_settings', [])
+ );
+
+ // Set initial measurements
+ self::$start_time = microtime(true);
+ self::$start_memory = memory_get_usage(true);
+
+ // Hook into WordPress performance points
+ add_action('init', [__CLASS__, 'start_monitoring'], 0);
+ add_action('wp_loaded', [__CLASS__, 'checkpoint_loaded']);
+ add_action('wp_footer', [__CLASS__, 'checkpoint_footer']);
+ add_action('shutdown', [__CLASS__, 'finalize_monitoring']);
+
+ // Database query monitoring
+ add_filter('query', [__CLASS__, 'monitor_query']);
+ add_action('wp_db_query', [__CLASS__, 'log_query_completion']);
+
+ // Memory monitoring
+ add_action('wp_loaded', [__CLASS__, 'checkpoint_memory']);
+ add_action('wp_footer', [__CLASS__, 'checkpoint_memory']);
+
+ // Schedule performance benchmarks
+ if (!wp_next_scheduled('hvac_performance_benchmark')) {
+ $frequency = self::$alert_settings['benchmark_frequency'];
+ wp_schedule_event(time(), $frequency, 'hvac_performance_benchmark');
+ }
+
+ add_action('hvac_performance_benchmark', [__CLASS__, 'run_performance_benchmark']);
+
+ // Admin interface
+ if (is_admin()) {
+ add_action('admin_menu', [__CLASS__, 'add_admin_menu']);
+ add_action('wp_ajax_hvac_performance_action', [__CLASS__, 'handle_performance_action']);
+ add_action('admin_bar_menu', [__CLASS__, 'add_admin_bar_stats'], 999);
+ }
+
+ // REST API endpoints
+ add_action('rest_api_init', [__CLASS__, 'register_rest_endpoints']);
+
+ // WP-CLI integration
+ if (defined('WP_CLI') && WP_CLI) {
+ WP_CLI::add_command('hvac performance', [__CLASS__, 'wp_cli_performance']);
+ }
+
+ // Emergency alerts for critical performance issues
+ add_action('hvac_critical_performance_issue', [__CLASS__, 'handle_critical_issue']);
+ }
+
+ /**
+ * Start monitoring
+ */
+ public static function start_monitoring() {
+ // Only monitor frontend requests and specific admin pages
+ if (!self::should_monitor()) {
+ return;
+ }
+
+ self::$metrics['start_time'] = microtime(true);
+ self::$metrics['start_memory'] = memory_get_usage(true);
+ self::$metrics['query_count'] = 0;
+ self::$metrics['slow_queries'] = [];
+
+ // Set up query monitoring
+ global $wpdb;
+ $wpdb->save_queries = true;
+ }
+
+ /**
+ * Check if we should monitor this request
+ */
+ private static function should_monitor() {
+ // Skip monitoring for certain requests
+ if (wp_doing_ajax() || wp_doing_cron() || (defined('WP_CLI') && WP_CLI)) {
+ return false;
+ }
+
+ // Skip for admin unless it's a plugin page
+ if (is_admin()) {
+ $screen = get_current_screen();
+ if (!$screen || strpos($screen->id, 'hvac') === false) {
+ return false;
+ }
+ }
+
+ // Skip for REST API unless it's our endpoints
+ if (defined('REST_REQUEST') && REST_REQUEST) {
+ $request_uri = $_SERVER['REQUEST_URI'] ?? '';
+ if (strpos($request_uri, '/hvac/v1/') === false) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Monitor database queries
+ */
+ public static function monitor_query($query) {
+ if (!isset(self::$metrics['start_time'])) {
+ return $query;
+ }
+
+ $start_time = microtime(true);
+
+ // Store query info for monitoring
+ self::$query_log[] = [
+ 'query' => $query,
+ 'start_time' => $start_time,
+ 'backtrace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5)
+ ];
+
+ return $query;
+ }
+
+ /**
+ * Log query completion
+ */
+ public static function log_query_completion($result) {
+ if (empty(self::$query_log)) {
+ return;
+ }
+
+ $current_query = &self::$query_log[count(self::$query_log) - 1];
+ $execution_time = microtime(true) - $current_query['start_time'];
+ $current_query['execution_time'] = $execution_time;
+
+ self::$metrics['query_count']++;
+
+ // Check for slow queries
+ if ($execution_time > self::THRESHOLDS['slow_query_time']) {
+ self::$metrics['slow_queries'][] = [
+ 'query' => substr($current_query['query'], 0, 200),
+ 'time' => $execution_time,
+ 'backtrace' => $current_query['backtrace']
+ ];
+
+ // Log slow query
+ HVAC_Logger::warning(
+ "Slow query detected: {$execution_time}s - " . substr($current_query['query'], 0, 100),
+ 'Performance Monitor'
+ );
+ }
+ }
+
+ /**
+ * Memory checkpoint
+ */
+ public static function checkpoint_memory($checkpoint = null) {
+ if (!isset(self::$metrics['start_time'])) {
+ return;
+ }
+
+ $current_memory = memory_get_usage(true);
+ $peak_memory = memory_get_peak_usage(true);
+
+ if ($checkpoint === null) {
+ $checkpoint = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['function'];
+ }
+
+ self::$memory_checkpoints[] = [
+ 'checkpoint' => $checkpoint,
+ 'time' => microtime(true),
+ 'current_memory' => $current_memory,
+ 'peak_memory' => $peak_memory,
+ 'memory_mb' => round($current_memory / 1024 / 1024, 2)
+ ];
+
+ // Check for memory threshold breach
+ $memory_mb = $current_memory / 1024 / 1024;
+ if ($memory_mb > self::THRESHOLDS['memory_usage_mb']) {
+ HVAC_Logger::warning(
+ "High memory usage detected: {$memory_mb}MB at checkpoint: $checkpoint",
+ 'Performance Monitor'
+ );
+ }
+ }
+
+ /**
+ * Checkpoint: WordPress loaded
+ */
+ public static function checkpoint_loaded() {
+ self::checkpoint_memory('wp_loaded');
+ }
+
+ /**
+ * Checkpoint: Footer
+ */
+ public static function checkpoint_footer() {
+ self::checkpoint_memory('wp_footer');
+ }
+
+ /**
+ * Finalize monitoring
+ */
+ public static function finalize_monitoring() {
+ if (!isset(self::$metrics['start_time'])) {
+ return;
+ }
+
+ $end_time = microtime(true);
+ $total_time = $end_time - self::$metrics['start_time'];
+ $peak_memory = memory_get_peak_usage(true);
+ $peak_memory_mb = $peak_memory / 1024 / 1024;
+
+ // Finalize metrics
+ self::$metrics['total_time'] = $total_time;
+ self::$metrics['peak_memory'] = $peak_memory;
+ self::$metrics['peak_memory_mb'] = $peak_memory_mb;
+ self::$metrics['timestamp'] = time();
+
+ // Calculate cache hit rate if object cache is available
+ if (function_exists('wp_cache_get_stats')) {
+ $cache_stats = wp_cache_get_stats();
+ if (isset($cache_stats['cache_hits']) && isset($cache_stats['cache_misses'])) {
+ $total_requests = $cache_stats['cache_hits'] + $cache_stats['cache_misses'];
+ if ($total_requests > 0) {
+ self::$metrics['cache_hit_rate'] = ($cache_stats['cache_hits'] / $total_requests) * 100;
+ }
+ }
+ }
+
+ // Check thresholds and send alerts
+ self::check_performance_thresholds();
+
+ // Store metrics for analysis
+ self::store_performance_metrics();
+
+ // Log performance summary for slow requests
+ if ($total_time > self::THRESHOLDS['page_load_time']) {
+ HVAC_Logger::warning(
+ "Slow page load: {$total_time}s, Memory: {$peak_memory_mb}MB, Queries: " . self::$metrics['query_count'],
+ 'Performance Monitor'
+ );
+ }
+ }
+
+ /**
+ * Check performance thresholds
+ */
+ private static function check_performance_thresholds() {
+ $alerts = [];
+
+ // Check page load time
+ if (self::$metrics['total_time'] > self::THRESHOLDS['page_load_time']) {
+ $alerts[] = [
+ 'type' => 'slow_page_load',
+ 'message' => 'Page load time exceeded threshold',
+ 'value' => self::$metrics['total_time'],
+ 'threshold' => self::THRESHOLDS['page_load_time']
+ ];
+ }
+
+ // Check memory usage
+ if (self::$metrics['peak_memory_mb'] > self::THRESHOLDS['memory_usage_mb']) {
+ $alerts[] = [
+ 'type' => 'high_memory_usage',
+ 'message' => 'Memory usage exceeded threshold',
+ 'value' => self::$metrics['peak_memory_mb'],
+ 'threshold' => self::THRESHOLDS['memory_usage_mb']
+ ];
+ }
+
+ // Check query count
+ if (self::$metrics['query_count'] > self::THRESHOLDS['db_query_count']) {
+ $alerts[] = [
+ 'type' => 'excessive_queries',
+ 'message' => 'Database query count exceeded threshold',
+ 'value' => self::$metrics['query_count'],
+ 'threshold' => self::THRESHOLDS['db_query_count']
+ ];
+ }
+
+ // Check slow queries
+ if (count(self::$metrics['slow_queries']) > 0) {
+ $alerts[] = [
+ 'type' => 'slow_queries',
+ 'message' => 'Slow queries detected',
+ 'value' => count(self::$metrics['slow_queries']),
+ 'threshold' => 0
+ ];
+ }
+
+ // Check cache hit rate
+ if (isset(self::$metrics['cache_hit_rate']) &&
+ self::$metrics['cache_hit_rate'] < self::THRESHOLDS['cache_hit_rate']) {
+ $alerts[] = [
+ 'type' => 'low_cache_hit_rate',
+ 'message' => 'Cache hit rate below threshold',
+ 'value' => self::$metrics['cache_hit_rate'],
+ 'threshold' => self::THRESHOLDS['cache_hit_rate']
+ ];
+ }
+
+ // Process alerts
+ if (!empty($alerts)) {
+ self::process_performance_alerts($alerts);
+ }
+ }
+
+ /**
+ * Process performance alerts
+ */
+ private static function process_performance_alerts($alerts) {
+ // Count recent alerts to avoid spam
+ $recent_alerts = self::get_recent_alerts(1800); // Last 30 minutes
+
+ if (count($recent_alerts) >= self::$alert_settings['alert_threshold']) {
+ return; // Cooldown period
+ }
+
+ // Store alerts
+ $stored_alerts = get_option('hvac_performance_alerts', []);
+ foreach ($alerts as $alert) {
+ $alert['timestamp'] = time();
+ $alert['request_uri'] = $_SERVER['REQUEST_URI'] ?? '';
+ $alert['user_agent'] = $_SERVER['HTTP_USER_AGENT'] ?? '';
+ $stored_alerts[] = $alert;
+ }
+
+ // Keep only last 1000 alerts
+ if (count($stored_alerts) > 1000) {
+ $stored_alerts = array_slice($stored_alerts, -1000);
+ }
+
+ update_option('hvac_performance_alerts', $stored_alerts);
+
+ // Send notifications
+ if (self::$alert_settings['email_alerts']) {
+ self::send_performance_alert_email($alerts);
+ }
+
+ // Check for critical issues
+ $critical_alerts = array_filter($alerts, function($alert) {
+ return $alert['type'] === 'slow_page_load' && $alert['value'] > 10 ||
+ $alert['type'] === 'high_memory_usage' && $alert['value'] > 256 ||
+ $alert['type'] === 'excessive_queries' && $alert['value'] > 500;
+ });
+
+ if (!empty($critical_alerts)) {
+ do_action('hvac_critical_performance_issue', $critical_alerts);
+ }
+ }
+
+ /**
+ * Get recent alerts
+ */
+ private static function get_recent_alerts($timeframe = 1800) {
+ $stored_alerts = get_option('hvac_performance_alerts', []);
+ $cutoff_time = time() - $timeframe;
+
+ return array_filter($stored_alerts, function($alert) use ($cutoff_time) {
+ return $alert['timestamp'] >= $cutoff_time;
+ });
+ }
+
+ /**
+ * Send performance alert email
+ */
+ private static function send_performance_alert_email($alerts) {
+ $admin_email = get_option('admin_email');
+ $site_name = get_bloginfo('name');
+
+ $subject = "[$site_name] Performance Alert";
+ $message = "Performance issues detected on $site_name:\n\n";
+
+ foreach ($alerts as $alert) {
+ $message .= "• {$alert['message']}\n";
+ $message .= " Value: {$alert['value']} (Threshold: {$alert['threshold']})\n\n";
+ }
+
+ $message .= "Request: " . ($_SERVER['REQUEST_URI'] ?? 'Unknown') . "\n";
+ $message .= "Time: " . date('Y-m-d H:i:s') . "\n";
+ $message .= "\nCheck the performance monitor for detailed analysis.";
+
+ wp_mail($admin_email, $subject, $message);
+ }
+
+ /**
+ * Store performance metrics
+ */
+ private static function store_performance_metrics() {
+ // Store in database for trend analysis
+ global $wpdb;
+
+ $metrics_data = [
+ 'timestamp' => time(),
+ 'page_load_time' => self::$metrics['total_time'],
+ 'peak_memory_mb' => self::$metrics['peak_memory_mb'],
+ 'query_count' => self::$metrics['query_count'],
+ 'slow_query_count' => count(self::$metrics['slow_queries']),
+ 'cache_hit_rate' => self::$metrics['cache_hit_rate'] ?? null,
+ 'request_uri' => $_SERVER['REQUEST_URI'] ?? '',
+ ];
+
+ // Store in options (simple approach - could use custom table for high-volume sites)
+ $stored_metrics = get_option('hvac_performance_metrics', []);
+ $stored_metrics[] = $metrics_data;
+
+ // Keep only last 1000 metrics
+ if (count($stored_metrics) > 1000) {
+ $stored_metrics = array_slice($stored_metrics, -1000);
+ }
+
+ update_option('hvac_performance_metrics', $stored_metrics);
+ }
+
+ /**
+ * Run performance benchmark
+ */
+ public static function run_performance_benchmark() {
+ $benchmark_results = [
+ 'timestamp' => time(),
+ 'database_benchmark' => self::benchmark_database(),
+ 'memory_benchmark' => self::benchmark_memory(),
+ 'cache_benchmark' => self::benchmark_cache(),
+ 'file_io_benchmark' => self::benchmark_file_io()
+ ];
+
+ // Store benchmark results
+ update_option('hvac_performance_benchmark', $benchmark_results);
+
+ HVAC_Logger::info(
+ 'Performance benchmark completed: ' . json_encode($benchmark_results),
+ 'Performance Monitor'
+ );
+
+ // Check if performance has degraded
+ $previous_benchmark = get_option('hvac_previous_benchmark', null);
+ if ($previous_benchmark) {
+ $degradation = self::check_performance_degradation($previous_benchmark, $benchmark_results);
+ if ($degradation) {
+ self::send_performance_alert_email([
+ [
+ 'type' => 'performance_degradation',
+ 'message' => 'Performance degradation detected',
+ 'details' => $degradation
+ ]
+ ]);
+ }
+ }
+
+ update_option('hvac_previous_benchmark', $benchmark_results);
+ }
+
+ /**
+ * Benchmark database performance
+ */
+ private static function benchmark_database() {
+ global $wpdb;
+
+ $start_time = microtime(true);
+
+ // Simple query benchmark
+ $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts}");
+ $simple_query_time = microtime(true) - $start_time;
+
+ // Complex query benchmark
+ $start_time = microtime(true);
+ $wpdb->get_results("
+ SELECT p.*, pm.meta_value
+ FROM {$wpdb->posts} p
+ LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
+ WHERE p.post_type = 'post'
+ AND p.post_status = 'publish'
+ LIMIT 10
+ ");
+ $complex_query_time = microtime(true) - $start_time;
+
+ return [
+ 'simple_query_time' => round($simple_query_time, 4),
+ 'complex_query_time' => round($complex_query_time, 4)
+ ];
+ }
+
+ /**
+ * Benchmark memory performance
+ */
+ private static function benchmark_memory() {
+ $start_memory = memory_get_usage();
+
+ // Create test data
+ $test_data = [];
+ for ($i = 0; $i < 1000; $i++) {
+ $test_data[] = str_repeat('x', 1000);
+ }
+
+ $peak_memory = memory_get_usage();
+ $memory_used = $peak_memory - $start_memory;
+
+ unset($test_data);
+
+ return [
+ 'memory_used_mb' => round($memory_used / 1024 / 1024, 2),
+ 'peak_memory_mb' => round(memory_get_peak_usage() / 1024 / 1024, 2)
+ ];
+ }
+
+ /**
+ * Benchmark cache performance
+ */
+ private static function benchmark_cache() {
+ $iterations = 100;
+ $test_key = 'hvac_performance_test_' . time();
+ $test_data = str_repeat('x', 1000);
+
+ // Write benchmark
+ $start_time = microtime(true);
+ for ($i = 0; $i < $iterations; $i++) {
+ wp_cache_set($test_key . $i, $test_data, 'hvac_perf_test', 60);
+ }
+ $write_time = microtime(true) - $start_time;
+
+ // Read benchmark
+ $start_time = microtime(true);
+ for ($i = 0; $i < $iterations; $i++) {
+ wp_cache_get($test_key . $i, 'hvac_perf_test');
+ }
+ $read_time = microtime(true) - $start_time;
+
+ // Cleanup
+ for ($i = 0; $i < $iterations; $i++) {
+ wp_cache_delete($test_key . $i, 'hvac_perf_test');
+ }
+
+ return [
+ 'write_time' => round($write_time, 4),
+ 'read_time' => round($read_time, 4),
+ 'writes_per_second' => round($iterations / $write_time, 2),
+ 'reads_per_second' => round($iterations / $read_time, 2)
+ ];
+ }
+
+ /**
+ * Benchmark file I/O performance
+ */
+ private static function benchmark_file_io() {
+ $upload_dir = wp_upload_dir()['basedir'];
+ $test_file = $upload_dir . '/hvac_perf_test.txt';
+ $test_data = str_repeat('Performance test data. ', 1000);
+
+ // Write benchmark
+ $start_time = microtime(true);
+ file_put_contents($test_file, $test_data);
+ $write_time = microtime(true) - $start_time;
+
+ // Read benchmark
+ $start_time = microtime(true);
+ $read_data = file_get_contents($test_file);
+ $read_time = microtime(true) - $start_time;
+
+ // Cleanup
+ if (file_exists($test_file)) {
+ unlink($test_file);
+ }
+
+ return [
+ 'write_time' => round($write_time, 4),
+ 'read_time' => round($read_time, 4),
+ 'data_size_kb' => round(strlen($test_data) / 1024, 2)
+ ];
+ }
+
+ /**
+ * Check performance degradation
+ */
+ private static function check_performance_degradation($previous, $current) {
+ $degradation_threshold = 0.5; // 50% increase
+ $issues = [];
+
+ // Check database performance
+ $db_degradation = ($current['database_benchmark']['complex_query_time'] /
+ $previous['database_benchmark']['complex_query_time']) - 1;
+ if ($db_degradation > $degradation_threshold) {
+ $issues[] = "Database queries " . round($db_degradation * 100, 1) . "% slower";
+ }
+
+ // Check cache performance
+ $cache_degradation = ($current['cache_benchmark']['read_time'] /
+ $previous['cache_benchmark']['read_time']) - 1;
+ if ($cache_degradation > $degradation_threshold) {
+ $issues[] = "Cache reads " . round($cache_degradation * 100, 1) . "% slower";
+ }
+
+ return empty($issues) ? false : $issues;
+ }
+
+ /**
+ * Handle critical performance issues
+ */
+ public static function handle_critical_issue($alerts) {
+ // Log critical issue
+ HVAC_Logger::error(
+ 'Critical performance issue detected: ' . json_encode($alerts),
+ 'Performance Monitor'
+ );
+
+ // Send immediate alert
+ $admin_email = get_option('admin_email');
+ $site_name = get_bloginfo('name');
+
+ $subject = "[$site_name] CRITICAL Performance Issue";
+ $message = "CRITICAL performance issues detected:\n\n";
+
+ foreach ($alerts as $alert) {
+ $message .= "• {$alert['message']}: {$alert['value']}\n";
+ }
+
+ $message .= "\nImmediate attention required!";
+
+ wp_mail($admin_email, $subject, $message);
+
+ // Trigger error recovery if available
+ if (class_exists('HVAC_Error_Recovery')) {
+ do_action('hvac_operation_failed', 'performance', 'Critical performance degradation', $alerts);
+ }
+ }
+
+ /**
+ * Get performance statistics
+ */
+ public static function get_performance_stats() {
+ $metrics = get_option('hvac_performance_metrics', []);
+ $alerts = get_option('hvac_performance_alerts', []);
+ $benchmark = get_option('hvac_performance_benchmark', null);
+
+ if (empty($metrics)) {
+ return [
+ 'avg_page_load_time' => 0,
+ 'avg_memory_usage' => 0,
+ 'avg_query_count' => 0,
+ 'total_requests' => 0,
+ 'recent_alerts' => 0,
+ 'benchmark' => null
+ ];
+ }
+
+ $total_requests = count($metrics);
+ $recent_cutoff = time() - 86400; // Last 24 hours
+
+ // Calculate averages
+ $avg_page_load_time = array_sum(array_column($metrics, 'page_load_time')) / $total_requests;
+ $avg_memory_usage = array_sum(array_column($metrics, 'peak_memory_mb')) / $total_requests;
+ $avg_query_count = array_sum(array_column($metrics, 'query_count')) / $total_requests;
+
+ // Recent alerts
+ $recent_alerts = count(array_filter($alerts, function($alert) use ($recent_cutoff) {
+ return $alert['timestamp'] >= $recent_cutoff;
+ }));
+
+ return [
+ 'avg_page_load_time' => round($avg_page_load_time, 3),
+ 'avg_memory_usage' => round($avg_memory_usage, 2),
+ 'avg_query_count' => round($avg_query_count, 1),
+ 'total_requests' => $total_requests,
+ 'recent_alerts' => $recent_alerts,
+ 'benchmark' => $benchmark
+ ];
+ }
+
+ /**
+ * Add admin menu
+ */
+ public static function add_admin_menu() {
+ if (current_user_can('manage_options')) {
+ add_management_page(
+ 'HVAC Performance Monitor',
+ 'HVAC Performance',
+ 'manage_options',
+ 'hvac-performance-monitor',
+ [__CLASS__, 'admin_page']
+ );
+ }
+ }
+
+ /**
+ * Add admin bar stats
+ */
+ public static function add_admin_bar_stats($admin_bar) {
+ if (!current_user_can('manage_options') || !isset(self::$metrics['start_time'])) {
+ return;
+ }
+
+ $current_memory = round(memory_get_usage(true) / 1024 / 1024, 1);
+ $query_count = get_num_queries();
+
+ $admin_bar->add_node([
+ 'id' => 'hvac-performance',
+ 'title' => "HVAC: {$current_memory}MB | {$query_count}Q",
+ 'href' => admin_url('tools.php?page=hvac-performance-monitor')
+ ]);
+ }
+
+ /**
+ * Admin page
+ */
+ public static function admin_page() {
+ $stats = self::get_performance_stats();
+ $recent_alerts = array_slice(get_option('hvac_performance_alerts', []), -20, 20, true);
+ $current_metrics = self::$metrics;
+
+ ?>
+
+
HVAC Performance Monitor
+
+
+
+
+
Recent Performance Alerts
+
+
+
+ | Time |
+ Type |
+ Message |
+ Value |
+ Threshold |
+
+
+
+
+
+ | No recent performance alerts |
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
Performance Thresholds
+
The following thresholds trigger performance alerts:
+
+ - Slow Query Time: s
+ - Memory Usage: MB
+ - Page Load Time: s
+ - Database Query Count: queries
+ - Cache Hit Rate: %
+
+
+
+
+
+
+
+ 'GET',
+ 'callback' => [__CLASS__, 'rest_performance_stats'],
+ 'permission_callback' => function() {
+ return current_user_can('manage_options');
+ }
+ ]);
+ }
+
+ /**
+ * REST API performance stats
+ */
+ public static function rest_performance_stats() {
+ $stats = self::get_performance_stats();
+
+ return new WP_REST_Response([
+ 'stats' => $stats,
+ 'timestamp' => time()
+ ], 200);
+ }
+
+ /**
+ * WP-CLI performance command
+ */
+ public static function wp_cli_performance($args, $assoc_args) {
+ $subcommand = $args[0] ?? 'stats';
+
+ switch ($subcommand) {
+ case 'stats':
+ $stats = self::get_performance_stats();
+ WP_CLI::line('HVAC Performance Statistics:');
+ WP_CLI::line('Average Page Load: ' . $stats['avg_page_load_time'] . 's');
+ WP_CLI::line('Average Memory: ' . $stats['avg_memory_usage'] . 'MB');
+ WP_CLI::line('Average Queries: ' . $stats['avg_query_count']);
+ WP_CLI::line('Recent Alerts: ' . $stats['recent_alerts']);
+ break;
+
+ case 'benchmark':
+ WP_CLI::line('Running performance benchmark...');
+ self::run_performance_benchmark();
+ WP_CLI::success('Benchmark completed');
+ break;
+
+ default:
+ WP_CLI::error('Unknown subcommand. Use: stats, benchmark');
+ }
+ }
+}
\ No newline at end of file
diff --git a/includes/class-hvac-plugin.php b/includes/class-hvac-plugin.php
index 9a106595..a78a5dbd 100644
--- a/includes/class-hvac-plugin.php
+++ b/includes/class-hvac-plugin.php
@@ -107,6 +107,12 @@ class HVAC_Plugin {
require_once HVAC_PLUGIN_DIR . 'includes/class-hvac-welcome-popup.php';
require_once HVAC_PLUGIN_DIR . 'includes/class-hvac-background-jobs.php';
require_once HVAC_PLUGIN_DIR . 'includes/class-hvac-query-monitor.php';
+ require_once HVAC_PLUGIN_DIR . 'includes/class-hvac-health-monitor.php';
+ require_once HVAC_PLUGIN_DIR . 'includes/class-hvac-error-recovery.php';
+ require_once HVAC_PLUGIN_DIR . 'includes/class-hvac-security-monitor.php';
+ require_once HVAC_PLUGIN_DIR . 'includes/class-hvac-performance-monitor.php';
+ require_once HVAC_PLUGIN_DIR . 'includes/class-hvac-backup-manager.php';
+ require_once HVAC_PLUGIN_DIR . 'includes/class-hvac-cache-optimizer.php';
// Feature includes - check if files exist before including
$feature_includes = [
@@ -346,6 +352,24 @@ class HVAC_Plugin {
// Initialize query monitoring
HVAC_Query_Monitor::init();
+ // Initialize health monitoring
+ HVAC_Health_Monitor::init();
+
+ // Initialize error recovery system
+ HVAC_Error_Recovery::init();
+
+ // Initialize security monitoring
+ HVAC_Security_Monitor::init();
+
+ // Initialize performance monitoring
+ HVAC_Performance_Monitor::init();
+
+ // Initialize backup management
+ HVAC_Backup_Manager::init();
+
+ // Initialize cache optimization
+ HVAC_Cache_Optimizer::init();
+
// Initialize other components
$this->init_components();
diff --git a/includes/class-hvac-security-monitor.php b/includes/class-hvac-security-monitor.php
new file mode 100644
index 00000000..1b5d5c1b
--- /dev/null
+++ b/includes/class-hvac-security-monitor.php
@@ -0,0 +1,923 @@
+ 'Failed Login Attempt',
+ 'suspicious_activity' => 'Suspicious Activity',
+ 'privilege_escalation' => 'Privilege Escalation Attempt',
+ 'file_modification' => 'Unauthorized File Modification',
+ 'sql_injection' => 'SQL Injection Attempt',
+ 'xss_attempt' => 'Cross-Site Scripting Attempt',
+ 'brute_force' => 'Brute Force Attack',
+ 'admin_access' => 'Unauthorized Admin Access'
+ ];
+
+ /**
+ * Threat levels
+ */
+ const THREAT_LOW = 'low';
+ const THREAT_MEDIUM = 'medium';
+ const THREAT_HIGH = 'high';
+ const THREAT_CRITICAL = 'critical';
+
+ /**
+ * Security settings
+ */
+ private static $settings = [
+ 'max_failed_logins' => 5,
+ 'lockout_duration' => 900, // 15 minutes
+ 'monitor_file_changes' => true,
+ 'scan_requests' => true,
+ 'alert_threshold' => 3,
+ 'auto_block_ips' => true
+ ];
+
+ /**
+ * Blocked IPs cache
+ */
+ private static $blocked_ips = [];
+
+ /**
+ * Initialize security monitoring
+ */
+ public static function init() {
+ // Load settings
+ self::$settings = array_merge(self::$settings, get_option('hvac_security_settings', []));
+ self::$blocked_ips = get_option('hvac_blocked_ips', []);
+
+ // Security monitoring hooks
+ add_action('wp_login_failed', [__CLASS__, 'handle_failed_login']);
+ add_action('wp_login', [__CLASS__, 'handle_successful_login'], 10, 2);
+ add_action('init', [__CLASS__, 'check_request_security']);
+ add_action('admin_init', [__CLASS__, 'monitor_admin_access']);
+
+ // File monitoring
+ if (self::$settings['monitor_file_changes']) {
+ add_action('wp_loaded', [__CLASS__, 'monitor_file_integrity']);
+ }
+
+ // Database monitoring
+ add_filter('query', [__CLASS__, 'monitor_database_queries']);
+
+ // Admin interface
+ if (is_admin()) {
+ add_action('admin_menu', [__CLASS__, 'add_admin_menu']);
+ add_action('wp_ajax_hvac_security_action', [__CLASS__, 'handle_security_action']);
+ }
+
+ // REST API for external monitoring
+ add_action('rest_api_init', [__CLASS__, 'register_rest_endpoints']);
+
+ // Cleanup old security events
+ add_action('wp_scheduled_delete', [__CLASS__, 'cleanup_old_events']);
+
+ // Emergency lockdown capability
+ add_action('hvac_emergency_lockdown', [__CLASS__, 'emergency_lockdown']);
+
+ // WP-CLI integration
+ if (defined('WP_CLI') && WP_CLI) {
+ WP_CLI::add_command('hvac security', [__CLASS__, 'wp_cli_security']);
+ }
+ }
+
+ /**
+ * Handle failed login attempts
+ */
+ public static function handle_failed_login($username) {
+ $ip = self::get_client_ip();
+
+ // Record the failed attempt
+ self::log_security_event('failed_login', self::THREAT_MEDIUM, [
+ 'username' => $username,
+ 'ip_address' => $ip,
+ 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
+ 'timestamp' => time()
+ ]);
+
+ // Check for brute force pattern
+ $recent_attempts = self::get_recent_events('failed_login', $ip, 3600); // Last hour
+
+ if (count($recent_attempts) >= self::$settings['max_failed_logins']) {
+ // Brute force detected
+ self::log_security_event('brute_force', self::THREAT_HIGH, [
+ 'ip_address' => $ip,
+ 'attempts' => count($recent_attempts),
+ 'usernames' => array_unique(array_column($recent_attempts, 'username')),
+ 'auto_blocked' => self::$settings['auto_block_ips']
+ ]);
+
+ if (self::$settings['auto_block_ips']) {
+ self::block_ip($ip, 'Brute force attack detected');
+ }
+
+ // Send immediate alert
+ self::send_security_alert('Brute Force Attack', [
+ 'ip_address' => $ip,
+ 'attempts' => count($recent_attempts),
+ 'action_taken' => self::$settings['auto_block_ips'] ? 'IP blocked' : 'Logged only'
+ ]);
+ }
+ }
+
+ /**
+ * Handle successful login
+ */
+ public static function handle_successful_login($username, $user) {
+ $ip = self::get_client_ip();
+
+ // Check if this is a suspicious login
+ $is_suspicious = false;
+ $reasons = [];
+
+ // Check for unusual location (simplified - could integrate with GeoIP)
+ $user_last_ip = get_user_meta($user->ID, 'hvac_last_login_ip', true);
+ if ($user_last_ip && $user_last_ip !== $ip) {
+ $is_suspicious = true;
+ $reasons[] = 'Different IP address';
+ }
+
+ // Check for admin role login
+ if (user_can($user, 'manage_options')) {
+ self::log_security_event('admin_access', self::THREAT_LOW, [
+ 'username' => $username,
+ 'ip_address' => $ip,
+ 'user_id' => $user->ID,
+ 'suspicious' => $is_suspicious,
+ 'reasons' => $reasons
+ ]);
+
+ if ($is_suspicious) {
+ self::send_security_alert('Suspicious Admin Login', [
+ 'username' => $username,
+ 'ip_address' => $ip,
+ 'reasons' => $reasons
+ ]);
+ }
+ }
+
+ // Update user's last login IP
+ update_user_meta($user->ID, 'hvac_last_login_ip', $ip);
+ update_user_meta($user->ID, 'hvac_last_login_time', time());
+ }
+
+ /**
+ * Check request security
+ */
+ public static function check_request_security() {
+ // Skip checks for admin, CLI, or cron
+ if (is_admin() || wp_doing_cron() || (defined('WP_CLI') && WP_CLI)) {
+ return;
+ }
+
+ $ip = self::get_client_ip();
+
+ // Check if IP is blocked
+ if (self::is_ip_blocked($ip)) {
+ self::block_request('IP address is blocked');
+ return;
+ }
+
+ if (!self::$settings['scan_requests']) {
+ return;
+ }
+
+ $request_data = $_REQUEST;
+ $threat_level = self::THREAT_LOW;
+ $threats_detected = [];
+
+ // Check for SQL injection patterns
+ $sql_patterns = [
+ '/union.*select/i',
+ '/drop.*table/i',
+ '/insert.*into/i',
+ '/delete.*from/i',
+ '/update.*set/i',
+ '/exec\s*\(/i'
+ ];
+
+ foreach ($request_data as $key => $value) {
+ if (is_string($value)) {
+ foreach ($sql_patterns as $pattern) {
+ if (preg_match($pattern, $value)) {
+ $threats_detected[] = 'SQL injection pattern in: ' . $key;
+ $threat_level = self::THREAT_HIGH;
+ }
+ }
+ }
+ }
+
+ // Check for XSS patterns
+ $xss_patterns = [
+ '/.*?<\/script>/i',
+ '/javascript:/i',
+ '/onload\s*=/i',
+ '/onerror\s*=/i',
+ '//i'
+ ];
+
+ foreach ($request_data as $key => $value) {
+ if (is_string($value)) {
+ foreach ($xss_patterns as $pattern) {
+ if (preg_match($pattern, $value)) {
+ $threats_detected[] = 'XSS pattern in: ' . $key;
+ if ($threat_level === self::THREAT_LOW) {
+ $threat_level = self::THREAT_MEDIUM;
+ }
+ }
+ }
+ }
+ }
+
+ // Check for file inclusion attempts
+ $file_patterns = [
+ '/\.\.\//i',
+ '/etc\/passwd/i',
+ '/proc\/.*?/i',
+ '/boot\.ini/i'
+ ];
+
+ foreach ($request_data as $key => $value) {
+ if (is_string($value)) {
+ foreach ($file_patterns as $pattern) {
+ if (preg_match($pattern, $value)) {
+ $threats_detected[] = 'File inclusion attempt in: ' . $key;
+ $threat_level = self::THREAT_HIGH;
+ }
+ }
+ }
+ }
+
+ // Log and respond to threats
+ if (!empty($threats_detected)) {
+ $event_type = strpos(implode(' ', $threats_detected), 'SQL') !== false ? 'sql_injection' : 'xss_attempt';
+
+ self::log_security_event($event_type, $threat_level, [
+ 'ip_address' => $ip,
+ 'threats' => $threats_detected,
+ 'request_uri' => $_SERVER['REQUEST_URI'] ?? '',
+ 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
+ 'request_data' => $request_data
+ ]);
+
+ // Auto-block for high/critical threats
+ if ($threat_level === self::THREAT_HIGH || $threat_level === self::THREAT_CRITICAL) {
+ if (self::$settings['auto_block_ips']) {
+ self::block_ip($ip, 'Malicious request detected: ' . implode(', ', $threats_detected));
+ }
+
+ self::send_security_alert('Malicious Request Blocked', [
+ 'ip_address' => $ip,
+ 'threats' => $threats_detected,
+ 'request_uri' => $_SERVER['REQUEST_URI'] ?? ''
+ ]);
+
+ self::block_request('Malicious request detected');
+ }
+ }
+ }
+
+ /**
+ * Monitor admin access
+ */
+ public static function monitor_admin_access() {
+ if (!current_user_can('manage_options')) {
+ return;
+ }
+
+ $user = wp_get_current_user();
+ $ip = self::get_client_ip();
+
+ // Check for privilege escalation attempts
+ if (isset($_POST['action']) && $_POST['action'] === 'update' && isset($_POST['users'])) {
+ self::log_security_event('privilege_escalation', self::THREAT_MEDIUM, [
+ 'user_id' => $user->ID,
+ 'username' => $user->user_login,
+ 'ip_address' => $ip,
+ 'action' => 'User role modification attempt'
+ ]);
+ }
+
+ // Monitor plugin/theme installations
+ if (isset($_REQUEST['action']) && in_array($_REQUEST['action'], ['install-plugin', 'install-theme', 'upload-plugin', 'upload-theme'])) {
+ self::log_security_event('suspicious_activity', self::THREAT_LOW, [
+ 'user_id' => $user->ID,
+ 'username' => $user->user_login,
+ 'ip_address' => $ip,
+ 'action' => $_REQUEST['action'],
+ 'item' => $_REQUEST['plugin'] ?? $_REQUEST['theme'] ?? 'unknown'
+ ]);
+ }
+ }
+
+ /**
+ * Monitor file integrity
+ */
+ public static function monitor_file_integrity() {
+ // Only run this check periodically to avoid performance issues
+ $last_check = get_option('hvac_last_file_check', 0);
+ if (time() - $last_check < 3600) { // Check every hour
+ return;
+ }
+
+ update_option('hvac_last_file_check', time());
+
+ // Check core plugin files
+ $critical_files = [
+ HVAC_PLUGIN_FILE,
+ HVAC_PLUGIN_DIR . 'includes/class-hvac-plugin.php',
+ HVAC_PLUGIN_DIR . 'includes/class-hvac-community-events.php'
+ ];
+
+ $stored_hashes = get_option('hvac_file_hashes', []);
+ $current_hashes = [];
+ $modified_files = [];
+
+ foreach ($critical_files as $file) {
+ if (file_exists($file)) {
+ $current_hash = md5_file($file);
+ $current_hashes[basename($file)] = $current_hash;
+
+ $stored_hash = $stored_hashes[basename($file)] ?? null;
+ if ($stored_hash && $stored_hash !== $current_hash) {
+ $modified_files[] = basename($file);
+ }
+ }
+ }
+
+ // Update stored hashes
+ if (empty($stored_hashes)) {
+ // First run - just store hashes
+ update_option('hvac_file_hashes', $current_hashes);
+ } else {
+ // Report modifications
+ if (!empty($modified_files)) {
+ self::log_security_event('file_modification', self::THREAT_HIGH, [
+ 'modified_files' => $modified_files,
+ 'ip_address' => self::get_client_ip(),
+ 'detection_time' => time()
+ ]);
+
+ self::send_security_alert('File Modification Detected', [
+ 'modified_files' => $modified_files,
+ 'total_files' => count($modified_files)
+ ]);
+ }
+
+ update_option('hvac_file_hashes', $current_hashes);
+ }
+ }
+
+ /**
+ * Monitor database queries
+ */
+ public static function monitor_database_queries($query) {
+ // Skip monitoring for admin area and known safe contexts
+ if (is_admin() || wp_doing_cron() || (defined('WP_CLI') && WP_CLI)) {
+ return $query;
+ }
+
+ // Check for suspicious patterns
+ $suspicious_patterns = [
+ '/UNION.*SELECT/i',
+ '/DROP\s+TABLE/i',
+ '/DELETE.*FROM.*WHERE.*1\s*=\s*1/i',
+ '/UPDATE.*SET.*WHERE.*1\s*=\s*1/i'
+ ];
+
+ foreach ($suspicious_patterns as $pattern) {
+ if (preg_match($pattern, $query)) {
+ self::log_security_event('sql_injection', self::THREAT_CRITICAL, [
+ 'query_pattern' => preg_replace('/\s+/', ' ', substr($query, 0, 200)),
+ 'ip_address' => self::get_client_ip(),
+ 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
+ 'request_uri' => $_SERVER['REQUEST_URI'] ?? ''
+ ]);
+
+ // Block immediately for critical SQL injection attempts
+ self::send_security_alert('Critical SQL Injection Attempt', [
+ 'ip_address' => self::get_client_ip(),
+ 'query_sample' => substr($query, 0, 100)
+ ]);
+
+ if (self::$settings['auto_block_ips']) {
+ self::block_ip(self::get_client_ip(), 'SQL injection attempt detected');
+ self::block_request('Malicious database query detected');
+ }
+ break;
+ }
+ }
+
+ return $query;
+ }
+
+ /**
+ * Log security event
+ */
+ private static function log_security_event($type, $threat_level, $data) {
+ global $wpdb;
+
+ $event = [
+ 'type' => $type,
+ 'threat_level' => $threat_level,
+ 'ip_address' => $data['ip_address'] ?? self::get_client_ip(),
+ 'user_id' => get_current_user_id(),
+ 'data' => json_encode($data),
+ 'timestamp' => time()
+ ];
+
+ // Store in options table (or create custom table for high-volume sites)
+ $events = get_option('hvac_security_events', []);
+ $events[] = $event;
+
+ // Keep only last 1000 events to prevent database bloat
+ if (count($events) > 1000) {
+ $events = array_slice($events, -1000);
+ }
+
+ update_option('hvac_security_events', $events);
+
+ // Log to WordPress error log as well
+ HVAC_Logger::warning(
+ "Security event: $type ($threat_level) - " . json_encode($data),
+ 'Security Monitor'
+ );
+
+ // Check if alert threshold is reached
+ $recent_high_threats = self::count_recent_threats([self::THREAT_HIGH, self::THREAT_CRITICAL], 3600);
+ if ($recent_high_threats >= self::$settings['alert_threshold']) {
+ self::send_security_alert('Security Alert Threshold Reached', [
+ 'recent_threats' => $recent_high_threats,
+ 'threshold' => self::$settings['alert_threshold'],
+ 'time_window' => '1 hour'
+ ]);
+ }
+ }
+
+ /**
+ * Get recent security events
+ */
+ private static function get_recent_events($type, $ip = null, $timeframe = 3600) {
+ $events = get_option('hvac_security_events', []);
+ $cutoff_time = time() - $timeframe;
+
+ return array_filter($events, function($event) use ($type, $ip, $cutoff_time) {
+ if ($event['timestamp'] < $cutoff_time) {
+ return false;
+ }
+ if ($event['type'] !== $type) {
+ return false;
+ }
+ if ($ip && $event['ip_address'] !== $ip) {
+ return false;
+ }
+ return true;
+ });
+ }
+
+ /**
+ * Count recent threats by level
+ */
+ private static function count_recent_threats($threat_levels, $timeframe = 3600) {
+ $events = get_option('hvac_security_events', []);
+ $cutoff_time = time() - $timeframe;
+
+ return count(array_filter($events, function($event) use ($threat_levels, $cutoff_time) {
+ return $event['timestamp'] >= $cutoff_time &&
+ in_array($event['threat_level'], $threat_levels);
+ }));
+ }
+
+ /**
+ * Block IP address
+ */
+ private static function block_ip($ip, $reason) {
+ self::$blocked_ips[$ip] = [
+ 'reason' => $reason,
+ 'timestamp' => time(),
+ 'expires' => time() + self::$settings['lockout_duration']
+ ];
+
+ update_option('hvac_blocked_ips', self::$blocked_ips);
+
+ HVAC_Logger::warning("IP blocked: $ip - $reason", 'Security Monitor');
+ }
+
+ /**
+ * Check if IP is blocked
+ */
+ private static function is_ip_blocked($ip) {
+ if (!isset(self::$blocked_ips[$ip])) {
+ return false;
+ }
+
+ $block_info = self::$blocked_ips[$ip];
+ if (time() > $block_info['expires']) {
+ // Block expired, remove it
+ unset(self::$blocked_ips[$ip]);
+ update_option('hvac_blocked_ips', self::$blocked_ips);
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Block current request
+ */
+ private static function block_request($reason) {
+ http_response_code(403);
+ die('Access Denied: ' . $reason);
+ }
+
+ /**
+ * Get client IP address
+ */
+ private static function get_client_ip() {
+ $headers = [
+ 'HTTP_CF_CONNECTING_IP',
+ 'HTTP_X_FORWARDED_FOR',
+ 'HTTP_X_FORWARDED',
+ 'HTTP_X_CLUSTER_CLIENT_IP',
+ 'HTTP_FORWARDED_FOR',
+ 'HTTP_FORWARDED',
+ 'REMOTE_ADDR'
+ ];
+
+ foreach ($headers as $header) {
+ if (!empty($_SERVER[$header])) {
+ $ips = explode(',', $_SERVER[$header]);
+ $ip = trim($ips[0]);
+ if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
+ return $ip;
+ }
+ }
+ }
+
+ return $_SERVER['REMOTE_ADDR'] ?? 'unknown';
+ }
+
+ /**
+ * Send security alert
+ */
+ private static function send_security_alert($subject, $data) {
+ $admin_email = get_option('admin_email');
+ $site_name = get_bloginfo('name');
+
+ $message = "Security Alert from $site_name\n\n";
+ $message .= "Alert: $subject\n\n";
+
+ foreach ($data as $key => $value) {
+ if (is_array($value)) {
+ $value = implode(', ', $value);
+ }
+ $message .= ucfirst(str_replace('_', ' ', $key)) . ": $value\n";
+ }
+
+ $message .= "\nTime: " . date('Y-m-d H:i:s') . "\n";
+ $message .= "Check the security monitor for more details.";
+
+ wp_mail($admin_email, "[$site_name] $subject", $message);
+ }
+
+ /**
+ * Emergency lockdown
+ */
+ public static function emergency_lockdown() {
+ // Block all non-admin access
+ update_option('hvac_emergency_lockdown', [
+ 'enabled' => true,
+ 'timestamp' => time(),
+ 'triggered_by' => get_current_user_id()
+ ]);
+
+ // Send emergency notification
+ self::send_security_alert('Emergency Lockdown Activated', [
+ 'triggered_by' => get_current_user_id(),
+ 'timestamp' => time(),
+ 'action' => 'All non-admin access blocked'
+ ]);
+
+ HVAC_Logger::error('Emergency lockdown activated', 'Security Monitor');
+ }
+
+ /**
+ * Get security statistics
+ */
+ public static function get_security_stats() {
+ $events = get_option('hvac_security_events', []);
+ $blocked_ips = get_option('hvac_blocked_ips', []);
+
+ // Count events by type and threat level
+ $stats = [
+ 'total_events' => count($events),
+ 'blocked_ips' => count($blocked_ips),
+ 'events_by_type' => [],
+ 'events_by_threat' => [],
+ 'recent_events' => count(array_filter($events, function($event) {
+ return $event['timestamp'] >= (time() - 86400); // Last 24 hours
+ }))
+ ];
+
+ foreach ($events as $event) {
+ $type = $event['type'];
+ $threat = $event['threat_level'];
+
+ $stats['events_by_type'][$type] = ($stats['events_by_type'][$type] ?? 0) + 1;
+ $stats['events_by_threat'][$threat] = ($stats['events_by_threat'][$threat] ?? 0) + 1;
+ }
+
+ return $stats;
+ }
+
+ /**
+ * Cleanup old security events
+ */
+ public static function cleanup_old_events() {
+ // Remove events older than 30 days
+ $events = get_option('hvac_security_events', []);
+ $cutoff_time = time() - (30 * 86400);
+
+ $events = array_filter($events, function($event) use ($cutoff_time) {
+ return $event['timestamp'] >= $cutoff_time;
+ });
+
+ update_option('hvac_security_events', array_values($events));
+
+ // Clean up expired IP blocks
+ $blocked_ips = get_option('hvac_blocked_ips', []);
+ $current_time = time();
+ $updated = false;
+
+ foreach ($blocked_ips as $ip => $block_info) {
+ if ($current_time > $block_info['expires']) {
+ unset($blocked_ips[$ip]);
+ $updated = true;
+ }
+ }
+
+ if ($updated) {
+ update_option('hvac_blocked_ips', $blocked_ips);
+ }
+ }
+
+ /**
+ * Add admin menu
+ */
+ public static function add_admin_menu() {
+ if (current_user_can('manage_options')) {
+ add_management_page(
+ 'HVAC Security Monitor',
+ 'HVAC Security',
+ 'manage_options',
+ 'hvac-security-monitor',
+ [__CLASS__, 'admin_page']
+ );
+ }
+ }
+
+ /**
+ * Admin page
+ */
+ public static function admin_page() {
+ $stats = self::get_security_stats();
+ $recent_events = array_slice(get_option('hvac_security_events', []), -20, 20, true);
+ $blocked_ips = get_option('hvac_blocked_ips', []);
+
+ ?>
+
+
HVAC Security Monitor
+
+
+
+
Security Overview
+
Total Events:
+
Recent Events (24h):
+
Blocked IPs:
+
+
+
+
Threat Distribution
+ $count): ?>
+
:
+
+
+
+
+
+
Recent Security Events
+
+
+
+ | Time |
+ Type |
+ Threat Level |
+ IP Address |
+ Details |
+
+
+
+
+
+ | No recent security events |
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+ View Details
+
+
+ |
+
+
+
+
+
+
+
+
+
Blocked IP Addresses
+
+
+
+ | IP Address |
+ Reason |
+ Blocked At |
+ Expires |
+ Action |
+
+
+
+
+
+ | No blocked IPs |
+
+
+ $block_info): ?>
+
+ |
+ |
+ |
+ |
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ 'GET',
+ 'callback' => [__CLASS__, 'rest_security_stats'],
+ 'permission_callback' => function() {
+ return current_user_can('manage_options');
+ }
+ ]);
+ }
+
+ /**
+ * REST API security stats
+ */
+ public static function rest_security_stats() {
+ $stats = self::get_security_stats();
+
+ return new WP_REST_Response([
+ 'stats' => $stats,
+ 'timestamp' => time()
+ ], 200);
+ }
+
+ /**
+ * WP-CLI security command
+ */
+ public static function wp_cli_security($args, $assoc_args) {
+ $subcommand = $args[0] ?? 'stats';
+
+ switch ($subcommand) {
+ case 'stats':
+ $stats = self::get_security_stats();
+ WP_CLI::line('HVAC Security Statistics:');
+ WP_CLI::line('Total Events: ' . $stats['total_events']);
+ WP_CLI::line('Recent Events (24h): ' . $stats['recent_events']);
+ WP_CLI::line('Blocked IPs: ' . $stats['blocked_ips']);
+ break;
+
+ case 'events':
+ $events = array_slice(get_option('hvac_security_events', []), -10);
+ WP_CLI::line('Recent Security Events:');
+ foreach ($events as $event) {
+ WP_CLI::line(sprintf(
+ '%s - %s (%s) - %s',
+ date('Y-m-d H:i:s', $event['timestamp']),
+ $event['type'],
+ $event['threat_level'],
+ $event['ip_address']
+ ));
+ }
+ break;
+
+ default:
+ WP_CLI::error('Unknown subcommand. Use: stats, events');
+ }
+ }
+}
\ No newline at end of file