Originally published at hamzaahmadaslam.com.
How this article was made: drafted with AI assistance from a researched brief, then checked against primary documentation before publishing.
Short answer: common causes of a slow WooCommerce store include an oversized hero image, too much JavaScript from plugins and tracking tags, pages that can't be cached, and a database bloated with old sessions, logs and autoloaded options. To speed up WooCommerce, profile the affected journey and prioritize the largest measured delay. Use field data as well as lab traces to verify the result.
Test the routes shoppers use: product pages, search, cart and checkout. The sections below cover different sources of delay. Start with the one your measurements identify.
Know the speed targets first
Google's Core Web Vitals are measured on real visitors, at the 75th percentile, on mobile and desktop separately.
| Metric | What it measures | Good | Poor |
|---|---|---|---|
| LCP (Largest Contentful Paint) | When the main content is visible | ≤ 2.5 s | > 4 s |
| INP (Interaction to Next Paint) | How quickly the page responds to taps and clicks | ≤ 200 ms | > 500 ms |
| CLS (Cumulative Layout Shift) | How much the layout jumps around | ≤ 0.1 | > 0.25 |
Check your field data in the Core Web Vitals report in Search Console or at the top of PageSpeed Insights. Lab tools like Lighthouse are great for debugging, but the field numbers are the ones that count.
Step 1: Fix the Largest Contentful Paint
On most product and home pages, the LCP element is a big image. Make it cheap to download and ask for it early:
- Serve WebP or AVIF at the size it is displayed, with proper
srcsetsizes. - Never lazy-load the LCP image. Lazy-load everything below the fold instead.
- Give the hero image priority:
<img src="/hero-1200.webp" srcset="/hero-800.webp 800w, /hero-1200.webp 1200w"
sizes="(min-width: 1024px) 50vw, 100vw" width="1200" height="800"
fetchpriority="high" alt="Oak dining table in a bright kitchen">
- Avoid sliders above the fold. They load several large images and a script before anything settles.
- Preload only the one font file used in the first screen, and use
font-display: swap.
Step 2: Put JavaScript on a diet (this is where INP lives)
A busy browser main thread can delay interactions even when the server responds quickly. Open Chrome DevTools, go to the Performance panel, record a tap on "Add to cart" and look for long tasks.
Common culprits and fixes:
- Plugins that load everywhere. A form, slider or review plugin often enqueues its scripts on every page. Unload them on pages that don't use them, with your theme's
functions.phpor an asset manager. - Cart fragments. Recent WooCommerce versions only load the
wc-cart-fragmentsscript where a mini-cart needs it. If your theme or a plugin still loads it everywhere, it can send an uncached?wc-ajax=get_refreshed_fragmentsPOST that skips the page cache on the first page view in a tab session, when the stored cart hash no longer matches the cart cookie after a cart change, and when stored fragments expire after 24 hours. Other page views reuse fragments saved insessionStorage. - Tag managers. Every marketing pixel adds work. Remove tags nobody reads, load the rest after the page is interactive, and consider server-side tagging for the heaviest ones.
- Chat widgets and heatmaps. Load them on interaction (for example, when the visitor clicks "Chat") instead of on page load.
Here is a small, safe example that stops a plugin's script loading outside the pages that need it:
add_action( 'wp_enqueue_scripts', function () {
if ( ! is_page( 'contact' ) ) {
wp_dequeue_script( 'example-form-plugin' );
wp_dequeue_style( 'example-form-plugin' );
}
}, 100 );
Use your plugin's real script handles, which you can find in the page source or with the Query Monitor plugin.
If cart fragments are part of that JavaScript work, check which pages load wc-cart-fragments and whether they need it to keep a cart widget up to date.
Step 3: Cache what can be cached (and nothing else)
Full-page caching is the biggest win for anonymous visitors, but a store has pages that must never be cached:
- Cart, checkout and my-account pages
- Any request carrying WooCommerce's session cookies, such as
woocommerce_items_in_cartandwp_woocommerce_session_*
Most good hosts and caching plugins know these rules. Check them anyway, because a cached checkout is a serious bug. On top of page caching, add a persistent object cache (Redis or Memcached) so logged-in shoppers and admin pages stop hammering the database.
Step 4: Clean the database
WooCommerce stores collect clutter quietly. Look at these three places:
- Autoloaded options. On WordPress 6.6 and later,
autoloadcan useyes,on,auto-onandautofor values WordPress loads by default, while WP-CLI's--autoload=onfilter only countsonandyes. Use the full autoloaded-options measurement method to measure the full set and find the largest entries before changing anything. - Scheduled actions. WooCommerce's Action Scheduler keeps a log of completed jobs. Review failed actions before removing their history, agree a retention policy for completed actions, and make sure WP-Cron runs (a system cron is more reliable than visitor-triggered cron).
- Orders storage. Check whether the store would benefit from High-Performance Order Storage (HPOS), which moves orders out of the generic posts tables into dedicated ones. It's the default for new stores. Older stores can switch from
WooCommerce → Settings → Advanced → Features. First check plugin compatibility and enable compatibility mode (order sync). Let the sync finish, then switch, and keep compatibility mode on for a while so you can revert if something breaks.
For order storage, see migrating to WooCommerce High-Performance Order Storage. For background-job buildup, see how to clear a WooCommerce Action Scheduler backlog.
Step 5: Server basics that still matter
- A PHP version that WordPress and WooCommerce recommend (8.3 or newer), with OPcache enabled. Confirm that your plugins and theme support the target PHP branch on staging before you upgrade.
- HTTP/2 or HTTP/3 and Brotli or gzip compression
- A CDN for images, CSS and JS
- A server close to your customers, or edge caching if they're spread out
Measure, change one thing, measure again
Performance work goes wrong when ten changes land at once. Keep a simple log: what you changed, the Lighthouse or WebPageTest result before and after, and the field data 28 days later. If a change doesn't help, roll it back.
During my time as website developer at Half Price Packaging, the site achieved a 10x boost in performance and a 5x increase in traffic. The work there included WordPress admin and theme changes, performance improvements and security cleanup. Those numbers describe that site; another store needs its own baseline.
Want a performance review of your store? Explore my WooCommerce Speed Optimization service or request a store audit.
Top comments (0)