Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014

1,294 views

Published on

WordPress has a few built-in ways to cache data that enable rapid development. Understanding your options and how to use them properly in your context is crucial to a performant and scalable site. The Transients API provides a powerful and easy way to store data with an expiration, and it comes with a few under-the-hood perks as well.

Join me in looking at the benefits you can gain from understanding and implementing “transients”. When we’re done, you’ll know what this API is, when it should be used, how to use it, and how to scale it. I’ll give real, useful code examples that you can implement immediately—without boring you to death. You’ll be able to do anything from caching data from a external API (like recent tweets) to storing a large, complex query.

We’ll also cover some of the more obscure aspects of this method, like:
-Object caching/Memcached
-Autoloading
-Race Conditions
-Expired transient cleanup
-Options table bloat

Do yourself and your visitors a favor by utilizing the Transients API. And, as you’ll see in this session, knowing how to use it will make all WordPress’s caching techniques easy to implement.

  • Be the first to comment

  • Be the first to like this

Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014

  1. 1. temporary cache assistance: transients
  2. 2. The 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.”
  3. 3. The Transients API
 ! ✓ like Options API, but with expiration ✓ uses fast memory (if configured) ✓ uses database otherwise
  4. 4. Native Object Cache Plugin Option Persistent (database) N/A Transient Persistent (database) Persistent (varies) Cache Non-persistent (memory) Persistent (varies) Thanks to Rarst.
  5. 5. ScrobblesFriendsTweets thetransientsAPI externalAPIs Options API: Username, URL, ID
  6. 6. Custom QueriesRatingsTag Cloud thetransientsAPI expensivequeries
  7. 7. 3! mainfunctions
  8. 8. mainfunctions set_transient set_transient( $transient, $value, $expiration );
  9. 9. mainfunctions set_transientargs $transient ! ✓ (string) a unique identifier for your cached data ✓ 45 characters or less in length ✓ For site transients, 40 characters or less in length
  10. 10. mainfunctions set_transientargs $value ! ✓ (array|object) Data to save, either a regular variable or an array/object ! ✓ Handles serialization of complex data for you
  11. 11. mainfunctions set_transientargs $expiration ! ✓ (integer) number of seconds to keep the data before refreshing ! ✓ Example: 60*60*24 or 86400 (24 hours)
  12. 12. mainfunctions timeconstants MINUTE_IN_SECONDS = 60 (seconds) HOUR_IN_SECONDS = 60 * MINUTE_IN_SECONDS DAY_IN_SECONDS = 24 * HOUR_IN_SECONDS WEEK_IN_SECONDS = 7 * DAY_IN_SECONDS YEAR_IN_SECONDS = 365 * DAY_IN_SECONDS
  13. 13. mainfunctions get_transient get_transient($transient); ! ✓ If the transient does not exist, or has expired, returns false ✓ An integer value of zero/empty could be the stored data ✓ Should not be used to hold plain boolean values; array or integers instead
  14. 14. mainfunctions delete_transient delete_transient($transient);
  15. 15. mainfunctions wpmultisite set_site_transient(); get_site_transient(); delete_site_transient(); These work ‘network wide’.
  16. 16. 3! exampleusecases
  17. 17. cachetagcloud
  18. 18. cachetagcloud function get_tag_cloud() { ! if ( false === ( $tag_cloud = get_transient( 'my_tag_cloud' ) ) ) { ! $tag_cloud = wp_tag_cloud( 'echo=0' ); set_transient( 'my_tag_cloud', $tag_cloud, 60*60*24 ); ! } else { ! $tag_cloud = get_transient( 'my_tag_cloud' ); ! } ! return $tag_cloud; ! }
  19. 19. EXPERT ! ! MODE
  20. 20. cachetagcloud function edit_term_delete_tag_cloud() { delete_transient( 'my_tag_cloud' ); ! } ! add_action( 'edit_post', 'edit_term_delete_tag_cloud' );
  21. 21. cachemyissues
  22. 22. cachemyissues function we_have_issues() { if ( false === ( $issues = get_transient( 'we_have_issues' ) ) ) { $response = wp_remote_get('https://api.github.com/repos/twbs/bootstrap/ issues?assignee'); if ( is_wp_error( $response ) ) { $error_message = $response->get_error_message(); echo "This borked: " . $error_message; } else { $issues = wp_remote_retrieve_body($response); set_transient( 'we_have_issues', $issues, 60*60*24 ); } } else { $issues = get_transient( 'we_have_issues' ); } $issues = json_decode($issues, true); $issuereturn = ''; for ( $i = 0; $i < 5; $i++ ) { $issuereturn .= "<h3><a href='" . $issues[$i]["html_url"] . "'>". $issues[$i]["title"] . "</a></h3>"; } return $issuereturn; }
  23. 23. EXPERT ! ! MODE
  24. 24. cachemyissues function refresh_my_issues() { if ( current_user_can('edit_plugins') && isset($_GET['forcedel']) && $_GET['forcedel'] === 'yes' ) { delete_transient( 'we_have_issues' ); } } ! function refresh_via_admin_bar() { ! global $wp_admin_bar; $wp_admin_bar->add_menu( array( 'title' => __('Refresh'), 'href' => '?forcedel=yes', 'id' => 'refresh-issues', 'parent' => false ) ); ! } ! add_action( 'wp_before_admin_bar_render', 'refresh_via_admin_bar' );
  25. 25. cachebigquery
  26. 26. cachebigquery function query_for_commenters() { if ( false === ( $commenters = get_transient( 'top_commenters_cached' ) ) ) { global $wpdb; $commenters = $wpdb->get_results(" select count(comment_author) as comments_count, comment_author, comment_type from $wpdb->comments where comment_type != 'pingback' and comment_author != '' and comment_approved = '1' group by comment_author order by comment_author desc LIMIT 10 "); set_transient( 'top_commenters_cached', $commenters, 60*60*24 ); } else { $commenters = get_transient( 'top_commenters_cached' ); } $comment_list = '<ol>'; foreach($commenters as $commenter) { $comment_list .= '<li>'; $comment_list .= $commenter->comment_author; $comment_list .= ' (' . $commenter->comments_count . ')'; $comment_list .= '</li>'; } $comment_list .= '</ol>'; return $comment_list; }
  27. 27. cachebigquery function delete_query_for_commenters() { ! delete_transient( 'top_commenters_cached' ); ! } ! add_action( 'comment_post', 'delete_query_for_commenters' );
  28. 28. cachebigquery function popular_posts( $num=10 ) { if ( false === ( $popular = get_transient( 'popular_posts' . $num ) ) ) { $query = new WP_Query( array( 'orderby' => 'comment_count', 'posts_per_page' => $num ) ); set_transient( 'popular_posts' . $num, $query, 60*60*24 ); } else { $query = get_transient( 'popular_posts' . $num ); } ! return $query; }
  29. 29. cachebigquery $newquery = popular_posts(3); if ( $newquery->have_posts() ) { while ( $newquery->have_posts() ) { $newquery->the_post(); ?> <h4><?php the_title(); ?></h4> <?php the_excerpt(); ?> <?php } wp_reset_postdata(); }
  30. 30. cachebigquery function clear_popular_posts() { ! for ( $i = 0; $i < 50; $i++ ) { ! delete_transient( 'popular_posts' . $i ); ! } ! } ! add_action( 'edit_post', 'clear_popular_posts' );
  31. 31. EXPERT ! ! MODE
  32. 32. cachebigquery function popular_posts_panic( $num=10 ) { if ( false === ( $popular = get_transient( 'popular_posts' . $num ) ) ) { return ''; } else { $query = get_transient( 'popular_posts' . $num ); } ! return $query; } Thanks to Andrew Gray for the idea. Once a transient expires, it remains so until the new result is saved. Heavy traffic can mean too many concurrent MySQL connections.
  33. 33. cachebigquery $newquery = popular_posts_panic(3); if ( $newquery !== '' ) { if ( $newquery->have_posts() ) { while ( $newquery->have_posts() ) { $newquery->the_post(); ?> <h4><?php the_title(); ?></h4> <?php the_excerpt(); ?> <?php } wp_reset_postdata(); } }
  34. 34. cachebigquery function renew_popular_posts() { for ( $i = 0; $i < 50; $i++ ) { $query = new WP_Query( array( 'orderby' => 'comment_count', 'posts_per_page' => $i ) ); set_transient( 'popular_posts' . $i, $query, 60*60*24*365 ); } } ! add_action( 'hourly_renew_popular_posts', 'renew_popular_posts' ); ! if ( !wp_next_scheduled( 'hourly_renew_popular_posts' ) ) { wp_schedule_event( time(), 'hourly', 'hourly_renew_popular_posts' ); }
  35. 35. TOP OF HACKER NEWS ! ! CONQUERED
  36. 36. 4! warnings
  37. 37. expiry&garbagecollection ✓ everything works on request ✓ expired != deleted, unless requested ✓ unrequested, undeleted transients stay until you remove them explicitly
  38. 38. scalarvalues ✓ accepts scalar values (integer, float, string or boolean) & non-scalar serializable values (arrays, some objects) ! ✓ SimpleXMLElement will FREAK. OUT., so convert it to a string or array of objects (i.e. simplexml_load_string)
  39. 39. infinitetransients ✓ transients set without an expiration time are autoloaded ! ✓ if you don’t need it on every page, set an expiration (even if it’s a year) ! ✓ consider the Options API for non- transient data

  40. 40. cachinggotchas ✓ in some shared hosting environments, object caching can be slower than using the database; check your host’s recommended settings ! ✓ always use the Transients API to access transients; don’t assume they’re in the database (or vice versa)
  41. 41. 3! usefultools
  42. 42. TLC Transients Supports soft- expiration, background updating usefultools Artiss Transient Cleaner Deletes expired transients and optimizes table Debug Bar Transients Adds panel to Debug Bar with transient info
  43. 43. @cliffseal

×