Repository: woocommerce/woocommerce
Pull request #55692: [Payments NOX] Migrate to using core feature flag instead of WCA one
Author: login: dmallory42
Labels: name: plugin: woocommerce
description: Issues related to the WooCommerce Core plugin.
name: plugin: woocommerce beta tester
description: Issues related to the WooCommerce Beta Tester plugin.
name: focus: e2e tests
description: Issues related to e2e tests
name: cherry pick to trunk
description: Dev only - Part of CFE, PRR flows
Created: 2025-02-20T14:05:38Z | Merged: 2025-03-25T16:25:25Z

### Submission Review Guidelines:

-   I have followed the [WooCommerce Contributing Guidelines](https://github.com/woocommerce/woocommerce/blob/trunk/.github/CONTRIBUTING.md) and the [WordPress Coding Standards](https://make.wordpress.org/core/handbook/best-practices/coding-standards/).
-   I have checked to ensure there aren't other open [Pull Requests](https://github.com/woocommerce/woocommerce/pulls) for the same update/change.
-   I have reviewed my code for [security best practices](https://developer.wordpress.org/apis/security/).
-   Following the above guidelines will result in quick merges and clear and detailed feedback when appropriate.

<!-- You can erase any parts of this template not applicable to your Pull Request. -->

### Changes proposed in this Pull Request:

<!-- If necessary, indicate if this PR is part of a bigger feature. Add a label with the format `focus: name of the feature [team:name of the team]`. -->

<!-- Describe the changes made to this Pull Request and the reason for such changes. -->

Closes #55324 .

<!-- Begin testing instructions -->

### How to test the changes in this Pull Request:

<!-- Include detailed instructions on how these changes can be tested. Review and follow the guide for how to write high-quality testing instructions. -->

Using the [WooCommerce Testing Instructions Guide](https://github.com/woocommerce/woocommerce/wiki/Writing-high-quality-testing-instructions), include your detailed testing instructions:

#### Prep work

1. Spin up a new JurassicNinja site:
    - **without** the Drop-In Cache plugin
    - without Jetpack
    - with Jetpack Beta and Woocommerce on this PR's branch from Jetpack Beta's options 
    - with WooCommerce Beta Tester
    - with WooPayments Dev Tools
1. Go through the core profiler, skip it and set your store location to US
1. Go to WooCommerce > Settings > Advanced > WooCommerce.com and make sure tracking is enabled:
![Screenshot 2025-02-14 at 10 52 28](https://github.com/user-attachments/assets/d82cc9d4-307f-4593-aa90-c3eb29cd9552)  
1. Go to Plugins > Add new and install and activate the [Transients Manager](https://wordpress.org/plugins/transients-manager/) plugin.
1. Go to Plugins > Add new and install and activate the [View User Metadata](https://wordpress.org/plugins/view-user-metadata/) plugin 
1.  Go to Tools > WCA Test Helper > Options, search for `reactify-classic-payments-settings` and if you have an option called `woocommerce_feature_reactify-classic-payments-settings_enabled`, delete it.
1. Make sure your store is in coming soon mode.

#### Testing the legacy Payments settings page and flows - control experiment variation

1. Go to Tools > Transients and search for `abtest_variation_`. You should see an entry called `abtest_variation_woocommerce_payment_settings_2025_v2` with the value `control`. 
1. Go to WooCommerce > Settings > Advanced > Features and make sure the `Payment Settings (beta)` feature is NOT enabled. Do NOT interact with the checkbox control.
1. Go to WooCommerce > Settings > General and set **India** as your store's location
1. Go to WooCommerce  > Home and you should see a "Get paid" task and a "Payments" top-level menu item WITHOUT a red dot notice:
![Screenshot 2025-01-13 at 19 19 10](https://github.com/user-attachments/assets/3b67f668-584f-46e4-a6c7-c9102c74f3d0)
1. Click on the "Payments" top-level menu item and you should see the Payments task page (notice the `/wp-admin/admin.php?page=wc-admin&task=payments` URL):
![Screenshot 2024-09-20 at 10 04 06](https://github.com/user-attachments/assets/d5ff1f99-1f0d-4fc2-b91a-5c6bb8341523)
1. Go to WooCommerce > Settings > General and change your store's location country to United States (the specific state doesn't matter)
1. Go to WooCommerce > Home and you should see a "Get paid with WooPayments" task with a discount badge and a "Payments" top-level menu item WITH a red dot notice:
![Screenshot 2025-01-13 at 19 24 15](https://github.com/user-attachments/assets/b82e02fe-656f-46d6-947c-7e3f59868a4e)
1. Click on the "Payments" top-level menu item and you should see the WooPayments incentives page:
![image](https://github.com/user-attachments/assets/af54f443-2598-4d58-8aee-897f17e423bf)
1. Dismiss the incentive by clicking on the "No thanks" link and then clicking on "Just dismiss WooPayments" in the modal.
1. You will be redirected to the WooCommerce > Home page with a "Get paid with WooPayments" task without a discount badge and a "Payments" top-level main menu item WITHOUT a red dot notice:
![Screenshot 2025-01-13 at 19 29 52](https://github.com/user-attachments/assets/08ab5f06-ffe8-4a13-9475-2656978e8bef)
1. Click on the "Payments" main menu item and you should see the Payments task page with WooPayments at the top:
![image](https://github.com/user-attachments/assets/3245b506-62f2-4b28-97c8-41446f43f124)
1. Navigate to WooCommerce -> Settings -> Payments. Check header reminders are shown.
![image](https://github.com/user-attachments/assets/6c76f149-eae9-4c43-8c91-97361c1e247f)

#### Testing the new Payments settings page and flows - treatment experiment variation

1. Go to Tools > Transients and search for `abtest_variation_`. You should see an entry called `abtest_variation_woocommerce_payment_settings_2025_v2` with the value `control`.
11. Click on edit for this transient and change its value to `treatment`:
![Screenshot 2025-02-14 at 10 47 10](https://github.com/user-attachments/assets/1ec64b42-3788-407f-887e-1ab002e65940)
![Screenshot 2025-02-14 at 10 47 37](https://github.com/user-attachments/assets/0b550b04-73e5-43a7-8404-1c66ecd18c81)
1. Go to WooCommerce > Settings > Advanced > Features and confirm the `Payment Settings (beta)` feature is enabled. Do NOT interact with the checkbox.
1. Go to WooCommerce > Home and you should see a "Get paid" task and a "Payments" top-level menu item WITH a red dot notice:
![Screenshot 2025-01-13 at 19 36 03](https://github.com/user-attachments/assets/037b6463-d74d-41e8-9ca6-c476fda1a008)
1. Click on the "Payments" main menu item and you will be taken to the new Payments settings page with the WooPayments Action incentive featured. Check no reminders are here:
![image](https://github.com/user-attachments/assets/e0b408f9-9d28-4a04-9512-0b5b0ab392c8)
1. Click on the "Dismiss" link, refresh the page and the "Payments" main menu item should not have a red dot notice and the WooPayments list item should be highlighted:
![image](https://github.com/user-attachments/assets/eb33443b-4ce2-4bb1-8fd1-c579e6669248)
1. Go to Users > Profile and from the View User Metadata section, delete the `woocommerce_admin_pes_incentive_dismissed` user meta entry:
![Screenshot 2025-01-13 at 19 45 34](https://github.com/user-attachments/assets/b47bf0cc-127d-4535-8078-67c4bd2a7bc7)
1. Click on the "Payments" main menu item and the WooPayments Action incentive banner should be back.
1. Click on the button with the "Save 10%" label, and then click on "Continue" at the payment methods configuration step:
![image](https://github.com/user-attachments/assets/b5d08773-f713-403b-8965-3b9b0da1936e)
1. Connect your WPCOM account to your store, wait for the payments setup to finish, and you should be taken back to the Payments settings page with a modal. Close the modal:
![Screenshot 2025-01-13 at 19 52 11](https://github.com/user-attachments/assets/577d2633-abb2-4157-a562-70f254904932)
1. The "Payments" main menu item should NOT have a red not notice anymore.
![image](https://github.com/user-attachments/assets/f47f4823-e681-48fc-8473-2c86813cbf40)
1. Go to Plugins and deactivate WooPayments.
1. Click on the "Payments" main menu item and you should see the Payments settings page with the WooPayments Action Incentive present only in the providers list since the banner was dismissed when you actioned it earlier. The "Payments" main menu item should not have a red dot notice:
![image](https://github.com/user-attachments/assets/c25e84a1-cbfc-46dc-bfee-7a132f240d9f)
1. Enable WooPayments back and navigate to WooCommerce -> Home.
1. Click Set up additional payments options
![image](https://github.com/user-attachments/assets/c4139810-a03b-42b8-a5a3-1be58fd55512)
1. You should be redirected to WooCommerce -> Settings with other payments section expanded
![image](https://github.com/user-attachments/assets/b73a676f-e887-45d8-9785-0663693dcc93)
1. Navigate to Offline payments section 
![image](https://github.com/user-attachments/assets/63ed33f6-9bd6-4ebf-b474-751397cf70b8)
1. Enable Cash on delivery
![image](https://github.com/user-attachments/assets/7412e294-38a1-47ed-aeff-d03e659f2b75)
1. Click Manage. Then check that go back button works correct.
![image](https://github.com/user-attachments/assets/1f8ab5ab-ee48-4e20-855c-80064f8067e2)
1. Check that go back from offline section works correct
![image](https://github.com/user-attachments/assets/d3111221-cacc-4c9f-b708-f83021f24f39)

#### Testing manually controlling the feature flag

1. Go to Plugins and deactivate WooPayments. 
1. Go to WooCommerce > Settings > Advanced > Features and disable the `Payment Settings (beta)` feature (it should have been enabled)
1. Navigate to WooCommerce -> Settings -> Payments and check you see the old page and payment recommendations
![image](https://github.com/user-attachments/assets/baf728f4-2f8d-45fb-b0f9-7314a1ebccb3)
1. Navigate to WooCommerce -> Home and Click Setup additional payment options
![image](https://github.com/user-attachments/assets/36e92562-68cd-4995-ba26-488d3f578558)
1. You should see this page
![image](https://github.com/user-attachments/assets/2bc59634-e95b-4ac8-8738-cb3b417e71ba)
1. Go to WooCommerce > Settings > Advanced > Features and enable the `Payment Settings (beta)` feature (it should have been disabled)
1. Click on the Payments main menu item and you should see the new Payments Settings page.
1. Go to Tools > Transients and search for `abtest_variation_`. You should see an entry called `abtest_variation_woocommerce_payment_settings_2025_v2` with the value `treatment`. Change its value to `control`.
1. Click on the Payments main menu item and you should _still_ see the new Payments Settings page.
1. Go to Tools > WCA Test Helper > Options, search for `reactify-classic-payments-settings` and you should have an option called `woocommerce_feature_reactify-classic-payments-settings_enabled`. Delete it (this way we allow the default feature values and experiment to kick in)
1. Navigate to WooCommerce -> Settings -> Payments and check you see the old page and payment recommendations
1.  Click on the Payments main menu item and you should see the legacy Payments task page:
![Screenshot 2025-02-14 at 15 01 52](https://github.com/user-attachments/assets/cf7f3a6f-a0f4-465a-b5e6-3f8f8a495330)


<!-- End testing instructions -->

### Changelog entry

<!-- You can optionally choose to enter a changelog entry by checking the box below and supplying data. -->
<!-- It will trigger the 'Add changelog to PR' CI job to create and push the entry into the branch. -->

<!-- Due to org permissions, the job might fail for PRs crated from a fork under GitHub organizations. Possible solutions: -->
<!-- * Create entry manually with `pnpm --filter='@woocommerce/plugin-woocommerce' changelog add` and push it into the branch (replace `@woocommerce/plugin-woocommerce` with package name from nearest `package.json` file) -->
<!-- * Create entry from supplied PR data and push it automatically `pnpm utils changefile pr-number-here -o github-org-name-here` -->

-   [ ] Automatically create a changelog entry from the details below.

<!-- If no changelog entry is required for this PR, you can specify that below and provide a comment explaining why. This cannot be used if you selected the option to automatically create a changelog entry above. -->

-   [ ] This Pull Request does not require a changelog entry. (Comment required below)

<details>

<summary>Changelog Entry Details</summary>

#### Significance

<!-- Choose only one -->

-   [ ] Patch
-   [ ] Minor
-   [ ] Major

#### Type

<!-- Choose only one -->

-   [ ] Fix - Fixes an existing bug
-   [ ] Add - Adds functionality
-   [ ] Update - Update existing functionality
-   [ ] Dev - Development related task
-   [ ] Tweak - A minor adjustment to the codebase
-   [ ] Performance - Address performance issues
-   [ ] Enhancement - Improvement to existing functionality

#### Message <!-- Add a changelog message here -->

</details>

<details>

<summary>Changelog Entry Comment</summary>

#### Comment <!-- If your Pull Request doesn't require a changelog entry, a comment explaining why is required instead -->

</details>


Linked issue #55324: New Payments Settings page - migrate feature flag to core
## Issue Description

Migrate the new Payments Settings page feature flag from WCA to the core feature system. This will allow it to be disabled via UI under advanced settings. Additionally, enable the feature by default.

Context: p1739195609406679-slack-C03KTTK2YMA

## Acceptance Criteria

* List the new Payments Settings page in WC Settings > Advanced > Features (not Experimental Features)
* Use the "Payments Settings" name for the section
* Use ID/key "reactify-classic-payments-settings".
* Use the "Enable the new payments settings experience." checkbox label
* Enable the feature by default
Linked issue comments: user: login: vladolaru
created_at: 2025-03-17T13:37:35Z
body: Updated the estimate to 3 because of the hardships with e2e tests needing updates.
author_association: CONTRIBUTOR
user: login: anu-rock
created_at: 2025-03-27T07:51:59Z
body: Closed by https://github.com/woocommerce/woocommerce/pull/55692.
author_association: CONTRIBUTOR

Diff:
diff --git a/plugins/woocommerce-beta-tester/changelog/update-migrate-reactify-feature-flag b/plugins/woocommerce-beta-tester/changelog/update-migrate-reactify-feature-flag
new file mode 100644
index 0000000000000..726cc6fa358d6
--- /dev/null
+++ b/plugins/woocommerce-beta-tester/changelog/update-migrate-reactify-feature-flag
@@ -0,0 +1,4 @@
+Significance: minor
+Type: update
+
+Remove reactify-classic-payments-settings flag as it was migrated to Core features
diff --git a/plugins/woocommerce-beta-tester/userscripts/wc-live-branches.user.js b/plugins/woocommerce-beta-tester/userscripts/wc-live-branches.user.js
index 1a2e6d500a6f3..c1930704d0d7e 100644
--- a/plugins/woocommerce-beta-tester/userscripts/wc-live-branches.user.js
+++ b/plugins/woocommerce-beta-tester/userscripts/wc-live-branches.user.js
@@ -111,7 +111,6 @@
 				'launch-your-store',
 				'minified-js',
 				'product-custom-fields',
-				'reactify-classic-payments-settings',
 				'settings',
 				'experimental-blocks',
 			];
diff --git a/plugins/woocommerce/changelog/update-migrate-reactify-feature-flag b/plugins/woocommerce/changelog/update-migrate-reactify-feature-flag
new file mode 100644
index 0000000000000..548f1d02fa24a
--- /dev/null
+++ b/plugins/woocommerce/changelog/update-migrate-reactify-feature-flag
@@ -0,0 +1,4 @@
+Significance: minor
+Type: update
+
+Migrate reactify settings page feature flag to Core feature system
diff --git a/plugins/woocommerce/client/admin/client/header/embed.tsx b/plugins/woocommerce/client/admin/client/header/embed.tsx
index c44a657fadfa6..5b2e29acd31c2 100644
--- a/plugins/woocommerce/client/admin/client/header/embed.tsx
+++ b/plugins/woocommerce/client/admin/client/header/embed.tsx
@@ -3,6 +3,7 @@
  */
 import './style.scss';
 import { isTaskListActive } from '~/hooks/use-tasklists-state';
+import { isFeatureEnabled } from '~/utils/features';
 import { BaseHeader } from './shared';
 
 export const EmbedHeader = ( {
@@ -13,7 +14,7 @@ export const EmbedHeader = ( {
 	query: Record< string, string >;
 } ) => {
 	const isReactifyPaymentsSettingsScreen = Boolean(
-		window.wcAdminFeatures?.[ 'reactify-classic-payments-settings' ] &&
+		isFeatureEnabled( 'reactify-classic-payments-settings' ) &&
 			query?.page === 'wc-settings' &&
 			query?.tab === 'checkout'
 	);
diff --git a/plugins/woocommerce/client/admin/client/payments/payment-recommendations-wrapper.tsx b/plugins/woocommerce/client/admin/client/payments/payment-recommendations-wrapper.tsx
index 0289d364d5c3a..50aded9032109 100644
--- a/plugins/woocommerce/client/admin/client/payments/payment-recommendations-wrapper.tsx
+++ b/plugins/woocommerce/client/admin/client/payments/payment-recommendations-wrapper.tsx
@@ -8,6 +8,7 @@ import { lazy, Suspense } from '@wordpress/element';
  */
 import { EmbeddedBodyProps } from '../embedded-body-layout/embedded-body-props';
 import RecommendationsEligibilityWrapper from '../settings-recommendations/recommendations-eligibility-wrapper';
+import { isFeatureEnabled } from '~/utils/features';
 
 const PaymentRecommendationsChunk = lazy(
 	() =>
@@ -25,7 +26,7 @@ export const PaymentRecommendations: React.FC< EmbeddedBodyProps > = ( {
 		page === 'wc-settings' &&
 		tab === 'checkout' &&
 		( ! section || section === 'main' ) &&
-		! window.wcAdminFeatures?.[ 'reactify-classic-payments-settings' ] // don't show this on the new payment settings page.
+		! isFeatureEnabled( 'reactify-classic-payments-settings' ) // don't show this on the new payment settings page.
 	) {
 		return (
 			<RecommendationsEligibilityWrapper>
diff --git a/plugins/woocommerce/client/admin/client/payments/test/payment-recommendations.test.tsx b/plugins/woocommerce/client/admin/client/payments/test/payment-recommendations.test.tsx
index 078444939fd46..3171ff22e7ff1 100644
--- a/plugins/woocommerce/client/admin/client/payments/test/payment-recommendations.test.tsx
+++ b/plugins/woocommerce/client/admin/client/payments/test/payment-recommendations.test.tsx
@@ -11,6 +11,7 @@ import { recordEvent } from '@woocommerce/tracks';
 import PaymentRecommendations from '../payment-recommendations';
 import { PaymentRecommendations as PaymentRecommendationsWrapper } from '../payment-recommendations-wrapper';
 import { isWCPaySupported } from '../../task-lists/fills/PaymentGatewaySuggestions/components/WCPay';
+import { isFeatureEnabled } from '~/utils/features';
 import { createNoticesFromResponse } from '../../lib/notices';
 
 jest.mock( '@woocommerce/tracks', () => ( { recordEvent: jest.fn() } ) );
@@ -66,6 +67,10 @@ jest.mock( '../../lib/notices', () => ( {
 	} ),
 } ) );
 
+jest.mock( '~/utils/features', () => ( {
+	isFeatureEnabled: jest.fn(),
+} ) );
+
 declare global {
 	interface Window {
 		wcAdminFeatures: Record< string, boolean >;
@@ -73,12 +78,10 @@ declare global {
 }
 
 describe( 'Payment recommendations', () => {
-	afterEach( () => {
-		window.wcAdminFeatures[ 'reactify-classic-payments-settings' ] = false;
-	} );
+	( isFeatureEnabled as jest.Mock ).mockReturnValue( false );
 
 	it( 'should not render paymentGatewaySuggestions if reactify-classic-payments-settings feature flag is on', () => {
-		window.wcAdminFeatures[ 'reactify-classic-payments-settings' ] = true;
+		( isFeatureEnabled as jest.Mock ).mockReturnValue( true );
 
 		const { container } = render(
 			<PaymentRecommendationsWrapper page="wc-settings" tab="checkout" />
diff --git a/plugins/woocommerce/client/admin/client/settings-payments/components/payment-method-list-item/payment-method-list-item.tsx b/plugins/woocommerce/client/admin/client/settings-payments/components/payment-method-list-item/payment-method-list-item.tsx
index 197cd78b2c4e2..2be7e8ce691b5 100644
--- a/plugins/woocommerce/client/admin/client/settings-payments/components/payment-method-list-item/payment-method-list-item.tsx
+++ b/plugins/woocommerce/client/admin/client/settings-payments/components/payment-method-list-item/payment-method-list-item.tsx
@@ -30,7 +30,7 @@ type PaymentMethodListItemProps = {
 };
 
 /**
- * A component that renders a recommened payment method as a list item.
+ * A component that renders a recommended payment method as a list item.
  * Displays the payment method's icon, title, description, and a toggle control to enable or disable it.
  */
 export const PaymentMethodListItem = ( {
diff --git a/plugins/woocommerce/client/admin/client/wp-admin-scripts/settings-embed/index.tsx b/plugins/woocommerce/client/admin/client/wp-admin-scripts/settings-embed/index.tsx
index 936da95b73d7b..100223edbb8a1 100644
--- a/plugins/woocommerce/client/admin/client/wp-admin-scripts/settings-embed/index.tsx
+++ b/plugins/woocommerce/client/admin/client/wp-admin-scripts/settings-embed/index.tsx
@@ -28,10 +28,7 @@ import { registerSettingsEmailPreviewFill } from '../../settings-email/settings-
 import { registerSettingsEmailFeedbackFill } from '~/settings-email/settings-email-feedback-slotfill';
 
 const renderPaymentsSettings = () => {
-	if (
-		! window.wcAdminFeatures ||
-		window.wcAdminFeatures[ 'reactify-classic-payments-settings' ] !== true
-	) {
+	if ( ! isFeatureEnabled( 'reactify-classic-payments-settings' ) ) {
 		// Render the payment settings components only if the feature flag is enabled.
 		return;
 	}
diff --git a/plugins/woocommerce/client/admin/config/core.json b/plugins/woocommerce/client/admin/config/core.json
index 71640601a1bf3..3767e6c4e8d8b 100644
--- a/plugins/woocommerce/client/admin/config/core.json
+++ b/plugins/woocommerce/client/admin/config/core.json
@@ -38,7 +38,6 @@
 		"async-product-editor-category-field": false,
 		"launch-your-store": true,
 		"product-editor-template-system": false,
-		"reactify-classic-payments-settings": true,
 		"use-wp-horizon": false,
 		"add-to-cart-with-options-stepper-layout": true,
 		"blockified-add-to-cart": false
diff --git a/plugins/woocommerce/client/admin/config/development.json b/plugins/woocommerce/client/admin/config/development.json
index c22e38370a507..d7908a79a29d7 100644
--- a/plugins/woocommerce/client/admin/config/development.json
+++ b/plugins/woocommerce/client/admin/config/development.json
@@ -38,7 +38,6 @@
 		"async-product-editor-category-field": true,
 		"launch-your-store": true,
 		"product-editor-template-system": false,
-		"reactify-classic-payments-settings": true,
 		"use-wp-horizon": false,
 		"add-to-cart-with-options-stepper-layout": true,
 		"blockified-add-to-cart": true
diff --git a/plugins/woocommerce/includes/abstracts/abstract-wc-payment-gateway.php b/plugins/woocommerce/includes/abstracts/abstract-wc-payment-gateway.php
index 62e5d84bd7447..566dfe6361320 100644
--- a/plugins/woocommerce/includes/abstracts/abstract-wc-payment-gateway.php
+++ b/plugins/woocommerce/includes/abstracts/abstract-wc-payment-gateway.php
@@ -12,6 +12,7 @@
 use Automattic\Jetpack\Constants;
 use Automattic\WooCommerce\Internal\Utilities\HtmlSanitizer;
 use Automattic\WooCommerce\Admin\Features\Features;
+use Automattic\WooCommerce\Utilities\FeaturesUtil;
 
 if ( ! defined( 'ABSPATH' ) ) {
 	exit;
@@ -205,7 +206,7 @@ public function get_method_description() {
 	 * Output the gateway settings screen.
 	 */
 	public function admin_options() {
-		$is_reactify_enabled      = Features::is_enabled( 'reactify-classic-payments-settings' );
+		$is_reactify_enabled      = FeaturesUtil::feature_is_enabled( 'reactify-classic-payments-settings' );
 		$offline_payment_gateways = array( WC_Gateway_BACS::ID, WC_Gateway_Cheque::ID, WC_Gateway_COD::ID );
 		$is_offline_gateway       = in_array( $this->id, $offline_payment_gateways, true );
 
diff --git a/plugins/woocommerce/includes/admin/class-wc-admin-settings.php b/plugins/woocommerce/includes/admin/class-wc-admin-settings.php
index 7a8e3efaa8edf..c4214532b924c 100644
--- a/plugins/woocommerce/includes/admin/class-wc-admin-settings.php
+++ b/plugins/woocommerce/includes/admin/class-wc-admin-settings.php
@@ -8,6 +8,7 @@
 
 use Automattic\Jetpack\Constants;
 use Automattic\WooCommerce\Admin\Features\Features;
+use Automattic\WooCommerce\Utilities\FeaturesUtil;
 
 if ( ! defined( 'ABSPATH' ) ) {
 	exit;
@@ -54,7 +55,7 @@ public static function get_settings_pages() {
 				$settings[] = include __DIR__ . '/settings/class-wc-settings-products.php';
 				$settings[] = include __DIR__ . '/settings/class-wc-settings-tax.php';
 				$settings[] = include __DIR__ . '/settings/class-wc-settings-shipping.php';
-				if ( \Automattic\WooCommerce\Admin\Features\Features::is_enabled( 'reactify-classic-payments-settings' ) ) {
+				if ( FeaturesUtil::feature_is_enabled( 'reactify-classic-payments-settings' ) ) {
 					$settings[] = include __DIR__ . '/settings/class-wc-settings-payment-gateways-react.php';
 				} else {
 					$settings[] = include __DIR__ . '/settings/class-wc-settings-payment-gateways.php';
diff --git a/plugins/woocommerce/includes/admin/settings/class-wc-settings-payment-gateways-react.php b/plugins/woocommerce/includes/admin/settings/class-wc-settings-payment-gateways-react.php
index a054c88a8c97e..c6dd202c799f5 100644
--- a/plugins/woocommerce/includes/admin/settings/class-wc-settings-payment-gateways-react.php
+++ b/plugins/woocommerce/includes/admin/settings/class-wc-settings-payment-gateways-react.php
@@ -59,6 +59,13 @@ public function __construct() {
 		parent::__construct();
 	}
 
+	/**
+	 * Setting page icon.
+	 *
+	 * @var string
+	 */
+	public $icon = 'payment';
+
 	/**
 	 * Output the settings.
 	 */
@@ -90,6 +97,26 @@ public function output() {
 		//phpcs:enable
 	}
 
+	/**
+	 * Get settings array.
+	 *
+	 * This is just for backward compatibility with the rest of the codebase (primarily API responses).
+	 *
+	 * @return array
+	 */
+	protected function get_settings_for_default_section() {
+		return array(
+			array(
+				'type' => 'title',
+				// this is needed as <table> tag is generated by this element, even if it has no other content.
+			),
+			array(
+				'type' => 'sectionend',
+				'id'   => 'payment_gateways_options',
+			),
+		);
+	}
+
 	/**
 	 * Check if the given section should be rendered using React.
 	 *
diff --git a/plugins/woocommerce/includes/admin/views/html-admin-settings.php b/plugins/woocommerce/includes/admin/views/html-admin-settings.php
index 6c10d5ab43ea2..e6fb4f78b060b 100644
--- a/plugins/woocommerce/includes/admin/views/html-admin-settings.php
+++ b/plugins/woocommerce/includes/admin/views/html-admin-settings.php
@@ -8,6 +8,7 @@
  */
 
 use Automattic\WooCommerce\Admin\Features\Features;
+use Automattic\WooCommerce\Utilities\FeaturesUtil;
 
 if ( ! defined( 'ABSPATH' ) ) {
 	exit;
@@ -33,7 +34,7 @@
 	exit;
 }
 
-$hide_nav = Features::is_enabled( 'reactify-classic-payments-settings' ) &&
+$hide_nav = FeaturesUtil::feature_is_enabled( 'reactify-classic-payments-settings' ) &&
 	( 'checkout' === $current_tab && 'offline' === $current_section );
 ?>
 
diff --git a/plugins/woocommerce/src/Admin/API/Options.php b/plugins/woocommerce/src/Admin/API/Options.php
index 770db4ee9fcbb..94dead2561702 100644
--- a/plugins/woocommerce/src/Admin/API/Options.php
+++ b/plugins/woocommerce/src/Admin/API/Options.php
@@ -225,6 +225,7 @@ public static function get_default_option_permissions() {
 			'woocommerce_show_lys_tour',
 			'woocommerce_remote_variant_assignment',
 			'woocommerce_gateway_order',
+			'woocommerce_feature_reactify-classic-payments-settings_enabled',
 			// WC Test helper options.
 			'wc-admin-test-helper-rest-api-filters',
 			'wc_admin_helper_feature_values',
diff --git a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/TaskLists.php b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/TaskLists.php
index ed0787c9d30c8..a891834b7af87 100644
--- a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/TaskLists.php
+++ b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/TaskLists.php
@@ -7,6 +7,8 @@
 
 use Automattic\WooCommerce\Admin\Features\Features;
 use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\ReviewShippingOptions;
+use Automattic\WooCommerce\Utilities\FeaturesUtil;
+
 /**
  * Task Lists class.
  */
@@ -133,7 +135,7 @@ public static function init_default_lists() {
 		}
 
 		// If the React-based Payments settings page is enabled, we don't need the dedicated WooPayments task.
-		if ( Features::is_enabled( 'reactify-classic-payments-settings' ) ) {
+		if ( FeaturesUtil::feature_is_enabled( 'reactify-classic-payments-settings' ) ) {
 			$key = array_search( 'WooCommercePayments', $tasks, true );
 			if ( false !== $key ) {
 				unset( $tasks[ $key ] );
diff --git a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/AdditionalPayments.php b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/AdditionalPayments.php
index 23d4c550c0fec..41d5acaf1b159 100644
--- a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/AdditionalPayments.php
+++ b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/AdditionalPayments.php
@@ -5,6 +5,7 @@
 
 use Automattic\WooCommerce\Admin\Features\Features;
 use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\Init;
+use Automattic\WooCommerce\Utilities\FeaturesUtil;
 
 /**
  * Payments Task
@@ -90,7 +91,7 @@ public function can_view() {
 		// Go ahead if either of the features are enabled.
 		// If the payment-gateway-suggestions are disabled,
 		// we are still good to go because we can use the default suggestions.
-		if ( ! Features::is_enabled( 'reactify-classic-payments-settings' ) &&
+		if ( ! FeaturesUtil::feature_is_enabled( 'reactify-classic-payments-settings' ) &&
 			! Features::is_enabled( 'payment-gateway-suggestions' ) ) {
 			// Hide task if both features are not enabled.
 			return false;
@@ -102,7 +103,7 @@ public function can_view() {
 
 		// Always show task if the React-based Payments settings page is enabled and
 		// there are any gateways enabled (i.e. the Payments task is complete).
-		if ( Features::is_enabled( 'reactify-classic-payments-settings' ) &&
+		if ( FeaturesUtil::feature_is_enabled( 'reactify-classic-payments-settings' ) &&
 			self::has_gateways() ) {
 			return true;
 		}
@@ -133,7 +134,7 @@ public function can_view() {
 	 */
 	public function get_action_url() {
 		// If the React-based Payments settings page is enabled, link to the new Payments settings page.
-		if ( Features::is_enabled( 'reactify-classic-payments-settings' ) ) {
+		if ( FeaturesUtil::feature_is_enabled( 'reactify-classic-payments-settings' ) ) {
 			// We auto-expand the "Other" section to show the additional payment methods.
 			return admin_url( 'admin.php?page=wc-settings&tab=checkout&other_pes_section=expanded' );
 		}
diff --git a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Payments.php b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Payments.php
index 53845cebfd04c..a2a235036f546 100644
--- a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Payments.php
+++ b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Payments.php
@@ -4,6 +4,7 @@
 
 use Automattic\WooCommerce\Admin\Features\Features;
 use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
+use Automattic\WooCommerce\Utilities\FeaturesUtil;
 
 /**
  * Payments Task
@@ -76,7 +77,7 @@ public function is_complete() {
 	 */
 	public function can_view() {
 		// If the React-based Payments settings page is enabled, the task is always visible.
-		if ( Features::is_enabled( 'reactify-classic-payments-settings' ) ) {
+		if ( FeaturesUtil::feature_is_enabled( 'reactify-classic-payments-settings' ) ) {
 			return true;
 		}
 
@@ -111,7 +112,7 @@ function( $gateway ) {
 	 */
 	public function get_action_url() {
 		// If the React-based Payments settings page is enabled, we want the task to link to the Payments Settings page.
-		if ( Features::is_enabled( 'reactify-classic-payments-settings' ) ) {
+		if ( FeaturesUtil::feature_is_enabled( 'reactify-classic-payments-settings' ) ) {
 			return admin_url( 'admin.php?page=wc-settings&tab=checkout' );
 		}
 
diff --git a/plugins/woocommerce/src/Internal/Admin/Settings/PaymentsController.php b/plugins/woocommerce/src/Internal/Admin/Settings/PaymentsController.php
index 9f83549fe8c62..27e3470b28fcf 100644
--- a/plugins/woocommerce/src/Internal/Admin/Settings/PaymentsController.php
+++ b/plugins/woocommerce/src/Internal/Admin/Settings/PaymentsController.php
@@ -3,8 +3,8 @@
 
 namespace Automattic\WooCommerce\Internal\Admin\Settings;
 
-use Automattic\WooCommerce\Admin\Features\Features;
-use Automattic\WooCommerce\Internal\Admin\Suggestions\PaymentExtensionSuggestions;
+use Automattic\WooCommerce\Internal\Features\FeaturesController;
+use Automattic\WooCommerce\Utilities\FeaturesUtil;
 use Exception;
 use WooCommerce\Admin\Experimental_Abtest;
 
@@ -27,12 +27,9 @@ class PaymentsController {
 	 * Register hooks.
 	 */
 	public function register() {
-		// Filter the feature config to allow the experiment to have effect.
-		// Use a priority of 9 to ensure that the filter runs before the user-set feature values
-		// are applied by the WC Beta Tester plugin.
-		// This way we allow users to control the feature flag via the WC Beta Tester plugin and disregard the experiment.
-		// @see plugins/woocommerce-beta-tester/plugin.php.
-		add_filter( 'woocommerce_admin_get_feature_config', array( $this, 'filter_feature_config_experiment' ), 9 );
+		add_action( 'woocommerce_register_feature_definitions', array( $this,
+			'adjust_feature_default_enablement_by_experiment'
+		) );
 
 		// Because we gate the hooking based on a feature flag,
 		// we need to delay the registration until the 'woocommerce_init' hook.
@@ -41,53 +38,46 @@ public function register() {
 	}
 
 	/**
-	 * Filter the feature flags list to modify the new Payments Settings page feature based on the experiment.
+	 * Adjust the new Payments Settings page feature default enablement based on the experiment.
 	 *
-	 * @param array $features The feature flags list.
+	 * @param FeaturesController $features_controller The features controller instance.
 	 *
-	 * @return array The updated feature flags list.
+	 * @return void
 	 */
-	public function filter_feature_config_experiment( $features ) {
-		// If the feature flag is not present or has been disabled, don't do anything.
-		if ( empty( $features['reactify-classic-payments-settings'] ) ) {
-			return $features;
+	public function adjust_feature_default_enablement_by_experiment( FeaturesController $features_controller ) {
+		// If the feature is disabled (or doesn't exist), don't do anything.
+		if ( ! $features_controller->feature_is_enabled( 'reactify-classic-payments-settings' ) ) {
+			return;
 		}
 
-		// Transient key to handle the experiment failure.
-		$transient_key = 'wc_experiment_failure_woocommerce_payment_settings_2025_v2';
+		// We only want to adjust the default feature value.
+		// If the feature value is already set in the DB, don't do anything.
+		$option_name = $features_controller->feature_enable_option_name( 'reactify-classic-payments-settings' );
+		if ( get_option( $option_name ) !== false ) {
+			return;
+		}
 
-		// Try to get cached result first.
-		$cached_result = get_transient( $transient_key );
+		// Transient key to handle the experiment group assignment failure.
+		$transient_key = 'wc_experiment_failure_woocommerce_payment_settings_2025_v2';
 
-		// If we have a cache entry that indicates an error, disable the feature.
-		if ( 'error' === $cached_result ) {
-			return array_merge(
-				$features,
-				array(
-					'reactify-classic-payments-settings' => false,
-				)
-			);
+		// If we failed to determine the experiment group assignment in the previous hour, don't do anything.
+		if ( 'error' === get_transient( $transient_key ) ) {
+			return;
 		}
 
 		try {
 			$in_treatment = Experimental_Abtest::in_treatment( 'woocommerce_payment_settings_2025_v2' );
 		} catch ( \Exception $e ) {
-			// If the experiment fails, set a transient to avoid repeated failures and set the flag to false.
-			$in_treatment = false;
+			// If the experiment group assignment fails, set a transient to avoid repeated fetches and
+			// consider the user not in the treatment group.
 			set_transient( $transient_key, 'error', HOUR_IN_SECONDS );
+			$in_treatment = false;
 		}
 
-		// If the feature flag is enabled, but the user is NOT in the experiment treatment group, disable the feature.
+		// If the user is NOT in the experiment treatment group disable the feature.
 		if ( ! $in_treatment ) {
-			return array_merge(
-				$features,
-				array(
-					'reactify-classic-payments-settings' => false,
-				)
-			);
+			$features_controller->change_feature_enable( 'reactify-classic-payments-settings', false );
 		}
-
-		return $features;
 	}
 
 	/**
@@ -95,7 +85,7 @@ public function filter_feature_config_experiment( $features ) {
 	 */
 	public function delayed_register() {
 		// Don't do anything if the feature is not enabled.
-		if ( ! Features::is_enabled( 'reactify-classic-payments-settings' ) ) {
+		if ( ! FeaturesUtil::feature_is_enabled( 'reactify-classic-payments-settings' ) ) {
 			return;
 		}
 
diff --git a/plugins/woocommerce/src/Internal/Admin/WCPayPromotion/Init.php b/plugins/woocommerce/src/Internal/Admin/WCPayPromotion/Init.php
index 8b4741a152eef..9e52d51d30665 100644
--- a/plugins/woocommerce/src/Internal/Admin/WCPayPromotion/Init.php
+++ b/plugins/woocommerce/src/Internal/Admin/WCPayPromotion/Init.php
@@ -7,10 +7,10 @@
 
 defined( 'ABSPATH' ) || exit;
 
-use Automattic\WooCommerce\Admin\Features\Features;
 use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\EvaluateSuggestion;
 use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
 use Automattic\WooCommerce\Admin\RemoteSpecs\RemoteSpecsEngine;
+use Automattic\WooCommerce\Utilities\FeaturesUtil;
 
 /**
  * WooPayments Promotion engine.
@@ -22,7 +22,7 @@ class Init extends RemoteSpecsEngine {
 	public function __construct() {
 		// If the React-based Payments settings page is enabled, we don't need the old WooPayments promotion system,
 		// as we will show the WooPayments suggestion with the new system.
-		if ( Features::is_enabled( 'reactify-classic-payments-settings' ) ) {
+		if ( FeaturesUtil::feature_is_enabled( 'reactify-classic-payments-settings' ) ) {
 			return;
 		}
 
@@ -85,11 +85,12 @@ public static function can_show_promotion() {
 	public static function set_gateway_top_of_list( $ordering ) {
 		$ordering = (array) $ordering;
 		$id       = WCPaymentGatewayPreInstallWCPayPromotion::GATEWAY_ID;
-		// Only tweak the ordering if the list hasn't been reordered with WooCommerce Payments in it already.
+		// Only tweak the ordering if the list hasn't been reordered with WooPayments in it already.
 		if ( ! isset( $ordering[ $id ] ) || ! is_numeric( $ordering[ $id ] ) ) {
-			$is_empty        = empty( $ordering ) || ( count( $ordering ) === 1 && $ordering[0] === false );
-			$ordering[ $id ] = $is_empty ? 0 : ( min( $ordering ) - 1 );
+			$is_empty        = empty( $ordering ) || ( count( $ordering ) === 1 && in_array( $ordering[0], array( false, '' ) ) );
+			$ordering[ $id ] = $is_empty ? 0 : ( min( array_map( 'intval', $ordering ) ) - 1 );
 		}
+
 		return $ordering;
 	}
 
diff --git a/plugins/woocommerce/src/Internal/Admin/WcPayWelcomePage.php b/plugins/woocommerce/src/Internal/Admin/WcPayWelcomePage.php
index f83ae1327e2b8..cbf2f75df0c5b 100644
--- a/plugins/woocommerce/src/Internal/Admin/WcPayWelcomePage.php
+++ b/plugins/woocommerce/src/Internal/Admin/WcPayWelcomePage.php
@@ -9,6 +9,7 @@
 use Automattic\WooCommerce\Admin\PageController;
 use Automattic\WooCommerce\Internal\Admin\Suggestions\PaymentExtensionSuggestionIncentives;
 use Automattic\WooCommerce\Internal\Admin\Suggestions\PaymentExtensionSuggestions;
+use Automattic\WooCommerce\Utilities\FeaturesUtil;
 
 /**
  * Class WCPayWelcomePage
@@ -68,7 +69,7 @@ public function register() {
 	 */
 	public function delayed_register() {
 		// Don't do anything if the feature is enabled.
-		if ( Features::is_enabled( 'reactify-classic-payments-settings' ) ) {
+		if ( FeaturesUtil::feature_is_enabled( 'reactify-classic-payments-settings' ) ) {
 			return;
 		}
 
diff --git a/plugins/woocommerce/src/Internal/Features/FeaturesController.php b/plugins/woocommerce/src/Internal/Features/FeaturesController.php
index e3f45475d6c46..27e9f9c03d7f8 100644
--- a/plugins/woocommerce/src/Internal/Features/FeaturesController.php
+++ b/plugins/woocommerce/src/Internal/Features/FeaturesController.php
@@ -200,7 +200,7 @@ private function get_feature_definitions() {
 			$tracking_enabled                 = WC_Site_Tracking::is_tracking_enabled();
 
 			$legacy_features = array(
-				'analytics'              => array(
+				'analytics'                          => array(
 					'name'               => __( 'Analytics', 'woocommerce' ),
 					'description'        => __( 'Enable WooCommerce Analytics', 'woocommerce' ),
 					'option_key'         => Analytics::TOGGLE_OPTION_NAME,
@@ -209,7 +209,7 @@ private function get_feature_definitions() {
 					'disable_ui'         => false,
 					'is_legacy'          => true,
 				),
-				'product_block_editor'   => array(
+				'product_block_editor'               => array(
 					'name'            => __( 'New product editor', 'woocommerce' ),
 					'description'     => __( 'Try the new product editor (Beta)', 'woocommerce' ),
 					'is_experimental' => true,
@@ -230,13 +230,13 @@ private function get_feature_definitions() {
 						return $string;
 					},
 				),
-				'cart_checkout_blocks'   => array(
+				'cart_checkout_blocks'               => array(
 					'name'            => __( 'Cart & Checkout Blocks', 'woocommerce' ),
 					'description'     => __( 'Optimize for faster checkout', 'woocommerce' ),
 					'is_experimental' => false,
 					'disable_ui'      => true,
 				),
-				'rate_limit_checkout'    => array(
+				'rate_limit_checkout'                => array(
 					'name'               => __( 'Rate limit Checkout', 'woocommerce' ),
 					'description'        => sprintf(
 						// translators: %s is the URL to the rate limiting documentation.
@@ -248,7 +248,7 @@ private function get_feature_definitions() {
 					'enabled_by_default' => false,
 					'is_legacy'          => true,
 				),
-				'marketplace'            => array(
+				'marketplace'                        => array(
 					'name'               => __( 'Marketplace', 'woocommerce' ),
 					'description'        => __(
 						'New, faster way to find extensions and themes for your WooCommerce store',
@@ -261,7 +261,7 @@ private function get_feature_definitions() {
 				),
 				// Marked as a legacy feature to avoid compatibility checks, which aren't really relevant to this feature.
 				// https://github.com/woocommerce/woocommerce/pull/39701#discussion_r1376976959.
-				'order_attribution'      => array(
+				'order_attribution'                  => array(
 					'name'               => __( 'Order Attribution', 'woocommerce' ),
 					'description'        => __(
 						'Enable this feature to track and credit channels and campaigns that contribute to orders on your site',
@@ -272,7 +272,7 @@ private function get_feature_definitions() {
 					'is_legacy'          => true,
 					'is_experimental'    => false,
 				),
-				'site_visibility_badge'  => array(
+				'site_visibility_badge'              => array(
 					'name'               => __( 'Site visibility badge', 'woocommerce' ),
 					'description'        => __(
 						'Enable the site visibility badge in the WordPress admin bar',
@@ -284,7 +284,7 @@ private function get_feature_definitions() {
 					'is_experimental'    => false,
 					'disabled'           => false,
 				),
-				'hpos_fts_indexes'       => array(
+				'hpos_fts_indexes'                   => array(
 					'name'               => __( 'HPOS Full text search indexes', 'woocommerce' ),
 					'description'        => __(
 						'Create and use full text search indexes for orders. This feature only works with high-performance order storage.',
@@ -295,7 +295,7 @@ private function get_feature_definitions() {
 					'is_legacy'          => true,
 					'option_key'         => CustomOrdersTableController::HPOS_FTS_INDEX_OPTION,
 				),
-				'hpos_datastore_caching' => array(
+				'hpos_datastore_caching'             => array(
 					'name'               => __( 'HPOS Data Caching', 'woocommerce' ),
 					'description'        => __(
 						'Enable order data caching in the datastore. This feature only works with high-performance order storage.',
@@ -321,7 +321,7 @@ private function get_feature_definitions() {
 					),
 					'option_key'         => CustomOrdersTableController::HPOS_DATASTORE_CACHING_ENABLED_OPTION,
 				),
-				'remote_logging'         => array(
+				'remote_logging'                     => array(
 					'name'               => __( 'Remote Logging', 'woocommerce' ),
 					'description'        => sprintf(
 						/* translators: %1$s: opening link tag, %2$s: closing link tag */
@@ -354,7 +354,7 @@ private function get_feature_definitions() {
 						},
 					),
 				),
-				'email_improvements'     => array(
+				'email_improvements'                 => array(
 					'name'            => __( 'Email improvements', 'woocommerce' ),
 					'description'     => __(
 						'Enable modern email design for transactional emails',
@@ -373,7 +373,7 @@ private function get_feature_definitions() {
 					'is_legacy'       => true,
 					'is_experimental' => false,
 				),
-				'blueprint'              => array(
+				'blueprint'                          => array(
 					'name'               => __( 'Blueprint (beta)', 'woocommerce' ),
 					'description'        => __(
 						'Enable blueprint to import and export settings in bulk',
@@ -393,7 +393,27 @@ private function get_feature_definitions() {
 					'is_legacy'          => true,
 					'is_experimental'    => false,
 				),
-				'block_email_editor'     => array(
+				'reactify-classic-payments-settings' => array(
+					'name'               => __( 'Payments Settings (beta)', 'woocommerce' ),
+					'description'        => __(
+						'Enable the new payments settings experience',
+						'woocommerce'
+					),
+					'enabled_by_default' => true,
+					'disable_ui'         => false,
+
+					/*
+					* This is not truly a legacy feature (it is not a feature that pre-dates the FeaturesController),
+					* but we wish to handle compatibility checking in a similar fashion to legacy features. The
+					* rational for setting legacy to true is therefore similar to that of the 'order_attribution'
+					* feature.
+					*
+					* @see https://github.com/woocommerce/woocommerce/pull/39701#discussion_r1376976959
+					*/
+					'is_legacy'          => true,
+					'is_experimental'    => false,
+				),
+				'block_email_editor'                 => array(
 					'name'               => __( 'Block Email Editor (alpha)', 'woocommerce' ),
 					'description'        => __(
 						'Enable the block-based email editor for transactional emails',
diff --git a/plugins/woocommerce/tests/e2e-pw/bin/test-helper-apis.php b/plugins/woocommerce/tests/e2e-pw/bin/test-helper-apis.php
index eaab75023abf4..8310fda2e31d0 100644
--- a/plugins/woocommerce/tests/e2e-pw/bin/test-helper-apis.php
+++ b/plugins/woocommerce/tests/e2e-pw/bin/test-helper-apis.php
@@ -35,6 +35,16 @@ function register_helper_api() {
 		)
 	);
 
+	register_rest_route(
+		'e2e-options',
+		'/delete',
+		array(
+			'methods'             => 'POST',
+			'callback'            => 'api_delete_option',
+			'permission_callback' => 'is_allowed',
+		)
+	);
+
 	register_rest_route(
 		'e2e-environment',
 		'/info',
@@ -120,6 +130,28 @@ function api_update_option( WP_REST_Request $request ) {
 	return new WP_REST_Response( 'Update option FAILED: ' . $option_name . ' => ' . $option_value, 400 );
 }
 
+/**
+ * Delete a WordPress option.
+ *
+ * @param WP_REST_Request $request
+ * @return WP_REST_Response
+ */
+function api_delete_option( WP_REST_Request $request ) {
+	$option_name  = sanitize_text_field( $request['option_name'] );
+
+	$option_exists = get_option( $option_name, null );
+
+	if ( null === $option_exists ) {
+		return new WP_REST_Response( 'Option ' . $option_name . ' does not exist.', 200 );
+	}
+
+	if ( delete_option( $option_name ) ) {
+		return new WP_REST_Response( 'Delete option SUCCESS: ' . $option_name, 200 );
+	}
+
+	return new WP_REST_Response( 'Delete option FAILED: ' . $option_name, 400 );
+}
+
 /**
  * Check if user is admin
  * @return bool
diff --git a/plugins/woocommerce/tests/e2e-pw/fixtures/site.setup.js b/plugins/woocommerce/tests/e2e-pw/fixtures/site.setup.js
index 9f9558d974ead..785ad7eca343e 100644
--- a/plugins/woocommerce/tests/e2e-pw/fixtures/site.setup.js
+++ b/plugins/woocommerce/tests/e2e-pw/fixtures/site.setup.js
@@ -5,6 +5,7 @@ import { test as setup } from './fixtures';
 import { ADMIN_STATE_PATH } from '../playwright.config';
 import { setComingSoon } from '../utils/coming-soon';
 import { skipOnboardingWizard } from '../utils/onboarding';
+import { setNewPaymentsSettingsPage } from '../utils/payments-settings';
 
 setup.use( { storageState: ADMIN_STATE_PATH } );
 
@@ -110,6 +111,10 @@ setup( 'disable onboarding wizard', async () => {
 	await skipOnboardingWizard();
 } );
 
+setup( 'disable new payments settings page', async ( { baseURL } ) => {
+	await setNewPaymentsSettingsPage( { baseURL, enabled: 'no' } );
+} );
+
 setup( 'determine if multisite', async ( { api } ) => {
 	const response = await api.get( 'system_status' );
 	const { environment } = response.data;
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/payment-gateways/payment-gateways-crud.test.js b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/payment-gateways/payment-gateways-crud.test.js
index 98f75e49b260b..a129cbb5d0a58 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/payment-gateways/payment-gateways-crud.test.js
+++ b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/payment-gateways/payment-gateways-crud.test.js
@@ -1,6 +1,20 @@
 const { test, expect } = require( '../../../fixtures/api-tests-fixtures' );
+const {
+	setNewPaymentsSettingsPage,
+	resetGatewayOrder,
+} = require( '../../../utils/payments-settings' );
+
+const { BASE_URL } = process.env;
+
+const disableNewPaymentsSettingsFeature = async () => {
+	await setNewPaymentsSettingsPage( { BASE_URL, enabled: 'no' } );
+};
 
 test.describe( 'Payment Gateways API tests', () => {
+	test.beforeAll( async () => {
+		await resetGatewayOrder( BASE_URL );
+		await disableNewPaymentsSettingsFeature();
+	} );
 	test( 'can view all payment gateways', async ( { request } ) => {
 		// call API to retrieve the payment gateways
 		const response = await request.get(
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/onboarding/payment-setup-task.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/onboarding/payment-setup-task.spec.js
index a01bf2e7851b2..140f49b0adc8c 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/onboarding/payment-setup-task.spec.js
+++ b/plugins/woocommerce/tests/e2e-pw/tests/onboarding/payment-setup-task.spec.js
@@ -47,6 +47,12 @@ const test = baseTest.extend( {
 			value: initialDefaultCountry.data.value,
 		} );
 		await wcAdminApi.put( 'options', initialTaskListHiddenState.data );
+
+		// Make sure the new Payments settings page feature is not enabled.
+		await wcAdminApi.put( 'options', {
+			'woocommerce_feature_reactify-classic-payments-settings_enabled':
+				'no',
+		} );
 	},
 } );
 
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/onboarding/setup-checklist.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/onboarding/setup-checklist.spec.js
index 6d9d5dea04e64..cb40e74e7f95e 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/onboarding/setup-checklist.spec.js
+++ b/plugins/woocommerce/tests/e2e-pw/tests/onboarding/setup-checklist.spec.js
@@ -20,6 +20,12 @@ const test = baseTest.extend( {
 
 		// Reset the task list to its initial state.
 		await wcAdminApi.put( 'options', initialTaskListState.data );
+
+		// Make sure the new Payments settings page feature is not enabled.
+		await wcAdminApi.put( 'options', {
+			'woocommerce_feature_reactify-classic-payments-settings_enabled':
+				'no',
+		} );
 	},
 
 	nonSupportedWooPaymentsCountryPage: async ( { page, api }, use ) => {
@@ -38,6 +44,12 @@ const test = baseTest.extend( {
 		await api.put( 'settings/general/woocommerce_default_country', {
 			value: initialDefaultCountry.data.value,
 		} );
+
+		// Make sure the new Payments settings page feature is not enabled.
+		await api.put( 'options', {
+			'woocommerce_feature_reactify-classic-payments-settings_enabled':
+				'no',
+		} );
 	},
 } );
 
diff --git a/plugins/woocommerce/tests/e2e-pw/utils/options.js b/plugins/woocommerce/tests/e2e-pw/utils/options.js
index 1c391fd9c2ab6..72d8bac185022 100644
--- a/plugins/woocommerce/tests/e2e-pw/utils/options.js
+++ b/plugins/woocommerce/tests/e2e-pw/utils/options.js
@@ -30,3 +30,25 @@ export const setOption = async (
 			return response.json();
 		} );
 };
+
+export const deleteOption = async ( request, baseURL, optionName ) => {
+	const apiContext = await request.newContext( {
+		baseURL,
+		extraHTTPHeaders: {
+			Authorization: `Basic ${ encodeCredentials(
+				admin.username,
+				admin.password
+			) }`,
+			cookie: '',
+		},
+	} );
+
+	return await apiContext
+		.post( './wp-json/e2e-options/delete', {
+			failOnStatusCode: true,
+			data: { option_name: optionName },
+		} )
+		.then( ( response ) => {
+			return response.json();
+		} );
+};
diff --git a/plugins/woocommerce/tests/e2e-pw/utils/payments-settings.js b/plugins/woocommerce/tests/e2e-pw/utils/payments-settings.js
new file mode 100644
index 0000000000000..7cad69a01f1c6
--- /dev/null
+++ b/plugins/woocommerce/tests/e2e-pw/utils/payments-settings.js
@@ -0,0 +1,28 @@
+const { request } = require( '@playwright/test' );
+const { setOption, deleteOption } = require( './options' );
+
+const setNewPaymentsSettingsPage = async ( { baseURL, enabled } ) => {
+	try {
+		await setOption(
+			request,
+			baseURL,
+			'woocommerce_feature_reactify-classic-payments-settings_enabled',
+			enabled
+		);
+	} catch ( error ) {
+		console.log( error );
+	}
+};
+
+const resetGatewayOrder = async ( baseURL ) => {
+	try {
+		await deleteOption( request, baseURL, 'woocommerce_gateway_order' );
+	} catch ( error ) {
+		console.log( error );
+	}
+};
+
+module.exports = {
+	setNewPaymentsSettingsPage,
+	resetGatewayOrder,
+};


Reviews:
user: login: dmallory42
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T12:21:57Z
user: login: dmallory42
body: Reviewed as although I authored the original PR, @vladolaru took over development of it. I'm not able to approve the PR as the original author, but confirming I tested and it works as expected and code looks good to me.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T12:35:43Z
user: login: elazzabi
body: Tested the PR with a test site and followed the testing instructions. Everything works as described 👍 

state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T12:47:25Z
user: login: vladolaru
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T13:12:47Z

Review comments:
diff_hunk: @@ -393,7 +393,27 @@ private function get_feature_definitions() {
 					'is_legacy'          => true,
 					'is_experimental'    => false,
 				),
-				'block_email_editor'     => array(
+				'reactify-classic-payments-settings' => array(
+					'name'               => __( 'Payment Settings (beta)', 'woocommerce' ),
+					'description'        => __(
+						'Enable the new payments settings experience',
path: plugins/woocommerce/src/Internal/Features/FeaturesController.php
user: login: dmallory42
body: Nitpick: I think `payment settings` instead of `payments settings` reads more naturally.
created_at: 2025-03-24T12:21:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -393,7 +393,27 @@ private function get_feature_definitions() {
 					'is_legacy'          => true,
 					'is_experimental'    => false,
 				),
-				'block_email_editor'     => array(
+				'reactify-classic-payments-settings' => array(
+					'name'               => __( 'Payment Settings (beta)', 'woocommerce' ),
+					'description'        => __(
+						'Enable the new payments settings experience',
path: plugins/woocommerce/src/Internal/Features/FeaturesController.php
user: login: vladolaru
body: Thanks for the nitpick @dmallory42 . Now if we consider that the tab label is "Payments" would you not call the page "Payments settings"? Same as for "Products settings"? Because it is about payments in general, not a specific gateway (probably there it makes more sense to use the singular).
created_at: 2025-03-24T13:12:47Z
author_association: CONTRIBUTOR

PR comments:
user: login: dmallory42
created_at: 2025-02-20T16:29:21Z
body: Noting that we should target 9.9 for this PR, since 9.8 will use the same experiment A/B test logic as 9.7.
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-02-20T16:41:27Z
body: 
## Test using WordPress Playground
The changes in this pull request can be previewed and tested using a [WordPress Playground](https://developer.wordpress.org/playground/) instance.
[WordPress Playground](https://developer.wordpress.org/playground/) is an experimental project that creates a full WordPress instance entirely within the browser.

[Test this pull request with WordPress Playground](https://playground.wordpress.net/#{"landingPage":"/wp-admin/admin.php?page=wc-admin","preferredVersions":{"php":"8.0","wp":"latest"},"phpExtensionBundles":["kitchen-sink"],"features":{"networking":true},"steps":[{"step":"installPlugin","pluginZipFile":{"resource":"url","url":"https://playground.wordpress.net/plugin-proxy.php?org=woocommerce&repo=woocommerce&workflow=Build%20Live%20Branch&artifact=plugins-14062992194&pr=55692"},"options":{"activate":true}},{"step":"installPlugin","pluginZipFile":{"resource":"url","url":"https://github-proxy.com/https://github.com/woocommerce/woocommerce/releases/download/wc-beta-tester-2.3.1/woocommerce-beta-tester.zip"},"options":{"activate":true}},{"step":"login","username":"admin","password":"password"}],"plugins":[]}).

Note that this URL is valid for 30 days from when this comment was last updated. You can update it by closing/reopening the PR or pushing a new commit.

author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-02-20T16:42:46Z
body: **Size Change:** +9 B (0%) 

**Total Size:** 5.6 MB



<a href="https://github.com/preactjs/compressed-size-action"><sub>compressed-size-action</sub></a>
author_association: CONTRIBUTOR
user: login: vladolaru
created_at: 2025-03-04T13:08:01Z
body: > Noting that we should target 9.9 for this PR, since 9.8 will use the same experiment A/B test logic as 9.7.

Update on this: In the interest of providing an easily accessible UI to users sooner rather than later, we will target 9.8.
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-03-24T11:57:53Z
body: ## Testing Guidelines
Hi @adimoldovan @woocommerce/moltres,

Apart from reviewing the code changes, please make sure to **review the testing instructions** ([Guide](https://github.com/woocommerce/woocommerce/wiki/Writing-high-quality-testing-instructions)) and verify that relevant tests (E2E, Unit, Integration, etc.) have been added or updated as needed.

**Reminder:** PR reviewers are required to document testing performed. This includes:
- 🖼️ **Screenshots or screen recordings**.
- 📝 **List of functionality tested / steps followed**.
- 🌐 **Site details** (environment attributes such as hosting type, plugins, theme, store size, store age, and relevant settings).
- 🔍 **Any analysis performed**, such as assessing potential impacts on environment attributes and other plugins, conducting performance profiling, or using LLM/AI-based analysis.

⚠️ Within the testing details you provide, please ensure that no sensitive information (such as API keys, passwords, user data, etc.) is included in this public issue.
author_association: CONTRIBUTOR
user: login: vladolaru
created_at: 2025-03-24T11:59:26Z
body: @adimoldovan, pinging you since you seem to have been all over the e2e tests lately. I have tried and tried and tried to get the e2e tests to pass - almost there, but a couple. I think these may have been fixed into `trunk` but I am not sure. Could you review the code changes I made around e2e tests? I tried to keep the store in a state without the new Payments Settings page feature enabled.
author_association: CONTRIBUTOR
user: login: vladolaru
created_at: 2025-03-25T10:24:34Z
body: Nevermind @adimoldovan I managed to dig myself out of the hole :D 
author_association: CONTRIBUTOR