generator = $generator; } /** * Register Action Scheduler hooks. * * @return void */ public function register(): void { add_action( self::GENERATE_ACTION, array( $this, 'handle_generate' ) ); add_action( self::PRODUCT_SYNC_ACTION, array( $this, 'handle_product_sync' ), 10, 1 ); } /** * Schedule recurring feed generation. * * @param int $interval_seconds Interval between generations. Default: 6 hours. * * @return void */ public function schedule_recurring( int $interval_seconds = 0 ): void { if ( 0 === $interval_seconds ) { $interval_seconds = self::DEFAULT_INTERVAL; } if ( $this->has_action_scheduler() ) { if ( ! as_has_scheduled_action( self::GENERATE_ACTION ) ) { as_schedule_recurring_action( time() + $interval_seconds, $interval_seconds, self::GENERATE_ACTION, array(), 'aicommerce' ); } } elseif ( ! wp_next_scheduled( self::GENERATE_ACTION ) ) { wp_schedule_event( time() + $interval_seconds, 'aicommerce_feed_interval', self::GENERATE_ACTION ); } } /** * Schedule an immediate one-time feed generation. * * @return void */ public function schedule_immediate(): void { if ( $this->has_action_scheduler() ) { as_enqueue_async_action( self::GENERATE_ACTION, array(), 'aicommerce' ); } else { wp_schedule_single_event( time(), self::GENERATE_ACTION ); } } /** * Schedule a single product re-sync. * * @param int $product_id Product ID to re-sync. * * @return void */ public function schedule_product_sync( int $product_id ): void { if ( $this->has_action_scheduler() ) { // Prevent duplicate sync actions for the same product. if ( ! as_has_scheduled_action( self::PRODUCT_SYNC_ACTION, array( $product_id ) ) ) { as_enqueue_async_action( self::PRODUCT_SYNC_ACTION, array( $product_id ), 'aicommerce' ); } } elseif ( ! wp_next_scheduled( self::PRODUCT_SYNC_ACTION, array( $product_id ) ) ) { wp_schedule_single_event( time(), self::PRODUCT_SYNC_ACTION, array( $product_id ) ); } } /** * Unschedule all feed generation actions. * * @return void */ public function unschedule_all(): void { if ( $this->has_action_scheduler() ) { as_unschedule_all_actions( self::GENERATE_ACTION, array(), 'aicommerce' ); as_unschedule_all_actions( self::PRODUCT_SYNC_ACTION, array(), 'aicommerce' ); } else { $timestamp = wp_next_scheduled( self::GENERATE_ACTION ); if ( $timestamp ) { wp_unschedule_event( $timestamp, self::GENERATE_ACTION ); } } } /** * Handle the scheduled full feed generation. * * @return void */ public function handle_generate(): void { $this->generator->generate_all(); } /** * Handle a single product feed sync. * * @param int $product_id The product ID to re-sync. * * @return void */ public function handle_product_sync( int $product_id ): void { $product = wc_get_product( $product_id ); if ( ! $product instanceof \WC_Product ) { return; } $this->generator->sync_product( $product ); } /** * Check if Action Scheduler is available. * * @return bool */ public function has_action_scheduler(): bool { return function_exists( 'as_enqueue_async_action' ); } /** * Register custom cron interval as fallback. * * @param array $schedules Existing cron schedules. * * @return array Modified schedules. */ public static function add_cron_interval( array $schedules ): array { $schedules['aicommerce_feed_interval'] = array( 'interval' => self::DEFAULT_INTERVAL, 'display' => __( 'Tyralix AI Discoverability Feed Generation Interval', 'ai-discoverability-kit' ), ); return $schedules; } }