Commit be715831a46 for woocommerce

commit be715831a461ed726f9b18e668cf21cf95634e9a
Author: Tom Cafferkey <tjcafferkey@gmail.com>
Date:   Tue Sep 1 10:55:27 2026 +0100

    Fix Store API cart recovery after redirect payments (#68102)

    * Fix Store API checkout payment session tracking

    * Add changelog entry for Store API cart recovery

    * Use persisted session in test

    * Check is_callable per PHPStan

diff --git a/plugins/woocommerce/changelog/fix-store-api-order-awaiting-payment b/plugins/woocommerce/changelog/fix-store-api-order-awaiting-payment
new file mode 100644
index 00000000000..cc36a3d0b0d
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-store-api-order-awaiting-payment
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Ensure Store API checkout carts clear after redirect payments.
diff --git a/plugins/woocommerce/src/StoreApi/Utilities/CheckoutTrait.php b/plugins/woocommerce/src/StoreApi/Utilities/CheckoutTrait.php
index d876951ab6e..5a5f8f9f4de 100644
--- a/plugins/woocommerce/src/StoreApi/Utilities/CheckoutTrait.php
+++ b/plugins/woocommerce/src/StoreApi/Utilities/CheckoutTrait.php
@@ -88,6 +88,13 @@ trait CheckoutTrait {
 	private function process_payment( \WP_REST_Request $request, PaymentResult $payment_result ) {
 		$order = $this->get_order_or_throw();

+		$session = WC()->session;
+		$session->set( 'order_awaiting_payment', $order->get_id() );
+		// Persist before invoking gateways because redirects or stalled requests may prevent the session from being saved on shutdown.
+		if ( is_callable( array( $session, 'save_data' ) ) ) {
+			$session->save_data();
+		}
+
 		try {
 			// Prepare the payment context object to pass through payment hooks.
 			$context = new PaymentContext();
diff --git a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Checkout.php b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Checkout.php
index 3065948c43e..abbb79f9a44 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Checkout.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Checkout.php
@@ -3098,6 +3098,37 @@ class Checkout extends \WP_Test_REST_TestCase {
 		$this->assertEmpty( WC()->session->get( 'store_api_draft_order' ), 'Successful checkout should clear the draft order pointer when the cart is emptied.' );
 	}

+	/**
+	 * @testdox Store API checkout stores the order awaiting payment before invoking the payment gateway.
+	 */
+	public function test_post_sets_order_awaiting_payment_before_processing_payment(): void {
+		WC()->session->set_customer_session_cookie( true );
+		WC()->session->save_data();
+
+		$order_id_during_payment = 0;
+		$payment_handler         = function ( $context, $payment_result ) use ( &$order_id_during_payment ) {
+			unset( $context );
+			$order_id_during_payment = (int) WC()->session->get( 'order_awaiting_payment' );
+			$payment_result->set_status( 'success' );
+		};
+
+		add_action( 'woocommerce_rest_checkout_process_payment_with_context', $payment_handler, 1, 2 );
+
+		try {
+			$response = rest_get_server()->dispatch( $this->build_valid_post_request() );
+		} finally {
+			remove_action( 'woocommerce_rest_checkout_process_payment_with_context', $payment_handler, 1 );
+		}
+
+		$this->assertEquals( 200, $response->get_status(), print_r( $response->get_data(), true ) );
+		$order_id = (int) $response->get_data()['order_id'];
+		$this->assertGreaterThan( 0, $order_id, 'Checkout should create an order.' );
+		$this->assertSame( $order_id, $order_id_during_payment, 'The order should be linked to the session before payment processing starts.' );
+		$persisted_session_data = WC()->session->get_session_data();
+		$this->assertArrayHasKey( 'order_awaiting_payment', $persisted_session_data, 'Redirect payments should persist the order link in the shopper session.' );
+		$this->assertSame( $order_id, (int) $persisted_session_data['order_awaiting_payment'], 'Redirect payments should leave the persisted order linked to the shopper session.' );
+	}
+
 	/**
 	 * Build a valid checkout POST request body for use by the sample-extension tests.
 	 *