WordPress Transients

this ⊆ WordPress Performance

Created by Ethan Clevenger
  @ethanclevenger
  ethanclevenger91

This is a tech talk

What Transients?

The Codex:

[The WordPress Transients API] offers a simple and standardized way of storing cached data in the database temporarily by giving it a custom name and a timeframe after which it will expire and be deleted.

Why Transients?

Performance

Slow site = high bounce rate

Fast site = fun site!

Big O - nx


foreach($foo as $b => $bar) {
  foreach($bar as $f => $fizz) {
    foreach($fizz as $z => $buzz){
      ...
    }
  }
}
            

APIs

$this->fetchUrl("https://graph.facebook.com/{$id}/posts?access_token={$tkn}");

Nasty SQL


SELECT AUI.idea_id, AUI.title, AUI.events,
  GROUP_CONCAT(IC.category_name SEPARATOR ';') as categories
  FROM (
  	SELECT UI.idea_id, UI.title, GROUP_CONCAT(IE.events SEPARATOR ';') as events ,
  	       CONCAT(';',UI.idea_categories,';') as temp_categories
   	FROM user_idea UI
  	LEFT JOIN idea_events IE ON UI.idea_id = IE.idea_id
  	GROUP BY UI.idea_id
  ) AS AUI
  INNER JOIN idea_categories IC
  ON AUI.temp_categories LIKE CONCAT('%;',IC.category_id,';%')
  GROUP BY AUI.idea_id;

When Transients?

Generally

  • You know when data will expire
  • You know the event that will cause data to expire

But Also

Any time a little outdated information isn't a big deal

How Transients?

A Simple, Local Example

Before


$mPosts = new WP_Query(['post_type'=>'post', 'posts_per_page'=>-1]);
if($mPposts->have_posts()): while($mPosts->have_posts()): $mPosts->the_post();
  echo '
'; echo '

'.get_the_title().'

'; the_content(); echo '
'; endwhile; endif;

After


$mPosts = get_transient('my_posts');
if($mPosts === false) {
  $mPosts = new WP_Query(['post_type'=>'post', 'posts_per_page'=>-1]);
  set_transient('my_posts', $mPosts, DAY_IN_SECONDS);
}
if($mPosts->have_posts()): while($mPosts->have_posts()): $mPosts->the_post();
  echo '
'; echo '

'.get_the_title().'

'; the_content(); echo '
'; endwhile; endif;

Still needs some work

  • Abstract that shit
  • What if I post?

Good


$mPosts = get_transient('my_posts');
if($mPosts === false) {
  $mPosts = new WP_Query(['post_type'=>'post', 'posts_per_page'=>-1]);
  set_transient('my_posts', $mPosts, DAY_IN_SECONDS);
}
if($mPosts->have_posts()): while($mPosts->have_posts()): $mPosts->the_post();
  //make it look pretty
endwhile; endif;

Better


$mPosts = getMyPosts();

function getMyPosts() {
  $mPosts = get_transient('my_posts');
  if($mPosts === false) {
    $mPosts = refreshPostsTransient();
  }
  return $mPosts;
}

function refreshPostsTransient() {
  $mPosts = new WP_Query(['post_type' => 'post', 'posts_per_page' =>-1]);
  set_transient('my_posts', $mPosts, DAY_IN_SECONDS);
  return $mPosts;
}

I just posted about an event in two hours and the transient doesn't expire for four hours!

Hook


add_action('save_post', 'refreshPostsTransient');

Best


add_action('save_post', [$this, 'refreshPostsTransient']);

A thought

What if my transient takes a really long time to generate?

How About a Cron?

Here's the pitch


http://mysite.com?mytransient=refresh

Glove ready


add_action('init', [$this, 'maybe_refresh_transient']);

Catch


public function maybe_refresh_transient() {
  if('refresh' === $_GET['mytransient']) {
    $this->refreshPostsTransient();
  }
}

Third-Party APIs


public function getResults($platform) {
  $results = get_transient("social_feeds_results_{$platform}");
  if(false === $results) {
    $results = array();

    switch($platform) {
      case 'twitter' :
      $results = $this->_getResultsTwitter();
      break;
      case 'facebook' :
      $results = $this->_getResultsFacebook();
      break;
    }
    set_transient("social_feeds_results_{$platform}", base64_encode(maybe_serialize($results)), HOUR_IN_SECONDS);
  }
  return maybe_unserialize(base64_decode($results));
}

$tweets = $socialFeeds->getResults('twitter');

Get Silly

Data URI as image src


function fetchLastThousandInstagramPicturesTransient() {
  $images = get_transient('thousand_instagram_pictures');
  if($images === false) {
    $images = fetchLastThousandInstagramPictures(); //an array of URLs
    $images = dataUriEncodeImages($images);
    set_transient('thousand_instagram_pictures', $images, HOUR_IN_SECONDS);
  }
  return $images;
}

function dataUriEncodeImages($images) {
  $imagesAsData = [];
  foreach($images as $image) {
    $imagesAsData[] = getDataURI($image);
  }
  return $imagesAsData;
}

function getDataURI($image) {
  return 'data: '.mime_content_type($image).';base64,'.base64_encode(file_get_contents($image));
}

$images = fetchLastThousandInstagramPicturesTransient();
foreach($images as $image) {
  echo '';
}

Resources

  1. David Walsh
  2. WordPress Codex
  3. Reveal.js

Find this talk

http://ethanclevenger.com/wordpress-transients