Fun with WordPress Transients

It has been awhile since I have written, but I wanted to detail how and when to use WordPress transients. First off, what are transients? WordPress has a great API for storing data that might be either the results of an expensive/complex query, or data that does not change that often. The rationale behind these is to make the pages load faster without having to do the expensive queries for every user that visits your site. They offer us an expiration date so that the data can be regenerated on a schedule. Let's say that you have a site displays posts after filtering by custom fields and categories. In order to perform this filter, there are a number of table joins that have to occur to generate the posts that meet the criteria. Transients are great because they give us the ability to store the results of the query in the options table for quick and easy retrieval. Once you set a transient value, a site visitor will retrieve that data as opposed to doing all of the database heavy lifting. If you put an expiration of 10 minutes on the data and you have 1000 visitors an hour coming to your site, that means that only 6 people will actually have to do the query from scratch. I will go through a couple of different examples below
<?php

// first a simple query to demonstrate how this works
// let's create a function that will return the transient for future use
function get_my_favorite_books() {

        // first try to go and get the transient
        $favorite_books = get_transient( 'favorite_books' );

        // then we check to see if the transient is there
        if ( !$favorite_books ) {

                // if it is not there, or has expired, then we can go and build the results
                $query_args = array(
                        'post_type' => 'post',
                        'tag'           => 'favorite-books'
                );

                $results = new WP_Query( $query_args );

                // now that we have the results we can store this in the transient for later retrieval
                // the arguments are " 'transient_name', $data_to_store, 'expiration date in seconds' )
                set_transient( 'favorite_books', $results, 3600 );
                $favorite_books = get_transient( 'favorite_books' );

        }

        // now we can return the results.
        // if the transient was there in the beginning, then we are just returning the original reference to $favorite_books,
        // otherwise we are returning the freshly set transient
        return $favorite_books;

}

// now you can call this function like this....
$favorite_books = get_my_favorite_books();
// now since this was a WP_Query object, we can do a regular loop
if ( $favorite_books->have_posts() ) : while ( $favorite_books->have_posts() ) : $favorite_books->the_post(); global $post;
?>
        <h2><?php the_title(); ?></h2>
        <div class="post_tags"><?php the_tags(); ?></div>
        <div class="post_content"><?php the_content(); ?></div>

<?php
endwhile; endif;
now let's try a more complicated query to see the real power of why these are really great
<?php
function get_complex_query_results() {

        // first try to go and get the transient
        $complex_query_results = get_transient( 'complex_query_results' );

        // then we check to see if the transient is there
        if ( !$complex_query_results ) {

                // if it is not there, or has expired, then we can go and build the results
                $query_args = array(
                        'post_type' => 'my-custom-post-type',
                        'tax_query' => array(
                                'relation' => 'OR',
                                array(
                                        'taxonomy' => 'my-custom-taxonomy',
                                        'field'    => 'slug',
                                        'terms'    => array( 'my-term-1', 'my-term-2' )
                                ),
                                array(
                                        'taxonomy' => 'my-other-custom-taxonomy',
                                        'field'    => 'slug',
                                        'terms'    => array( 'my-other-term-1', 'my-other-term-2' )
                                )                               
                        ),
                        'meta_query' => array(
                                array(
                                        'key'     => 'price',
                                        'value'   => array( '100','1000' ),
                                        'type'    => 'numeric',
                                        'compare' => 'BETWEEN'
                                )
                        ),
                        'orderby' => 'title',
                        'order'   => 'ASC'
                );

                $results = new WP_Query( $query_args );

                // One cool use of this is that you can feed in POST or GET variables into the query_args and cache search results
                // you could use the search query as the transient and then look for that transient.
                // if the transient exists, then someone else has performed the same search.  
                // why do the query if someone else already has?

                // now that we have the results we can store this in the transient for later retrieval
                // the arguments are " 'transient_name', $data_to_store, 'expiration date in seconds' )
                set_transient( 'complex_query_results', $results, 86400 );
                $complex_query_results = get_transient( 'complex_query_results' );

        }

        // now we can return the results.
        // if the transient was there in the beginning, then we are just returning the original reference to $complex_query_results,
        // otherwise we are returning the freshly set transient
        return $complex_query_results;  

}

// now you can call this function like this....
$complex_query_results = get_complex_query_results();
// now since this was a WP_Query object, we can do a regular loop
if ( $complex_query_results->have_posts() ) : while ( $complex_query_results->have_posts() ) : $complex_query_results->the_post(); global $post;
?>
        <h2><?php the_title(); ?></h2>
        <div class="post_content"><?php the_content(); ?></div>

<?php
endwhile; endif;
?>
Now let's say that you only write a new article that would be displayed by the complex query once a week. Why should every user be getting the results by performing the query? With the complex example, the transient will live for 1 day. So over the course of a day, only one user will be actually doing the database heavy lifting. I hope this helps you out and will make your blog or site more efficient. These are very helpful and should be used to eliminate excess database queries. For more information, view the Transients API on the WordPress Codex
Post a comment
  1. Jean Galea

    Very well explained. What is the purpose of line 24?

    • Matthew Price

      Hi Thanks for the kind words. So the way the works is as follows. The first thing you do is try to get the transient from the database. If it doesn't exist then we need to grab a fresh copy of the data. So after you set the transient with the new data, you need to get the data again so when you "return $favorite_books;", you actually return valid data. If the transient exists, then the function uses the value from line 8. Make sense?






Real Time Web Analytics ^