WordPress has a caching problem the way a house has a storage problem: the solution depends on what is cluttering the space. A page cache stores finished HTML. An object cache stores the results of database queries and expensive calculations. OPcache stores compiled PHP bytecode. A CDN stores copies at the edge. They overlap in effect, not in mechanism, and adding another layer without diagnosing the current one is how sites end up with four caches and a 4-second TTFB.

What to remember
  • Page cache makes anonymous pages fast; it does nothing for carts, checkout, or logged-in users.
  • Object cache reduces database work for every request; Redis and Memcached are two implementations.
  • OPcache is not optional; it ships with PHP and should be enabled and sized correctly.
  • Redis is the better default for WordPress because of persistence, data types, and host support.
  • Memcached is simpler and scales well for pure key-value caching, but offers less operational flexibility.
  • Invalidation is the hard part. A cache that never clears is a bug with a fast response time.

The four layers, in plain language

WordPress cache layers / what each one solves
LayerStoresSpeeds upDoes not help
Page cacheFinal HTML for anonymous URLsHomepage, posts, catalog pagesCart, checkout, account, logged-in views
Object cacheQuery results, options, transientsDynamic requests, admin, repeated queriesFirst computation; writes; large uncached assets
OPcacheCompiled PHP bytecodeEvery PHP requestDatabase queries, network latency, front-end assets
CDN / edgeHTML, assets, images at PoPsGlobal latency, static assets, cached pagesUncached origin requests, private cart data

If a visitor is logged out and sees a slow homepage, start with the page cache and the CDN. If a logged-in customer sees a slow cart, the page cache is irrelevant; look at object cache, PHP workers, and database latency. If every page is slow, including the admin, start with OPcache, PHP version, and the database.

Redis vs Memcached, without the folklore

Both are in-memory key-value stores. Both can back the WordPress object cache through a drop-in. The differences are architectural and operational, not mystical.

Redis vs Memcached / WordPress decision table
DimensionRedisMemcached
Data typesStrings, hashes, lists, sets, sorted sets, streamsStrings and opaque blobs
PersistenceOptional RDB snapshots and AOFNone; memory only
ReplicationBuilt-in primary/replicaNot built-in; client-side sharding
ThreadingMostly single-threaded command executionMulti-threaded; strong for high concurrency
EvictionConfigurable policies (LRU, LFU, TTL-based)LRU, segmented LRU
Best fitObject cache, sessions, queues, rate limitsPure object cache at very high throughput
WordPress supportBroad; most managed hosts offer itAvailable, but less commonly bundled

For a typical WordPress site, Redis is the safer default because it is more likely to be supported by the host, easier to observe, and flexible enough to handle sessions or queues later. Memcached can be marginally faster for a pure cache workload with many concurrent clients, but the operational difference rarely justifies switching a working Redis setup.

Diagnose before you install

Enable query monitoring on staging and capture a representative page load. If the page runs 60 queries and 40 are repeated option lookups, an object cache will help. If it runs 12 queries and spends 800 ms waiting on a remote API, Redis will not fix the API. If the page cache is missing and every visit bootstraps WordPress, fix the page cache first.

# Quick checks on a staging clone
wp plugin list --status=active
wp cache type
wp eval 'global $wpdb; echo $wpdb->num_queries;'

# Redis connectivity and memory
redis-cli -h 127.0.0.1 -p 6379 ping
redis-cli -h 127.0.0.1 -p 6379 info memory
redis-cli -h 127.0.0.1 -p 6379 info stats | grep -E 'keyspace|evicted|hit|miss'

# OPcache status (web SAPI)
php -i | grep opcache

On a managed host, some of these commands are unavailable. Use the panel's cache analytics, or ask support for the object cache hit ratio and eviction count. If the host cannot answer those questions, that is a data point about the platform.

Configure Redis correctly

WordPress uses a persistent object cache through a drop-in at `wp-content/object-cache.php`. The common implementation is the Redis Object Cache plugin, which ships its own drop-in and a WP-CLI interface. Define the connection in `wp-config.php` or let the host inject it; avoid hard-coding credentials in a file that might be committed to version control.

// wp-config.php — example constants; values come from your host
define('WP_REDIS_HOST', '127.0.0.1');
define('WP_REDIS_PORT', 6379);
define('WP_REDIS_PASSWORD', getenv('REDIS_PASSWORD') ?: '');
define('WP_REDIS_DATABASE', 0);
define('WP_REDIS_PREFIX', 'pwph_');
define('WP_REDIS_MAXTTL', 86400);

