Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Caching and scheduled tasks

A request to an external service or a heavy selection need not run every time a page is opened. The result is saved for a while — in a transient. And what must happen regularly — cleaning up, syncing, mailing — is given to the WP-Cron scheduler.

Transients

A transient is a value with a limited lifetime:

function mytheme_get_rates(): array
{
    $rates = get_transient('mytheme_rates');
 
    if ($rates !== false) {
        return $rates;
    }
 
    $response = wp_remote_get('https://api.example.com/rates', ['timeout' => 5]);
 
    if (is_wp_error($response)) {
        return [];
    }
 
    $rates = json_decode(wp_remote_retrieve_body($response), true) ?: [];
 
    set_transient('mytheme_rates', $rates, HOUR_IN_SECONDS);
 
    return $rates;
}

get_transient() returns false if the value does not exist or has expired. Then the data is fetched again and saved for an hour.

Time constants

ConstantValue
MINUTE_IN_SECONDS60
HOUR_IN_SECONDS3600
DAY_IN_SECONDS86400
WEEK_IN_SECONDS604800

Clearing the cache

A saved value is deleted when the data changes:

add_action('save_post_book', function () {
    delete_transient('mytheme_top_books');
});

The object cache

By default transients live in the options table. If Redis or Memcached is installed on the server and an object cache plugin is connected, they move into memory automatically, and code can use groups as well:

$books = wp_cache_get('top', 'books');
 
if ($books === false) {
    $books = get_posts(['post_type' => 'book', 'numberposts' => 5]);
 
    wp_cache_set('top', $books, 'books', HOUR_IN_SECONDS);
}

Without such a plugin wp_cache_set() keeps the value only until the end of the current request.

A scheduled task

// books.php
 
register_activation_hook(__FILE__, function () {
    if (!wp_next_scheduled('books_daily_cleanup')) {
        wp_schedule_event(time(), 'daily', 'books_daily_cleanup');
    }
});
 
add_action('books_daily_cleanup', function () {
    // delete drafts older than a month
});
 
register_deactivation_hook(__FILE__, function () {
    wp_clear_scheduled_hook('books_daily_cleanup');
});

wp_schedule_event() ties a schedule to a hook name, and a regular add_action() does the work. The built-in intervals: hourly, twicedaily, daily, weekly.

A one-off task

wp_schedule_single_event(time() + 10 * MINUTE_IN_SECONDS, 'books_send_reminder', [$orderId]);

How WP-Cron works

WP-Cron is not a real scheduler. It checks the schedule when someone opens the site. On a site without visitors a task does not run on time, and on a busy one the check happens on every request. So on a live site the built-in trigger is turned off and the system cron calls it:

// wp-config.php
 
define('DISABLE_WP_CRON', true);
*/5 * * * * cd /var/www/blog && wp cron event run --due-now

Checking

wp cron event list
wp cron event run books_daily_cleanup
wp transient delete --all

Common mistake

Calling wp_schedule_event() without the wp_next_scheduled() check — and on the init hook at that — adds a new task on every page load. A day later the schedule holds thousands of copies, and the site runs them all. Schedule a task once, on plugin activation, and remove it on deactivation.

Thanks for reading!

Donate to the site — we work hard for you.