Commit f3ac26246c for woocommerce

commit f3ac26246c85635bd688baa13a420d3562cebd1b
Author: Ahmed <ahmed.el.azzabi@automattic.com>
Date:   Tue Jul 1 10:38:49 2025 +0200

    Improve offline payments settings navigation to avoid unnecessary refresh (#59163)

    * Update settings URL for offline payment methods

    * Add removeOriginFromURL function to help with navigation

    * For offline payment methods, navigate to the URL instead of using href

    * Navigate instead of changing location href

    * Update the offline placeholder to include a header to avoid sudden changes in the UI

    * Update links to the new format

    * Update BACS component to use a header

    * Add a header to the offline payment methods page

    * Add a header to the BACS PM

    * Add necessary header styles

    * Remove unnecessary margin forcing

    * Add cheque payments header

    * Add COD header

    * Add header to the loading state to avoid sudden UI changes

    * Move SettingsPaymentsMainWrapper to after components definitions and declare new routes

    * reduce code duplication by removing the header out of suspense and the component

    * reduce code duplication by removing the header out of suspense and the component

    * reduce code duplication by moving the header out for COD

    * reduce duplication by moving the header out of the cheque component

    * Fix typo in check payments

    * Fix styling issues by wrapping the components in a div

    * Update comment

    * add redirection for old paths

    * First try to fix lint issues

    * Add a comma after the last argument

    * Fix tests after changing the URLs

    * Add changefile(s) from automation for the following project(s): @woocommerce/data, woocommerce, woocommerce/client/admin

    * Default to url if we can not run a replace

    * reduce code duplication by using a central component

    * Remove the Header as it's not used anymore

    * Fix components layouts

    * Wrap SettingsPaymentsMain test file in Router

    * Add margins for offline settings

    * Remove non used Take offline payments header

    * remove unit from CSS

    * remove border bottom from header layout

    * add margins for offline container to match the settings container

    * Get back to the checkout tab in settings in order to remove the path query arg

    * clear store when navigating back to offline PMs list

    * Add get_settings_url for cod, cheque, and bacs

    ---------

    Co-authored-by: github-actions <github-actions@github.com>
    Co-authored-by: Oleksandr Aratovskyi <79862886+oaratovskyi@users.noreply.github.com>
    Co-authored-by: Vlad Olaru <vlad.olaru@automattic.com>

diff --git a/packages/js/data/changelog/59163-update-update-offline-pms-navigation b/packages/js/data/changelog/59163-update-update-offline-pms-navigation
new file mode 100644
index 0000000000..eda5f06e45
--- /dev/null
+++ b/packages/js/data/changelog/59163-update-update-offline-pms-navigation
@@ -0,0 +1,4 @@
+Significance: minor
+Type: update
+
+Update the navigation for offline payment methods to avoid unnecessary page refresh
\ No newline at end of file
diff --git a/packages/js/data/src/payment-settings/test/helpers/stub.ts b/packages/js/data/src/payment-settings/test/helpers/stub.ts
index 2edad8823a..923afaaab7 100644
--- a/packages/js/data/src/payment-settings/test/helpers/stub.ts
+++ b/packages/js/data/src/payment-settings/test/helpers/stub.ts
@@ -183,7 +183,7 @@ export const offlinePaymentGatewaysStub: OfflinePaymentMethodProvider[] = [
 		management: {
 			_links: {
 				settings: {
-					href: 'http://localhost:8082/wp-admin/admin.php?page=wc-settings&tab=checkout&section=bacs',
+					href: 'http://localhost:8082/wp-admin/admin.php?page=wc-settings&tab=checkout&path=/offline/bacs',
 				},
 			},
 		},
@@ -195,7 +195,7 @@ export const offlinePaymentGatewaysStub: OfflinePaymentMethodProvider[] = [
 			},
 			_links: {
 				onboard: {
-					href: 'http://localhost:8082/wp-admin/admin.php?page=wc-settings&tab=checkout&section=bacs',
+					href: 'http://localhost:8082/wp-admin/admin.php?page=wc-settings&tab=checkout&path=/offline/bacs',
 				},
 			},
 		},
@@ -226,7 +226,7 @@ export const offlinePaymentGatewaysStub: OfflinePaymentMethodProvider[] = [
 		management: {
 			_links: {
 				settings: {
-					href: 'http://localhost:8082/wp-admin/admin.php?page=wc-settings&tab=checkout&section=cheque',
+					href: 'http://localhost:8082/wp-admin/admin.php?page=wc-settings&tab=checkout&path=/offline/cheque',
 				},
 			},
 		},
@@ -238,7 +238,7 @@ export const offlinePaymentGatewaysStub: OfflinePaymentMethodProvider[] = [
 			},
 			_links: {
 				onboard: {
-					href: 'http://localhost:8082/wp-admin/admin.php?page=wc-settings&tab=checkout&section=cheque',
+					href: 'http://localhost:8082/wp-admin/admin.php?page=wc-settings&tab=checkout&path=/offline/cheque',
 				},
 			},
 		},
@@ -269,7 +269,7 @@ export const offlinePaymentGatewaysStub: OfflinePaymentMethodProvider[] = [
 		management: {
 			_links: {
 				settings: {
-					href: 'http://localhost:8082/wp-admin/admin.php?page=wc-settings&tab=checkout&section=cod',
+					href: 'http://localhost:8082/wp-admin/admin.php?page=wc-settings&tab=checkout&path=/offline/cod',
 				},
 			},
 		},
@@ -281,7 +281,7 @@ export const offlinePaymentGatewaysStub: OfflinePaymentMethodProvider[] = [
 			},
 			_links: {
 				onboard: {
-					href: 'http://localhost:8082/wp-admin/admin.php?page=wc-settings&tab=checkout&section=cod',
+					href: 'http://localhost:8082/wp-admin/admin.php?page=wc-settings&tab=checkout&path=/offline/cod',
 				},
 			},
 		},
diff --git a/plugins/woocommerce/changelog/59163-update-update-offline-pms-navigation b/plugins/woocommerce/changelog/59163-update-update-offline-pms-navigation
new file mode 100644
index 0000000000..eda5f06e45
--- /dev/null
+++ b/plugins/woocommerce/changelog/59163-update-update-offline-pms-navigation
@@ -0,0 +1,4 @@
+Significance: minor
+Type: update
+
+Update the navigation for offline payment methods to avoid unnecessary page refresh
\ No newline at end of file
diff --git a/plugins/woocommerce/client/admin/client/settings-payments/components/buttons/settings-button.tsx b/plugins/woocommerce/client/admin/client/settings-payments/components/buttons/settings-button.tsx
index 12eccf614a..081df9e1a6 100644
--- a/plugins/woocommerce/client/admin/client/settings-payments/components/buttons/settings-button.tsx
+++ b/plugins/woocommerce/client/admin/client/settings-payments/components/buttons/settings-button.tsx
@@ -6,12 +6,17 @@ import { Button } from '@wordpress/components';
 import {
 	OfflinePaymentMethodProvider,
 	PaymentGatewayProvider,
+	PaymentsProviderType,
 } from '@woocommerce/data';
+import { useNavigate } from 'react-router-dom';

 /**
  * Internal dependencies
  */
-import { recordPaymentsProviderEvent } from '~/settings-payments/utils';
+import {
+	recordPaymentsProviderEvent,
+	removeOriginFromURL,
+} from '~/settings-payments/utils';

 interface SettingsButtonProps {
 	/**
@@ -43,6 +48,8 @@ export const SettingsButton = ( {
 	isInstallingPlugin,
 	buttonText = __( 'Manage', 'woocommerce' ),
 }: SettingsButtonProps ) => {
+	const isOffline = gatewayProvider._type === PaymentsProviderType.OfflinePm;
+	const navigate = useNavigate();
 	const recordButtonClickEvent = () => {
 		recordPaymentsProviderEvent( 'provider_manage_click', gatewayProvider );
 	};
@@ -50,9 +57,14 @@ export const SettingsButton = ( {
 	return (
 		<Button
 			variant={ 'secondary' }
-			href={ settingsHref }
+			href={ ! isOffline ? settingsHref : undefined }
 			disabled={ isInstallingPlugin }
-			onClick={ recordButtonClickEvent }
+			onClick={ () => {
+				recordButtonClickEvent();
+				if ( isOffline ) {
+					navigate( removeOriginFromURL( settingsHref ) );
+				}
+			} }
 		>
 			{ buttonText }
 		</Button>
diff --git a/plugins/woocommerce/client/admin/client/settings-payments/components/buttons/test/settings-button.test.tsx b/plugins/woocommerce/client/admin/client/settings-payments/components/buttons/test/settings-button.test.tsx
index 0a05e081c9..4a0c8f80ac 100644
--- a/plugins/woocommerce/client/admin/client/settings-payments/components/buttons/test/settings-button.test.tsx
+++ b/plugins/woocommerce/client/admin/client/settings-payments/components/buttons/test/settings-button.test.tsx
@@ -3,6 +3,7 @@
  */
 import { recordEvent } from '@woocommerce/tracks';
 import { render, fireEvent } from '@testing-library/react';
+import { MemoryRouter as Router } from 'react-router-dom';
 import {
 	PaymentGatewayProvider,
 	PaymentsProviderState,
@@ -22,35 +23,37 @@ jest.mock( '@woocommerce/tracks', () => ( {
 describe( 'SettingsButton', () => {
 	it( 'should record settings_payments_provider_manage_click event on click of the button', () => {
 		const { getByRole } = render(
-			<SettingsButton
-				gatewayProvider={
-					{
-						id: 'test-gateway',
-						state: {
-							enabled: true,
-							account_connected: false,
-							needs_setup: true,
-							test_mode: false,
-							dev_mode: false,
-						} as PaymentsProviderState,
-						onboarding: {
+			<Router>
+				<SettingsButton
+					gatewayProvider={
+						{
+							id: 'test-gateway',
 							state: {
-								started: true,
-								completed: false,
+								enabled: true,
+								account_connected: false,
+								needs_setup: true,
 								test_mode: false,
-							} as PaymentsProviderOnboardingState,
-						},
-						plugin: {
-							slug: 'test-plugin',
-							file: 'test-file',
-							status: 'installed',
-						} as PluginData,
-						_suggestion_id: 'test-suggestion',
-						_type: 'gateway',
-					} as PaymentGatewayProvider
-				}
-				settingsHref={ '' }
-			/>
+								dev_mode: false,
+							} as PaymentsProviderState,
+							onboarding: {
+								state: {
+									started: true,
+									completed: false,
+									test_mode: false,
+								} as PaymentsProviderOnboardingState,
+							},
+							plugin: {
+								slug: 'test-plugin',
+								file: 'test-file',
+								status: 'installed',
+							} as PluginData,
+							_suggestion_id: 'test-suggestion',
+							_type: 'gateway',
+						} as PaymentGatewayProvider
+					}
+					settingsHref={ '' }
+				/>
+			</Router>
 		);
 		fireEvent.click( getByRole( 'link', { name: 'Manage' } ) );
 		expect( recordEvent ).toHaveBeenCalledWith(
diff --git a/plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list/payment-gateway-list.tsx b/plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list/payment-gateway-list.tsx
index 6035290e52..ca55237abe 100644
--- a/plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list/payment-gateway-list.tsx
+++ b/plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list/payment-gateway-list.tsx
@@ -10,6 +10,7 @@ import {
 	PaymentsExtensionSuggestionProvider,
 } from '@woocommerce/data';
 import { Gridicon } from '@automattic/components';
+import { useNavigate } from 'react-router-dom';

 /**
  * Internal dependencies
@@ -22,6 +23,7 @@ import {
 import { PaymentExtensionSuggestionListItem } from '~/settings-payments/components/payment-extension-suggestion-list-item';
 import { PaymentGatewayListItem } from '~/settings-payments/components/payment-gateway-list-item';
 import './payment-gateway-list.scss';
+import { removeOriginFromURL } from '~/settings-payments/utils';

 interface PaymentGatewayListProps {
 	/**
@@ -86,6 +88,8 @@ export const PaymentGatewayList = ( {
 	updateOrdering,
 	setIsOnboardingModalOpen,
 }: PaymentGatewayListProps ) => {
+	const navigate = useNavigate();
+
 	return (
 		<SortableContainer< PaymentsProvider >
 			items={ providers }
@@ -146,8 +150,12 @@ export const PaymentGatewayList = ( {
 									id={ offlinePmsGroup.id }
 									className="transitions-disabled woocommerce-list__item clickable-list-item enter-done"
 									onClick={ () => {
-										window.location.href =
-											offlinePmsGroup.management._links.settings.href;
+										navigate(
+											removeOriginFromURL(
+												offlinePmsGroup.management
+													._links.settings.href
+											)
+										);
 									} }
 								>
 									<div className="woocommerce-list__item-inner">
diff --git a/plugins/woocommerce/client/admin/client/settings-payments/components/settings/settings.scss b/plugins/woocommerce/client/admin/client/settings-payments/components/settings/settings.scss
index 441b01c41a..0cc5bcde44 100644
--- a/plugins/woocommerce/client/admin/client/settings-payments/components/settings/settings.scss
+++ b/plugins/woocommerce/client/admin/client/settings-payments/components/settings/settings.scss
@@ -1,7 +1,3 @@
-.woocommerce-layout__header {
-	border-bottom: 1px solid $gray-200;
-}
-
 .settings-layout {
 	margin: 48px 12px 0;
 	display: flex;
diff --git a/plugins/woocommerce/client/admin/client/settings-payments/index.tsx b/plugins/woocommerce/client/admin/client/settings-payments/index.tsx
index 17eb13df97..ada17ae876 100644
--- a/plugins/woocommerce/client/admin/client/settings-payments/index.tsx
+++ b/plugins/woocommerce/client/admin/client/settings-payments/index.tsx
@@ -4,7 +4,7 @@
 import { Gridicon } from '@automattic/components';
 import { Button, Placeholder, SelectControl } from '@wordpress/components';
 import { paymentSettingsStore } from '@woocommerce/data';
-import { useSelect } from '@wordpress/data';
+import { useSelect, useDispatch } from '@wordpress/data';
 import React, {
 	useState,
 	lazy,
@@ -20,7 +20,6 @@ import {
 } from 'react-router-dom';
 import { getHistory, getNewPath } from '@woocommerce/navigation';
 import { __ } from '@wordpress/i18n';
-import { getAdminLink } from '@woocommerce/settings';
 import { recordEvent } from '@woocommerce/tracks';

 /**
@@ -96,6 +95,70 @@ const SettingsPaymentsChequeChunk = lazy(
 		)
 );

+interface OfflinePaymentGatewayWrapperProps {
+	title: string;
+	chunkComponent: React.ComponentType;
+}
+
+const OfflinePaymentGatewayWrapper = ( {
+	title,
+	chunkComponent: ChunkComponent,
+}: OfflinePaymentGatewayWrapperProps ) => {
+	const { invalidateResolution, invalidateResolutionForStoreSelector } =
+		useDispatch( paymentSettingsStore );
+
+	return (
+		<>
+			<div className="settings-payments-offline__container">
+				<div className="settings-payment-gateways">
+					<div className="settings-payments-offline__header">
+						<div
+							onClick={ () => {
+								// Invalidate the payment providers and offline payment gateways stores.
+								// This is to ensure that the data is refreshed when the user navigates back to the offline payment settings page.
+								invalidateResolution(
+									'getPaymentProviders',
+									[]
+								);
+								invalidateResolutionForStoreSelector(
+									'getOfflinePaymentGateways'
+								);
+							} }
+							role="button"
+							tabIndex={ 0 }
+							onKeyDown={ ( e ) => {
+								if ( e.key === 'Enter' ) {
+									invalidateResolutionForStoreSelector(
+										'getOfflinePaymentGateways'
+									);
+								}
+							} }
+						>
+							<BackButton
+								href={ getNewPath( {}, '/offline' ) }
+								title={ __(
+									'Return to payments settings',
+									'woocommerce'
+								) }
+								isRoute={ true }
+								from={ 'woopayments_payment_methods' }
+							/>
+						</div>
+						<h1 className="components-truncate components-text woocommerce-layout__header-heading woocommerce-layout__header-left-align settings-payments-offline__header-title">
+							<span className="woocommerce-settings-payments-header__title">
+								{ title }
+							</span>
+						</h1>
+					</div>
+					<Suspense fallback={ <Placeholder /> }>
+						<ChunkComponent />
+					</Suspense>
+				</div>
+			</div>
+		</>
+	);
+};
+
 /**
  * Hides or displays the WooCommerce navigation tab based on the provided display style.
  */
@@ -313,63 +376,37 @@ export const SettingsPaymentsMethods = () => {
 	);
 };

-/**
- * Wraps the main payment settings and payment methods settings pages.
- */
-export const SettingsPaymentsMainWrapper = () => {
-	return (
-		<>
-			<Header
-				title={ __( 'Settings', 'woocommerce' ) }
-				context={ 'wc_settings_payments__main' }
-			/>
-			<HistoryRouter history={ getHistory() }>
-				<Routes>
-					<Route
-						path="/payment-methods"
-						element={ <SettingsPaymentsMethods /> }
-					/>
-					<Route path="/*" element={ <SettingsPaymentsMain /> } />
-				</Routes>
-			</HistoryRouter>
-		</>
-	);
-};
-
 /**
  * Wraps the offline payment gateways settings page.
  */
 export const SettingsPaymentsOfflineWrapper = () => {
 	return (
 		<>
-			<Header
-				title={ __( 'Take offline payments', 'woocommerce' ) }
-				backLink={ getAdminLink(
-					'admin.php?page=wc-settings&tab=checkout'
-				) }
-				context={ 'wc_settings_payments__offline_pms' }
-			/>
-			<Suspense
-				fallback={
-					<>
-						<div className="settings-payments-offline__container">
-							<div className="settings-payment-gateways">
-								<div className="settings-payment-gateways__header">
-									<div className="settings-payment-gateways__header-title">
-										{ __(
-											'Payment methods',
-											'woocommerce'
-										) }
-									</div>
-								</div>
-								<ListPlaceholder rows={ 3 } />
-							</div>
-						</div>
-					</>
-				}
-			>
-				<SettingsPaymentsOfflineChunk />
-			</Suspense>
+			<div className="settings-payments-offline__container">
+				<div className="settings-payments-offline__header">
+					<BackButton
+						href={ getNewPath(
+							{ page: 'wc-settings', tab: 'checkout' },
+							'/',
+							{}
+						) }
+						title={ __(
+							'Return to payments settings',
+							'woocommerce'
+						) }
+						isRoute={ true }
+						from={ 'woopayments_payment_methods' }
+					/>
+					<h1 className="components-truncate components-text woocommerce-layout__header-heading woocommerce-layout__header-left-align">
+						<span className="woocommerce-settings-payments-header__title">
+							{ __( 'Take offline payments', 'woocommerce' ) }
+						</span>
+					</h1>
+				</div>
+				<Suspense fallback={ <ListPlaceholder rows={ 3 } /> }>
+					<SettingsPaymentsOfflineChunk />
+				</Suspense>
+			</div>
 		</>
 	);
 };
@@ -391,107 +428,59 @@ export const SettingsPaymentsWooPaymentsWrapper = () => {
 	);
 };

-export const SettingsPaymentsBacsWrapper = () => {
-	return (
-		<>
-			<Header
-				title={ __( 'Direct bank transfer', 'woocommerce' ) }
-				backLink={ getAdminLink(
-					'admin.php?page=wc-settings&tab=checkout&section=offline'
-				) }
-				context={ 'wc_settings_payments__offline_pms_bacs' }
-			/>
-			<Suspense
-				fallback={
-					<>
-						<div className="settings-payments-bacs__container">
-							<div className="settings-payment-gateways">
-								<div className="settings-payment-gateways__header">
-									<div className="settings-payment-gateways__header-title">
-										{ __(
-											'Direct bank transfer',
-											'woocommerce'
-										) }
-									</div>
-								</div>
-								<Placeholder />
-							</div>
-						</div>
-					</>
-				}
-			>
-				<SettingsPaymentsBacsChunk />
-			</Suspense>
-		</>
-	);
-};
+export const SettingsPaymentsBacsWrapper = () =>
+	OfflinePaymentGatewayWrapper( {
+		title: __( 'Direct bank transfer', 'woocommerce' ),
+		chunkComponent: SettingsPaymentsBacsChunk,
+	} );

-export const SettingsPaymentsCodWrapper = () => {
-	return (
-		<>
-			<Header
-				title={ __( 'Cash on delivery', 'woocommerce' ) }
-				backLink={ getAdminLink(
-					'admin.php?page=wc-settings&tab=checkout&section=offline'
-				) }
-				context={ 'wc_settings_payments__offline_pms_cod' }
-			/>
-			<Suspense
-				fallback={
-					<>
-						<div className="settings-payments-cod__container">
-							<div className="settings-payment-gateways">
-								<div className="settings-payment-gateways__header">
-									<div className="settings-payment-gateways__header-title">
-										{ __(
-											'Cash on delivery',
-											'woocommerce'
-										) }
-									</div>
-								</div>
-								<Placeholder />
-							</div>
-						</div>
-					</>
-				}
-			>
-				<SettingsPaymentsCodChunk />
-			</Suspense>
-		</>
-	);
-};
+export const SettingsPaymentsCodWrapper = () =>
+	OfflinePaymentGatewayWrapper( {
+		title: __( 'Cash on delivery', 'woocommerce' ),
+		chunkComponent: SettingsPaymentsCodChunk,
+	} );

-export const SettingsPaymentsChequeWrapper = () => {
+export const SettingsPaymentsChequeWrapper = () =>
+	OfflinePaymentGatewayWrapper( {
+		title: __( 'Check payments', 'woocommerce' ),
+		chunkComponent: SettingsPaymentsChequeChunk,
+	} );
+
+/**
+ * Wraps the main payment settings and payment methods settings pages.
+ */
+export const SettingsPaymentsMainWrapper = () => {
 	return (
 		<>
 			<Header
-				title={ __( 'Check payments', 'woocommerce' ) }
-				backLink={ getAdminLink(
-					'admin.php?page=wc-settings&tab=checkout&section=offline'
-				) }
-				context={ 'wc_settings_payments__offline_pms_cheque' }
+				title={ __( 'Settings', 'woocommerce' ) }
+				context={ 'wc_settings_payments__main' }
 			/>
-			<Suspense
-				fallback={
-					<>
-						<div className="settings-payments-cheque__container">
-							<div className="settings-payment-gateways">
-								<div className="settings-payment-gateways__header">
-									<div className="settings-payment-gateways__header-title">
-										{ __(
-											'Check payments',
-											'woocommerce'
-										) }
-									</div>
-								</div>
-								<Placeholder />
-							</div>
-						</div>
-					</>
-				}
-			>
-				<SettingsPaymentsChequeChunk />
-			</Suspense>
+			<HistoryRouter history={ getHistory() }>
+				<Routes>
+					<Route
+						path="/payment-methods"
+						element={ <SettingsPaymentsMethods /> }
+					/>
+					<Route
+						path="/offline"
+						element={ <SettingsPaymentsOfflineWrapper /> }
+					/>
+					<Route
+						path="/offline/bacs"
+						element={ <SettingsPaymentsBacsWrapper /> }
+					/>
+					<Route
+						path="/offline/cod"
+						element={ <SettingsPaymentsCodWrapper /> }
+					/>
+					<Route
+						path="/offline/cheque"
+						element={ <SettingsPaymentsChequeWrapper /> }
+					/>
+					<Route path="/*" element={ <SettingsPaymentsMain /> } />
+				</Routes>
+			</HistoryRouter>
 		</>
 	);
 };
diff --git a/plugins/woocommerce/client/admin/client/settings-payments/offline/settings-payments-bacs.tsx b/plugins/woocommerce/client/admin/client/settings-payments/offline/settings-payments-bacs.tsx
index 9beb3e9258..10159015bd 100644
--- a/plugins/woocommerce/client/admin/client/settings-payments/offline/settings-payments-bacs.tsx
+++ b/plugins/woocommerce/client/admin/client/settings-payments/offline/settings-payments-bacs.tsx
@@ -20,6 +20,7 @@ import { Settings } from '~/settings-payments/components/settings';
 import { FieldPlaceholder } from '~/settings-payments/components/field-placeholder';
 import { BankAccountsList } from '~/settings-payments/components/bank-accounts-list';
 import { BankAccount } from '~/settings-payments/components/bank-accounts-list/types';
+
 /**
  * This page is used to manage the settings for the BACS (Direct bank transfer) payment gateway.
  */
diff --git a/plugins/woocommerce/client/admin/client/settings-payments/settings-payments-body.scss b/plugins/woocommerce/client/admin/client/settings-payments/settings-payments-body.scss
index 067fb19eae..44240eb942 100644
--- a/plugins/woocommerce/client/admin/client/settings-payments/settings-payments-body.scss
+++ b/plugins/woocommerce/client/admin/client/settings-payments/settings-payments-body.scss
@@ -9,12 +9,12 @@ body.woocommerce-settings-payments-tab {
 	#wpcontent {
 		background-color: #fff;
 	}
+}

-	.woocommerce-layout .woocommerce-store-alerts {
-		margin-top: $gap-large;
-	}
+.settings-payments-offline__container {
+	margin: 0 -30px;

-	#wpbody.has-settings-layout {
-		margin-top: 60px !important;
+	.settings-layout {
+		margin: 0 48px 0;
 	}
 }
diff --git a/plugins/woocommerce/client/admin/client/settings-payments/settings-payments-main.scss b/plugins/woocommerce/client/admin/client/settings-payments/settings-payments-main.scss
index 355f2bd394..59dc93007e 100644
--- a/plugins/woocommerce/client/admin/client/settings-payments/settings-payments-main.scss
+++ b/plugins/woocommerce/client/admin/client/settings-payments/settings-payments-main.scss
@@ -492,3 +492,19 @@ body.woocommerce-settings-payments-tab {
 		width: 256px;
 	}
 }
+
+.settings-payments-offline__container {
+	.settings-payments-offline__header {
+		display: flex;
+		padding: 8px 48px 24px;
+		align-items: center;
+
+		h1 {
+			padding-left: $gap-smaller * 2;
+			// This is the same as the Payments settings header.
+			// This is used to keep the UI consistent across when navigating to the offline payments settings page.
+			line-height: 38px;
+			color: #3c434a;
+		}
+	}
+}
diff --git a/plugins/woocommerce/client/admin/client/settings-payments/settings-payments-offline.tsx b/plugins/woocommerce/client/admin/client/settings-payments/settings-payments-offline.tsx
index 6e3f9afc72..b0599c8793 100644
--- a/plugins/woocommerce/client/admin/client/settings-payments/settings-payments-offline.tsx
+++ b/plugins/woocommerce/client/admin/client/settings-payments/settings-payments-offline.tsx
@@ -66,7 +66,7 @@ export const SettingsPaymentsOffline = () => {
 	}

 	return (
-		<div className="settings-payments-offline__container">
+		<>
 			{ isFetching ? (
 				<ListPlaceholder rows={ 3 } />
 			) : (
@@ -77,7 +77,7 @@ export const SettingsPaymentsOffline = () => {
 					setGateways={ handleOrderingUpdate }
 				/>
 			) }
-		</div>
+		</>
 	);
 };

diff --git a/plugins/woocommerce/client/admin/client/settings-payments/test/settings-payments-main.test.tsx b/plugins/woocommerce/client/admin/client/settings-payments/test/settings-payments-main.test.tsx
index 31a5f62860..fdae6797e6 100644
--- a/plugins/woocommerce/client/admin/client/settings-payments/test/settings-payments-main.test.tsx
+++ b/plugins/woocommerce/client/admin/client/settings-payments/test/settings-payments-main.test.tsx
@@ -3,6 +3,7 @@
  */
 import { recordEvent } from '@woocommerce/tracks';
 import { render, fireEvent, screen } from '@testing-library/react';
+import { MemoryRouter as Router } from 'react-router-dom';

 /**
  * Internal dependencies
@@ -19,7 +20,11 @@ jest.mock( '~/utils/features', () => ( {

 describe( 'SettingsPaymentsMain', () => {
 	it( 'should record settings_payments_pageview event on load', () => {
-		render( <SettingsPaymentsMain /> );
+		render(
+			<Router>
+				<SettingsPaymentsMain />
+			</Router>
+		);

 		expect( recordEvent ).toHaveBeenCalledWith(
 			'settings_payments_pageview',
@@ -30,7 +35,11 @@ describe( 'SettingsPaymentsMain', () => {
 	} );

 	it( 'should trigger event recommendations_other_options when clicking the WooCommerce Marketplace link', () => {
-		render( <SettingsPaymentsMain /> );
+		render(
+			<Router>
+				<SettingsPaymentsMain />
+			</Router>
+		);

 		fireEvent.click( screen.getByText( 'the WooCommerce Marketplace' ) );

@@ -56,7 +65,11 @@ describe( 'SettingsPaymentsMain', () => {
 			value: mockLocation,
 		} );

-		render( <SettingsPaymentsMain /> );
+		render(
+			<Router>
+				<SettingsPaymentsMain />
+			</Router>
+		);

 		fireEvent.click( screen.getByText( 'the WooCommerce Marketplace' ) );

diff --git a/plugins/woocommerce/client/admin/client/settings-payments/utils.ts b/plugins/woocommerce/client/admin/client/settings-payments/utils.ts
index df33eb6d6f..f1b601bdec 100644
--- a/plugins/woocommerce/client/admin/client/settings-payments/utils.ts
+++ b/plugins/woocommerce/client/admin/client/settings-payments/utils.ts
@@ -9,6 +9,7 @@ import {
 import { getAdminLink } from '@woocommerce/settings';
 import apiFetch from '@wordpress/api-fetch';
 import { recordEvent } from '@woocommerce/tracks';
+import { parseAdminUrl } from '@woocommerce/navigation';

 /**
  * Internal dependencies
@@ -449,3 +450,20 @@ export const recordPaymentsOnboardingEvent = (

 	recordEvent( eventName, data );
 };
+
+/**
+ * Strips the origin from a URL. This is used for front-end navigation using react-router-dom.
+ *
+ * @example
+ * ```
+ * removeOriginFromURL( 'https://example.com/wp-admin/admin.php?page=wc-settings&tab=checkout&path=/offline' )
+ * // returns '/wp-admin/admin.php?page=wc-settings&tab=checkout&path=/offline'
+ * ```
+ *
+ * @param url The URL to strip the origin from.
+ * @return The URL with the origin stripped.
+ */
+export const removeOriginFromURL = ( url: string ) => {
+	const parsedUrl = parseAdminUrl( url );
+	return parsedUrl.href?.replace( parsedUrl.origin, '' ) ?? url;
+};
diff --git a/plugins/woocommerce/includes/admin/class-wc-admin.php b/plugins/woocommerce/includes/admin/class-wc-admin.php
index b4148bded7..a78946838d 100644
--- a/plugins/woocommerce/includes/admin/class-wc-admin.php
+++ b/plugins/woocommerce/includes/admin/class-wc-admin.php
@@ -141,7 +141,9 @@ class WC_Admin {
 	}

 	/**
-	 * Handle redirects to setup/welcome page after install and updates.
+	 * Handle redirects:
+	 * 1. To setup/welcome page after install and updates.
+	 * 2. To offline payment gateway(s) new settings page.
 	 *
 	 * The user must have access rights, and we must ignore the network/bulk plugin updaters.
 	 */
@@ -168,6 +170,37 @@ class WC_Admin {
 			exit;
 		}

+		// Check if we have a section parameter for offline payment gateways and redirect to the new path.
+		if ( ! empty( $_GET['section'] ) ) {
+			$section = wc_clean( wp_unslash( $_GET['section'] ) );
+
+			// Handle offline payment gateway(s) redirections.
+			if ( 'offline' === $section || WC_Gateway_BACS::ID === $section || WC_Gateway_COD::ID === $section || WC_Gateway_Cheque::ID === $section ) {
+				// Get current URL and remove source parameter.
+				$current_url = remove_query_arg( 'section' );
+
+				if ( 'offline' === $section ) {
+					$redirect_url = add_query_arg(
+						array(
+							'path' => '/offline',
+						),
+						$current_url,
+					);
+				} else {
+					$redirect_url = add_query_arg(
+						array(
+							'path' => '/offline/' . strtolower( $section ),
+						),
+						$current_url,
+					);
+				}
+
+				// Perform the redirect.
+				wp_safe_redirect( $redirect_url );
+				exit;
+			}
+		}
+
 		// phpcs:enable WordPress.Security.NonceVerification.Recommended
 	}

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 3dc1503243..92382647f9 100644
--- a/plugins/woocommerce/includes/gateways/bacs/class-wc-gateway-bacs.php
+++ b/plugins/woocommerce/includes/gateways/bacs/class-wc-gateway-bacs.php
@@ -485,4 +485,13 @@ class WC_Gateway_BACS extends WC_Payment_Gateway {
 		return $this->locale;

 	}
+
+	/**
+	 * Get the settings URL for the gateway.
+	 *
+	 * @return string
+	 */
+	public function get_settings_url() {
+		return admin_url( 'admin.php?page=wc-settings&tab=checkout&path=/offline/bacs' );
+	}
 }
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 9e27ff4a45..099f19d26b 100644
--- a/plugins/woocommerce/includes/gateways/cheque/class-wc-gateway-cheque.php
+++ b/plugins/woocommerce/includes/gateways/cheque/class-wc-gateway-cheque.php
@@ -169,4 +169,13 @@ class WC_Gateway_Cheque extends WC_Payment_Gateway {
 			'redirect' => $this->get_return_url( $order ),
 		);
 	}
+
+	/**
+	 * Get the settings URL for the gateway.
+	 *
+	 * @return string
+	 */
+	public function get_settings_url() {
+		return admin_url( 'admin.php?page=wc-settings&tab=checkout&path=/offline/cheque' );
+	}
 }
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 f7b7e8dd91..ee083988f9 100644
--- a/plugins/woocommerce/includes/gateways/cod/class-wc-gateway-cod.php
+++ b/plugins/woocommerce/includes/gateways/cod/class-wc-gateway-cod.php
@@ -367,4 +367,13 @@ class WC_Gateway_COD extends WC_Payment_Gateway {
 			echo wp_kses_post( wpautop( wptexturize( $this->instructions ) ) . PHP_EOL );
 		}
 	}
+
+	/**
+	 * Get the settings URL for the gateway.
+	 *
+	 * @return string
+	 */
+	public function get_settings_url() {
+		return admin_url( 'admin.php?page=wc-settings&tab=checkout&path=/offline/cod' );
+	}
 }
diff --git a/plugins/woocommerce/src/Internal/Admin/Settings/Payments.php b/plugins/woocommerce/src/Internal/Admin/Settings/Payments.php
index 0c5abdbaea..33105594bf 100644
--- a/plugins/woocommerce/src/Internal/Admin/Settings/Payments.php
+++ b/plugins/woocommerce/src/Internal/Admin/Settings/Payments.php
@@ -158,7 +158,7 @@ class Payments {
 				'management'  => array(
 					'_links' => array(
 						'settings' => array(
-							'href' => admin_url( 'admin.php?page=wc-settings&tab=checkout&section=offline' ),
+							'href' => admin_url( 'admin.php?page=wc-settings&tab=checkout&path=/offline' ),
 						),
 					),
 				),
diff --git a/plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/PaymentGateway.php b/plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/PaymentGateway.php
index 46c59772d2..97bd9d6828 100644
--- a/plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/PaymentGateway.php
+++ b/plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/PaymentGateway.php
@@ -11,6 +11,9 @@ use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
 use Throwable;
 use WC_HTTPS;
 use WC_Payment_Gateway;
+use WC_Gateway_BACS;
+use WC_Gateway_COD;
+use WC_Gateway_Cheque;

 defined( 'ABSPATH' ) || exit;

@@ -542,6 +545,17 @@ class PaymentGateway {
 			);
 		}

+		// Special handling for offline payment gateways to use the front-end navigation.
+		if ( WC_Gateway_BACS::ID === $payment_gateway->id || WC_Gateway_COD::ID === $payment_gateway->id || WC_Gateway_Cheque::ID === $payment_gateway->id ) {
+			return Utils::wc_payments_settings_url(
+				null,
+				array(
+					'path' => '/offline/' . strtolower( $payment_gateway->id ),
+					'from' => Payments::FROM_PAYMENTS_SETTINGS,
+				)
+			);
+		}
+
 		return Utils::wc_payments_settings_url(
 			null,
 			array(
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/payment-gateways.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/payment-gateways.php
index 592cd0c01b..f4b449542e 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/payment-gateways.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/payment-gateways.php
@@ -79,7 +79,7 @@ class Payment_Gateways_V2 extends WC_REST_Unit_Test_Case {
 				),
 				'needs_setup'            => false,
 				'post_install_scripts'   => array(),
-				'settings_url'           => 'http://' . WP_TESTS_DOMAIN . '/wp-admin/admin.php?page=wc-settings&tab=checkout&section=cheque',
+				'settings_url'           => 'http://' . WP_TESTS_DOMAIN . '/wp-admin/admin.php?page=wc-settings&tab=checkout&path=/offline/cheque',
 				'connection_url'         => '',
 				'setup_help_text'        => '',
 				'required_settings_keys' => array(),
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/payment-gateways.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/payment-gateways.php
index c242261bed..ae1fc927f1 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/payment-gateways.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/payment-gateways.php
@@ -82,7 +82,7 @@ class Payment_Gateways extends WC_REST_Unit_Test_Case {
 				),
 				'needs_setup'            => false,
 				'post_install_scripts'   => array(),
-				'settings_url'           => 'http://' . WP_TESTS_DOMAIN . '/wp-admin/admin.php?page=wc-settings&tab=checkout&section=cheque',
+				'settings_url'           => 'http://' . WP_TESTS_DOMAIN . '/wp-admin/admin.php?page=wc-settings&tab=checkout&path=/offline/cheque',
 				'connection_url'         => '',
 				'setup_help_text'        => '',
 				'required_settings_keys' => array(),
diff --git a/plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsRestControllerTest.php b/plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsRestControllerTest.php
index e3822d46de..75e3a57130 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsRestControllerTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsRestControllerTest.php
@@ -983,7 +983,7 @@ class PaymentsRestControllerTest extends WC_REST_Unit_Test_Case {
 				'management'  => array(
 					'_links' => array(
 						'settings' => array(
-							'href' => 'http://localhost:8888/wp-admin/admin.php?page=wc-settings&tab=checkout&section=bacs',
+							'href' => 'http://localhost:8888/wp-admin/admin.php?page=wc-settings&tab=checkout&path=/offline/bacs',
 						),
 					),
 				),
@@ -1019,7 +1019,7 @@ class PaymentsRestControllerTest extends WC_REST_Unit_Test_Case {
 				'management'  => array(
 					'_links' => array(
 						'settings' => array(
-							'href' => 'http://localhost:8888/wp-admin/admin.php?page=wc-settings&tab=checkout&section=cheque',
+							'href' => 'http://localhost:8888/wp-admin/admin.php?page=wc-settings&tab=checkout&path=/offline/cheque',
 						),
 					),
 				),
@@ -1055,7 +1055,7 @@ class PaymentsRestControllerTest extends WC_REST_Unit_Test_Case {
 				'management'  => array(
 					'_links' => array(
 						'settings' => array(
-							'href' => 'http://localhost:8888/wp-admin/admin.php?page=wc-settings&tab=checkout&section=cod',
+							'href' => 'http://localhost:8888/wp-admin/admin.php?page=wc-settings&tab=checkout&path=/offline/cod',
 						),
 					),
 				),