43
Advanced Caching An Introduction to methods in WordPress

Intro to advanced caching in WordPress

Embed Size (px)

DESCRIPTION

Presented at WordCamp Jerusalem 2013 (Feb. 20, 2013)

Citation preview

Page 1: Intro to advanced caching in WordPress

Advanced CachingAn Introduction to

methods in WordPress

Page 2: Intro to advanced caching in WordPress

Maor Chasen

WP Developer @ illumineaCore contributor for 3.5Have plugins on WordPress.orgOpen Source FanaticDesign EnthusiastFlying kites

Page 3: Intro to advanced caching in WordPress
Page 4: Intro to advanced caching in WordPress

It's not scary.

It's fun.

Page 5: Intro to advanced caching in WordPress

1. It's easy2. Your site = faster3. Can save you $$4. It will knock

your socks off5. You'll sleep better

at night.

Why caching is good for you?A question you shouldn't ask your mom

Page 6: Intro to advanced caching in WordPress

What we will talk about● What is fragment / object caching

● Why caching is important

● How to cache

● What to cache

● When to cache

Page 7: Intro to advanced caching in WordPress

What we won't talk about● Server setups

● Caching plugins

Page 8: Intro to advanced caching in WordPress
Page 9: Intro to advanced caching in WordPress

Transients APIfirst things first

Page 10: Intro to advanced caching in WordPress

Transients are● temporary bits of data (usually raw data)

● like options, but w/ expiration time

● always persistent out of the box

● stored in wp_options by default

● stored in memory if a caching backend (APC,

Memcache, XCache, etc.) is available

● available since 2.8

Page 11: Intro to advanced caching in WordPress

● fetching data from a remote source

● performing an expensive* query or request

○ meta_query

○ tax_query

● data persistence is absolutely required**

Use Transients when

* operations that require high CPU usage or high latency (Identify slow

queries with Debug Bar)

** ex. - when polling data from external sources

Page 12: Intro to advanced caching in WordPress

Transients functionsat your disposal

read core?wp-includes/option.php

Page 13: Intro to advanced caching in WordPress

get_transient( $transient );

Get it.

unique string (key) representing a piece of data

Page 14: Intro to advanced caching in WordPress

set_transient( $transient,$value,$expiration = 0

);

Set it.the data you wish to store

for how long?

Page 15: Intro to advanced caching in WordPress

delete_transient( $transient );

Scrap it.

unique string (key) representing a piece of data

Page 16: Intro to advanced caching in WordPress

get_site_transient();

set_site_transient();

delete_site_transient();

Multisite?You're in luck! All Transients functions have their network-wide counterparts.

Page 17: Intro to advanced caching in WordPress

Use case:Using Transients to store

fragmented data

Page 18: Intro to advanced caching in WordPress

wp_nav_menu( array( 'theme_location' => 'primary',

) );

<ul id="menu-primary" class="menu">

<li id="menu-item-10" class="menu-item">

<a href="...">...</a>

</li>

...

</ul>

Page 19: Intro to advanced caching in WordPress

Without usingwp_nav_menu()

After usingwp_nav_menu()

That is ~5 extra queries(for each menu)

Page 20: Intro to advanced caching in WordPress

Instead, we can cache the menu in a transientand save on DB queries

Page 21: Intro to advanced caching in WordPress

// Get an existing copy of our transient data

$menu_html = get_transient( 'wcj_2013_menu' );

if ( false === $menu_html ) {

// data is not available, let's generate it

$menu_html = wp_nav_menu( array(

'theme_location' => 'primary',

'echo' => false,

) );

set_transient( 'wcj_2013_menu', $menu_html, DAY_IN_SECONDS );

}

// do something with $menu_html

echo $menu_html; 60 * 60 * 24

returns the menu instead of printing

Page 22: Intro to advanced caching in WordPress

// Get an existing copy of our transient data

$menu_html = get_transient( 'wcj_2013_menu' );

if ( false === $menu_html ) {

// data is not available, let's generate it

$menu_html = wp_nav_menu( array(

'theme_location' => 'primary',

'echo' => false,

) );

set_transient( 'wcj_2013_menu', $menu_html );

}

// do something with $menu_html

echo $menu_html; doesn't expire, but it might anyway

Page 23: Intro to advanced caching in WordPress

function wcj_2013_invldt_menu( $menu_id, $menu_data ) {

delete_transient( 'wcj_2013_menu' );

}

add_action( 'wp_update_nav_menu', 'wcj_2013_invldt_menu', 10, 2 );

Now, let's invalidate

this action runs whenever a menu is being saved

Page 24: Intro to advanced caching in WordPress

Use Transients when fetching data from a remote source

http://...https://...

Page 25: Intro to advanced caching in WordPress

Twitter APIFacebook API

Google+ API

Pick your poison

last.fm API

Page 26: Intro to advanced caching in WordPress

Example (Twitter API):Retrieve follower count and cache the results

Page 27: Intro to advanced caching in WordPress

