get_meta( self::PAID_META ) ) { return; } $action_id = as_enqueue_async_action( self::HOOK, array( 'order.paid', (int) $order->get_id(), 0, 0 ), self::GROUP ); if ( $action_id <= 0 ) { // Leave PAID_META unset so the next trigger (processing, completed, payment_complete) retries. Log::warning( 'Order event not queued: Action Scheduler refused order.paid for order ' . $order->get_id() . '.' ); return; } $order->update_meta_data( self::PAID_META, (string) time() ); $order->save_meta_data(); } catch ( \Throwable $e ) { try { Log::error( 'Order event not queued: ' . $e->getMessage() ); } catch ( \Throwable $ignored ) { // A broken logger must not fatal checkout either: fail closed means no event queued, quietly. unset( $ignored ); } } } /** * @param int|string $order_id Order id. * @param int|string $refund_id Refund id. */ public function on_refunded( $order_id, $refund_id ): void { try { if ( ! self::can_queue() ) { return; } as_enqueue_async_action( self::HOOK, array( 'order.refunded', (int) $order_id, (int) $refund_id, 0 ), self::GROUP ); } catch ( \Throwable $e ) { try { Log::error( 'Order event not queued: ' . $e->getMessage() ); } catch ( \Throwable $ignored ) { // A broken logger must not fatal checkout either: fail closed means no event queued, quietly. unset( $ignored ); } } } /** * Drops every queued order event (the store disconnected). */ public static function unschedule_all(): void { if ( function_exists( 'as_unschedule_all_actions' ) ) { // The stub types $args as array, but Action Scheduler's own implementation treats null (not array()) // as "any args"; array() would only cancel actions whose args are exactly empty, leaving every real // queued order event behind. // @phpstan-ignore-next-line argument.type as_unschedule_all_actions( self::HOOK, null, self::GROUP ); } } private static function can_queue(): bool { return Options::is_connected() && function_exists( 'as_enqueue_async_action' ); } }