get_cron_array_safely(); accessibility_audio_tts_debug_log( 'Cron Status Data: Cron array retrieved, jobs count: ' . count( $cron_array ) . '.' ); $scheduled_jobs = array(); $jobs_count = 0; // Process cron jobs safely. foreach ( $cron_array as $timestamp => $cron ) { if ( ! is_array( $cron ) ) { continue; } $this->process_cron_jobs( $cron, $timestamp, $scheduled_jobs, $jobs_count ); } accessibility_audio_tts_debug_log( 'Cron Status Data: Found ' . $jobs_count . ' scheduled jobs.' ); return array( 'jobs_count' => $jobs_count, 'scheduled_jobs' => $scheduled_jobs, ); } /** * Get cron array safely with error handling. * * @return array Cron array. */ private function get_cron_array_safely() { $cron_array = array(); if ( function_exists( '_get_cron_array' ) ) { $cron_array = _get_cron_array(); if ( ! is_array( $cron_array ) ) { $cron_array = array(); } } return $cron_array; } /** * Process individual cron jobs from the cron array. * * @param array $cron Cron entry. * @param int $timestamp Timestamp. * @param array &$scheduled_jobs Scheduled jobs list (by ref). * @param int &$jobs_count Jobs counter (by ref). */ private function process_cron_jobs( $cron, $timestamp, &$scheduled_jobs, &$jobs_count ) { foreach ( $cron as $hook => $dings ) { if ( $this->is_accessibility_audio_tts_hook( $hook ) && is_array( $dings ) ) { $this->process_accessibility_audio_tts_jobs( $dings, $timestamp, $hook, $scheduled_jobs, $jobs_count ); } } } /** * Check if hook is AAT related. * * @param string $hook Hook name. * @return bool True if AAT hook. */ private function is_accessibility_audio_tts_hook( $hook ) { $aat_hooks = array( 'accessibility_audio_tts_process_audio_queue', // legacy. 'accessibility_audio_tts_process_queue', 'accessibility_audio_tts_process_background_posts', 'accessibility_audio_tts_execute_auto_trigger', 'accessibility_audio_tts_auto_schedule_post_conversion', ); return in_array( $hook, $aat_hooks, true ); } /** * Process AAT specific cron jobs. * * @param array $dings Ding entries. * @param int $timestamp Timestamp. * @param string $hook Hook name. * @param array &$scheduled_jobs Scheduled jobs list (by ref). * @param int &$jobs_count Jobs counter (by ref). */ private function process_accessibility_audio_tts_jobs( $dings, $timestamp, $hook, &$scheduled_jobs, &$jobs_count ) { foreach ( $dings as $sig => $data ) { ++$jobs_count; $time_left = max( 0, intval( $timestamp ) - time() ); $scheduled_jobs[] = array( 'hook' => $hook, 'timestamp' => intval( $timestamp ), 'time_formatted' => gmdate( 'Y-m-d H:i:s', intval( $timestamp ) ), 'time_left' => $time_left, 'time_until' => $this->format_time_until( $time_left ), 'args' => isset( $data['args'] ) && is_array( $data['args'] ) ? $data['args'] : array(), 'signature' => $sig, ); } } /** * Format time until execution in human-readable format. * * @param int $seconds Seconds until execution. * @return string Formatted time. */ private function format_time_until( $seconds ) { if ( $seconds <= 0 ) { return __( 'Overdue', 'accessibility-audio-tts-text-to-speech-for-articles' ); } if ( $seconds < 60 ) { /* translators: auto */ return sprintf( __( '%d seconds', 'accessibility-audio-tts-text-to-speech-for-articles' ), $seconds ); } elseif ( $seconds < 3600 ) { /* translators: auto */ return sprintf( __( '%d minutes', 'accessibility-audio-tts-text-to-speech-for-articles' ), floor( $seconds / 60 ) ); } elseif ( $seconds < 86400 ) { /* translators: auto */ return sprintf( __( '%d hours', 'accessibility-audio-tts-text-to-speech-for-articles' ), floor( $seconds / 3600 ) ); } else { /* translators: auto */ return sprintf( __( '%d days', 'accessibility-audio-tts-text-to-speech-for-articles' ), floor( $seconds / 86400 ) ); } } /** * Get current WordPress time information. * * @return array Current time data. */ public function get_current_time_data() { $current_timestamp = time(); $wp_time = current_time( 'mysql' ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested -- Diagnostic purpose only, not for scheduling. $wp_timestamp = current_time( 'timestamp' ); return array( 'server_time' => gmdate( 'Y-m-d H:i:s', $current_timestamp ), 'server_timestamp' => $current_timestamp, 'wp_time' => $wp_time, 'wp_timestamp' => $wp_timestamp, 'timezone' => wp_timezone_string(), 'gmt_offset' => get_option( 'gmt_offset' ), ); } /** * Get next scheduled run for specific hook. * * @param string $hook Hook name. * @return array|null Next run data or null if not scheduled. */ public function get_next_scheduled_run( $hook ) { $next_run = wp_next_scheduled( $hook ); if ( ! $next_run ) { return null; } $time_until = max( 0, $next_run - time() ); return array( 'timestamp' => $next_run, 'formatted' => gmdate( 'Y-m-d H:i:s', $next_run ), 'time_until' => $time_until, 'time_until_formatted' => $this->format_time_until( $time_until ), 'hook' => $hook, ); } /** * Get all AAT scheduled runs. * * @return array All scheduled AAT hooks. */ public function get_all_scheduled_runs() { $hooks = array( 'accessibility_audio_tts_process_audio_queue', // legacy. 'accessibility_audio_tts_process_queue', 'accessibility_audio_tts_process_background_posts', 'accessibility_audio_tts_execute_auto_trigger', 'accessibility_audio_tts_auto_schedule_post_conversion', ); $scheduled_runs = array(); foreach ( $hooks as $hook ) { $run_data = $this->get_next_scheduled_run( $hook ); if ( $run_data ) { $scheduled_runs[] = $run_data; } } // Sort by timestamp. usort( $scheduled_runs, function ( $a, $b ) { return $a['timestamp'] - $b['timestamp']; } ); return $scheduled_runs; } /** * Get basic status data for cron system. * This is the main method called by Cron_Status_Provider. * * @return array Basic cron status data. */ public function get_basic_status_data() { accessibility_audio_tts_debug_log( 'Cron Status Data Provider: Generating basic status data.' ); try { $wp_cron_status = $this->get_wp_cron_status(); $cron_data = $this->get_cron_data(); $time_data = $this->get_current_time_data(); $scheduled_runs = $this->get_all_scheduled_runs(); $basic_status = array( 'status' => 'active', 'cron_enabled' => 'enabled' === $wp_cron_status, 'wp_cron_status' => $wp_cron_status, 'total_jobs' => $cron_data['jobs_count'], 'scheduled_jobs' => $cron_data['scheduled_jobs'], 'accessibility_audio_tts_scheduled_runs' => $scheduled_runs, 'current_time' => $time_data, 'last_updated' => current_time( 'mysql' ), ); accessibility_audio_tts_debug_log( 'Cron Status Data Provider: Basic status data generated successfully.' ); return $basic_status; } catch ( \Exception $e ) { accessibility_audio_tts_debug_log( 'Cron Status Data Provider: Error generating basic status - ' . $e->getMessage() . '.' ); return array( 'status' => 'error', 'message' => 'Error generating basic status: ' . $e->getMessage(), 'cron_enabled' => false, 'total_jobs' => 0, 'last_updated' => current_time( 'mysql' ), ); } } }