The Problem
Migrated a client's marketplace from the shortcode checkout to the WooCommerce checkout block last week. Stripe and PayPal showed up fine. Their custom bank-transfer gateway, a paid plugin that had been working for two years, disappeared from the payment options list. The admin settings still showed it as enabled. The classic [woocommerce_checkout] shortcode still rendered it. The block did not.
Site Health had no errors. The console threw one:
Uncaught TypeError: Cannot read properties of undefined (reading 'register')
at registerPaymentMethod (blocks-registry.js:42)
Disabling the block and going back to the shortcode brought the gateway back. Re-enabling the block hid it again. That is the symptom that tells you the gateway never registered itself with the Blocks checkout. The React-based checkout uses a completely separate registration layer from the classic PHP checkout, and a gateway that only knows about the old one is invisible to the new one.
Why It Happens
The classic WooCommerce checkout calls every gateway's process_payment() and payment_fields() methods through PHP. The block checkout, default since WooCommerce 10.7, renders entirely in React. It loads payment methods from a JavaScript registry, not from PHP.
A gateway plugin written before the block became default usually has nothing in that registry. The plugin author extended WC_Payment_Gateway correctly, registered the class through woocommerce_payment_gateways, and stopped. That is the old contract. The new contract requires a second class that implements AbstractPaymentMethodType from @woocommerce/blocks-registry and a script that calls registerPaymentMethod with a React component for the checkout UI.
When that second class is missing, the gateway exists on the server but is invisible to the block. Plugins that ship a half-finished integration (a PHP class with no script enqueue, or a script that registers but does not pass an edit component) throw the undefined.register console error because the registry rejects the payload.
The block-based checkout payment integration guide has the full contract. The short version is below.
The Fix
Add a Blocks integration alongside the existing classic gateway. Three pieces: a PHP class that registers the method type, a JS file that registers the React component, and a hook that wires both into WooCommerce.
1. The PHP integration class. Put it in includes/class-mygateway-blocks.php:
use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
final class MyGateway_Blocks extends AbstractPaymentMethodType {
protected $name = 'mygateway';
public function initialize() {
$this->settings = get_option('woocommerce_mygateway_settings', []);
}
public function is_active() {
return ($this->settings['enabled'] ?? 'no') === 'yes';
}
public function get_payment_method_script_handles() {
wp_register_script(
'mygateway-blocks',
plugins_url('assets/js/blocks.js', __FILE__),
['wc-blocks-registry', 'wp-element', 'wp-i18n'],
'1.0.0',
true
);
return ['mygateway-blocks'];
}
public function get_payment_method_data() {
return [
'title' => $this->settings['title'] ?? 'Bank Transfer',
'description' => $this->settings['description'] ?? '',
'supports' => ['products'],
];
}
}
2. The JS file at assets/js/blocks.js. This is what the registry actually consumes:
const { registerPaymentMethod } = window.wc.wcBlocksRegistry;
const { getSetting } = window.wc.wcSettings;
const { createElement } = window.wp.element;
const settings = getSetting('mygateway_data', {});
const Content = () => createElement('div', null, settings.description);
registerPaymentMethod({
name: 'mygateway',
label: settings.title,
content: createElement(Content),
edit: createElement(Content),
canMakePayment: () => true,
ariaLabel: settings.title,
supports: { features: settings.supports },
});
The edit property is the one most gateways miss. It is the component used inside the block editor preview, separate from content. Skip it and the registry call rejects with the undefined.register error because the block editor cannot render a placeholder.
3. Register the integration. Hook into woocommerce_blocks_loaded:
add_action('woocommerce_blocks_loaded', function () {
if (!class_exists('Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry')) {
return;
}
require_once __DIR__ . '/includes/class-mygateway-blocks.php';
add_action(
'woocommerce_blocks_payment_method_type_registration',
function ($registry) {
$registry->register(new MyGateway_Blocks());
}
);
});
Clear the WooCommerce cache from WooCommerce → Status → Tools → Clear transients, hard-refresh the checkout, and the gateway appears in the block alongside Stripe and PayPal.
Verify the integration. Open the checkout in an incognito window and inspect the network tab. You should see one extra request for blocks.js and no console errors. Place a test order. The gateway processes through its existing PHP process_payment() method. The block only handles the UI; payment processing still runs on the server.
If the gateway shows up but submitting the order does nothing, the JS name does not match the PHP $name. Both must be the exact string the server expects, character for character.
The Lesson
The checkout block has its own payment registry. A gateway that works in the shortcode checkout will not work in the block until you add an AbstractPaymentMethodType subclass and a React component, then wire them in through woocommerce_blocks_loaded. The classic registration is necessary but no longer sufficient.
If your store moved to the checkout block and a custom or paid gateway vanished, that is a fix I run regularly on client sites. See my services. For a related block migration gotcha, read WooCommerce checkout block payment methods missing.
Stuck on a WooCommerce checkout migration? Get it shipped.