Commit 949aeea68d for woocommerce
commit 949aeea68d787268ae43b489edb7288e8871fcf4
Author: Michal Iwanow <4765119+mcliwanow@users.noreply.github.com>
Date: Wed Feb 25 13:12:05 2026 +0100
Short-circuit payment gateway availability checks when disabled (#63344)
* Short-circuit payment gateway availability when disabled
* Add @since 10.7.0 docs and harden COD disabled-gateway test cleanup
- Move WC()->cart and order-pay query var mutations inside try/finally in COD unit test.
- Add @since 10.7.0 annotations for is_available() behavior changes in abstract and COD gateways.
---------
Co-authored-by: Herman <KokkieH@users.noreply.github.com>
diff --git a/plugins/woocommerce/includes/abstracts/abstract-wc-payment-gateway.php b/plugins/woocommerce/includes/abstracts/abstract-wc-payment-gateway.php
index 85d91f4d75..d1d23508ec 100644
--- a/plugins/woocommerce/includes/abstracts/abstract-wc-payment-gateway.php
+++ b/plugins/woocommerce/includes/abstracts/abstract-wc-payment-gateway.php
@@ -340,10 +340,15 @@ abstract class WC_Payment_Gateway extends WC_Settings_API {
/**
* Check if the gateway is available for use.
*
+ * @since 10.7.0 Added early return when gateway is disabled.
* @return bool
*/
public function is_available() {
- $is_available = ( 'yes' === $this->enabled );
+ if ( 'yes' !== $this->enabled ) {
+ return false;
+ }
+
+ $is_available = true;
if ( WC()->cart && 0 < $this->get_order_total() && 0 < $this->max_amount && $this->max_amount < $this->get_order_total() ) {
$is_available = false;
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 b48c3721bb..7cf0c6fbbb 100644
--- a/plugins/woocommerce/includes/gateways/cod/class-wc-gateway-cod.php
+++ b/plugins/woocommerce/includes/gateways/cod/class-wc-gateway-cod.php
@@ -149,9 +149,14 @@ class WC_Gateway_COD extends WC_Payment_Gateway {
/**
* Check If The Gateway Is Available For Use.
*
+ * @since 10.7.0 Added early return when gateway is disabled.
* @return bool
*/
public function is_available() {
+ if ( 'yes' !== $this->enabled ) {
+ return false;
+ }
+
$is_virtual = true;
$shipping_methods = array();
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/gateways/gateways.php b/plugins/woocommerce/tests/legacy/unit-tests/gateways/gateways.php
index 065787e87a..ef1a545927 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/gateways/gateways.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/gateways/gateways.php
@@ -85,5 +85,42 @@ class WC_Tests_Gateways extends WC_Unit_Test_Case {
$this->assertEquals( $gateway->pay_button_id, $gateway->get_pay_button_id() );
}
-}
+ /**
+ * Test WC_Payment_Gateway::is_available() returns early when gateway is disabled.
+ */
+ public function test_is_available_does_not_calculate_order_total_when_disabled() {
+ $cart = WC()->cart;
+
+ WC()->cart = new stdClass();
+
+ $gateway = new class() extends WC_Mock_Payment_Gateway {
+ /**
+ * Number of times get_order_total() is called.
+ *
+ * @var int
+ */
+ public $get_order_total_call_count = 0;
+
+ /**
+ * Get the order total and track how many times this method is called.
+ *
+ * @return float
+ */
+ protected function get_order_total() {
+ ++$this->get_order_total_call_count;
+ return 10.0;
+ }
+ };
+
+ $gateway->enabled = 'no';
+ $gateway->max_amount = 100;
+
+ try {
+ $this->assertFalse( $gateway->is_available() );
+ $this->assertSame( 0, $gateway->get_order_total_call_count );
+ } finally {
+ WC()->cart = $cart;
+ }
+ }
+}
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/payment-gateways/cod.php b/plugins/woocommerce/tests/legacy/unit-tests/payment-gateways/cod.php
index fdc256b740..4041ad03f1 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/payment-gateways/cod.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/payment-gateways/cod.php
@@ -84,4 +84,47 @@ class WC_Tests_Payment_Gateway_COD extends WC_Unit_Test_Case {
$this->assertArrayHasKey( 'enable_for_methods', $form_fields );
$this->assertNotEmpty( $form_fields['enable_for_methods']['options'] );
}
+
+ /**
+ * Make sure is_available() returns early for disabled gateways.
+ */
+ public function test_is_available_returns_early_when_disabled() {
+ $gateway = new WC_Gateway_COD();
+ $gateway->enabled = 'no';
+
+ $cart = WC()->cart;
+ $has_order_pay_query_var = array_key_exists( 'order-pay', $GLOBALS['wp']->query_vars );
+ $order_pay_query_var = $has_order_pay_query_var ? $GLOBALS['wp']->query_vars['order-pay'] : null;
+
+ try {
+ WC()->cart = new class() {
+ /**
+ * Number of times needs_shipping() is called.
+ *
+ * @var int
+ */
+ public $needs_shipping_call_count = 0;
+
+ /**
+ * Track calls to needs_shipping().
+ *
+ * @return bool
+ */
+ public function needs_shipping() {
+ ++$this->needs_shipping_call_count;
+ return false;
+ }
+ };
+ unset( $GLOBALS['wp']->query_vars['order-pay'] );
+
+ $this->assertFalse( $gateway->is_available() );
+ $this->assertSame( 0, WC()->cart->needs_shipping_call_count );
+ } finally {
+ WC()->cart = $cart;
+
+ if ( $has_order_pay_query_var ) {
+ $GLOBALS['wp']->query_vars['order-pay'] = $order_pay_query_var;
+ }
+ }
+ }
}