Temporary Options (Transients API)
In WordPress, there is a temporary caching mechanism — the so-called Transient Caching. In this type of caching, data is stored in the WordPress Database, in the wp_options
table for a specified period.
This type of caching is suitable for storing the results of complex or long operations. For example, saving the result of an HTTP request or saving the result of a heavy SQL query.
Temporary options (Transient options) standardize the caching of data in the database (or object cache). Data is stored as a pair key = value
for which a lifetime is specified. After the lifetime expires, the data will be deleted or overwritten (the row in the database will be deleted).
Temporary options are identical to regular WordPress options. They differ only in that a lifetime is added to temporary options.
IMPORTANT! If you have persistent object caching enabled, then the entire logic of Transient Caching automatically begins to work with object cache, i.e., the data is saved there instead of in the Database.
Auto-loading options
As you may know, all options with the autoload
flag in the wp_options
table are requested in one query and stored in the object cache. See the parameter $autoload in add_option().
However, if a lifetime is set for a transient option - parameter $expiration, then such an option will not be automatically loaded into the object cache, and two simple queries will be made to the database when it is retrieved: one to get the option itself, and another to get the lifetime of the option.
All Transient Option Functions
- get_transient( $transient )
- Get the value of a transient (a temporary option).
- set_transient( $transient, $value, $expiration )
- Set/update the value of a transient.
- get_site_transient( $transient )
- Retrieves the value of a site transient.
- set_site_transient( $transient, $value, $expiration )
- Sets/updates the value of a site transient.
- delete_expired_transients( $force_db )
- Deletes all expired transients.
- delete_site_transient( $transient )
- Deletes a site transient.
- delete_transient( $transient )
- Delete a transient.
Using Transient Options
The simplest example
Suppose we need to get HTML from a remote site and display it on our site. Let it be a block of the latest news. This is an expensive operation, so we will cache it for an hour in the transient cache:
$key = 'last_news_fetch'; $html = get_transient( $key ); if ( $html === false ) { // get HTML $resp = wp_remote_get( 'https://example.com/api/last-news' ); $html = wp_remote_retrieve_body( $resp ); set_transient( $key, $html, HOUR_IN_SECONDS ); } echo $html;
Done, now the request will be made only once an hour.
It is also important to sanitize the obtained HTML code for security, but I skipped this moment in the code for simplicity. You can use wp_kses() for sanitization.
Get likes from the Facebook API
Suppose we have a function that calls the Facebook API, requests an object (specifically a page) wpmag.ru, and returns the number of likes for that page.
function get_facebook_followers_count() { $result = wp_remote_get( 'https://graph.facebook.com/wpmag.ru' ); $result = wp_remote_retrieve_body( $result ); $result = json_decode( $result ); return $result->likes; } echo "Number of likes: " . get_facebook_followers_count();
The execution time of this function is huge and can take 0.5-2 seconds. This means that using this function on the site will increase the loading time of each page by that time.
To speed up this function, we can use WordPress transient caching and save the result for 1 hour:
function get_facebook_followers_count() { $cache_key = 'fb_followers'; // Output from transient cache $cached = get_transient( $cache_key ); if ( $cached !== false ) { return $cached; } $result = wp_remote_get( 'https://graph.facebook.com/wpmag.ru' ); $result = wp_remote_retrieve_body( $result ); $result = json_decode( $result ); $likes = $result->likes; // Write to transient cache for 1 hour set_transient( $cache_key, $likes, HOUR_IN_SECONDS ); return $likes; }
Thus, when this function is called for the first time, after receiving the request from Facebook, WordPress will write the result to the database, and for the next hour, it will return this result from the database without making repeated requests to the Facebook server. After an hour, the function will again call Facebook for data.
With this approach, only one call to this function per hour will increase the request time by 1-3 seconds, and subsequent calls will be returned instantly.
But for high-load projects, unfortunately, even this option is not suitable. Read more below.
Serialization of values
If a value needs to be serialized, it does not need to be done separately, WP does this automatically before saving.
Special time constants
WordPress has special time constants created for convenience:
MINUTE_IN_SECONDS // 60 (seconds) HOUR_IN_SECONDS // 60 * MINUTE_IN_SECONDS DAY_IN_SECONDS // 24 * HOUR_IN_SECONDS WEEK_IN_SECONDS // 7 * DAY_IN_SECONDS YEAR_IN_SECONDS // 365 * DAY_IN_SECONDS
Deleting Transient Options
Cleaning temporary options
WP automatically deletes all expired transient options after the expiration period. Deletion will occur:
-
When trying to get the value of an expired option through get_transient(). Calling
get_transient( 'option_name' )
will delete the expired option from the database and return false. - When a cron job is triggered to delete expired transient options. For this, the function delete_expired_transients() is triggered by cron.
When you need to manually delete a transient option, you can use the function delete_transient( $transient ). This may be useful, for example, when you need to delete a temporary option when saving a post, adding a category, and other events when the necessary temporary option should be cleared.
Example code for deleting a temporary option special_query_results
:
delete_transient( 'special_query_results' );
Transient Caching in High-Load Projects
The problem with transient caching in high-traffic projects is that when the cache expires, there is a time during which each request can re-initiate the data update procedure.
Suppose we are storing data from the Facebook API in the cache. Updating the transient cache in this case takes 1-3 seconds. Suppose we have 50 requests per second coming to the same page, which means we can get up to 50-150 requests trying to update the same transient cache.
That’s 50-150 HTTP requests to Facebook, as well as that many requests which will generate the page with a delay of 1-3 seconds (at best). For a project of such scale, this is a disaster.
Such problems are often referred to as "race conditions," and locks help solve them. For example, before making a request to Facebook for new data, our function can set a flag that will signal to other requests that the data update is already in progress, and repeated requests to Facebook should not be made.
function get_facebook_followers_count() { $cached = get_transient( 'fb_followers' ); if ( $cached !== false ) { return $cached; } // Set a lock $lock = add_lock( 'fb_followers' ); if ( ! $lock ) { return 0; } $result = wp_remote_get( 'https://graph.facebook.com/wpmag.ru' ); $result = json_decode( wp_remote_retrieve_body( $result ) ); $likes = $result->likes; // Write to transient cache for 1 hour set_transient( 'fb_followers', $likes, 1 * HOUR_IN_SECONDS ); // Release the lock release_lock( 'fb_followers' ); return $likes; }
The functions add_lock()
and release_lock()
are pseudo-functions; they are here only for demonstration. The locking mechanism can vary depending on the project, such as the server Memcached
or Redis
, GET_LOCK() in MySQL, or even an additional transient in WordPress.
Thus, the first request to update the transient cache will set a named lock. Subsequent requests will also attempt to set the lock but will not be able to since it has already been assigned to the first request, so subsequent requests will return 0 until the transient cache update is completed.
This method is far from ideal for two main reasons:
- Some visitors may see an inaccurate number of likes for 1-3 seconds
- The first request will still add 1-3 seconds to the page loading time
Of course, you can go further, store the last number of likes in an option and return it instead of zero, and you can make the option update process background using the WordPress task scheduler. Or you can use the TLC Transients library (see below).
TLC Transients Library
TLC Transients — is a library written by Mark Jaquith, one of the lead developers of the WordPress core. It provides functionality similar to the regular transient cache in WordPress but has some nice additions:
- When the cache expires, the value is not deleted.
- Cache updates occur exclusively via a background request.
- Convenient syntax for getting and updating the cache.
Let’s consider an example of using the TLC Transients library based on our task of obtaining the number of likes for a Facebook page:
// Get the number of likes for a Facebook page function get_facebook_followers_count() { $result = wp_remote_get( 'https://graph.facebook.com/wpmag.ru' ); $result = json_decode( wp_remote_retrieve_body( $result ) ); return $result->likes; } // Output the number of likes using TLC Transients echo tlc_transient( 'fb_followers' ) ->updates_with( 'get_facebook_followers_count' ) ->expires_in( 1 * HOUR_IN_SECONDS ) ->background_only() ->get();
The function get_facebook_followers_count()
calls the Facebook API for data, but unlike our first example, we never call this function directly. Instead, we use the object tlc_transient()
specifying our function for updating, the lifetime of the cache, and forcing background mode.
In this case, if the transient object fb_followers
exists, it will be displayed on the screen. If its lifetime has expired, it will still be displayed on the screen, but a separate request will asynchronously initiate the data update procedure, and only once.
Note that the function passed to the updates_with()
method must exist in the main context of WordPress, as the update procedure runs asynchronously separate from the current request.
You can learn more about the TLC Transients project on GitHub.
--
Used in writing:
- https://wpmag.ru/2015/transient-cache-wordpress/
- https://developer.wordpress.org/apis/handbook/transients/
- /2465/http-api-wordpress#keshirovanie-vo-vremennye-optsii