Commit d11149c813e for woocommerce
commit d11149c813e1e715627fdb3b4e29762ebad43e5f
Author: Seghir Nadir <nadir.seghir@gmail.com>
Date: Mon Jun 29 11:50:20 2026 +0100
Fix express payment methods wrongly flagged as incompatible in editor (#66017)
Match the editor's incompatible-gateway check on paymentMethodId (falling
back to name) instead of the store key, and thread paymentMethodId through
the stored express payment-method shape so a gateway whose client-side name
differs from its server-side gateway ID is no longer shown as incompatible.
diff --git a/docs/block-development/extensible-blocks/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md b/docs/block-development/extensible-blocks/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md
index 606324ba7b0..19e1fa19b34 100644
--- a/docs/block-development/extensible-blocks/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md
+++ b/docs/block-development/extensible-blocks/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md
@@ -71,7 +71,7 @@ const options = {
| `content` | ReactNode | React node output in the express payment method area when the block is rendered in the frontend. Receives props from the checkout payment method interface. | Yes |
| `edit` | ReactNode | React node output in the express payment method area when the block is rendered in the editor. Receives props from the payment method interface to checkout (with preview data). | Yes |
| `canMakePayment` | Function | Callback to determine whether the payment method should be available for the shopper. | Yes |
-| `paymentMethodId` | String | Identifier accompanying the checkout processing request to the server. Used to identify the payment method gateway class for processing the payment. | No |
+| `paymentMethodId` | String | Identifier accompanying the checkout processing request to the server. Used to identify the payment method gateway class for processing the payment. Should match the gateway's server-side ID, as it is also used to detect whether the gateway is compatible with the Checkout block in the editor. Defaults to the value of `name` when omitted. | No |
| `supports:features` | Array | Array of payment features supported by the gateway. Used to crosscheck if the payment method can be used for the cart content. Defaults to `['products']` if no value is provided. | No |
| `supports:style` | Array | This is an array of style variations supported by the express payment method. These are styles that are applied across all the active express payment buttons and can be controlled from the express payment block in the editor. Supported values for these are one of `['height', 'borderRadius']`. | No |
diff --git a/plugins/woocommerce/changelog/wooplug-6248-express-payment-incompatible-notice b/plugins/woocommerce/changelog/wooplug-6248-express-payment-incompatible-notice
new file mode 100644
index 00000000000..c43f12f0157
--- /dev/null
+++ b/plugins/woocommerce/changelog/wooplug-6248-express-payment-incompatible-notice
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix false "incompatible extension" notice shown in the block editor for express payment methods whose client-side `name` differs from their server-side gateway ID. The compatibility check now matches on `paymentMethodId` (falling back to `name`).
diff --git a/plugins/woocommerce/client/blocks/assets/js/data/payment/selectors.ts b/plugins/woocommerce/client/blocks/assets/js/data/payment/selectors.ts
index 60bf608dff6..13b3576fc08 100644
--- a/plugins/woocommerce/client/blocks/assets/js/data/payment/selectors.ts
+++ b/plugins/woocommerce/client/blocks/assets/js/data/payment/selectors.ts
@@ -131,14 +131,17 @@ export const getIncompatiblePaymentMethods = createSelector(
return {};
}
+ // Match express methods on `paymentMethodId` (falling back to `name`) rather
+ // than their store key, so a distinct client-side `name` isn't flagged.
+ const availableExpressPaymentMethodIds = Object.values(
+ availableExpressPaymentMethods
+ ).map( ( method ) => method.paymentMethodId ?? method.name );
+
return Object.fromEntries(
- Object.entries( globalPaymentMethods ).filter( ( [ k ] ) => {
+ Object.entries( globalPaymentMethods ).filter( ( [ id ] ) => {
return ! (
- k in
- {
- ...availablePaymentMethods,
- ...availableExpressPaymentMethods,
- }
+ id in availablePaymentMethods ||
+ availableExpressPaymentMethodIds.includes( id )
);
} )
);
diff --git a/plugins/woocommerce/client/blocks/assets/js/data/payment/test/selectors.js b/plugins/woocommerce/client/blocks/assets/js/data/payment/test/selectors.js
index 093fc718e09..5bc1b267a0e 100644
--- a/plugins/woocommerce/client/blocks/assets/js/data/payment/test/selectors.js
+++ b/plugins/woocommerce/client/blocks/assets/js/data/payment/test/selectors.js
@@ -26,7 +26,10 @@ import {
SavedPaymentMethodOptions,
} from '../../../blocks/cart-checkout-shared/payment-methods';
import { defaultCartState } from '../../cart/default-state';
-import { getRegisteredExpressPaymentMethods } from '../selectors';
+import {
+ getRegisteredExpressPaymentMethods,
+ getIncompatiblePaymentMethods,
+} from '../selectors';
jest.mock( '@wordpress/data', () => {
const originalModule = jest.requireActual( '@wordpress/data' );
@@ -76,6 +79,15 @@ jest.mock( '@woocommerce/settings', () => {
],
};
}
+ if ( setting === 'globalPaymentMethods' ) {
+ return [
+ {
+ id: 'woo-payment-gateway',
+ title: 'Woo Payment Gateway',
+ },
+ { id: 'stripe', title: 'Stripe' },
+ ];
+ }
return originalModule.getSetting( setting, ...rest );
},
};
@@ -502,4 +514,100 @@ describe( 'Payment Selectors Unit Tests', () => {
} );
} );
} );
+
+ describe( 'getIncompatiblePaymentMethods', () => {
+ // The mocked `globalPaymentMethods` setting (see jest.mock above) exposes
+ // two server-side gateways: `woo-payment-gateway` and `stripe`.
+ const buildState = ( {
+ availablePaymentMethods = {},
+ availableExpressPaymentMethods = {},
+ } ) => ( {
+ status: 'idle',
+ activePaymentMethod: '',
+ availablePaymentMethods,
+ availableExpressPaymentMethods,
+ registeredExpressPaymentMethods: {},
+ savedPaymentMethods: {},
+ paymentMethodData: {},
+ paymentResult: null,
+ paymentMethodsInitialized: true,
+ expressPaymentMethodsInitialized: true,
+ shouldSavePaymentMethod: false,
+ } );
+
+ it( 'does not flag an express method whose client-side name differs from its gateway id', () => {
+ const state = buildState( {
+ // Keyed by the client-side `name`, which differs from the
+ // server-side gateway id. The match must happen via
+ // `paymentMethodId`, not the key.
+ availableExpressPaymentMethods: {
+ woo_express: {
+ name: 'woo_express',
+ title: 'Woo Express',
+ description: '',
+ gatewayId: 'woo-payment-gateway',
+ paymentMethodId: 'woo-payment-gateway',
+ supportsStyle: [],
+ },
+ },
+ availablePaymentMethods: {
+ stripe: {
+ name: 'stripe',
+ title: 'Stripe',
+ description: '',
+ gatewayId: 'stripe',
+ supportsStyle: [],
+ },
+ },
+ } );
+
+ expect( getIncompatiblePaymentMethods( state ) ).toEqual( {} );
+ } );
+
+ it( 'falls back to `name` when an express method has no paymentMethodId', () => {
+ const state = buildState( {
+ availableExpressPaymentMethods: {
+ stripe: {
+ name: 'stripe',
+ title: 'Stripe',
+ description: '',
+ gatewayId: 'stripe',
+ // No paymentMethodId — should fall back to `name`.
+ paymentMethodId: undefined,
+ supportsStyle: [],
+ },
+ },
+ availablePaymentMethods: {
+ 'woo-payment-gateway': {
+ name: 'woo-payment-gateway',
+ title: 'Woo Payment Gateway',
+ description: '',
+ gatewayId: 'woo-payment-gateway',
+ supportsStyle: [],
+ },
+ },
+ } );
+
+ expect( getIncompatiblePaymentMethods( state ) ).toEqual( {} );
+ } );
+
+ it( 'still flags a server gateway that has no matching available method', () => {
+ const state = buildState( {
+ availablePaymentMethods: {
+ stripe: {
+ name: 'stripe',
+ title: 'Stripe',
+ description: '',
+ gatewayId: 'stripe',
+ supportsStyle: [],
+ },
+ },
+ availableExpressPaymentMethods: {},
+ } );
+
+ expect( getIncompatiblePaymentMethods( state ) ).toEqual( {
+ 'woo-payment-gateway': 'Woo Payment Gateway',
+ } );
+ } );
+ } );
} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/data/payment/utils/check-payment-methods.ts b/plugins/woocommerce/client/blocks/assets/js/data/payment/utils/check-payment-methods.ts
index 64d14c476ed..8edc1cb9e2f 100644
--- a/plugins/woocommerce/client/blocks/assets/js/data/payment/utils/check-payment-methods.ts
+++ b/plugins/woocommerce/client/blocks/assets/js/data/payment/utils/check-payment-methods.ts
@@ -177,8 +177,14 @@ export const checkPaymentMethodsCanPay = async ( express = false ) => {
| ExpressPaymentMethodConfigInstance
) => {
if ( express ) {
- const { name, title, description, gatewayId, supports } =
- paymentMethod as ExpressPaymentMethodConfigInstance;
+ const {
+ name,
+ title,
+ description,
+ gatewayId,
+ supports,
+ paymentMethodId,
+ } = paymentMethod as ExpressPaymentMethodConfigInstance;
availablePaymentMethods = {
...availablePaymentMethods,
@@ -187,6 +193,7 @@ export const checkPaymentMethodsCanPay = async ( express = false ) => {
title,
description,
gatewayId,
+ paymentMethodId: paymentMethodId ?? name,
supportsStyle: supports?.style,
},
};
diff --git a/plugins/woocommerce/client/blocks/assets/js/types/type-defs/payments.ts b/plugins/woocommerce/client/blocks/assets/js/types/type-defs/payments.ts
index 531fd9d146f..de16dff6b86 100644
--- a/plugins/woocommerce/client/blocks/assets/js/types/type-defs/payments.ts
+++ b/plugins/woocommerce/client/blocks/assets/js/types/type-defs/payments.ts
@@ -166,9 +166,15 @@ export type PlainPaymentMethods = Record<
>;
/**
- * Used to represent payment methods in a context where storing objects is not allowed, i.e. in data stores.
+ * Like `PlainPaymentMethods`, but express methods may also carry a `paymentMethodId`
+ * (the server-side gateway id, defaulting to `name`) for matching registered gateways.
*/
-export type PlainExpressPaymentMethods = PlainPaymentMethods;
+export type PlainExpressPaymentMethods = Record<
+ string,
+ PlainPaymentMethods[ string ] & {
+ paymentMethodId?: string;
+ }
+>;
export type ExpressPaymentMethods =
| Record< string, ExpressPaymentMethodConfigInstance >