api = $api; $this->events = $events; $this->orders = $orders; // Register health check endpoint add_action('rest_api_init', array($this, 'register_health_endpoint')); } /** * Register health check REST endpoint */ public function register_health_endpoint() { register_rest_route('ticket-tailor/v1', '/health', array( 'methods' => 'GET', 'callback' => array($this, 'get_health_status'), 'permission_callback' => array($this, 'health_check_permission'), )); register_rest_route('ticket-tailor/v1', '/health/detailed', array( 'methods' => 'GET', 'callback' => array($this, 'get_detailed_health_status'), 'permission_callback' => array($this, 'detailed_health_check_permission'), )); } /** * Permission callback for basic health check * ENTERPRISE: Can be accessed without authentication for monitoring */ public function health_check_permission() { // Allow unauthenticated access for monitoring tools return true; } /** * Permission callback for detailed health check * ENTERPRISE: Requires authentication */ public function detailed_health_check_permission() { return current_user_can('manage_options'); } /** * Get basic health status * ENTERPRISE: Fast check for monitoring systems */ public function get_health_status() { $status = 'healthy'; $checks = array(); // Check API configuration $checks['api_configured'] = $this->api->is_configured(); if (!$checks['api_configured']) { $status = 'degraded'; } // Check database connectivity global $wpdb; $checks['database'] = $wpdb->check_connection(); if (!$checks['database']) { $status = 'unhealthy'; } // Check if syncs are running (not stuck) $event_sync = get_transient('ticket_tailor_sync_events_lock'); $order_sync = get_transient('ticket_tailor_sync_orders_lock'); $checks['sync_status'] = array( 'events_syncing' => !empty($event_sync), 'orders_syncing' => !empty($order_sync), ); // Check if locks are stale (stuck for > 10 minutes) if ($event_sync && (time() - $event_sync) > 600) { $status = 'degraded'; $checks['sync_status']['events_stuck'] = true; } if ($order_sync && (time() - $order_sync) > 600) { $status = 'degraded'; $checks['sync_status']['orders_stuck'] = true; } $response = array( 'status' => $status, 'timestamp' => current_time('mysql'), 'checks' => $checks, ); $http_status = ($status === 'healthy') ? 200 : (($status === 'degraded') ? 200 : 503); return new WP_REST_Response($response, $http_status); } /** * Get detailed health status * ENTERPRISE: Comprehensive diagnostics for administrators */ public function get_detailed_health_status() { $status = 'healthy'; $diagnostics = array(); // 1. API Configuration $diagnostics['api'] = array( 'configured' => $this->api->is_configured(), 'rate_limit' => $this->api->get_rate_limit_info(), ); // Test API connectivity $api_test = $this->api->test_connection(); $diagnostics['api']['connectivity'] = !is_wp_error($api_test); if (is_wp_error($api_test)) { $diagnostics['api']['error'] = $api_test->get_error_message(); $status = 'unhealthy'; } // 2. Database Health global $wpdb; $diagnostics['database'] = array( 'connected' => $wpdb->check_connection(), 'events_table_exists' => $this->check_table_exists($wpdb->prefix . 'ticket_tailor_events'), 'orders_table_exists' => $this->check_table_exists($wpdb->prefix . 'ticket_tailor_orders'), 'security_log_table_exists' => $this->check_table_exists($wpdb->prefix . 'ticket_tailor_security_log'), 'rate_limit_table_exists' => $this->check_table_exists($wpdb->prefix . 'ticket_tailor_rate_limits'), ); // 3. Cache Statistics $diagnostics['cache'] = array( 'events' => $this->events->get_cache_stats(), 'orders' => $this->orders->get_cache_stats(), ); // 4. Sync Status $last_event_sync = get_option('ticket_tailor_last_event_sync', 0); $last_order_sync = get_option('ticket_tailor_last_order_sync', 0); $diagnostics['sync'] = array( 'last_event_sync' => $last_event_sync ? gmdate('Y-m-d H:i:s', $last_event_sync) : 'never', 'last_order_sync' => $last_order_sync ? gmdate('Y-m-d H:i:s', $last_order_sync) : 'never', 'event_sync_age_hours' => $last_event_sync ? round((time() - $last_event_sync) / 3600, 1) : null, 'order_sync_age_hours' => $last_order_sync ? round((time() - $last_order_sync) / 3600, 1) : null, 'events_lock' => get_transient('ticket_tailor_sync_events_lock'), 'orders_lock' => get_transient('ticket_tailor_sync_orders_lock'), ); // Check for stale syncs if ($last_event_sync && (time() - $last_event_sync) > 86400) { $diagnostics['sync']['event_sync_stale'] = true; $status = 'degraded'; } if ($last_order_sync && (time() - $last_order_sync) > 86400) { $diagnostics['sync']['order_sync_stale'] = true; $status = 'degraded'; } // 5. Cron Jobs $diagnostics['cron'] = array( 'event_sync_scheduled' => wp_next_scheduled('ticket_tailor_sync_events') ? true : false, 'order_sync_scheduled' => wp_next_scheduled('ticket_tailor_sync_orders') ? true : false, 'security_cleanup_scheduled' => wp_next_scheduled('ticket_tailor_cleanup_security_logs') ? true : false, 'rate_limit_cleanup_scheduled' => wp_next_scheduled('ticket_tailor_cleanup_rate_limits') ? true : false, ); // 6. PHP Environment $diagnostics['environment'] = array( 'php_version' => PHP_VERSION, 'wordpress_version' => get_bloginfo('version'), 'plugin_version' => TICKET_TAILOR_VERSION, 'openssl_enabled' => function_exists('openssl_encrypt'), 'curl_enabled' => function_exists('curl_init'), 'memory_limit' => ini_get('memory_limit'), 'max_execution_time' => ini_get('max_execution_time'), ); // 7. Security Configuration $diagnostics['security'] = array( 'api_key_encrypted' => !empty(get_option('ticket_tailor_api_key_encrypted')), 'webhook_secret_configured' => !empty(get_option('ticket_tailor_webhook_secret')), 'security_alerts_enabled' => get_option('ticket_tailor_security_alerts', true), ); $response = array( 'status' => $status, 'timestamp' => current_time('mysql'), 'diagnostics' => $diagnostics, ); $http_status = ($status === 'healthy') ? 200 : (($status === 'degraded') ? 200 : 503); return new WP_REST_Response($response, $http_status); } /** * Check if table exists */ private function check_table_exists($table_name) { global $wpdb; $result = $wpdb->get_var($wpdb->prepare( "SHOW TABLES LIKE %s", $wpdb->esc_like($table_name) )); return !empty($result); } /** * Get health check URL */ public function get_health_check_url() { return rest_url('ticket-tailor/v1/health'); } /** * Get detailed health check URL */ public function get_detailed_health_check_url() { return rest_url('ticket-tailor/v1/health/detailed'); } }