// Optional: disable the object cache in local development
// define('WP_REDIS_DISABLED', true);

Use a separate Redis database or key prefix per site on a shared instance. Two WordPress installations sharing database 0 without a prefix will read each other's keys, which produces spectacularly confusing bugs. If the host offers one Redis instance for multiple sites, confirm the isolation model before enabling the drop-in.

Set an eviction policy deliberately. For a dedicated cache, `allkeys-lru` is a common choice. If the instance also stores sessions or queue data, use `volatile-lru` or a separate instance so a cache fill cannot evict data that must survive. Size the instance so evictions are rare; a high eviction rate means the working set does not fit.

Invalidation: the part that decides whether caching works

A cache is only correct if it is invalidated when the underlying data changes. WordPress core and well-behaved plugins call `wp_cache_delete()` and related functions when they update options, posts, and terms. A plugin that writes directly to the database without clearing the cache will serve stale data indefinitely.

The common symptoms are a price that will not update, a menu that reappears after deletion, or a widget that shows yesterday's configuration. Before blaming Redis, disable the object cache and see whether the behavior disappears. If it does, the bug is invalidation, not the cache server.

Do not use FLUSHALL on a shared Redis. It wipes every database, including sessions and queues. Use wp cache flush or the plugin's scoped flush. If you must clear a specific database, use FLUSHDB only after confirming isolation.

WooCommerce: where object caching helps and where it does not

Redis helps WooCommerce with read-heavy work: product queries, term and attribute lookups, settings, and repeated metadata calls. It reduces the database load that makes catalog pages and the admin sluggish. It does not make checkout writes faster, and it cannot cache the cart or checkout for a logged-in shopper.

WooCommerce sessions are stored in the database by default. Some hosts and plugins move them to Redis, which can reduce database writes but adds a dependency: if Redis is evicted or lost, carts disappear. If you move sessions, use a separate database with persistence and a policy that does not evict session keys.

The checkout path depends on PHP workers, database write latency, and payment-provider latency. Adding Redis to a store with saturated workers may improve catalog pages while checkout stays slow. Use the load test to see which resource is actually limiting.

When Memcached is the right choice

Memcached is a good fit when you need a pure, volatile cache with very high concurrency and no persistence requirement. It is multi-threaded, simple to operate, and predictable under load. Some large WordPress deployments use it because their infrastructure already standardizes on it, not because it produces a measurably faster page.

It is a poor fit if you want a single store for object cache, sessions, and queues; if you need replication or persistence; or if your host only supports Redis. The WordPress object cache API is the same either way, so switching later is possible but not free.

The cache checklist

  1. Measure the baseline. Query count, TTFB, and p75 for cached and uncached pages.
  2. Fix the page cache first. A persistent object cache cannot compensate for a missing full-page cache on anonymous traffic.
  3. Enable OPcache and size it. Confirm `opcache.enable=1`, a sensible `memory_consumption`, and a revalidation frequency that fits your deploy cadence.
  4. Add Redis with a prefix and a separate database. Confirm connectivity and the drop-in status.
  5. Set an eviction policy and monitor evictions. Size for the working set, not the database size.
  6. Test invalidation. Update a product price, a menu, and a widget; confirm the changes appear immediately.
  7. Test a cache purge under load. A cold cache during a campaign is a capacity event, not a cache event.
  8. Document the flush procedure. The on-call engineer should not be guessing which button is safe at 2 a.m.
Caching does not make a slow application fast. It makes a fast application repeatable.

Turn on Redis. Keep the page cache. Fix the queries.

For most WordPress sites on a host that supports it, enable Redis as a persistent object cache, keep the page cache and CDN, and leave OPcache alone once it is correctly sized. Use Memcached only if your platform standardizes on it or you have a measured reason to prefer it. The bigger wins are usually invalidation discipline, query reduction, and fixing the plugin that runs 40 queries on every page.

If you are choosing a host, ask three questions: Is Redis included or an add-on? Is it isolated per site? What is the eviction policy and the memory limit? A host that cannot answer those questions is not ready to be trusted with your cache layer.

PWPH Test Lab

Cache testing is part of the performance protocol. Read the methodology or the commercial disclosure.