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().
*