Why WooCommerce checkout gets slow, and what to fix first
Checkout is the one page you cannot cache your way out of. When a store slows down, this is almost always where it shows first and hurts most.
Checkout cannot be page-cached, and that changes everything
Cart, checkout and account pages are per-visitor by definition, so a full-page cache has to exclude them. Everything you measured on a cached category page tells you nothing about checkout. The homepage serving in 200ms while checkout takes six seconds is completely normal and completely invisible until someone complains.
This means checkout speed is real application speed: every query, every plugin hook and every external API call runs on every load. Measure it directly, logged in, with a full cart. Anything else is measuring the wrong page.
Autoloaded options: the first thing to check
WordPress loads every option marked autoload = yes on every single request, including checkout. Plugins accumulate here and rarely clean up after themselves — particularly ones that store logs, licence payloads or cached API responses in the options table.
A healthy site autoloads a few hundred kilobytes. Stores with a long plugin history regularly reach several megabytes, which is deserialised into PHP memory on every request before your code does anything at all. It is the cheapest large win available: find the biggest autoloaded rows, confirm what wrote them, and turn autoload off for the ones that are not needed on every page.
Cart fragments and the admin-ajax problem
WooCommerce keeps the cart widget current with an AJAX call to admin-ajax.php. On a store with a heavy theme that request can take longer than the page it is updating, and it fires on pages where nothing shows the cart at all.
Two honest fixes. Stop it loading where it is not needed, or replace it with a cached count that updates on cart change. What you should not do is disable it globally without checking — if your theme genuinely relies on it, you will silently break the cart counter and nobody will report it for weeks.
Plugin queries that scale with order count
A store with 500 orders and a store with 500,000 run the same code very differently. Reporting, analytics, points and loyalty plugins commonly query the orders table without the index they need. That query is instant in year one and takes eight seconds in year three, and nothing in the code changed.
Turn on the slow query log for a day, or use a profiler that attributes queries to plugins, and you will usually find one or two offenders responsible for most of the time. The fix is often a single index rather than removing the plugin.
External calls in the checkout path
Address validation, tax lookup, fraud scoring, shipping rates and currency conversion all tend to be synchronous HTTP calls made while the customer waits. Each one adds its full round trip to your checkout time, and each one can fail.
The question to ask of every such call is: what happens when this provider is slow? If the answer is checkout hangs for thirty seconds
, it needs a short timeout and a defined fallback. Shipping rates in particular are worth caching per postcode and weight band rather than fetching live on every load.
The order to work in
- Measure checkout logged in with a full cart, not the homepage.
- Check autoloaded options size and trim what does not belong.
- Find slow queries and index them before removing plugins.
- Put timeouts and fallbacks on every external call in the checkout path.
- Only then look at object caching and PHP version.
Most of the value is in the first three. Object caching is genuinely useful, but adding Redis in front of a query that needs an index just caches the symptom.
Common questions
Will a caching plugin fix slow checkout?
No. Cart, checkout and account pages must be excluded from full-page caching because they are per-visitor. Caching plugins improve the pages around checkout, which is worth doing, but they cannot make checkout itself faster.
How many plugins is too many?
The count matters far less than what they do on each request. Thirty light plugins can be faster than five that each query the orders table unindexed on every page load. Profile before removing anything.
Is switching host the answer?
Sometimes, but check the application first. Moving an unindexed query to faster hardware makes it proportionally faster, not fast. If a query takes eight seconds because it scans a large table, better hardware might get it to four.
Need this done properly?
Describe the problem in plain language and I’ll tell you what it actually needs — including if that is less work than you expected.
