WooCommerce

WooCommerce Checkout Block: The Customisation Points

The checkout block is not the shortcode checkout with a new skin. What the editor changes, what the Additional Checkout Fields API allows.

5 min read
WooCommerce Checkout Block: The Customisation Points
WooCommerceCheckoutBlock Editor
968 words5 min read

The mental model shift

The shortcode checkout was PHP templates and a hundred hooks. If you wanted a field moved, a label changed or a section added, there was a filter for it, and years of Stack Overflow answers to copy. The checkout block is a React application rendered from the Store API. Most of those hooks do not fire, the templates do not exist, and the Stack Overflow answers produce nothing.

What replaced them is a smaller, more deliberate set of customisation points. Knowing which exist stops hours of trying to make old approaches work.

Tier 1: the editor

Open the checkout page in the block editor and select the checkout block or its inner blocks. Without code you can:

  • Reorder and remove inner blocks: contact, shipping address, billing address, shipping options, payment, order note, terms, order summary. Some are required and cannot be removed.
  • Toggle fields: company, address line 2, phone. Set each to hidden, optional or required.
  • Edit text: section headings, the place order button label, the terms and privacy text and links.
  • Show or hide the coupon field, the order note, the "create account" option, the shipping and billing address toggle.
  • Choose the layout: order summary position, whether the return-to-cart link shows.
  • Style via the site editor's block styles and theme.json: colours, typography, spacing, button styles, following the theme.

This covers most business needs, and it is where to start. A lot of "the checkout block can't do X" is X being in the sidebar under a different name.

Tier 2: Additional Checkout Fields API

Since WooCommerce 8.9, custom fields are registered in PHP with woocommerce_register_additional_checkout_field() and appear in one of three locations: contact, address (billing and shipping) or order (the additional information section).

PHP
add_action( 'woocommerce_init', function () {
  if ( ! function_exists( 'woocommerce_register_additional_checkout_field' ) ) return;

  woocommerce_register_additional_checkout_field( [
    'id'       => 'acme/delivery-instructions',
    'label'    => 'Delivery instructions',
    'location' => 'order',
    'type'     => 'text',
    'required' => false,
    'attributes' => [ 'maxLength' => 200 ],
  ] );

  woocommerce_register_additional_checkout_field( [
    'id'       => 'acme/gift-wrap',
    'label'    => 'Gift wrap this order',
    'location' => 'order',
    'type'     => 'checkbox',
  ] );
} );

Field types: text, select, checkbox. Validation via woocommerce_validate_additional_field and woocommerce_sanitize_additional_field. Values are saved automatically to the order (and to the customer for contact and address fields), shown in the admin order screen, and available via $order->get_additional_field_value( 'acme/delivery-instructions' ) for emails and fulfilment.

This is the supported way to add fields, and it replaces the old woocommerce_checkout_fields filter entirely for the block. Its limits: three field types, three locations, no conditional show/hide without JavaScript, and no fields inside the payment section.

Tier 3: JavaScript slot/fill and the Checkout Block API

For UI that is not a field, a notice, a delivery date picker, a loyalty points panel, a custom summary line, the block exposes slots you fill with React components registered from a script:

  • ExperimentalOrderMeta and ExperimentalDiscountsMeta for content in the order summary.
  • ExperimentalOrderShippingPackages for shipping package content.
  • Inner block areas where custom blocks can be inserted (register a block with parent: ['woocommerce/checkout-fields-block'] and it appears in the editor's inserter inside the checkout).

Registering a fill:

JavaScript
import { registerPlugin } from '@wordpress/plugins';
import { ExperimentalOrderMeta } from '@woocommerce/blocks-checkout';

const Render = () => (
  <ExperimentalOrderMeta>
    <div className="acme-eta">Estimated delivery: 2 to 3 working days</div>
  </ExperimentalOrderMeta>
);

registerPlugin( 'acme-eta', { render: Render, scope: 'woocommerce-checkout' } );

Data flow: extensionCartUpdate posts data to the server and returns an updated cart; ExtendSchema (the Store API's extensibility) exposes server-side data to the client. Build with @wordpress/scripts and enqueue with dependencies on the checkout block's scripts.

This tier is where real customisation lives and it requires a JavaScript build. The APIs marked Experimental have been stable in practice for a long time but the names carry a warning.

Tier 4: Store API filters (server side)

Cart and checkout data can be filtered server-side: woocommerce_store_api_cart_errors, the ExtendSchema registration for custom data on cart items and the checkout, woocommerce_store_api_checkout_update_order_from_request to act on submitted data before the order is placed, and woocommerce_store_api_checkout_order_processed after. These replace many woocommerce_checkout_* hooks and fire for both block and shortcode when the Store API is used.

Filters for rendered content exist through the __experimental_woocommerce_blocks_... and woocommerce_blocks_... registry: cart item names, prices, subtotals, and place-order button label, via registerCheckoutFilters in JavaScript.

What is not customisable

  • The payment method section's internals. Each gateway renders its own UI. You cannot inject fields into it.
  • Field order within a section beyond what the editor offers. Address fields follow the country's format.
  • Multi-step checkout. The block is single page. Plugins that promised multi-step for the shortcode do not apply.
  • Arbitrary HTML between sections without a custom block or a fill.
  • Anything via the old PHP template overrides. checkout/form-checkout.php and friends are not used.

If a requirement is on this list, the honest options are a fill (tier 3), the shortcode checkout, or accepting the block's behaviour.

Choosing block or shortcode

The block is the default for new stores and gets the development attention; the shortcode remains supported and is more customisable in the old ways. For a store whose checkout requirements fit tiers 1 and 2, the block is the better experience. For a store with heavy legacy customisation, migrating means re-implementing it in tiers 2 to 4, which is a project, and staying on the shortcode is legitimate until that project is scheduled.

Where this sits

Deciding which tier a requirement lives in is the first step of any WooCommerce checkout work we take on, because it decides whether the answer is a sidebar toggle, a few lines of PHP, or a JavaScript build. The Additional Checkout Fields API covers more than people expect, and the fills cover most of the rest.

All writingHire me for this