| @@ -76,19 +76,16 @@ | ||
| 76 | 76 | add_action( 'wp_ajax_wpforo_ai_duplicate_task', [ $this, 'ajax_duplicate_task' ] ); |
| 77 | 77 | add_action( 'wp_ajax_wpforo_ai_get_task_stats', [ $this, 'ajax_get_task_stats' ] ); |
| 78 | 78 | } |
| 79 | 79 | |
| 80 | - // Register cron hooks (2 args: task_id, board_id) | |
| 80 | + // Register cron callbacks unconditionally so any already-scheduled | |
| 81 | + // event (from a prior connected state or from a single-event task) | |
| 82 | + // still has a handler. Scheduling of the recurring task-checker is | |
| 83 | + // gated by AI connection — see schedule_cron_jobs(). | |
| 81 | 84 | add_action( 'wpforo_ai_execute_task', [ $this, 'cron_execute_task' ], 10, 2 ); |
| 82 | 85 | add_action( 'wpforo_ai_check_scheduled_tasks', [ $this, 'cron_check_scheduled_tasks' ] ); |
| 83 | - // Hook for run_on_approval tasks (3 args: task_id, topic_id, board_id) | |
| 84 | 86 | add_action( 'wpforo_ai_execute_task_for_topic', [ $this, 'cron_execute_task_for_topic' ], 10, 3 ); |
| 85 | 87 | |
| 86 | - // Schedule the task checker if not already scheduled | |
| 87 | - if ( ! wp_next_scheduled( 'wpforo_ai_check_scheduled_tasks' ) ) { | |
| 88 | - wp_schedule_event( time(), 'hourly', 'wpforo_ai_check_scheduled_tasks' ); | |
| 89 | - } | |
| 90 | - | |
| 91 | 88 | // Check and reschedule overdue tasks when admin page loads |
| 92 | 89 | add_action( 'admin_init', [ $this, 'reschedule_overdue_tasks' ] ); |
| 93 | 90 | |
| 94 | 91 | // Hook into topic/post approval for run_on_approval tasks |
| @@ -100,8 +97,35 @@ | ||
| 100 | 97 | add_action( 'wpforo_after_add_post', [ $this, 'on_post_created' ], 20, 3 ); |
| 101 | 98 | } |
| 102 | 99 | |
| 103 | 100 | /** |
| 101 | + * Schedule the recurring task-checker cron. | |
| 102 | + * | |
| 103 | + * Called from AIClient::register_ai_crons() on tenant connect. | |
| 104 | + */ | |
| 105 | + public function schedule_cron_jobs() { | |
| 106 | + if ( ! wp_next_scheduled( 'wpforo_ai_check_scheduled_tasks' ) ) { | |
| 107 | + wp_schedule_event( time(), 'hourly', 'wpforo_ai_check_scheduled_tasks' ); | |
| 108 | + } | |
| 109 | + } | |
| 110 | + | |
| 111 | + /** | |
| 112 | + * Unschedule the recurring task-checker cron. | |
| 113 | + * | |
| 114 | + * Called from AIClient::unregister_ai_crons() on tenant disconnect. | |
| 115 | + * Single-event tasks (wpforo_ai_execute_task / _for_topic) are cleared | |
| 116 | + * elsewhere on a per-task basis; the recurring checker is the only one | |
| 117 | + * managed here. | |
| 118 | + */ | |
| 119 | + public function unschedule_cron_jobs() { | |
| 120 | + $ts = wp_next_scheduled( 'wpforo_ai_check_scheduled_tasks' ); | |
| 121 | + if ( $ts ) { | |
| 122 | + wp_unschedule_event( $ts, 'wpforo_ai_check_scheduled_tasks' ); | |
| 123 | + } | |
| 124 | + wp_clear_scheduled_hook( 'wpforo_ai_check_scheduled_tasks' ); | |
| 125 | + } | |
| 126 | + | |
| 127 | + /** | |
| 104 | 128 | * Reschedule overdue active tasks |
| 105 | 129 | * Called on admin_init to catch tasks that missed their cron execution |
| 106 | 130 | * Iterates over all boards to find overdue tasks |
| 107 | 131 | */ |
| @@ -3118,12 +3142,14 @@ | ||
| 3118 | 3142 | // Get active tag_maintenance tasks with run_on_approval enabled |
| 3119 | 3143 | $tasks = $this->get_run_on_approval_tasks( 'tag_maintenance', $forumid ); |
| 3120 | 3144 | |
| 3121 | 3145 | foreach ( $tasks as $task ) { |
| 3122 | - // Schedule async execution 5 seconds from now to ensure topic is committed | |
| 3146 | + // Schedule async execution 1.5 hours from now to batch multiple topics | |
| 3147 | + // and avoid WP-Cron being triggered immediately on page redirect | |
| 3123 | 3148 | $task_id = intval( $task['task_id'] ); |
| 3124 | 3149 | $board_id = intval( $task['board_id'] ?? 0 ); |
| 3125 | - wp_schedule_single_event( time() + 5, 'wpforo_ai_execute_task_for_topic', [ $task_id, $topicid, $board_id ] ); | |
| 3150 | + $delay = (int) apply_filters( 'wpforo_ai_task_on_approval_delay', 5400, 'tag_maintenance', $task_id ); | |
| 3151 | + wp_schedule_single_event( time() + $delay, 'wpforo_ai_execute_task_for_topic', [ $task_id, $topicid, $board_id ] ); | |
| 3126 | 3152 | } |
| 3127 | 3153 | } |
| 3128 | 3154 | |
| 3129 | 3155 | /** |
| @@ -3184,12 +3210,14 @@ | ||
| 3184 | 3210 | // Get active reply_generator tasks with run_on_approval enabled |
| 3185 | 3211 | $tasks = $this->get_run_on_approval_tasks( 'reply_generator', $forumid ); |
| 3186 | 3212 | |
| 3187 | 3213 | foreach ( $tasks as $task ) { |
| 3188 | - // Schedule async execution 5 seconds from now to ensure post is committed | |
| 3214 | + // Schedule async execution 1.5 hours from now to batch multiple posts | |
| 3215 | + // and avoid WP-Cron being triggered immediately on page redirect | |
| 3189 | 3216 | $task_id = intval( $task['task_id'] ); |
| 3190 | 3217 | $board_id = intval( $task['board_id'] ?? 0 ); |
| 3191 | - wp_schedule_single_event( time() + 5, 'wpforo_ai_execute_task_for_topic', [ $task_id, $topicid, $board_id ] ); | |
| 3218 | + $delay = (int) apply_filters( 'wpforo_ai_task_on_approval_delay', 5400, 'reply_generator', $task_id ); | |
| 3219 | + wp_schedule_single_event( time() + $delay, 'wpforo_ai_execute_task_for_topic', [ $task_id, $topicid, $board_id ] ); | |
| 3192 | 3220 | } |
| 3193 | 3221 | } |
| 3194 | 3222 | |
| 3195 | 3223 | /** |