Redis Object Cache
A persistent WordPress object cache backed by Redis via the PhpRedis extension. New in
v2.0.0. Replaces wp-content/object-cache.php with a Redis-backed WP_Object_Cache
that's a drop-in superset of Till Krüss's redis-cache and Pantheon's wp-redis —
you can swap in without editing wp-config.php.
What it does
Persistent storage for the WordPress object cache, so values written by
wp_cache_set() survive across PHP requests. Without a drop-in like this one,
WordPress's default object cache lives in PHP memory for a single request and is
discarded when the request ends — every page rebuilds everything from scratch.
Requirements
- The PhpRedis PHP extension (a C extension, much faster than pure-PHP alternatives).
- A reachable Redis server.
If PhpRedis isn't installed, the Object Cache tab in wp-admin tells you so and the plugin doesn't try to install the drop-in.
Common installation paths:
- Debian/Ubuntu:
apt install php-redis - RHEL/Rocky/Alma:
dnf install php-pecl-redis6(via remi-modular) - macOS (Homebrew PHP):
pecl install redis
Installation
- Set the Redis connection constants in
wp-config.php(onlyWP_REDIS_HOSTis strictly required for a local Redis on the default port):
define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_DATABASE', 0 );
define( 'WP_REDIS_PREFIX', 'mysite_' );
-
In wp-admin, open Cacheability Pro → Object Cache. Confirm the connection shows green (sub-millisecond is normal on a local Redis).
-
Click Install drop-in. The drop-in is copied to
wp-content/object-cache.php. The tab will reload and show "Installed (ours, v1)". -
Browse a few pages, then come back. The connection panel updates; the drop-in is now serving cache reads.
To remove it, click Remove drop-in. We never touch a foreign drop-in installed by another plugin.
Configuration constants
All read from wp-config.php. None are required for a local Redis on default port.
| Constant | Default | Purpose |
|---|---|---|
WP_REDIS_HOST |
127.0.0.1 |
Redis hostname or IP. |
WP_REDIS_PORT |
6379 |
Redis port. |
WP_REDIS_SOCKET |
(none) | Unix socket path. Used instead of host/port when set. |
WP_REDIS_DATABASE |
0 |
Redis DB number to SELECT. |
WP_REDIS_PREFIX |
(none) | Cluster-wide key prefix. Use {blog_id} token for multisite to keep sites isolated, e.g. site_{blog_id}_. |
WP_REDIS_PASSWORD |
(none) | Redis AUTH password. |
WP_REDIS_USERNAME |
(none) | Redis 6 ACL username (paired with PASSWORD). |
WP_REDIS_TIMEOUT |
1.0 |
Connect timeout in seconds. |
WP_REDIS_READ_TIMEOUT |
1.0 |
Read timeout in seconds. |
WP_REDIS_URL |
(none) | One-line config: redis://[user:pass@]host:port[/db][?prefix=foo:]. Decomposes into the individual constants above. |
WP_REDIS_TLS |
false |
When true, connects over TLS. The host is prefixed with tls:// automatically. |
WP_REDIS_TLS_CA |
(none) | Path to CA cert for TLS verification. |
WP_REDIS_TLS_VERIFY_PEER |
true |
Verify the Redis server's TLS cert. |
WP_REDIS_DISABLED |
false |
Master kill switch. When true, the drop-in returns early and WordPress falls back to its default in-memory cache. Set this if Redis is misbehaving and you need an instant rollback. |
WP_REDIS_PERSISTENT |
false |
Use pconnect() instead of connect(). Faster but can leak handles on PHP fatals. |
WP_REDIS_MAXTTL |
0 (no cap) |
Maximum TTL we'll accept; longer expirations get capped. The cap counter is surfaced in the admin tab so you know when it fires. |
WP_REDIS_GRACEFUL |
true |
Swallow RedisException silently. Disable for development if you want errors to surface. |
WP_REDIS_GLOBAL_GROUPS |
(none) | Array of group names treated as global across multisite (extends our defaults). |
WP_REDIS_IGNORED_GROUPS |
(none) | Array of group names that stay in-process and never round-trip Redis (extends our defaults). |
WP_REDIS_SCAN_COUNT |
1000 |
Batch size for SCAN operations during flush. |
WP_REDIS_ALLOWED_CLASSES |
(built-in safelist) | Override the object-injection safelist. Array of allowed class names, or true to allow all (debug only). |
Storage format
The drop-in writes every value with a 2-byte type prefix so reads dispatch correctly without trial-and-error unserializing:
| Prefix | Meaning | Example |
|---|---|---|
s: |
raw string scalar | s:hello world |
i: |
integer | i:42 |
b: |
boolean | b:1 |
f: |
float | f:3.14 |
p: |
PHP serialize() payload | p:a:1:{s:1:"a";i:1;} |
This is custom — other drop-ins won't read it. The key namespace is ours alone, so
there's no collision. If you inspect Redis with redis-cli you'll see these prefixes.
Migration from redis-cache (Till Krüss)
- Run
wp redis disableto remove that plugin's drop-in cleanly via WP_Filesystem. - Deactivate the "Redis Object Cache" plugin in Plugins.
- Confirm
wp-content/object-cache.phpis gone. - In Cacheability Pro → Object Cache, click Install drop-in.
If WP-CLI isn't available, deactivate the plugin and delete the file by hand via SFTP / your file manager, then install ours.
Migration from wp-redis (Pantheon)
- Deactivate the "WP Redis" plugin in Plugins.
- Delete (or unlink)
wp-content/object-cache.php. - In Cacheability Pro → Object Cache, click Install drop-in.
Note: Pantheon's plugin doesn't ship a CLI uninstaller, so the manual file deletion is required.
Comparison with redis-cache and wp-redis
| What we do differently | Till Krüss redis-cache |
Pantheon wp-redis |
|---|---|---|
One round-trip MGET for wp_cache_get_multiple |
Per-key timing + serialize loop | Hash-fallback loop |
Scalars stored without serialize() (raw i:42) |
serialize("42") → "i:42;" |
Always serialize non-int |
wp_cache_flush scoped to site only, SCAN + UNLINK |
Hardcoded SCAN count, global flush risk | Blocking FLUSHDB |
Object-injection-safe unserialize with class safelist |
(paid-tier feature) | Raw unserialize |
| Re-serializes a string that looks serialized | Yes (bug) | OK |
Per-group wp_cache_delete always hits Redis |
OK | Footgun: WP_REDIS_USE_CACHE_GROUPS=false by default |
| TLS + Redis 6 ACL out of the box | Paid-tier feature | None |
WP_REDIS_DISABLED honored |
Yes | No |
| One-click installer in wp-admin | Yes | No (manual symlink) |
| Detects and warns about competing drop-ins | Limited | None |
| Multisite shared-prefix warning | None | None |
Each row is backed by a test in tests/test_redis_cache.py (the file's docstring lists
which tests prove which claim). Run make tests-redis-up to see them green.
Troubleshooting
Connection refused. Redis isn't running on the configured host/port. Run
redis-cli ping from the WordPress host to confirm reachability.
AUTH required. Set WP_REDIS_PASSWORD (and WP_REDIS_USERNAME for ACL users).
DB mismatch. Make sure WP_REDIS_DATABASE matches what you intend — Redis defaults
to DB 0, but if another service uses DB 0 you may want DB 1, 2, etc.
Cache won't flush. We use SCAN + UNLINK scoped to our prefix, so flushes never
clobber other prefixes in the same Redis DB. If you see stale data, double-check that
WP_REDIS_PREFIX is set the way you expect and that no other code path is writing
under that prefix.
Foreign drop-in warning. Another plugin has installed wp-content/object-cache.php.
Follow the migration steps above for that plugin before installing ours. The warning
links to the right steps for the detected plugin.
Site goes down after enabling. Set define( 'WP_REDIS_DISABLED', true ); in
wp-config.php as an instant rollback — the drop-in returns early and WordPress falls
back to its default in-memory cache.
Multisite
Use {blog_id} in WP_REDIS_PREFIX so each site has its own namespace and wp_cache_flush
on one site doesn't affect the others:
define( 'WP_REDIS_PREFIX', 'site_{blog_id}_' );
The admin tab shows a red warning when it detects multisite without a per-site prefix.