Transients with dynamic WP_Query

I have read quite a few of your posts and it seems like your queries are really complex which either slows the page or simply crashes it.

Transients are definitely an option to store the results of such labor intensive queries. As @s_ha_dum mentioned, you’ll need to look into what you will be saving.

Would the “extra load” of transient checking and the space required in database outweight the possible resorce gain from transients?

You need to remember that transients are quite expensive to create, so that is something that you would not want to do every hour like you have said. A transient should be created with expiry times that would make them useful, like set the deletion time to something like days or month.

Once created, checking and getting data from a transients simply means 2 db calls in less than 0.002 seconds, so you definitely gain quite a lot on really expensive operations.

Space should never be an issue in the db as you would only want to store post ID’s and not the complete object. We want to store as little data in our transient as possible. It is going to mean that you would need to run a second query to get the post objects, but this query will be much leaner. The big score here would be that the first expensive query is dealt with and eliminated. The first query should also be much leaner because we would query id’s only.

You can and must in situations where input data is dynamic, use the input data to create a dynamic transient name. You need to remember, a transient’s name can only be 45 characters long. A name longer than 45 characters make that the transient is not created, and every page load tries to create a transient. As I said, transients are expensive to create and you do not want to create a transient on every page load as this will add even more load on an already overloaded query. I always pass my input data to md5() (which generate a 32 character key) to create a unique hashed key and then have a transient name like some_name_{md5()_result}. Just remember to convert arrays with json_encode() first and then use that result to pass to md5(). You can look into some of these posts to see examples using md5().

What might be an issue here is the amount of transients you are going to create. If you have a possible 1 million dynamic input combinations, you are going to create 1 million transients which can have effects when you delete the transients. This can again cause an issue with crashing the back end.

If the input is dynamic, you are going to save empty values as well for queries where no posts are returned, so you would need to take that into consideration.

What really is also a big factor here is, what is the possibility of two or ten or hundred users using the same exact input values in a week. I mean, there are no usefulness in creating a transient if only one or two people are ever going to use the same exact input values. As I said, creating transients are expensive, so you would not want to unnecessarily create a transient just for one or two people

At the end of day, you will need to take this info and decide how useful or useless a transient would be and then act on that.

Here is just an idea if you wish to have transients

// Here is your string of inputs
$args="value-1=value&value-2=250000";
// Create a unique hashed key from the arguments
$key = md5( $args );
//$key = md5( json_encode( $args ) ); // If $args is an array
// Set the transient name
$transient_name="custom_input_" . $key;

if ( false === ( $query = get_transient( $transient_name ) ) ) {
    $query = get_posts( $args . '&fields=ids' ) // Only get post ids. Alter if $args is an array

    // Set the transient only if we have results
    if ( $query )
        set_transient( 
            $transient_name, // Transient name
            $query, // What should be saved
            7 * DAY_IN_SECONDS // Lifespan of transient is 7 days
        );
}

// Now run the second query to get the full objects. Just add 'post_type' if this is not 'post' posts
if ( $query ) {
    $args = [
        'post__in'       => $query,
        'posts_per_page' => count( $query ),
        'order'          => 'ASC',
        'orderby'        => 'post_in'
    ];
    $q = new WP_Query( $args );
    var_dump( $q );
}

We can then just flush all transients when we publish a new post, deletes it, undelete or update a post

add_action( 'transition_post_status', function ()
{
    global $wpdb;
    $wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient%_custom_input_%')" );
    $wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient_timeout%_custom_input_%')" );
});