'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(); ?>
Last checked:
Status:
Checked in: s
'; 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'); } } }