function wcj_2013_get_twitter_followers_for( $handle ) {

$key = "wcj_2013_followers_$handle";

if ( false === ( $followers_count = get_transient( $key ) ) ) {

// transient expired, regenerate!

$followers_count = wp_remote_retrieve_body(

wp_remote_get( "http://api.twitter.com/1/users/show.json?

screen_name=$handle" )

);

// request failed?

if ( empty( $followers_count ) )

return false;

// extract the number of followers

$json = (object) json_decode( $followers_count );

$followers_count = absint( $json->followers_count );

// request was complete, store data in a transient for 6 hours

set_transient( $key, $followers_count, 6 * HOUR_IN_SECONDS );

}

return $followers_count;

}

Page 28: Intro to advanced caching in WordPress

function wcj_2013_get_twitter_followers_for( $handle ) {

$key = "wcj_2013_followers_$handle";

if ( false === ( $followers_count = get_transient( $key ) ) ) {

// transient expired, regenerate!

$followers_count = wp_remote_retrieve_body(

wp_remote_get( "http://api.twitter.com/1/users/show.json?

screen_name=$handle" )

);

// request failed?

if ( empty( $followers_count ) )

return false;

// extract the number of followers

$json = (object) json_decode( $followers_count );

$followers_count = absint( $json->followers_count );

// request was complete, store data in a transient for 6 hours

set_transient( $key, $followers_count, 6 * HOUR_IN_SECONDS );

}

return $followers_count;

}

Page 29: Intro to advanced caching in WordPress

function wcj_2013_get_twitter_followers_for( $handle ) {

$key = "wcj_2013_followers_$handle";

if ( false === ( $followers_count = get_transient( $key ) ) ) {

// transient expired, regenerate!

$followers_count = wp_remote_retrieve_body(

wp_remote_get( "http://api.twitter.com/1/users/show.json?

screen_name=$handle" )

);

// request failed?

if ( empty( $followers_count ) )

return false;

// extract the number of followers

$json = (object) json_decode( $followers_count );

$followers_count = absint( $json->followers_count );

// request was complete, store data in a transient for 6 hours

set_transient( $key, $followers_count, 6 * HOUR_IN_SECONDS );

}

return $followers_count;

}

Page 30: Intro to advanced caching in WordPress

function wcj_2013_get_twitter_followers_for( $handle ) {

$key = "wcj_2013_followers_$handle";

if ( false === ( $followers_count = get_transient( $key ) ) ) {

// transient expired, regenerate!

$followers_count = wp_remote_retrieve_body(

wp_remote_get( "http://api.twitter.com/1/users/show.json?

screen_name=$handle" )

);

// request failed?

if ( empty( $followers_count ) )

return false;

// extract the number of followers

$json = (object) json_decode( $followers_count );

$followers_count = absint( $json->followers_count );

// request was complete, store data in a transient for 6 hours

set_transient( $key, $followers_count, 6 * HOUR_IN_SECONDS );

}

return $followers_count;

}

printf( 'I have %d followers!', wcj_2013_get_twitter_followers_for( 'maorh' ) );

Page 31: Intro to advanced caching in WordPress

Let's spice it upGot some metrics!

Page 32: Intro to advanced caching in WordPress

Without Transients0.36014295 seconds

WITH Transients0.00010109 seconds

Page 33: Intro to advanced caching in WordPress

That is

3,562 X FASTER

Page 34: Intro to advanced caching in WordPress
Page 35: Intro to advanced caching in WordPress

Object Cache APIlast but not least

Page 36: Intro to advanced caching in WordPress

Object Cache is● non-persistent out of the box

● stored in PHP memory by default

● ideally* persistent when a caching backend is

available

● similar to Transients

● available since 2.0

* Success depends on server environment

Page 37: Intro to advanced caching in WordPress

Is post_id = 13

cached?

Do something with that post

Store results in Object Cache

DBSELECT * FROM

wp_posts WHERE ID =

13

Yes

No

Common use of the Object Cache API

Page 38: Intro to advanced caching in WordPress

Object Cache functionsat your disposal

read core?wp-includes/cache.php

Page 39: Intro to advanced caching in WordPress

● wp_cache_add( $k, $d, $g, $ex )

● wp_cache_get( $k )

● wp_cache_set( $k, $d, $g, $ex )

● wp_cache_delete( $k, $g )

● wp_cache_incr( $k, $offset, $g )

Object Cache functionsat your disposal

$key, $data, $group, $expiration

Page 40: Intro to advanced caching in WordPress

$song_obj = wp_cache_get( $id, 'songs' );

if ( false === $song_obj ) {

$song_obj = $wpdb->get_row(

$wpdb->prepare( "SELECT * FROM

$wpdb->songs WHERE ID = %d", $id )

);

wp_cache_set( $id, $song_obj, 'songs' );

}

// do something with $song_obj

Example

Page 41: Intro to advanced caching in WordPress

Best Practicesfor the best of us

● prefer refreshing the cache ONLY when data is

added/changed

● Avoid, if possible, caching on front end page requests

(instead, generate the data on an admin event*)

● Design to fail gracefully (never assume that data is in the

cache)

* useful events: publish_post, transition_post_status, created_{$taxonomy}, edited_{$taxonomy}

Page 42: Intro to advanced caching in WordPress

Out of the boxMemory Cache

Backend

Transients API persistent - database Persistent

Object Cache APInon-persistent -

memoryIdeally Persistent

http://wordpress.stackexchange.com/a/45137

Side-by-side comparison

Page 43: Intro to advanced caching in WordPress

Questions?Thanks!

@maorhkeep in touch