A persistent object cache keeps the results of WordPress's database lookups in Valkey between requests, so the next request reads them from memory instead of asking the database again. On a site with logged-in users, a busy admin area or a WooCommerce shop, it cuts database queries per page sharply and makes the admin noticeably faster. On a brochure site whose pages are already served from a page cache, it changes almost nothing - the page never reaches PHP, so there are no queries to save.
That distinction is the whole post in one sentence. The setup itself is ten minutes: a plugin, four lines in wp-config.php, and a button. What takes thought is knowing whether your site is the kind that benefits, sizing the cache, and recognising the handful of failure modes - stale options, a missing drop-in, a cache shared between sites by accident. This post covers all of it.
What the object cache is#
WordPress has always had an object cache: the WP_Object_Cache class behind wp_cache_get() and wp_cache_set(). Core uses it for options, posts, post meta, terms, users and query results, and plugins use it for their own data. By default it lives in PHP memory and dies at the end of each request. It saves repeated lookups within one page load, and nothing between page loads.
A persistent object cache replaces that class with one that stores the same data in an external server. WordPress loads the replacement from a drop-in file, wp-content/object-cache.php, before almost anything else. With it in place, the second request for the same post does not query the database for the post, its meta, its terms or its author; it fetches them from Valkey.
Since WordPress 6.1, the Site Health screen recommends a persistent object cache on sites it considers large enough to benefit, which is why many site owners first hear about it there.
What it speeds up, and what it does not#
The object cache only helps requests that run PHP and query the database. So the question is which requests do that on your site.
| Workload | Page cache helps | Object cache helps |
|---|---|---|
| Anonymous visitors on a blog | A lot | Little - cached pages skip PHP |
| Logged-in members or a community | Not at all - pages are personal | A lot |
| WooCommerce cart, checkout, account | Not at all - excluded from page cache | A lot |
wp-admin and the block editor | Not at all | Noticeably |
| REST API and AJAX endpoints | Rarely | Yes |
| A slow query on an unindexed meta field | No | Only on repeat |
| Heavy PHP work (page builders, image processing) | Only if cached | No |
The last two rows are the uncomfortable ones. If a page is slow because a plugin runs a meta_query that scans a hundred thousand rows, the object cache serves the result fast the second time and just as slowly the first - including every time the cache is flushed. And if a page is slow because a page builder spends 800 ms assembling HTML in PHP, no data cache changes that. Measure before you add anything. Query Monitor shows the number and time of queries per page, and whether the object cache is hitting.
Order of operations for a slow WordPress site:
- A page cache for anonymous traffic, which is the biggest win for most sites.
- Fix the slowest queries and the heaviest plugins.
- A persistent object cache for everything a page cache cannot serve.
- Then think about more PHP workers or more memory.
WordPress speed and caching goes through the page-cache side and how the layers fit together.
The plugins#
There are a few ways to get a drop-in that talks to Valkey. All speak the Redis protocol, so they connect to Valkey unchanged.
- Redis Object Cache (free, by Till Krüss) is the most widely used. It installs
object-cache.php, shows status and hit-rate metrics in the admin, and is configured withWP_REDIS_*constants. It can use the phpredis extension, Relay, or Predis, a pure-PHP client bundled with it - so it works even where you cannot install PHP extensions. - Object Cache Pro is the commercial version from the same author, with better serialisation and compression, more efficient group flushing and support. It is aimed at large shops and agencies.
- W3 Total Cache and LiteSpeed Cache include object-cache options alongside their page caching. Reasonable if you already use one of them; avoid running two object-cache drop-ins at once - there is only one
object-cache.php.
This post uses Redis Object Cache, because it is free, common and well documented.
Setup, step by step#
- Check that WordPress can reach Valkey. From any machine with the client,
valkey-cli -h <host> -p <port> --askpassthenPINGshould answerPONG. If your WordPress runs on one server and Valkey on another, this is a network call on every cache read, so they should be in the same location. On RE:NODE both web hosting and Valkey run in Germany, and a Valkey plan comes with its host, port and a generated password. - Check for the phpredis extension. A file containing
<?php phpinfo();in the web root, loaded once and then deleted, shows aredissection if the extension is present. If it is not, the plugin falls back to Predis, which is slower but works. - Add the constants to `wp-config.php`, above the line that says
That's all, stop editing!:
define( 'WP_REDIS_HOST', '203.0.113.20' );define( 'WP_REDIS_PORT', 6380 );define( 'WP_REDIS_PASSWORD', 'the-generated-password' );define( 'WP_REDIS_DATABASE', 0 );define( 'WP_REDIS_PREFIX', 'shop_example_com:' );define( 'WP_REDIS_TIMEOUT', 1 );define( 'WP_REDIS_READ_TIMEOUT', 1 );define( 'WP_REDIS_MAXTTL', 86400 );- Install and activate Redis Object Cache from Plugins, then Add New.
- Enable it under Settings, then Redis, with the Enable Object Cache button. This copies the drop-in to
wp-content/object-cache.php. With WP-CLI,wp redis enabledoes the same andwp redis statusreports the connection. - Load a few pages and check the status screen: it should say Connected, with hits climbing. Query Monitor should show far fewer database queries on a second load of the same admin page.
The constants worth understanding:
- `WP_REDIS_PREFIX` is mandatory in practice. Two WordPress sites pointed at the same Valkey without distinct prefixes share option caches and serve each other's settings - one of the most confusing bugs you can create. Use the domain.
- `WP_REDIS_MAXTTL` caps the lifetime of every key. Some plugins store cache entries with no expiry; without a cap they live until evicted. A day is a sensible ceiling.
- `WP_REDIS_TIMEOUT` and `WP_REDIS_READ_TIMEOUT` are seconds. Keep them short: if Valkey is unreachable, every page waits for the timeout before falling back.
- `WP_REDIS_PASSWORD` accepts an array,
[ 'username', 'password' ], when you use an ACL user rather than the default user. - `WP_REDIS_DISABLED`, set to
true, bypasses the cache without removing the drop-in - the emergency switch.
Keep the password out of version control if wp-config.php is in a repository. Install WordPress manually covers the rest of wp-config.php.
Sizing Valkey for WordPress#
An object cache's size is roughly the set of objects your site touches regularly: options (including autoloaded ones), posts, meta, terms, users, transients and whatever plugins add. For most sites that is surprisingly small.
| Site | Typical object cache size | Starting plan |
|---|---|---|
| Blog or brochure site, a few hundred posts | Tens of MB | 256 MB |
| Membership site or small shop, a few thousand products | 100-300 MB | 512 MB |
| WooCommerce with tens of thousands of products and orders | Several hundred MB and up | 1-2 GB |
| Multisite network with many sub-sites | Sum of the sites | Measure |
Measure rather than guess: after a day of normal traffic, INFO memory shows used_memory_human, and the plugin's status screen shows the same figure.
The right eviction policy for a Valkey used only as an object cache is allkeys-lru or allkeys-lfu: when memory fills, the least useful entries are discarded and WordPress rebuilds them from the database. With noeviction, a full cache makes writes fail and the plugin reports errors. If the same Valkey also holds sessions or queues for another application, that conflict is a reason to give WordPress its own instance; Valkey memory and eviction policies explains the trade-off.
Persistence is less important for an object cache than for anything else in Valkey, because everything in it can be rebuilt. It still helps: after a restart, a persisted cache is warm immediately instead of every page paying for a cold start at once.
Transients, autoloaded options and stale data#
Two WordPress mechanisms change behaviour when a persistent object cache is installed, and both explain bugs people report.
Transients move out of the database. Without an object cache, set_transient() writes to the wp_options table. With one, transients live only in Valkey and never touch the database. That is usually an improvement - expired transients no longer pile up in wp_options - but it means that a plugin which stores something essential in a transient loses it when the cache is flushed or the key is evicted. Transients are meant to be disposable; a plugin that treats them as storage has a bug that the object cache exposes.
Options are cached, including `alloptions`. WordPress loads all autoloaded options in one go and caches them as one entry. If you change an option directly in the database - with phpMyAdmin, a migration script or a search-replace - WordPress keeps serving the cached value until the cache is flushed. That is the classic "I changed the site URL in the database and nothing happened". After any direct database edit, flush the cache from the plugin's screen or with wp cache flush.
A related trap is a huge alloptions entry. Some plugins autoload hundreds of kilobytes of options; every request then fetches that blob from Valkey, and memory per request goes up. Query Monitor and wp option list --autoload=on --format=total_bytes show the size. Trimming autoloaded options helps with or without an object cache.
Staging copies, migrations and multisite
Three situations make the cache a source of confusion rather than speed, and each has a simple rule.
Staging copies. Clone a site to staging, copy wp-config.php along with it, and the staging site now reads and writes production's cache entries - same host, same prefix. Staging's edits appear on production until the keys expire, and production's options appear on staging. Give every copy its own WP_REDIS_PREFIX, or its own Valkey, before the first page load. Setting WP_ENVIRONMENT_TYPE correctly does not change cache keys on its own.
Migrations. Moving a site to a new host with a search-replace of URLs is a direct database edit, so flush the object cache on the new host after the import and before testing. Migrating WordPress to a new host covers the rest of the move. If you are moving the database but keeping the same Valkey, flush there too.
Multisite. A network shares one drop-in and one prefix; the plugin separates sub-sites by blog id and treats some groups, such as users and site metadata, as global across the network. Do not try to give each sub-site its own prefix by editing constants per site. Size the cache for the whole network, and expect a flush to affect every sub-site at once.
Deploys. Most code deploys need no flush at all. A deploy that changes how a plugin stores cached data - a new structure under the same key - does, and the plugin's own upgrade routine usually handles it. When a deploy produces errors that vanish after a flush, that is what happened.
Troubleshooting#
"Error establishing a Redis connection" or the status says Not Connected. Check host, port and password from the WordPress server with valkey-cli. A connection refused means the address or port is wrong; WRONGPASS or NOAUTH means the password is.
The site shows another site's settings or name. Two sites share a prefix and database. Give each a unique WP_REDIS_PREFIX, then flush.
Changes made in the database do not appear. Cached options. Flush the object cache.
Pages got slower after enabling it. Usually latency: if each cache call crosses a slow network, hundreds of calls per page add up. Check that WordPress and Valkey are close together. Less often, Predis on a site making thousands of cache calls per page is slower than phpredis.
`object-cache.php` keeps disappearing or is from another plugin. Two cache plugins competing for the drop-in. Pick one and remove the other's object-cache feature.
The site breaks entirely after a Valkey outage. It should not - the plugin falls back to the database. If it does, set WP_REDIS_DISABLED to true to get the site up, and check the timeouts.
FAQ#
Do I need an object cache if I already have a page cache?
If almost all of your traffic is anonymous and served from the page cache, it adds little. If you have logged-in users, a shop, a busy admin or many uncached API requests, the two solve different problems and are worth having together.
Is Redis Object Cache compatible with Valkey?
It speaks the Redis protocol through phpredis, Relay or Predis, and Valkey implements that protocol, so it connects with the same host, port and password settings. Point the constants at the Valkey server and enable it as usual.
Can several WordPress sites share one Valkey instance?
Yes, with a unique WP_REDIS_PREFIX per site, or separate logical databases with WP_REDIS_DATABASE. They will share memory, so a large site can push a small one's entries out. For important sites, separate instances keep them independent.
Will flushing the object cache lose data?
Not if plugins behave: everything in the object cache can be rebuilt from the database. Expect a slower minute while it warms up. The exception is a plugin that keeps essential data only in transients, which is a plugin bug.
Does the object cache help WooCommerce checkout?
Yes - cart, checkout and account pages cannot be page-cached, so they run PHP and query the database on every load. Caching products, options and session-related lookups reduces that work. It does not speed up payment gateway calls, which are external.




Comments
Completely anonymous: no account, no email, no cookie. We store the name you type, the text and the time - nothing else. Links are limited and markup is not rendered.