$hook, 'description' => '', 'interval' => 'hourly', 'callback' => null, 'args' => array(), 'priority' => 10, 'enabled' => true, 'dependencies' => array(), 'timeout' => 300, // 5 minutes default timeout. 'retry_count' => 3, 'category' => 'general', ); self::$jobs[ $hook ] = array_merge( $default_metadata, $metadata ); accessibility_audio_tts_debug_log( "Registered CRON job: {$hook}" ); } /** * Register default plugin jobs. */ private static function register_default_jobs(): void { // Main processing queue. self::register_job( 'accessibility_audio_tts_process_queue', array( 'name' => 'Audio Processing Queue', 'description' => 'Processes queued audio generation requests', 'interval' => 'accessibility_audio_tts_custom_interval', 'callback' => array( \Accessibility_Audio_TTS\Cron\Schedulers\Cron_Executor::class, 'execute_process_queue' ), 'priority' => 5, 'category' => 'processing', 'timeout' => 600, // 10 minutes for processing. 'dependencies' => array( 'elevenlabs_api' ), ) ); // Background posts processing. self::register_job( 'accessibility_audio_tts_process_background_posts', array( 'name' => 'Background Posts Processing', 'description' => 'Processes posts in background for audio generation', 'interval' => 'manual', // Triggered manually. 'callback' => array( \Accessibility_Audio_TTS\Cron\Schedulers\Cron_Executor::class, 'execute_background_posts' ), 'priority' => 7, 'category' => 'processing', 'timeout' => 900, // 15 minutes for bulk processing. 'dependencies' => array( 'elevenlabs_api', 'database' ), ) ); // Security cleanup. self::register_job( 'accessibility_audio_tts_security_cleanup', array( 'name' => 'Security Data Cleanup', 'description' => 'Cleans up expired security data and logs', 'interval' => 'daily', 'callback' => array( \Accessibility_Audio_TTS\Cron\Schedulers\Cron_Executor::class, 'execute_security_cleanup' ), 'priority' => 8, 'category' => 'maintenance', 'timeout' => 180, // 3 minutes. 'dependencies' => array( 'database' ), ) ); accessibility_audio_tts_debug_log( 'Default CRON jobs registered.' ); } /** * Get all registered jobs. * * @return array All registered jobs. */ public static function get_all_jobs(): array { return self::$jobs; } /** * Get a specific job by hook name. * * @param string $hook The hook name. * @return array|null Job metadata or null if not found. */ public static function get_job( string $hook ): ?array { return self::$jobs[ $hook ] ?? null; } /** * Get jobs by category. * * @param string $category The category name. * @return array Jobs in the specified category. */ public static function get_jobs_by_category( string $category ): array { $jobs = array(); foreach ( self::$jobs as $hook => $metadata ) { if ( $metadata['category'] === $category ) { $jobs[ $hook ] = $metadata; } } return $jobs; } /** * Get enabled jobs only. * * @return array Enabled jobs. */ public static function get_enabled_jobs(): array { $enabled_jobs = array(); foreach ( self::$jobs as $hook => $metadata ) { if ( $metadata['enabled'] ) { $enabled_jobs[ $hook ] = $metadata; } } return $enabled_jobs; } /** * Enable or disable a job. * * @param string $hook The hook name. * @param bool $enabled Whether to enable the job. * @return bool True on success, false if job not found. */ public static function set_job_enabled( string $hook, bool $enabled ): bool { if ( ! isset( self::$jobs[ $hook ] ) ) { return false; } self::$jobs[ $hook ]['enabled'] = $enabled; accessibility_audio_tts_debug_log( "Job {$hook} " . ( $enabled ? 'enabled' : 'disabled' ) ); return true; } /** * Register a dependency for jobs. * * @param string $name Dependency name. * @param callable $checker Function to check if dependency is available. */ public static function register_dependency( string $name, callable $checker ): void { self::$dependencies[ $name ] = $checker; accessibility_audio_tts_debug_log( "Registered dependency: {$name}" ); } /** * Check if a dependency is available. * * @param string $name Dependency name. * @return bool True if available, false otherwise. */ public static function is_dependency_available( string $name ): bool { if ( ! isset( self::$dependencies[ $name ] ) ) { return false; } try { return call_user_func( self::$dependencies[ $name ] ); } catch ( \Exception $e ) { accessibility_audio_tts_debug_log( "Dependency check failed for {$name}: " . $e->getMessage() ); return false; } } /** * Check if all dependencies for a job are available. * * @param string $hook The hook name. * @return bool True if all dependencies are available. */ public static function are_job_dependencies_available( string $hook ): bool { $job = self::get_job( $hook ); if ( ! $job || empty( $job['dependencies'] ) ) { return true; } foreach ( $job['dependencies'] as $dependency ) { if ( ! self::is_dependency_available( $dependency ) ) { accessibility_audio_tts_debug_log( "Job {$hook} dependency not available: {$dependency}" ); return false; } } return true; } /** * Get jobs sorted by priority. * * @return array Jobs sorted by priority (lower number = higher priority). */ public static function get_jobs_by_priority(): array { $jobs = self::$jobs; uasort( $jobs, function ( $a, $b ) { return $a['priority'] <=> $b['priority']; } ); return $jobs; } /** * Get job execution statistics. * * @return array Statistics for all jobs. */ public static function get_job_statistics(): array { $stats = array(); foreach ( self::$jobs as $hook => $metadata ) { $next_run = wp_next_scheduled( $hook ); $stats[ $hook ] = array( 'name' => $metadata['name'], 'category' => $metadata['category'], 'enabled' => $metadata['enabled'], 'scheduled' => (bool) $next_run, 'next_run' => $next_run, 'next_run_formatted' => $next_run ? gmdate( 'Y-m-d H:i:s', $next_run ) : 'Not scheduled', 'interval' => $metadata['interval'], 'priority' => $metadata['priority'], 'dependencies_met' => self::are_job_dependencies_available( $hook ), ); } return $stats; } /** * Initialize default dependencies. */ public static function init_default_dependencies(): void { // ElevenLabs API dependency. self::register_dependency( 'elevenlabs_api', function () { $api_key = get_option( 'accessibility_audio_tts_elevenlabs_api_key' ); return ! empty( $api_key ) && class_exists( '\\Accessibility_Audio_TTS\\API\\ElevenLabs\\ElevenLabs_Client' ); } ); // Database dependency. self::register_dependency( 'database', function () { global $wpdb; return $wpdb instanceof \wpdb; } ); // License system dependency. accessibility_audio_tts_debug_log( 'Default dependencies initialized.' ); } /** * Validate job configuration. * * @param string $hook The hook name. * @return array Validation results. */ public static function validate_job( string $hook ): array { $job = self::get_job( $hook ); if ( ! $job ) { return array( 'valid' => false, 'errors' => array( 'Job not found' ), ); } $errors = array(); $warnings = array(); // Check if callback is callable. if ( $job['callback'] && ! is_callable( $job['callback'] ) ) { $errors[] = 'Callback is not callable'; } // Check dependencies. foreach ( $job['dependencies'] as $dependency ) { if ( ! self::is_dependency_available( $dependency ) ) { $warnings[] = "Dependency '{$dependency}' is not available"; } } // Check timeout. if ( $job['timeout'] < 30 ) { $warnings[] = 'Timeout is very short (less than 30 seconds)'; } return array( 'valid' => empty( $errors ), 'errors' => $errors, 'warnings' => $warnings, ); } }