Speed and caching for a shop
Module 6: Management and security · Reading time: 10 minutes
Learning objective: After this lesson you can set up caching for a WooCommerce shop so the shop is fast and personal pages never end up in the cache, and you can check this in the headers.
Key concepts: page cache, exclusions (cart, checkout, My account), cookies that bypass the cache, no-cache headers, DONOTCACHEPAGE, object cache, Redis, cart fragments, geolocation with a page cache, cleaning up scheduled actions
Two kinds of pages
The basics of caching (page cache, browser cache, object cache, OPcache, a CDN) are covered in the WordPress course, lesson 6.2. That lesson also gives the most important rule for shops: personal pages must never go into the page cache. This lesson works that out in detail.
A shop has two kinds of pages:
| Kind | Examples | Cache |
|---|---|---|
| The same for everyone | home page, shop page, categories, product pages, information pages | Page cache: yes, this is where you gain the most |
| Different for each visitor | cart, checkout, My account, the withdrawal page with a logged-in customer | Page cache: never |
If it goes wrong, you notice straight away: a customer sees someone else's cart or, worse, someone's address on the checkout page. That is also a data breach under the GDPR (KB 6749).
What WooCommerce already does
WooCommerce helps a cache in three ways. It is good to know them, so you can spot when something removes them:
- Constants. On the cart, checkout and My account pages, WooCommerce sets
DONOTCACHEPAGE(and the equivalents for object and database caching). Many caching plugins read this constant and then skip the page. - Headers. On those same pages, WooCommerce sends the WordPress no-cache headers:
Cache-Control: no-cache, must-revalidate, max-age=0, privateand anExpiresin the past. A proxy or CDN that follows the rules will then not store the page. For logged-in users,no-storeis added. - Cookies. As soon as someone adds something to the cart, WooCommerce sets cookies such as
woocommerce_items_in_cart,woocommerce_cart_hashandwp_woocommerce_session_.... Good caches stop serving stored pages to visitors with such a cookie, product pages included, because the mini cart in the header, for example, is then different for each visitor.
The WooCommerce documentation tells caching plugins to exclude the cart, My account and checkout pages, plus the cookies woocommerce_cart_hash, woocommerce_items_in_cart, wp_woocommerce_session_, woocommerce_recently_viewed and store_notice[...]. For Varnish it also gives rules for addresses with ?add-to-cart=.
Where it goes wrong in practice
- Different addresses for the shop pages. You renamed the cart to
/basket/, or a translation plugin creates/de/warenkorb/. A cache that excludes fixed addresses such as/cartmisses these. Caching plugins that know WooCommerce read the pages from the settings; a cache on the server or at a CDN does not. - A CDN that caches everything. Some CDN rules ("cache everything") ignore the headers. In that case, exclude the shop pages and the cookies listed above explicitly.
- A plugin that overwrites the headers. A security or speed plugin sometimes sets
Cache-Control: public, max-age=...on every page. Then the no-cache headers are gone. - A session for every visitor. Normally WooCommerce only sets a session cookie once something is in the cart. If a plugin or theme starts a session for every visitor (a
wp_woocommerce_session_orPHPSESSIDcookie on the first visit), the page cache stops working for everyone and your shop becomes slow when it is busy. - Geolocation. Under WooCommerce > Settings > General you choose the default customer location. With plain "Geolocate", the server works out the country for each visitor, and with prices per country that does not fit a page cache. That is why WooCommerce offers "Geolocate (with page caching support)", which determines the country through an extra request in the browser. If you do not need prices or VAT per country before checkout, choose the shop country: that is the simplest. For geolocation, WooCommerce regularly downloads a database from MaxMind.
On a LiteSpeed server (as at WebOké), the LiteSpeed Cache plugin handles the exclusions for WooCommerce itself; check them in its exclude settings. With other web servers and hosting providers, a different caching plugin works in a similar way.
What the page cache does not solve
The cart and checkout are always built by PHP and the database. When it is busy (a sale, a newsletter), these are exactly the pages where your customers spend money. Other things help there:
- An object cache such as Redis keeps the results of database queries in memory. In a shop, with many pages that cannot go into the page cache, this makes a noticeably bigger difference than on an ordinary site. Your hosting has to offer Redis (WebOké does, DA 15.7); you then switch it on with a plugin.
- Cart fragments. Classic themes update the mini cart in the header with a script (
wc-cart-fragments) that makes an extra request when the cart has items in it. Modern block themes with the Mini-Cart block need this less. Do not load such scripts on pages where they do nothing. - Cleaned-up scheduled actions. WooCommerce uses the Action Scheduler for background tasks (lesson 7.3). Completed actions are cleaned up after a month by default. If the list still grows to hundreds of thousands, often because of an extension that keeps scheduling things or because of failed actions, database queries slow down. Check the number of failed and pending actions under WooCommerce > Status > Scheduled Actions.
- HPOS. Storing orders in their own tables (lesson 1.2) makes searching orders faster than in the old posts table. Existing shops have to switch over themselves (lesson 6.2 on making backups first).
- An up-to-date PHP version and enough memory (lesson 7.2).
In practice: this is how it looks in WooCommerce
Check it for Theehuis Example in a private window with your browser's developer tools (F12, Network tab, first request):
- Home page, load it twice: on the second load you see a header such as
x-litespeed-cache: hitorcf-cache-status: HIT. Nowp_woocommerce_session_cookie on the first visit. shop.example.com/winkelwagen/, load it twice: no hit, andcache-controlwithno-cacheorprivate.- Do the same for checkout and My account.
- Add a product to the cart and load a product page: you see your own cart, not a stored version.
Summary
- Pages that are the same for everyone go into the cache; the cart, checkout and My account never do.
- WooCommerce sets DONOTCACHEPAGE, no-cache headers and cookies itself; check that nothing removes or ignores them.
- Watch out for renamed addresses, CDN rules, plugins that overwrite headers, sessions for every visitor and geolocation.
- Redis, cleaned-up scheduled actions, HPOS and a good PHP version help where the page cache cannot.
- Test by loading pages twice in a private window and reading the headers.
Quiz
Exercise
Exercise A6.4: Do the cart and checkout stay out of the cache? Enter the address of your shop and the addresses of your cart and checkout pages (and My account, if you like). The tool requests the home page twice, 2 seconds apart, without cookies, and then requests each shop page twice as well. Nothing is added to the cart and nothing is ordered. Green if the home page comes from the cache on the second request (or is clearly faster) without setting a session cookie, and if each shop page has no cache hit on the second request and sends a Cache-Control with no-cache, no-store, private or max-age=0. Orange if the home page does not use a cache, or if a shop page has no hit but also no no-cache header. Red if there is a cache hit on the cart, checkout or My account, or if the home page starts a WooCommerce session for every visitor.
A green tick means this check passes right now, not that your shop is secure.
Further reading
Steps in a control panel apply to WebOké; with other providers it works in a similar way.
- Free WordPress course 6.2: Caching
- Free WordPress course 6.3: Images, PHP and other speed gains
- DirectAdmin guide 15.7: Redis
- My website is slow or uses too much CPU: here's how to make it faster
- Is this a data breach and do I need to report it?
- Configuring caching plugins (developer.woocommerce.com): https://developer.woocommerce.com/docs/best-practices/performance/configuring-caching-plugins/
