init_hooks(); } /** * Initialize hooks. */ private function init_hooks() { add_action( 'afridirect_payment_check_expired_orders', array( $this, 'check_expired_orders' ) ); } /** * Check and expire orders that have passed their deadline. */ public function check_expired_orders() { // Only query orders that are still pending or have proof uploaded. $orders = wc_get_orders( array( 'status' => array( 'adp-pending', 'adp-proof' ), 'payment_method' => 'afridirect_payment', 'limit' => 100, // Process in batches for efficiency. 'return' => 'ids', // No non-meta way to find orders by their expiry timestamp; this // runs at most every 5 minutes on a small, limited-to-100 batch. // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 'meta_query' => array( array( 'key' => '_afridirect_expires_at', 'value' => time(), 'compare' => '<', 'type' => 'NUMERIC', ), ), ) ); if ( empty( $orders ) ) { return; } $current_time = time(); $expired_count = 0; foreach ( $orders as $order_id ) { $order = wc_get_order( $order_id ); if ( ! $order ) { continue; } // Double-check expiration time. $expires_at = $order->get_meta( '_afridirect_expires_at' ); $order_status = $order->get_status(); // Only expire if still in pending or proof status and expired. if ( $expires_at && $current_time > $expires_at && in_array( $order_status, array( 'adp-pending', 'adp-proof' ), true ) ) { // update_status() already fires woocommerce_order_status_adp-expired, // which the email handler is hooked to; no manual do_action needed. $order->update_status( 'adp-expired', __( 'Payment deadline expired.', 'afridirect-payment' ) ); $expired_count++; } } } }