0, 'processed' => 0, 'errors' => 0, 'last_execution' => null, ); try { $stats = $this->gather_background_statistics(); accessibility_audio_tts_debug_log( 'Cron Background Stats: Statistics gathered successfully.' ); } catch ( \Exception $e ) { accessibility_audio_tts_debug_log( 'Cron Background Stats: Error gathering stats: ' . $e->getMessage() . '.' ); } return $stats; } /** * Gather background processing statistics from options and database. * * @return array Statistics array. */ private function gather_background_statistics() { $pending_queue = get_option( 'accessibility_audio_tts_pending_queue', array() ); $queue_count = is_array( $pending_queue ) ? count( $pending_queue ) : 0; // Get real count from database - posts without audio. $real_pending_count = $this->get_real_pending_posts_count(); // Get next scheduled run time for accessibility_audio_tts_process_queue. $next_run = wp_next_scheduled( 'accessibility_audio_tts_process_queue' ); $next_run_formatted = $next_run ? gmdate( 'Y-m-d H:i:s', $next_run ) . ' (' . human_time_diff( $next_run ) . ')' : __( 'Not scheduled', 'accessibility-audio-tts-text-to-speech-for-articles' ); // Calculate time until next run. $time_until_next = $next_run ? max( 0, $next_run - time() ) : 0; accessibility_audio_tts_debug_log( 'Cron Background Stats: Queue count: ' . $queue_count . ', Real pending: ' . $real_pending_count . ', Next run: ' . $next_run_formatted . '.' ); return array( 'pending_posts' => max( $queue_count, $real_pending_count ), // Use higher count. 'queue_posts' => $queue_count, 'database_posts' => $real_pending_count, 'processed' => absint( get_option( 'accessibility_audio_tts_bg_processed', 0 ) ), 'errors' => absint( get_option( 'accessibility_audio_tts_bg_errors', 0 ) ), 'last_execution' => get_option( 'accessibility_audio_tts_last_cron_run' ), 'next_run_timestamp' => $next_run, 'next_run_formatted' => $next_run_formatted, 'time_until_next' => $time_until_next, 'auto_conversion_enabled' => get_option( 'accessibility_audio_tts_auto_conversion', false ), 'processing_mode' => get_option( 'accessibility_audio_tts_processing_mode', 'wp_cron' ), 'total_posts_with_audio' => $this->get_posts_with_audio_count(), ); } /** * Get real count of posts that need audio processing from database. * * @return int Count of pending posts. */ private function get_real_pending_posts_count() { try { $post_types = get_option( 'accessibility_audio_tts_post_types', array( 'post' ) ); if ( empty( $post_types ) || ! is_array( $post_types ) ) { $post_types = array( 'post' ); } $query = new \WP_Query( array( 'post_type' => $post_types, 'post_status' => 'publish', 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Required for counting posts without audio in cron. array( 'key' => 'accessibility_audio_tts_generated', 'compare' => 'NOT EXISTS', ), ), 'fields' => 'ids', 'posts_per_page' => 1, 'no_found_rows' => false, 'update_post_meta_cache' => false, 'update_post_term_cache' => false, ) ); return max( 0, (int) $query->found_posts ); } catch ( \Exception $e ) { accessibility_audio_tts_debug_log( 'Cron Background Stats: Error counting pending posts: ' . $e->getMessage() . '.' ); return 0; } } /** * Get count of posts that already have audio. * * @return int Count of posts with audio. */ private function get_posts_with_audio_count() { try { $post_types = get_option( 'accessibility_audio_tts_post_types', array( 'post' ) ); if ( empty( $post_types ) || ! is_array( $post_types ) ) { $post_types = array( 'post' ); } $query = new \WP_Query( array( 'post_type' => $post_types, 'post_status' => 'publish', 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Required for counting posts with audio in cron. array( 'key' => 'accessibility_audio_tts_generated', 'value' => '1', 'compare' => '=', ), ), 'fields' => 'ids', 'posts_per_page' => 1, 'no_found_rows' => false, 'update_post_meta_cache' => false, 'update_post_term_cache' => false, ) ); return max( 0, (int) $query->found_posts ); } catch ( \Exception $e ) { accessibility_audio_tts_debug_log( 'Cron Background Stats: Error counting posts with audio: ' . $e->getMessage() . '.' ); return 0; } } /** * Get queue information and details. * * @return array Queue info. */ public function get_queue_info() { $pending_queue = get_option( 'accessibility_audio_tts_pending_queue', array() ); $processing_mode = get_option( 'accessibility_audio_tts_processing_mode', 'wp_cron' ); $auto_conversion = get_option( 'accessibility_audio_tts_auto_conversion', false ); return array( 'queue_size' => is_array( $pending_queue ) ? count( $pending_queue ) : 0, 'queue_items' => is_array( $pending_queue ) ? array_slice( $pending_queue, 0, 10 ) : array(), // First 10 items. 'processing_mode' => $processing_mode, 'auto_conversion_enabled' => $auto_conversion, 'queue_last_updated' => get_option( 'accessibility_audio_tts_queue_last_updated' ), 'queue_status' => $this->get_queue_status(), ); } /** * Get current queue processing status. * * @return string Queue status. */ private function get_queue_status() { $processing_mode = get_option( 'accessibility_audio_tts_processing_mode', 'wp_cron' ); $auto_conversion = get_option( 'accessibility_audio_tts_auto_conversion', false ); $next_run = wp_next_scheduled( 'accessibility_audio_tts_process_queue' ); if ( 'wp_cron' !== $processing_mode ) { return 'disabled'; } if ( ! $auto_conversion ) { return 'manual'; } if ( ! $next_run ) { return 'idle'; } return 'scheduled'; } /** * Get processing performance metrics. * * @return array Performance metrics. */ public function get_performance_metrics() { $processed = absint( get_option( 'accessibility_audio_tts_bg_processed', 0 ) ); $errors = absint( get_option( 'accessibility_audio_tts_bg_errors', 0 ) ); $total_attempts = $processed + $errors; $success_rate = 0 < $total_attempts ? round( ( $processed / $total_attempts ) * 100, 2 ) : 0; return array( 'total_processed' => $processed, 'total_errors' => $errors, 'total_attempts' => $total_attempts, 'success_rate' => $success_rate, 'error_rate' => 100 - $success_rate, 'average_per_day' => $this->calculate_average_per_day(), 'last_execution' => get_option( 'accessibility_audio_tts_last_cron_run' ), 'execution_history' => $this->get_execution_history(), ); } /** * Calculate average posts processed per day. * * @return float Average per day. */ private function calculate_average_per_day() { $first_run = get_option( 'accessibility_audio_tts_first_cron_run' ); $processed = absint( get_option( 'accessibility_audio_tts_bg_processed', 0 ) ); if ( ! $first_run || 0 === $processed ) { return 0.0; } $days_active = max( 1, ( time() - strtotime( $first_run ) ) / DAY_IN_SECONDS ); return round( $processed / $days_active, 2 ); } /** * Get recent execution history. * * @return array Execution history. */ private function get_execution_history() { $history = get_option( 'accessibility_audio_tts_execution_history', array() ); if ( ! is_array( $history ) ) { return array(); } // Return last 10 executions. return array_slice( $history, -10 ); } /** * Reset background processing statistics. * * @return bool Success status. */ public function reset_statistics() { $options_to_reset = array( 'accessibility_audio_tts_bg_processed', 'accessibility_audio_tts_bg_errors', 'accessibility_audio_tts_execution_history', 'accessibility_audio_tts_queue_last_updated', ); foreach ( $options_to_reset as $option ) { delete_option( $option ); } accessibility_audio_tts_debug_log( 'Cron Background Stats: Statistics reset successfully.' ); return true; } /** * Update processing statistics after execution. * * @param int $processed Number of successfully processed posts. * @param int $errors Number of errors. * @return bool Success status. */ public function update_statistics( $processed, $errors ) { $current_processed = absint( get_option( 'accessibility_audio_tts_bg_processed', 0 ) ); $current_errors = absint( get_option( 'accessibility_audio_tts_bg_errors', 0 ) ); update_option( 'accessibility_audio_tts_bg_processed', $current_processed + $processed ); update_option( 'accessibility_audio_tts_bg_errors', $current_errors + $errors ); update_option( 'accessibility_audio_tts_last_cron_run', current_time( 'mysql' ) ); // Update execution history. $this->add_execution_to_history( $processed, $errors ); accessibility_audio_tts_debug_log( "Cron Background Stats: Updated statistics - Processed: +{$processed}, Errors: +{$errors}." ); return true; } /** * Add execution to history. * * @param int $processed Number processed. * @param int $errors Number of errors. */ private function add_execution_to_history( $processed, $errors ) { $history = get_option( 'accessibility_audio_tts_execution_history', array() ); if ( ! is_array( $history ) ) { $history = array(); } $history[] = array( 'timestamp' => current_time( 'mysql' ), 'processed' => $processed, 'errors' => $errors, 'total' => $processed + $errors, ); // Keep only last 50 executions. if ( count( $history ) > 50 ) { $history = array_slice( $history, -50 ); } update_option( 'accessibility_audio_tts_execution_history', $history ); } /** * Get background processing statistics. * This is the main method called by Cron_Status_Provider. * * @return array Background processing statistics. */ public function get_background_processing_stats() { accessibility_audio_tts_debug_log( 'Cron Background Statistics: Generating processing stats.' ); try { $background_stats = $this->get_background_stats(); $queue_info = $this->get_queue_info(); $performance_metrics = $this->get_performance_metrics(); $processing_stats = array_merge( array( 'background_stats_section' => true ), $background_stats, $queue_info, $performance_metrics ); accessibility_audio_tts_debug_log( 'Cron Background Statistics: Processing stats generated successfully.' ); return $processing_stats; } catch ( \Exception $e ) { accessibility_audio_tts_debug_log( 'Cron Background Statistics: Error generating stats - ' . $e->getMessage() . '.' ); return array( 'background_stats_section' => true, 'status' => 'error', 'message' => 'Error generating background statistics: ' . $e->getMessage(), ); } } }