Commit 0bc7bb2a4c3 for woocommerce

commit 0bc7bb2a4c37da44ad507d5fff6a90707feacb61
Author: Rubens Castro <orubenscastro@gmail.com>
Date:   Mon Oct 5 10:19:02 2026 -0300

    Add Checkout block incompatibility badge to Payments settings (#67601)

    * Add Checkout block incompatibility badge to Payments settings

    * Add changelog entry for Checkout block incompatibility badge

    * Remove trailing slash from documentation link anchor

    * Make Checkout block compatibility tests self-contained

    * Changes copy, removes underscore from badge icon

    * Update incompatibility tooltip copy to reference classic checkout

    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

    * Fix typo in incompatibility tooltip copy (Payments -> Payment)

    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

    * Re-trigger CI (flaky PHP 7.4 composer bin install race)

    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

    * Update plugins/woocommerce/src/Internal/Admin/Settings/PaymentsController.php

    Co-authored-by: Oleksandr Aratovskyi <79862886+oaratovskyi@users.noreply.github.com>

    * Update plugins/woocommerce/src/Internal/Admin/Settings/PaymentsController.php

    Co-authored-by: Oleksandr Aratovskyi <79862886+oaratovskyi@users.noreply.github.com>

    * Update plugins/woocommerce/src/Internal/Admin/Settings/PaymentsController.php

    Co-authored-by: Oleksandr Aratovskyi <79862886+oaratovskyi@users.noreply.github.com>

    * Update plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsControllerTest.php

    Co-authored-by: Oleksandr Aratovskyi <79862886+oaratovskyi@users.noreply.github.com>

    * Update plugins/woocommerce/client/admin/client/settings-payments/settings-payments-main.scss

    Co-authored-by: Oleksandr Aratovskyi <79862886+oaratovskyi@users.noreply.github.com>

    * Update plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list-item/test/payment-gateway-list-item.test.tsx

    Co-authored-by: Oleksandr Aratovskyi <79862886+oaratovskyi@users.noreply.github.com>

    * Update plugins/woocommerce/changelog/62707-add-payment-gateway-checkout-compatibility-warning

    Co-authored-by: Oleksandr Aratovskyi <79862886+oaratovskyi@users.noreply.github.com>

    * Update plugins/woocommerce/client/admin/client/typings/global.d.ts

    Co-authored-by: Oleksandr Aratovskyi <79862886+oaratovskyi@users.noreply.github.com>

    * Update plugins/woocommerce/src/Internal/Admin/Settings/PaymentsController.php

    Co-authored-by: Oleksandr Aratovskyi <79862886+oaratovskyi@users.noreply.github.com>

    * Update plugins/woocommerce/src/Internal/Admin/Settings/PaymentsController.php

    Co-authored-by: Oleksandr Aratovskyi <79862886+oaratovskyi@users.noreply.github.com>

    * Remove unnecessary delete_option line

    * Address payment gateway compatibility review feedback

    * Fix payment gateway compatibility test formatting

    * Fix prettier formatting in payment gateway list item

    * Remove external link style override from status badge popover

    * Use the design system Link in the compatibility badge popover

    * Match the compatibility popover link to the page's Link pattern

    ---------

    Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
    Co-authored-by: Oleksandr Aratovskyi <79862886+oaratovskyi@users.noreply.github.com>

diff --git a/plugins/woocommerce/changelog/62707-add-payment-gateway-checkout-compatibility-warning b/plugins/woocommerce/changelog/62707-add-payment-gateway-checkout-compatibility-warning
new file mode 100644
index 00000000000..07a5c5b0657
--- /dev/null
+++ b/plugins/woocommerce/changelog/62707-add-payment-gateway-checkout-compatibility-warning
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Show a "Limited compatibility" badge on the Payments settings page when an enabled payment gateway has no Checkout block integration.
diff --git a/plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list-item/payment-gateway-list-item.tsx b/plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list-item/payment-gateway-list-item.tsx
index 81189466e88..2316eee8fb1 100644
--- a/plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list-item/payment-gateway-list-item.tsx
+++ b/plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list-item/payment-gateway-list-item.tsx
@@ -6,6 +6,8 @@ import { __ } from '@wordpress/i18n';
 import { decodeEntities } from '@wordpress/html-entities';
 import { PaymentGatewayProvider } from '@woocommerce/data';
 import { Tooltip } from '@wordpress/components';
+import { createInterpolateElement } from '@wordpress/element';
+import { Link } from '@woocommerce/components';

 /**
  * Internal dependencies
@@ -49,6 +51,13 @@ export const PaymentGatewayListItem = ( {
 	const itemIsWooPayments = isWooPayments( gateway.id );
 	const incentive = hasIncentive( gateway ) ? gateway._incentive : null;

+	const isIncompatibleWithCheckoutBlock =
+		gateway.state.enabled &&
+		(
+			window.wcSettings?.admin?.woocommerce_checkout_block_compatibility
+				?.incompatible_gateway_ids ?? []
+		).includes( gateway.id );
+
 	const gatewayHasRecommendedPaymentMethods =
 		( gateway.onboarding?.recommended_payment_methods ?? [] ).length > 0;

@@ -153,6 +162,37 @@ export const PaymentGatewayListItem = ( {
 								popoverContent={ determineGatewayStatusMessage() }
 							/>
 						) }
+						{ isIncompatibleWithCheckoutBlock && (
+							<StatusBadge
+								status="not_supported"
+								message={ __(
+									'Limited compatibility',
+									'woocommerce'
+								) }
+								popoverContent={
+									<p>
+										{ createInterpolateElement(
+											__(
+												'Payment methods from this provider will only appear on classic checkout. <a>Learn more</a>',
+												'woocommerce'
+											),
+											{
+												a: (
+													<Link
+														href="https://woocommerce.com/document/woocommerce-store-editing/customizing-cart-and-checkout/#incompatible-extensions"
+														target="_blank"
+														rel="noreferrer"
+														type="external"
+													>
+														{ null }
+													</Link>
+												),
+											}
+										) }
+									</p>
+								}
+							/>
+						) }
 						{ /* If the gateway has a matching suggestion, it is an official extension. */ }
 						{ gateway._suggestion_id && (
 							<OfficialBadge
diff --git a/plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list-item/test/payment-gateway-list-item.test.tsx b/plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list-item/test/payment-gateway-list-item.test.tsx
index cc5d0210da0..26ccaa16021 100644
--- a/plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list-item/test/payment-gateway-list-item.test.tsx
+++ b/plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list-item/test/payment-gateway-list-item.test.tsx
@@ -31,13 +31,15 @@ jest.mock( '~/lib/sanitize-html', () => ( {
 jest.mock( '~/settings-payments/components/status-badge', () => ( {
 	StatusBadge: ( {
 		status,
+		message,
 		popoverContent,
 	}: {
 		status: string;
+		message?: string;
 		popoverContent?: React.ReactNode;
 	} ) => (
 		<div data-testid="status-badge" data-status={ status }>
-			StatusBadge-{ status }
+			{ message || `StatusBadge-${ status }` }
 			{ popoverContent && (
 				<div data-testid="status-badge-popover">{ popoverContent }</div>
 			) }
@@ -46,37 +48,34 @@ jest.mock( '~/settings-payments/components/status-badge', () => ( {
 } ) );

 jest.mock( '~/settings-payments/components/ellipsis-menu-content', () => ( {
-	// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Mock is used by PaymentGatewayListItem component
 	EllipsisMenuWrapper: ( { provider }: { provider: { id: string } } ) => (
 		<div data-testid="ellipsis-menu">EllipsisMenu-{ provider.id }</div>
 	),
 } ) );

 jest.mock( '~/settings-payments/components/sortable', () => ( {
-	// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Mock is used by PaymentGatewayListItem component
 	DefaultDragHandle: () => <div data-testid="drag-handle">DragHandle</div>,
 } ) );

 jest.mock( '~/settings-payments/components/buttons', () => ( {
-	// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Mock is used by PaymentGatewayListItem component
 	ActivatePaymentsButton: ( { incentive }: { incentive?: unknown } ) => (
 		<button data-testid="activate-payments-button">
 			ActivatePayments{ incentive ? '-with-incentive' : '' }
 		</button>
 	),
-	// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Mock is used by PaymentGatewayListItem component
+
 	CompleteSetupButton: ( { disabled }: { disabled?: boolean } ) => (
 		<button data-testid="complete-setup-button" disabled={ disabled }>
 			CompleteSetup
 		</button>
 	),
-	// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Mock is used by PaymentGatewayListItem component
+
 	EnableGatewayButton: ( { incentive }: { incentive?: unknown } ) => (
 		<button data-testid="enable-gateway-button">
 			Enable{ incentive ? '-with-incentive' : '' }
 		</button>
 	),
-	// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Mock is used by PaymentGatewayListItem component
+
 	SettingsButton: () => (
 		<button data-testid="settings-button">Settings</button>
 	),
@@ -85,7 +84,6 @@ jest.mock( '~/settings-payments/components/buttons', () => ( {
 jest.mock(
 	'~/settings-payments/components/buttons/reactivate-live-payments-button',
 	() => ( {
-		// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Mock is used by PaymentGatewayListItem component
 		ReactivateLivePaymentsButton: () => (
 			<button data-testid="reactivate-live-payments-button">
 				ReactivateLivePayments
@@ -95,20 +93,19 @@ jest.mock(
 );

 jest.mock( '~/settings-payments/components/incentive-status-badge', () => ( {
-	// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Mock is used by PaymentGatewayListItem component
 	IncentiveStatusBadge: ( { incentive }: { incentive: { id: string } } ) => (
 		<div data-testid="incentive-badge">Incentive-{ incentive.id }</div>
 	),
 } ) );

 jest.mock( '~/settings-payments/components/official-badge', () => ( {
-	// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Mock is used by PaymentGatewayListItem component
 	OfficialBadge: ( { suggestionId }: { suggestionId: string } ) => (
 		<div data-testid="official-badge">Official-{ suggestionId }</div>
 	),
 } ) );

 jest.mock( '@wordpress/components', () => ( {
+	...jest.requireActual( '@wordpress/components' ),
 	Tooltip: ( { children }: { children: React.ReactNode } ) => (
 		<div>{ children }</div>
 	),
@@ -623,6 +620,151 @@ describe( 'PaymentGatewayListItem', () => {
 		} );
 	} );

+	describe( 'Checkout Block Incompatibility Badge', () => {
+		const enabledGatewayState = {
+			enabled: true,
+			account_connected: true,
+			needs_setup: false,
+			test_mode: false,
+			dev_mode: false,
+		};
+
+		const onboardedGateway = {
+			state: {
+				supported: true,
+				started: true,
+				completed: true,
+				test_mode: false,
+			},
+			messages: {},
+			_links: {
+				onboard: { href: '/onboard' },
+				reset: { href: '/reset' },
+			},
+			recommended_payment_methods: [],
+			type: 'standard',
+		};
+
+		const setIncompatibleGatewayIds = ( ids: string[] ) => {
+			window.wcSettings.admin.woocommerce_checkout_block_compatibility = {
+				incompatible_gateway_ids: ids,
+			};
+		};
+
+		afterEach( () => {
+			delete window.wcSettings.admin
+				.woocommerce_checkout_block_compatibility;
+		} );
+
+		it( 'shows the badge when an enabled gateway is incompatible', () => {
+			setIncompatibleGatewayIds( [ 'test-gateway' ] );
+			const gateway = createMockGateway( {
+				state: enabledGatewayState,
+				onboarding: onboardedGateway,
+			} );
+			const { getByText, getAllByTestId } = render(
+				<PaymentGatewayListItem
+					gateway={ gateway }
+					{ ...defaultProps }
+				/>
+			);
+
+			expect( getByText( 'Limited compatibility' ) ).toBeInTheDocument();
+			expect(
+				getAllByTestId( 'status-badge' ).map( ( badge ) =>
+					badge.getAttribute( 'data-status' )
+				)
+			).toEqual( [ 'active', 'not_supported' ] );
+		} );
+
+		it( 'explains the incompatibility in the badge popover', () => {
+			setIncompatibleGatewayIds( [ 'test-gateway' ] );
+			const gateway = createMockGateway( {
+				state: enabledGatewayState,
+			} );
+			const { getByTestId } = render(
+				<PaymentGatewayListItem
+					gateway={ gateway }
+					{ ...defaultProps }
+				/>
+			);
+
+			expect( getByTestId( 'status-badge-popover' ) ).toHaveTextContent(
+				'Payment methods from this provider will only appear on classic checkout.'
+			);
+		} );
+
+		it( 'links to the incompatible extensions documentation from the popover', () => {
+			setIncompatibleGatewayIds( [ 'test-gateway' ] );
+			const gateway = createMockGateway( {
+				state: enabledGatewayState,
+			} );
+			const { getByRole } = render(
+				<PaymentGatewayListItem
+					gateway={ gateway }
+					{ ...defaultProps }
+				/>
+			);
+
+			expect(
+				getByRole( 'link', { name: /Learn more/ } )
+			).toHaveAttribute(
+				'href',
+				'https://woocommerce.com/document/woocommerce-store-editing/customizing-cart-and-checkout/#incompatible-extensions'
+			);
+		} );
+
+		it( 'does not show the badge when the gateway is not incompatible', () => {
+			setIncompatibleGatewayIds( [ 'another-gateway' ] );
+			const gateway = createMockGateway( {
+				state: enabledGatewayState,
+			} );
+			const { queryByText } = render(
+				<PaymentGatewayListItem
+					gateway={ gateway }
+					{ ...defaultProps }
+				/>
+			);
+
+			expect(
+				queryByText( 'Limited compatibility' )
+			).not.toBeInTheDocument();
+		} );
+
+		it( 'does not show the badge when the incompatible gateway is disabled', () => {
+			setIncompatibleGatewayIds( [ 'test-gateway' ] );
+			const gateway = createMockGateway( {
+				state: { ...enabledGatewayState, enabled: false },
+			} );
+			const { queryByText } = render(
+				<PaymentGatewayListItem
+					gateway={ gateway }
+					{ ...defaultProps }
+				/>
+			);
+
+			expect(
+				queryByText( 'Limited compatibility' )
+			).not.toBeInTheDocument();
+		} );
+
+		it( 'does not show the badge when no compatibility data is preloaded', () => {
+			const gateway = createMockGateway( {
+				state: enabledGatewayState,
+			} );
+			const { queryByText } = render(
+				<PaymentGatewayListItem
+					gateway={ gateway }
+					{ ...defaultProps }
+				/>
+			);
+
+			expect(
+				queryByText( 'Limited compatibility' )
+			).not.toBeInTheDocument();
+		} );
+	} );
+
 	describe( 'Badge Rendering', () => {
 		it( 'shows OfficialBadge when _suggestion_id exists', () => {
 			const gateway = createMockGateway( {
diff --git a/plugins/woocommerce/client/admin/client/typings/global.d.ts b/plugins/woocommerce/client/admin/client/typings/global.d.ts
index ace9d9b9249..2a970a228ab 100644
--- a/plugins/woocommerce/client/admin/client/typings/global.d.ts
+++ b/plugins/woocommerce/client/admin/client/typings/global.d.ts
@@ -78,6 +78,9 @@ declare global {
 				woocommerce_payments_nox_profile?: {
 					business_country_code: string;
 				};
+				woocommerce_checkout_block_compatibility?: {
+					incompatible_gateway_ids: string[];
+				};
 				wcpay_welcome_page_connect_nonce: string;
 				currentUserData: {
 					first_name: string;
diff --git a/plugins/woocommerce/src/Internal/Admin/Settings/PaymentsController.php b/plugins/woocommerce/src/Internal/Admin/Settings/PaymentsController.php
index f8941344fc3..e9cac7ce279 100644
--- a/plugins/woocommerce/src/Internal/Admin/Settings/PaymentsController.php
+++ b/plugins/woocommerce/src/Internal/Admin/Settings/PaymentsController.php
@@ -3,6 +3,9 @@ declare( strict_types=1 );

 namespace Automattic\WooCommerce\Internal\Admin\Settings;

+use Automattic\WooCommerce\Blocks\Package as BlocksPackage;
+use Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry;
+use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
 use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\WooPayments\WooPaymentsService;
 use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
 use Throwable;
@@ -147,9 +150,41 @@ class PaymentsController {
 		}
 		$settings[ Payments::PAYMENTS_NOX_PROFILE_KEY ]['business_country_code'] = $this->payments->get_country();

+		global $current_tab;
+
+		// Add the gateways that are not available in the Checkout block, but only when the store uses it.
+		if ( 'checkout' === $current_tab && CartCheckoutUtils::is_checkout_block_default() ) {
+			$settings['woocommerce_checkout_block_compatibility'] = array(
+				'incompatible_gateway_ids' => $this->get_gateway_ids_incompatible_with_checkout_block(),
+			);
+		}
+
 		return $settings;
 	}

+	/**
+	 * Get the IDs of the payment gateways that have no Checkout block payment method integration.
+	 *
+	 * The enabled state of the gateways is not taken into account.
+	 *
+	 * Matching is by integration name: a gateway counts as compatible when a registered
+	 * Checkout block payment method integration has the same name as the gateway ID.
+	 * Integrations registered only on the front end are not visible here, so their gateways are listed too.
+	 *
+	 * @return string[] The list of gateway IDs.
+	 */
+	private function get_gateway_ids_incompatible_with_checkout_block(): array {
+		$registered_payment_method_names = array_map(
+			static fn( $payment_method ) => $payment_method->get_name(),
+			BlocksPackage::container()->get( PaymentMethodRegistry::class )->get_all_registered()
+		);
+
+		// `payment_gateways()` is keyed by gateway ID; pluck the IDs as a plain list for the diff below.
+		$gateway_ids = wp_list_pluck( WC()->payment_gateways()->payment_gateways(), 'id' );
+
+		return array_values( array_diff( $gateway_ids, $registered_payment_method_names ) );
+	}
+
 	/**
 	 * Adds promo note IDs to the list of allowed ones.
 	 *
diff --git a/plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsControllerTest.php b/plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsControllerTest.php
new file mode 100644
index 00000000000..315d12fbf4e
--- /dev/null
+++ b/plugins/woocommerce/tests/php/src/Internal/Admin/Settings/PaymentsControllerTest.php
@@ -0,0 +1,259 @@
+<?php
+declare( strict_types=1 );
+
+namespace Automattic\WooCommerce\Tests\Internal\Admin\Settings;
+
+use Automattic\WooCommerce\Blocks\Package as BlocksPackage;
+use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
+use Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry;
+use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsController;
+use Automattic\WooCommerce\Tests\Internal\Admin\Settings\Mocks\FakePaymentGateway;
+use WC_Unit_Test_Case;
+
+/**
+ * Tests for the PaymentsController class.
+ */
+class PaymentsControllerTest extends WC_Unit_Test_Case {
+
+	/**
+	 * The System Under Test.
+	 *
+	 * @var PaymentsController
+	 */
+	private $sut;
+
+	/**
+	 * The ID of the checkout page created for the test.
+	 *
+	 * @var int
+	 */
+	private $checkout_page_id;
+
+	/**
+	 * The callback used to register the fake gateway, if any.
+	 *
+	 * @var callable|null
+	 */
+	private $gateways_filter_callback = null;
+
+	/**
+	 * The names of the Checkout block payment method integrations registered by the test.
+	 *
+	 * @var string[]
+	 */
+	private $registered_integration_names = array();
+
+	/**
+	 * Set up test fixtures.
+	 */
+	public function setUp(): void {
+		parent::setUp();
+
+		set_current_screen( 'woocommerce_page_wc-settings' );
+		$GLOBALS['current_tab'] = 'checkout';
+
+		$this->checkout_page_id = $this->factory->post->create(
+			array(
+				'post_type'    => 'page',
+				'post_content' => '<!-- wp:woocommerce/checkout --><!-- /wp:woocommerce/checkout -->',
+			)
+		);
+		update_option( 'woocommerce_checkout_page_id', $this->checkout_page_id );
+
+		$this->sut = wc_get_container()->get( PaymentsController::class );
+	}
+
+	/**
+	 * Tear down test fixtures.
+	 */
+	public function tearDown(): void {
+		unset( $GLOBALS['current_tab'] );
+		set_current_screen( 'front' );
+
+		if ( null !== $this->gateways_filter_callback ) {
+			remove_filter( 'woocommerce_payment_gateways', $this->gateways_filter_callback );
+			$this->gateways_filter_callback = null;
+		}
+		WC()->payment_gateways()->payment_gateways = array();
+		WC()->payment_gateways()->init();
+
+		foreach ( $this->registered_integration_names as $name ) {
+			if ( $this->get_payment_method_registry()->is_registered( $name ) ) {
+				$this->get_payment_method_registry()->unregister( $name );
+			}
+		}
+		$this->registered_integration_names = array();
+
+		parent::tearDown();
+	}
+
+	/**
+	 * @testdox Should list gateways that have no Checkout block payment method integration.
+	 */
+	public function test_preload_settings_lists_gateways_without_a_checkout_block_integration(): void {
+		$this->register_fake_gateway();
+		$this->register_fake_block_payment_integration( 'other-fake-gateway-id' );
+
+		$settings = $this->sut->preload_settings();
+
+		$this->assertContains(
+			'fake-gateway-id',
+			$settings['woocommerce_checkout_block_compatibility']['incompatible_gateway_ids'],
+			'A gateway without a Checkout block integration should be reported as incompatible'
+		);
+	}
+
+	/**
+	 * @testdox Should not list gateways that have a Checkout block payment method integration.
+	 */
+	public function test_preload_settings_skips_gateways_with_a_checkout_block_integration(): void {
+		$this->register_fake_gateway();
+		$this->register_fake_block_payment_integration( 'fake-gateway-id' );
+
+		$settings = $this->sut->preload_settings();
+
+		$this->assertNotContains(
+			'fake-gateway-id',
+			$settings['woocommerce_checkout_block_compatibility']['incompatible_gateway_ids'],
+			'A gateway with a Checkout block integration should not be reported as incompatible'
+		);
+	}
+
+	/**
+	 * @testdox Should list incompatible gateways regardless of them being enabled.
+	 */
+	public function test_preload_settings_lists_incompatible_gateways_that_are_disabled(): void {
+		$this->register_fake_gateway( 'no' );
+		$this->register_fake_block_payment_integration( 'other-fake-gateway-id' );
+
+		$settings = $this->sut->preload_settings();
+
+		$this->assertContains(
+			'fake-gateway-id',
+			$settings['woocommerce_checkout_block_compatibility']['incompatible_gateway_ids'],
+			'The enabled state of a gateway should not influence the compatibility list'
+		);
+	}
+
+	/**
+	 * @testdox Should not add compatibility data when the checkout page does not use the Checkout block.
+	 */
+	public function test_preload_settings_adds_no_compatibility_data_for_the_classic_checkout(): void {
+		wp_update_post(
+			array(
+				'ID'           => $this->checkout_page_id,
+				'post_content' => '<!-- wp:shortcode -->[woocommerce_checkout]<!-- /wp:shortcode -->',
+			)
+		);
+		$this->register_fake_gateway();
+
+		$settings = $this->sut->preload_settings();
+
+		$this->assertArrayNotHasKey(
+			'woocommerce_checkout_block_compatibility',
+			$settings,
+			'Stores on the classic checkout should not receive compatibility data'
+		);
+	}
+
+	/**
+	 * @testdox Should not add compatibility data outside of the payments settings tab.
+	 */
+	public function test_preload_settings_adds_no_compatibility_data_outside_the_payments_tab(): void {
+		$GLOBALS['current_tab'] = 'general';
+		$this->register_fake_gateway();
+
+		$settings = $this->sut->preload_settings();
+
+		$this->assertArrayNotHasKey(
+			'woocommerce_checkout_block_compatibility',
+			$settings,
+			'Compatibility data is only needed by the payments settings page'
+		);
+	}
+
+	/**
+	 * @testdox Should not list gateways whose Checkout block integration only sets its name in initialize().
+	 */
+	public function test_preload_settings_skips_gateways_whose_integration_is_named_on_initialize(): void {
+		$this->register_fake_gateway();
+
+		// Like WooPayments: `$name` stays at the default '' when the registry keys it in register(),
+		// and is only assigned once initialize() runs.
+		$integration = new class() extends AbstractPaymentMethodType {
+			/**
+			 * Initializes the payment method type.
+			 */
+			public function initialize() {
+				$this->name = 'fake-gateway-id';
+			}
+		};
+
+		$this->get_payment_method_registry()->register( $integration );
+		$integration->initialize();
+
+		// The registry keyed it under the default empty name, so that is what teardown must unregister.
+		$this->registered_integration_names[] = '';
+
+		$settings = $this->sut->preload_settings();
+
+		$this->assertNotContains(
+			'fake-gateway-id',
+			$settings['woocommerce_checkout_block_compatibility']['incompatible_gateway_ids'],
+			'A gateway whose integration only sets its name in initialize() should not be reported as incompatible'
+		);
+	}
+
+	/**
+	 * Add a gateway without a Checkout block integration to the list of loaded gateways.
+	 *
+	 * @param string $enabled Whether the gateway is enabled: 'yes' or 'no'.
+	 */
+	private function register_fake_gateway( string $enabled = 'yes' ): void {
+		$this->gateways_filter_callback = function ( $gateways ) use ( $enabled ) {
+			$gateway          = new FakePaymentGateway();
+			$gateway->enabled = $enabled;
+			$gateways[]       = $gateway;
+
+			return $gateways;
+		};
+		add_filter( 'woocommerce_payment_gateways', $this->gateways_filter_callback );
+
+		WC()->payment_gateways()->init();
+	}
+
+	/**
+	 * Register a minimal Checkout block payment method integration.
+	 *
+	 * @param string $name The integration name, matching the gateway ID it stands for.
+	 */
+	private function register_fake_block_payment_integration( string $name ): void {
+		$integration = new class( $name ) extends AbstractPaymentMethodType {
+			/**
+			 * Constructor.
+			 *
+			 * @param string $name The integration name.
+			 */
+			public function __construct( string $name ) {
+				$this->name = $name;
+			}
+
+			/**
+			 * Initializes the payment method type.
+			 */
+			public function initialize() {}
+		};
+
+		$this->get_payment_method_registry()->register( $integration );
+		$this->registered_integration_names[] = $name;
+	}
+
+	/**
+	 * Get the Checkout block payment method registry.
+	 *
+	 * @return PaymentMethodRegistry
+	 */
+	private function get_payment_method_registry(): PaymentMethodRegistry {
+		return BlocksPackage::container()->get( PaymentMethodRegistry::class );
+	}
+}