How to cache posts based on $_GET? Option name is too long? Options / transients

I have a search feature set up that is fairly expensive and I want to cache the results, based on the $_get string, like: ?search_type=product&relation=or&date=all&s=tagsearch&merchcat=cotton&brand=brandx&color=blue&etc=morestuff

So, i’m trying to cache the array of posts that I get:

Read More
if (false === ( $products = get_transient($name) ) ) {
    $products = getproducts();
    set_transient($name, $products, 60*60*12);
}

for the transient name, I’ve been trying various things like

$name= base64_encode(serialize($_GET));

But, I’m running into the problem of the option name getting truncated and possibly encoded, slashed, etc.

How would you go about solving this?

Related posts

1 comment

  1. Take a look at the relevant bits of the database description for that table.

    Field           Type        
    option_name     varchar(64)      
    option_value    longtext                  
    

    The key is 64 characters max. The value is longtext which should be more than you need.

    To have you caching work, you need a unique value for the key, but it doesn’t have to be readable. My suggestion would be to hash the GET string. It should be unique and well shy of 64 characters.

    Instead of this: $name= base64_encode(serialize($_GET));

    Try this: $name= wp_hash($_GET);

    Proof of concept using the sample GET string above:

    $str = '?search_type=product&relation=or&date=all&s=tagsearch&merchcat=cotton&brand=brandx&color=blue&etc=morestuff';
    var_dump(base64_encode(serialize($str)));
    // vs
    var_dump(wp_hash($str));
    

    Edit based on the discussion below (thanks @G-M):

    The order of the arguments in the GET string could effect the hash values. The safe thing to do is to normalize the array. The following should do that:

    $str = $_GET;
    ksort($str);
    $str = add_query_arg($str,'');
    $str = wp_hash($str);
    var_dump($str);
    

    All arguments are preserved, even the empty ones, which seem to be what the OP wants, though I personally believe that running the array through array_filter to remove empty values would actually provide better caching.

    $str = $_GET;
    $str = array_filter($str);
    ksort($str);
    $str = add_query_arg($str,'');
    var_dump(wp_hash($str));
    

    No data validation/sanitization was attempted.

    When you save that key to the database, I would also suggest prepending a string to make it identifiable– something like $str = 'my_plugin_slug'.$str before saving it.

Comments are closed.