WordPress Caching Explained: Object Cache vs Transients vs Reality

Table of Contents

Ask five developers how WordPress caching works, and you’ll likely get five different answers.

The confusion usually centers around two systems:

  • Object Cache
  • Transients API

They look similar. They are often used interchangeably. But they behave very differently—especially when persistent caching (Redis, Memcached) enters the picture.

This article breaks down the real mechanics behind these systems so you can stop guessing and start designing efficient caching strategies.

The Big Picture

WordPress caching operates in layers:

SQL
Request
↓
Object Cache (in-memory)
↓
Persistent Cache (Redis/Memcached) [optional]
↓
Database (fallback)

Transients sit on top of this system—but don’t behave the way most developers assume.

What is the Object Cache?

The Object Cache is a low-level caching system built into WordPress.

It stores data in memory during a request.

Basic Usage

PHP
<?php

\wp_cache_set( 'my_key', 'Hello World', 'my_group');
$value = \wp_cache_get( 'my_key', 'my_group');

echo $value;

Key Characteristics

  • In-memory (per request by default)
  • Fast (no database hit)
  • Grouped storage
  • Not persistent unless extended

Persistent vs Non-Persistent Object Cache

Non-Persistent (Default)

Without any plugin:

  • Cache exists only during the request
  • Cleared at the end of execution

Persistent (Redis / Memcached)

With a drop-in like object-cache.php:

  • Cache survives between requests
  • Stored in Redis or Memcached
  • Shared across processes

Example Behavior

PHP
// Request 1
\wp_cache_set( 'key', 'value' );

// Request 2
\wp_cache_get( 'key' ); // NULL without persistent cache

With Redis:

PHP
// Request 2
\wp_cache_get( 'key' ); // 'value'

Cache Groups (Underrated Feature)

Every cache entry belongs to a group.

PHP
<?php

\wp_cache_set( 'user_1', $data, 'users' );
\wp_cache_set( 'post_1', $data, 'posts' );

This allows:

  • Logical separation
  • Selective invalidation
  • Performance tuning

Persistent Groups

Some groups are always persistent:

PHP
<?php

\wp_cache_add_global_groups( ['users', 'site-options'] );

These are shared across requests even in multisite setups.

What Are Transients?

Transients are a higher-level caching API.

They provide:

  • Expiration support
  • Simplified interface

Basic Usage

PHP
<?php

\set_transient( 'my_data', 'Hello World', 3600 );
$value = \get_transient( 'my_data' );

Where Are Transients Stored?

This is where confusion begins.

  • Without persistent cache → stored in database
  • With persistent cache → stored in object cache

Transients Internals

Without Redis/Memcached:

YAML
wp_options table:
_transient_my_data
_transient_timeout_my_data

With Redis:

They bypass the database entirely.

Critical Misconception #1

“Transients are always database-based.”

False.

They are only database-backed when no persistent object cache exists.

Critical Misconception #2

“Transients always expire exactly on time.”

False.

Expiration is a maximum lifetime, not a guarantee.

They can disappear earlier due to:

  • Cache eviction (Redis/Memcached)
  • Manual deletion
  • Database cleanup

Critical Misconception #3

“Object cache and transients are separate systems.”

Not really.

Transients often use the object cache under the hood.

Redis / Memcached Behavior

With persistent caching:

  • Object cache becomes global
  • Transients skip database
  • Cache eviction policies apply

Example: Eviction Risk

If Redis memory is full:

  • Least recently used keys are removed
  • Transients may disappear early

Real-World Example: API Caching

PHP
<?php

$data = \get_transient( 'api_response' );

if ( $data === false ) {
    $data = file_get_contents( 'https://api.example.com/data' );
    \set_transient( 'api_response', $data, 600 );
}

echo $data;

This works across both database and Redis setups.

Advanced Pattern: Hybrid Caching

PHP
<?php

$key = 'expensive_query';

$data = \wp_cache_get( $key, 'custom' );

if ( $data === false ) {
    $data = \get_transient( $key );

    if ( $data === false ) {
        $data = run_expensive_query();
        \set_transient( $key, $data, 3600 );
    }

    \wp_cache_set( $key, $data, 'custom' );
}

This combines:

  • Fast in-memory cache
  • Persistent fallback

Performance Implications

  • Object cache reduces repeated computation
  • Persistent cache eliminates database hits
  • Transients simplify expiration logic

But misuse leads to:

  • Cache bloat
  • Stale data
  • Unpredictable expiration

When to Use What

Use Object Cache When:

  • Within a single request
  • You need maximum speed
  • No expiration needed

Use Transients When:

  • You need expiration
  • Data should persist across requests
  • Simplicity matters

Key Insight Most Developers Miss

Transients are not a storage system—they are a caching hint.

Object cache is not persistent—unless you make it so.

Once you understand this, everything becomes predictable.

FAQ

What is the difference between object cache and transients?

Object cache is a low-level in-memory caching system, while transients are a higher-level API that adds expiration and may use the object cache internally.

Are transients stored in the database?

Only when no persistent object cache is available. Otherwise, they are stored in memory systems like Redis.

Do transients expire exactly on time?

No, expiration is a maximum lifetime and transients can be removed earlier.

What is a persistent object cache?

It is an external caching system like Redis or Memcached that allows cache data to persist across requests.

Should I use Redis or Memcached?

Both are excellent, but Redis is more commonly used in modern WordPress setups due to flexibility and features.

Can I rely on transients for critical data?

No, transients should only be used for cacheable data since they can disappear at any time.

Final takeaway: WordPress caching isn’t confusing once you realize one thing—everything depends on whether your cache persists or not.

← How WordPress Hooks Actually Work: WP_Hook Deep Dive sunrise.php: The File That Lets You Override WordPress Multisite Routing →
Share this page
Back to top