WordPress Caching Strategies: Page Cache, Object Cache, and Transients

Caching is the single most effective way to improve WordPress performance. The right strategy depends on what you’re caching: full HTML pages, expensive database queries, or the results of external API calls. Here’s how the three main caching layers work and when to use each one.

Problem: A WordPress site is slow because it runs the same expensive database queries or external API calls on every page load, even when the underlying data has not changed.

Solution: Match the caching tool to the data: use a page cache plugin (WP Super Cache, W3 Total Cache) for full HTML output, the Object Cache API backed by Redis or Memcached for shared in-memory data, and the Transients API for short-lived external API responses stored in the database.

1. Page cache — stores the complete HTML output of a page so PHP and MySQL are bypassed entirely on subsequent requests. Plugins like W3 Total Cache, WP Super Cache, or LiteSpeed Cache handle this. On Nginx, you can also use FastCGI cache at the server level for the best performance.

2. Object cache (wp_cache API) — stores individual values in memory for the duration of the current request. Useful for de-duplicating expensive operations within a page load:

function get_all_categories_cached() {
    $cache_key = 'all_categories_tree';
    $cached    = wp_cache_get( $cache_key );

    if ( false !== $cached ) {
        return $cached;
    }

    $categories = get_terms( [ 'taxonomy' => 'category', 'hide_empty' => false ] );
    wp_cache_set( $cache_key, $categories );

    return $categories;
}

By default wp_cache is an in-memory store that's flushed at the end of every request. Install a persistent object cache backend (Redis or Memcached) to make it survive between requests:

# Install Redis and the WordPress drop-in
sudo apt install redis-server
wp plugin install redis-cache --activate
wp redis enable

3. Transients — a wrapper around the options table (or the object cache if a persistent backend is present) that stores time-limited values. Ideal for caching the results of external API calls:

function get_weather_data( $city ) {
    $transient_key = 'weather_' . sanitize_key( $city );
    $data          = get_transient( $transient_key );

    if ( false !== $data ) {
        return $data;
    }

    $response = wp_remote_get( "https://api.weather.example.com/v1/{$city}" );
    if ( is_wp_error( $response ) ) {
        return null;
    }

    $data = json_decode( wp_remote_retrieve_body( $response ), true );

    // Cache for 30 minutes
    set_transient( $transient_key, $data, 30 * MINUTE_IN_SECONDS );

    return $data;
}

NOTE: Transients stored in the database accumulate over time and are never automatically cleaned up unless they expire and are then accessed. Run wp transient delete --expired periodically via WP-Cron to keep the wp_options table tidy. With a persistent object cache backend, expired transients are evicted automatically by the cache layer.