Commit 0b68089427 for woocommerce
commit 0b68089427b7961a7a05002cebc760a98961f539
Author: Vlad Olaru <vlad.olaru@automattic.com>
Date: Mon Nov 3 09:00:36 2025 +0200
[Payments NOX] Prevent WC core-provided gateways showing deactivation actions (#61700)
* Core payment provider should not return a plugin file path
* test: Add core payment provider tests to ensure no plugin file
* Add changelog
* test: Fix payments providers integration tests
---------
Co-authored-by: Cvetan Cvetanov <cvetan.cvetanov@automattic.com>
diff --git a/plugins/woocommerce/changelog/fix-WOOPLUG-5598-nox-wc-core-gateways-deactivation b/plugins/woocommerce/changelog/fix-WOOPLUG-5598-nox-wc-core-gateways-deactivation
new file mode 100644
index 0000000000..79937d9109
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-WOOPLUG-5598-nox-wc-core-gateways-deactivation
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Prevent core-provided payment gateways from showing deactivation actions on the Payments settings page.
diff --git a/plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/WCCore.php b/plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/WCCore.php
index 40bd04f766..929d758e30 100644
--- a/plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/WCCore.php
+++ b/plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/WCCore.php
@@ -91,4 +91,21 @@ class WCCore extends PaymentGateway {
return parent::is_in_test_mode_onboarding( $payment_gateway );
}
+
+ /**
+ * Get the plugin details for a WC core-provided payment gateway.
+ *
+ * @param WC_Payment_Gateway $payment_gateway The payment gateway object.
+ *
+ * @return array The plugin details for the payment gateway.
+ */
+ public function get_plugin_details( WC_Payment_Gateway $payment_gateway ): array {
+ $plugin_details = parent::get_plugin_details( $payment_gateway );
+
+ // Since these are core-provided gateways, we need to make sure that the provider (WC) can't be deactivated.
+ // The way to do this is to NOT provide a plugin file path.
+ $plugin_details['file'] = '';
+
+ return $plugin_details;
+ }
}
diff --git a/plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsProviders/WCCoreTest.php b/plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsProviders/WCCoreTest.php
index f6e470380e..b3b52527be 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsProviders/WCCoreTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsProviders/WCCoreTest.php
@@ -32,6 +32,54 @@ class WCCoreTest extends WC_Unit_Test_Case {
$this->sut = new WCCore();
}
+ /**
+ * Data provider for core gateway IDs.
+ *
+ * @return array<string, array<string, string>>
+ */
+ public function provider_core_gateway_ids(): array {
+ return array(
+ 'BACS' => array( 'gateway_id' => WC_Gateway_BACS::ID ),
+ 'Cheque' => array( 'gateway_id' => WC_Gateway_Cheque::ID ),
+ 'COD' => array( 'gateway_id' => WC_Gateway_COD::ID ),
+ 'PayPal' => array( 'gateway_id' => WC_Gateway_Paypal::ID ),
+ );
+ }
+
+ /**
+ * Test get_plugin_details returns empty file path to prevent deactivation.
+ *
+ * @dataProvider provider_core_gateway_ids
+ *
+ * @param string $gateway_id The gateway ID to test.
+ */
+ public function test_get_plugin_details_prevents_deactivation( string $gateway_id ) {
+ // Arrange.
+ $fake_gateway = new FakePaymentGateway(
+ $gateway_id,
+ array(
+ 'enabled' => true,
+ 'plugin_slug' => 'woocommerce',
+ 'plugin_file' => 'woocommerce/woocommerce.php',
+ 'method_title' => 'Test Gateway',
+ 'method_description' => 'Test gateway description.',
+ ),
+ );
+
+ // Act.
+ $plugin_details = $this->sut->get_plugin_details( $fake_gateway );
+
+ // Assert - Core gateways should have empty file path to prevent deactivation.
+ $this->assertIsArray( $plugin_details );
+ $this->assertArrayHasKey( 'file', $plugin_details );
+ $this->assertSame( '', $plugin_details['file'], "Gateway $gateway_id should have empty file path for the plugin details." );
+
+ // Assert - Other expected keys should still be present.
+ $this->assertArrayHasKey( '_type', $plugin_details );
+ $this->assertArrayHasKey( 'slug', $plugin_details );
+ $this->assertArrayHasKey( 'status', $plugin_details );
+ }
+
/**
* Test get_icon.
*/
diff --git a/plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsRestControllerIntegrationTest.php b/plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsRestControllerIntegrationTest.php
index 52b49bc29a..1c63d4d3b8 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsRestControllerIntegrationTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsRestControllerIntegrationTest.php
@@ -573,7 +573,7 @@ class PaymentsRestControllerIntegrationTest extends WC_REST_Unit_Test_Case {
$this->assertArrayHasKey( 'status', $offline_pms_group['plugin'], 'Provider (offline payment methods group) `plugin[status]` entry is missing' );
$this->assertSame( PaymentsProviders::EXTENSION_ACTIVE, $offline_pms_group['plugin']['status'] );
- // Assert that the PayPal gateway is returned as enabled.
+ // Assert that the PayPal Standard gateway is returned as enabled.
$provider = $data['providers'][3];
$this->assertTrue( $provider['state']['enabled'] );
// Assert that the PayPal gateway has all the details.
@@ -587,9 +587,13 @@ class PaymentsRestControllerIntegrationTest extends WC_REST_Unit_Test_Case {
$this->assertIsList( $provider['supports'], 'Provider (gateway) `supports` entry is not a list' );
$this->assertArrayHasKey( 'plugin', $provider, 'Provider (gateway) `plugin` entry is missing' );
$this->assertArrayHasKey( '_type', $provider['plugin'], 'Provider (gateway) `plugin[_type]` entry is missing' );
+ $this->assertSame( PaymentsProviders::EXTENSION_TYPE_WPORG, $provider['plugin']['_type'], 'PayPal Standard gateway `plugin[_type]` entry is not `' . PaymentsProviders::EXTENSION_TYPE_WPORG . '`' );
$this->assertArrayHasKey( 'slug', $provider['plugin'], 'Provider (gateway) `plugin[slug]` entry is missing' );
+ $this->assertSame( 'woocommerce', $provider['plugin']['slug'] );
$this->assertArrayHasKey( 'file', $provider['plugin'], 'Provider (gateway) `plugin[file]` entry is missing' );
+ $this->assertSame( '', $provider['plugin']['file'] ); // Always empty since it's part of WooCommerce core and we don't want to allow deactivation.
$this->assertArrayHasKey( 'status', $provider['plugin'], 'Provider (gateway) `plugin[status]` entry is missing' );
+ $this->assertSame( PaymentsProviders::EXTENSION_ACTIVE, $provider['plugin']['status'], 'PayPal Standard gateway `plugin[status]` entry is not `' . PaymentsProviders::EXTENSION_ACTIVE . '`' );
$this->assertArrayHasKey( 'links', $provider, 'Provider (gateway) `links` entry is missing' );
$this->assertCount( 1, $provider['links'] );
$this->assertArrayHasKey( 'state', $provider, 'Provider (gateway) `state` entry is missing' );
@@ -630,7 +634,7 @@ class PaymentsRestControllerIntegrationTest extends WC_REST_Unit_Test_Case {
$this->assertArrayHasKey( 'slug', $offline_pm['plugin'], 'Offline payment method `plugin[slug]` entry is missing' );
$this->assertSame( 'woocommerce', $offline_pm['plugin']['slug'] );
$this->assertArrayHasKey( 'file', $offline_pm['plugin'], 'Offline payment method `plugin[file]` entry is missing' );
- $this->assertSame( 'woocommerce/woocommerce', $offline_pm['plugin']['file'] ); // Skips the .php extension.
+ $this->assertSame( '', $offline_pm['plugin']['file'] ); // Always empty since it's part of WooCommerce core and we don't want to allow deactivation.
$this->assertArrayHasKey( 'status', $offline_pm['plugin'], 'Offline payment method `plugin[status]` entry is missing' );
$this->assertSame( PaymentsProviders::EXTENSION_ACTIVE, $offline_pm['plugin']['status'] );
$this->assertArrayHasKey( 'management', $offline_pm, 'Offline payment method `management` entry is missing' );