Checkout design
How to customise the WooCommerce checkout page
There are four ways to change a WooCommerce checkout, and picking the wrong one is how a simple job turns into an afternoon or a silent breakage eighteen months later. Here is what each route can do, where it stops, and which one your change actually needs.
What this article covers
- Find out which checkout you have first. Classic and block checkouts are customised by completely different means, and half the advice online silently assumes the other one.
- There are four routes: CSS, hooks, template overrides and a plugin. Each has a hard ceiling, and knowing where it is saves you an afternoon.
- Template overrides are the trap. They work perfectly and then drift out of date silently, which is how a checkout breaks three WooCommerce releases after anyone touched it.
- Most of what people want is five changes, and they are the same five on nearly every store.
First, find out which checkout you have
This takes ten seconds and determines everything that follows. Open your checkout page in the WordPress editor.
- If you see a single
[woocommerce_checkout]shortcode block, you are on the classic checkout. It is a PHP template, it responds to WordPress filters and actions, and everything in this article applies. - If you see a Checkout block with an inspector sidebar full of toggles, you are on the block checkout. It is a React application fed by the Store API. PHP hooks that target the classic form will not fire, and CSS class names are different.
Neither is wrong and the classic checkout is not deprecated, whatever you have read. If you are trying to decide between them, we wrote a full decision guide: should you switch to the WooCommerce block checkout?
Why this matters more than it sounds. The most common wasted afternoon in WooCommerce is pasting a snippet, seeing nothing change, and blaming caching. Usually the snippet was written for the classic checkout and the store is on blocks. Nothing errors. The hook is registered, it simply has no template to attach to.
The four routes, and where each one stops
Pick by what you actually want to change, not by what you are most comfortable with. The most common mistake is reaching for a template override to do something CSS could have done.
| Route | Good for | Cannot do | Breaks when |
|---|---|---|---|
| CSS only | Colours, spacing, fonts, button size, hiding things | Reordering, adding fields, changing logic | Your theme or WooCommerce changes class names |
| Hooks and filters | Adding, removing and reordering content and fields | Restructuring the page layout itself | You move to the block checkout |
| Template override | Total control of the markup | Nothing, and that is the danger | WooCommerce updates the original and yours drifts |
| A plugin | Layout, fields and behaviour without maintenance | Anything the plugin did not anticipate | Rarely, but you inherit its opinions |
The rule of thumb: use the least powerful route that does the job. Power here is a synonym for maintenance.
Route 1: CSS, which covers more than people expect
If your complaint is that the checkout looks dated, cramped or off brand, CSS is very likely the whole answer, and it survives WooCommerce updates better than any other route.
Put it in Appearance, Customise, Additional CSS, or in your child theme's stylesheet. The useful selectors on a classic checkout:
/* The whole form */
.woocommerce-checkout form.checkout { }
/* Billing and shipping column */
#customer_details { }
/* The order summary and payment column */
#order_review { }
/* One field row. Woo adds .form-row-first / .form-row-last for the half widths */
.form-row { }
/* The pay button */
#place_order { }
/* Coupon prompt, notices, and the login prompt above the form */
.checkout_coupon, .woocommerce-info { }
The handful of classic checkout selectors worth knowing
Three things worth doing while you are in there, because they are cheap and they are measurable:
- Set inputs to at least 16px. iOS Safari zooms the page when a shopper focuses an input smaller than that, and the layout jumps. This is the cause of most "my checkout jumps around on iPhone" reports.
- Give the pay button a real minimum height, 48 pixels or more, and full width on mobile.
- Increase the gap between field rows. Cramped forms feel harder than they are, and whitespace is free.
Hiding a field with CSS is not the same as removing it. WooCommerce still validates the field on the server. If it was required, the shopper submits, gets an error about something they cannot see, and cannot complete the order. Make the field optional first. The correct way to do that is in how to remove or edit WooCommerce checkout fields.
Route 2: hooks, for adding and moving things
The classic checkout template is stitched together from action hooks. If you want a trust line above the pay button, a delivery note under the address, or a field in a different section, this is the route, and it survives WooCommerce updates because you are using the documented extension points rather than replacing the file.
The map, in the order they fire down the page:
woocommerce_before_checkout_form // above everything, incl. the login prompt
woocommerce_checkout_before_customer_details
woocommerce_before_checkout_billing_form
woocommerce_after_checkout_billing_form
woocommerce_before_checkout_shipping_form
woocommerce_after_checkout_shipping_form
woocommerce_before_order_notes
woocommerce_after_order_notes
woocommerce_checkout_after_customer_details
woocommerce_checkout_before_order_review // the summary column
woocommerce_review_order_before_payment
woocommerce_review_order_before_submit // just above the pay button
woocommerce_review_order_after_submit
woocommerce_after_checkout_form
Classic checkout action hooks, top to bottom
Using one is five lines. This puts a reassurance line directly above the pay button, which is the highest value piece of real estate on the page:
add_action( 'woocommerce_review_order_before_submit', 'oc_trust_line' );
function oc_trust_line() {
echo '<p class="oc-trust">Free 30 day returns. Secure payment. Dispatched next working day.</p>';
}
Add a line above the Place Order button
Put it in a small site plugin rather than your theme's functions.php. A site plugin survives a theme switch, and it keeps checkout logic out of a file that gets replaced when you change how the site looks.
The hook that catches people out. Anything you place inside the order review column lives in markup that WooCommerce replaces wholesale over AJAX every time the shopper changes country, postcode or shipping method. Your HTML survives, because the hook re-runs. Your JavaScript event listeners do not. Re-bind them on the updated_checkout event, or they stop working the moment somebody picks a different delivery option.
Route 3: template overrides, and the drift trap
WooCommerce lets you copy its template files into your theme and edit them. Copy woocommerce/templates/checkout/form-checkout.php to yourtheme/woocommerce/checkout/form-checkout.php and yours wins.
It works. It gives you complete control. And it is the route most likely to break your checkout eighteen months from now, for a reason that is not obvious at the time.
Overrides go stale silently. Each WooCommerce template carries a version number in its header. When WooCommerce updates the original and your copy stays as it was, your checkout keeps rendering the old markup, missing whatever the update added. Nothing errors. The only signal is a list under WooCommerce, Status, Templates, headed "outdated templates", which almost nobody reads until something is already wrong. If you override templates, put "check the Status page" on your update checklist.
If you are going to do it anyway, keep the blast radius small:
- Override the smallest file that does the job.
form-checkout.phpis the whole page.review-order.phporform-billing.phpis usually what you actually wanted. - Keep every action hook you find in the original. Deleting a
do_actionline silently disables other plugins. This is the single most common cause of "my order bump plugin stopped rendering after we customised the checkout". - Record the version number you copied from, in a comment at the top, so the next person can diff it.
- Never edit the WooCommerce plugin folder directly. It is overwritten on every update, along with your work.
Route 4: a plugin, and when it is the right call
Worth saying plainly, from people who sell one: a plugin is the wrong answer for a small change and the right answer for a layout.
Do not buy a plugin if you want two fields gone and slightly better spacing. That is a snippet and twenty lines of CSS, it is an afternoon, and you will maintain it approximately never.
Do consider one when what you want is structural, because that is where hand rolling gets expensive fast:
- A multi step flow, which needs per step validation, a progress indicator, browser back button handling and a mobile layout that survives the keyboard.
- A checkout that stays coherent on a phone at every step, including the ones behind two Continue clicks.
- Field controls you can change without redeploying code.
- Order bumps, side carts or a designed confirmation page, all of which involve money and state rather than markup.
- Anything you want to A/B test rather than argue about.
The other honest reason is maintenance. A snippet plus a template override is free today and is your problem forever. A plugin is not free and is somebody else's problem forever. Which of those is cheaper depends entirely on what your time is worth. If you get that far, we compared the main options including our own in CheckoutWC alternatives, compared honestly.
The five changes that are actually worth making
Across a lot of checkouts, the same short list does most of the work. In order:
- Make the total impossible to miss. On mobile the summary collapses and the total goes with it. Keep the number on the collapsed bar, and put it on the button: "Pay 84.50" beats "Place order".
- Remove the two or three fields that earn nothing. Phone, company, address line 2. Leave country, street, town and postcode alone; your shipping and tax are calculated from them.
- Move errors next to their fields. One error summary at the top of a phone screen means scrolling to find out what is wrong, and scrolling is where people leave.
- Put reassurance above the pay button. Returns, security, delivery. Not a wall of badges, one line of specifics. The hook is
woocommerce_review_order_before_submit. - Set the autocomplete and inputmode attributes so the browser can autofill and the right keyboard appears. Cheapest measurable win in mobile checkout, and most themes leave it on the floor.
Notice what is not on that list: a fundamentally different layout. Layout matters, but it is worth less than these five, and it is the change people reach for first.
How to verify a checkout change without shipping a bug
The checkout hides most of itself behind interaction, which is why so many customisations look fine and are not.
- Use a realistic cart. Three items, a long product name, a long address. Overflow and collapse are content dependent, so a one item test cart with a short name is the input least likely to reproduce them.
- Walk to the payment step. On a multi step checkout it sits behind two Continue clicks. On an accordion it is behind the last Save and continue. A quick look only ever exercises the first screen, which is how every defect on the payment step ships.
- Test a short viewport, not just a narrow one. Everybody resizes to 390 pixels wide. Height is what catches the below the fold failures, and a layout can pass at 1920 by 950 and at 390 by 740 and still fail at 1366 by 700.
- Do not diagnose from a full page screenshot. It is taken by expanding the viewport to the document height, which changes how sticky and fixed elements render. For anything sticky, take a viewport shot at a known scroll position.
- Place one real order with a real card, then refund it. Sandbox modes routinely behave differently from production. Everything above can pass while the order still fails.
The wider version of this, with the five specific mobile failures worth hunting, is in why your WooCommerce checkout breaks on mobile.
Or skip the maintenance
OptiCheckout restyles the classic WooCommerce checkout with seven templates and a visual builder. No migration, no template overrides to keep in sync, and your gateways, shipping and tax extensions keep working as they do now.
Read next
Checkout fieldsHow to remove or edit WooCommerce checkout fields
The working snippet, the four fields that are safe to remove, the four that will break your shipping and tax, and why the same code does nothing on blocks.
11 min read Checkout designHow to build a multi-step WooCommerce checkout
What Baymard actually concludes about multi-step versus one page, why most case studies are confounded, and the five mistakes that make it convert worse.
12 min read ConversionHow to reduce cart abandonment in WooCommerce
The ranked reasons people abandon, what each is worth, and the two highest value fixes, neither of which needs a plugin.
13 min read