Commit d3dcaf4aea7 for woocommerce

commit d3dcaf4aea7b4bb325b6dd2ea8b0a5b2c8f0899c
Author: Tom Cafferkey <tjcafferkey@gmail.com>
Date:   Tue Jul 7 08:25:27 2026 +0100

    Fix existing order payments clearing active cart (#66090)

    * Fix existing order payments clearing active cart

    * Add changelog entry for existing order cart fix

    * Use cart hash when clearing cart after payment

    * Reset paypal

    * Only clear cart with the hashes match

    * Add additional order instance checks

diff --git a/plugins/woocommerce/changelog/fix-pay-for-order-preserve-cart b/plugins/woocommerce/changelog/fix-pay-for-order-preserve-cart
new file mode 100644
index 00000000000..88e9a719239
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-pay-for-order-preserve-cart
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Preserve cart contents when paying for an existing order.
diff --git a/plugins/woocommerce/includes/gateways/bacs/class-wc-gateway-bacs.php b/plugins/woocommerce/includes/gateways/bacs/class-wc-gateway-bacs.php
index 8421db3710f..90a70af0011 100644
--- a/plugins/woocommerce/includes/gateways/bacs/class-wc-gateway-bacs.php
+++ b/plugins/woocommerce/includes/gateways/bacs/class-wc-gateway-bacs.php
@@ -410,8 +410,10 @@ class WC_Gateway_BACS extends WC_Payment_Gateway {
 			$order->payment_complete();
 		}

-		// Remove cart.
-		WC()->cart->empty_cart();
+		// Remove cart if it still matches the order being processed.
+		if ( $order instanceof WC_Order && WC()->cart && $order->has_cart_hash( WC()->cart->get_cart_hash() ) ) {
+			WC()->cart->empty_cart();
+		}

 		// Return thankyou redirect.
 		return array(
diff --git a/plugins/woocommerce/includes/gateways/cheque/class-wc-gateway-cheque.php b/plugins/woocommerce/includes/gateways/cheque/class-wc-gateway-cheque.php
index 7e87b11ba53..3997d7f2d9c 100644
--- a/plugins/woocommerce/includes/gateways/cheque/class-wc-gateway-cheque.php
+++ b/plugins/woocommerce/includes/gateways/cheque/class-wc-gateway-cheque.php
@@ -161,8 +161,10 @@ class WC_Gateway_Cheque extends WC_Payment_Gateway {
 			$order->payment_complete();
 		}

-		// Remove cart.
-		WC()->cart->empty_cart();
+		// Remove cart if it still matches the order being processed.
+		if ( $order instanceof WC_Order && WC()->cart && $order->has_cart_hash( WC()->cart->get_cart_hash() ) ) {
+			WC()->cart->empty_cart();
+		}

 		// Return thankyou redirect.
 		return array(
diff --git a/plugins/woocommerce/includes/gateways/cod/class-wc-gateway-cod.php b/plugins/woocommerce/includes/gateways/cod/class-wc-gateway-cod.php
index 7cf0c6fbbb3..e131cc670ff 100644
--- a/plugins/woocommerce/includes/gateways/cod/class-wc-gateway-cod.php
+++ b/plugins/woocommerce/includes/gateways/cod/class-wc-gateway-cod.php
@@ -326,8 +326,10 @@ class WC_Gateway_COD extends WC_Payment_Gateway {
 			$order->payment_complete();
 		}

-		// Remove cart.
-		WC()->cart->empty_cart();
+		// Remove cart if it still matches the order being processed.
+		if ( $order instanceof WC_Order && WC()->cart && $order->has_cart_hash( WC()->cart->get_cart_hash() ) ) {
+			WC()->cart->empty_cart();
+		}

 		// Return thankyou redirect.
 		return array(
diff --git a/plugins/woocommerce/includes/wc-cart-functions.php b/plugins/woocommerce/includes/wc-cart-functions.php
index a8632511c1f..7d4ff014f58 100644
--- a/plugins/woocommerce/includes/wc-cart-functions.php
+++ b/plugins/woocommerce/includes/wc-cart-functions.php
@@ -177,6 +177,7 @@ function wc_clear_cart_after_payment() {

 	$should_clear_cart_after_payment = false;
 	$after_payment                   = false;
+	$order                           = null;

 	// If the order has been received, clear the cart.
 	if ( ! empty( $wp->query_vars['order-received'] ) ) {
@@ -218,6 +219,11 @@ function wc_clear_cart_after_payment() {
 	 */
 	$should_clear_cart_after_payment = apply_filters( 'woocommerce_should_clear_cart_after_payment', $should_clear_cart_after_payment );

+	// If the order is different from the cart, don't clear the cart. This can happen if the user has multiple tabs open and completes a different order than the one in the cart.
+	if ( $should_clear_cart_after_payment && $order instanceof WC_Order && ! WC()->cart->is_empty() ) {
+		$should_clear_cart_after_payment = $order->has_cart_hash( WC()->cart->get_cart_hash() );
+	}
+
 	if ( $should_clear_cart_after_payment ) {
 		WC()->cart->empty_cart();
 	}
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/cart/functions.php b/plugins/woocommerce/tests/legacy/unit-tests/cart/functions.php
index ee4e07b1a5a..ff1ffd96973 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/cart/functions.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/cart/functions.php
@@ -87,6 +87,57 @@ class WC_Tests_Cart_Functions extends WC_Unit_Test_Case {
 		$this->assertEquals( 0, WC()->cart->get_cart_contents_count() );
 	}

+	/**
+	 * Test wc_clear_cart_after_payment() clears the cart when the order cart hash matches the cart hash.
+	 */
+	public function test_wc_clear_cart_after_payment_clears_matching_cart_hash() {
+		global $wp;
+
+		$product = WC_Helper_Product::create_simple_product();
+
+		WC()->cart->empty_cart();
+		WC()->cart->add_to_cart( $product->get_id(), 4 );
+
+		$order = WC_Helper_Order::create_order( 1, $product );
+		$order->set_cart_hash( WC()->cart->get_cart_hash() );
+		$order->save();
+
+		$wp->query_vars['order-received'] = $order->get_id();
+		$_GET['key']                      = $order->get_order_key();
+
+		wc_clear_cart_after_payment();
+
+		unset( $wp->query_vars['order-received'], $_GET['key'] );
+
+		$this->assertEquals( 0, WC()->cart->get_cart_contents_count() );
+	}
+
+	/**
+	 * Test wc_clear_cart_after_payment() preserves the cart when the order cart hash does not match the cart hash.
+	 */
+	public function test_wc_clear_cart_after_payment_preserves_different_cart_hash() {
+		global $wp;
+
+		$product = WC_Helper_Product::create_simple_product();
+		$order   = WC_Helper_Order::create_order( 1, $product );
+		$order->set_cart_hash( 'different-cart-hash' );
+		$order->save();
+
+		WC()->cart->empty_cart();
+		WC()->cart->add_to_cart( $product->get_id(), 1 );
+
+		$wp->query_vars['order-received'] = $order->get_id();
+		$_GET['key']                      = $order->get_order_key();
+
+		wc_clear_cart_after_payment();
+
+		unset( $wp->query_vars['order-received'], $_GET['key'] );
+
+		$this->assertEquals( 1, WC()->cart->get_cart_contents_count() );
+
+		WC()->cart->empty_cart();
+	}
+
 	/**
 	 * Test wc_format_list_of_items().
 	 *