When developing a bit of plugin code the other day, I ran into an issue with my transients not saving. Initially I thought there was a problem in my code, but diving deeper I found that it was actually an issue inside WordPress core!
I wanted to pull tweets from the Twitter API, but I wanted to cache the result in a transient, so that I don’t hit the API on every page load. Here is my code:
public function get_tweets($username, $args) { $transient_key = $username . '-tweets-' . md5(serialize($args)); if ( ($data = get_transient( $transient_key )) === false ) { //transient has expired - fetch fresh tweets $data = $this->get_tweets_from_api( $username, $args ); if ( $data !== false ) { set_transient( $transient_key, $data, $this->transient_expires ); } } return $data; }
Notice the line:
$transient_key = $username . '-tweets-' . md5(serialize($args));
This was hashing my arguments so that if I changed any argument then I would pull from the API again. For example, to get 10 tweets instead of 5, I did not want the cached transient to be returned, but rather a new transient key to be used. I thought I was being so clever
Don’t Use Long Transient Names
My calls to set_transient were not saving the values and my call to the Twitter API was being run on every page load, which killed my page load times. I was not happy.
So I stepped into the set_transient function to see what was going down, and that function in turn calls add_option which was silently throwing a MySQL error on the insert statement.
The reason: my transient key was too long. The ‘name’ field in the wp_options table only takes 64 characters, so an expiring transient can only have a maximum key length of 45 characters!
45 Is Your Max
45 is the max length for expiring transient keys. When an expiring transient is saved, a timeout option is also saved alongside it. And the key for that is ‘_transient_timeout_’ + your_transient_key.
For example, when trying to set the transient with a key of:
themergency-tweets-3cbf79c5a0bd8e255af9f0e7c181aa1a
it was also storing an option with a key of
_transient_timeout_themergency-tweets-3cbf79c5a0bd8e255af9f0e7c181aa1a
which ended up being 71 characters. The insert statement then failed and the transient was not being saved. Boooooo!
Surely 64 Characters is Not Enough?
64 characters just doesn’t seem long enough to me. And it seems I am not alone on this. Scribu submitted a trac ticket to change this. He submitted it 3 years ago and it is still not included in core!
Oh well, I guess that means it will never make it into core.