Caching in WordPress

I’ve been learning a lot about caching in WordPress lately and thought I’d share a few things I’ve learned (and document them for myself).

Why Cache?

Caching is a common technique used to speed up your experience on the Internet. The general idea is that instead of requesting resources (images, files, etc.) directly from the source, you instead request them from a cache, which is generally faster. In the case of WordPress, each time you request a page, the server has to process a bunch of PHP and come up with the HTML to render. Depending on your site, this processing can be pretty resource intensive, making you wait an extra second or two for the page to load.

Caching speeds up that PHP processing by caching the result(s) for future use. Let’s say you have a sidebar widget that displays the most recent posts. Without cache, each time a page was loaded, WordPress would have to query the database and find the three most recent posts. This is inefficient since this list likely doesn’t change between every page load. With cache, the first time this list is generated, it makes sense to put it in cache so that next time someone needs the list of most recent posts, it doesn’t have to query the database–instead, it just pulls it directly from cache.

When the list of recent posts changes (i.e. you publish a new post) you can “bust” the cache and delete the old list. The next time a page is requested, it’ll query the database, get the new list, and put in the cache for any future requests.

Now for the WordPress specific implementations of cache:

WP Object Cache

The object cache does just that–caches objects. It does this by using key/value pairs, with an optional group (for namespacing purposes) and expiration date. By default, however, this cache is not persisted–it lives for the duration of the request only. The WP documentation says that if you need to guarantee that something is cached, use the Transients API instead.

The Transients API

Transients are also cached objects using key/value pairs, like the Object Cache, but with two major differences:

  1. They are persisted in the wp_options table by default (Object Cache isn’t persisted by default), and
  2. They require an expiration date (which is optional for Object Cache)

Transients are better suited for information that you know will expire.

Persistent Cache

If you have a persistent cache plugin enabled and configured, then it changes the behavior of both the Transients API and the WP Object Cache. Most notably: with persistent caching enabled, the Transients API will use the WP Object Cache methods and store to persistent cache instead of saving to the wp_options table. These two caching methods are essentially combined into one and stored in persistent cache.

For example, calling this method:

set_transient( $key, $value, $expiration );

will actually do this:

wp_cache_set( $key, $value, 'transient', $expiration );

The object cache group is automatically set to ‘transient’ when using the Transients API with persistent cache.

How Persistent Cache Works

The way persistent cache works is pretty simple. When persistent cache is configured, each request that would normally go to the database will first check the cache. If nothing is found in cache, then the request continues on to the database. Once the request gets a response from the database, it puts that response in cache for future requests.

With persistent caching enabled, if the requested object is cached, the database is never touched.

Persistent Cache Plugins for WordPress

There are several WordPress plugins that offer persistent caching. You might be familiar with a few of the major players, like W3 Total Cache or WP Super Cache. I’m not going to go into detail on the pros and cons of the plugins here–there are plenty of blog posts out there that address this. Any plugin that deals with caching is going to take some configuration, so expect that upfront.

Manually Purging WooCommerce Shipping Rate Cache

I’ve been working on changing the shipping structure for a client site running WooCommerce. When I started changing the shipping options and refreshing the page, the shipping options weren’t changing. I didn’t know that WooCommerce caches shipping rates for an hour. Once I figured that out, I found the Shipping Debug Mode under WooCommerce -> System Settings -> Tools:

So I checked the box, refreshed the page–and nothing changed. The Debug Mode didn’t seem to be working.

I couldn’t figure out why the debug mode didn’t work. And clearing the transients in that same page wasn’t working for whatever reason. So I went in search of the value in the database. Once I found the value and deleted it, refreshing the page finally showed my latest changes to the shipping settings.

Manual Purge

The shipping rates are cached as transients in the wp_options table. These transients start with ‘wc_ship_’, so do a LIKE lookup:

Screen Shot 2015-01-13 at 8.15.59 PM

Run that query on the wp_options table and you should see the transients. Just delete them and you should be good to go.

Screen Shot 2015-01-13 at 8.16.07 PM

Hopefully this can save someone a few hours of banging their head against a wall. And if you know why the debug mode and clearing transients on the settings page didn’t work, let me know.

Excluding PayPal as a referrer in Google Analytics

For about a month, my analytics for Stitch People weren’t super helpful. PayPal kept showing up as the top referral source for transactions in my Shopify store analytics:

Google Analytics

As you can see, the bulk of my transactions were showing as having come from paypal.com, which I knew wasn’t really the case. But for some reason, the real referral source of these transactions was being blown away by PayPal.

What’s going on?

It turns out that Google starts a new session anytime someone comes to your site from another site. If we think about this flow when you have PayPal enabled as a payment solution in Shopify (or any other ecommerce platform for that matter), it makes sense. A user comes to your store, adds something to the cart, then goes to checkout with PayPal. They’re redirected to PayPal.com to complete their transaction, and then they come back to your site.

Because someone came to your site from another site (paypal.com in this case), Google Analytics counts it as a new session. This means that PayPal gets credit as the referral for the transaction because it was the last site someone visited before coming to your site and completing a transaction.

How to fix it

First, make sure you’re using Universal Analytics. You can follow the steps outlined here to make sure you’re upgraded.

Now, go to the Admin section in Google Analytics:

Screen Shot 2014-10-08 at 5.10.56 PM

Once there, select the Account you want to change on the left:

Screen Shot 2014-10-08 at 5.12.17 PM

Now, head to the middle column (Property) and open up the Referral Exclusion List under Tracking Info:

Screen Shot 2014-10-08 at 5.08.04 PM

Now, make sure you add paypal.com to this list:

Screen Shot 2014-10-08 at 5.14.53 PM

You’ll also want to add the domains of any other payment gateways you’re using. Here’s the official Shopify documentation.

Session Settings

I’ve also heard reports that this doesn’t always work if a user spends a lot of time at PayPal. This could happen if someone clicks the Checkout with PayPal button, gets redirected to PayPal, and then gets distracted and comes back later to complete their checkout. If you’re running into this problem, try extending the session timeout in Session Settings. By default it’s 30 minutes, but can be changed to 4 hours max.

Session Timeout Settings

Why does this work?

When you add a domain to this list, it doesn’t create a new session when someone visits from one of these domains. In the case of users checking out with PayPal, Google Analytics will check the referring site (paypal.com) against this list. If it finds a match, it won’t create a new session like it was doing before. Instead, the user session will continue and the transaction will be credited to the right source.

Once I made this change, paypal.com stopped showing up as the referral for my transactions, giving me clear insight into where the money was really coming from.

Keep in mind:  This won’t retroactively fix all the transactions that came through with PayPal as the referrer in the past. Because analytics are just a snapshot in time, this will only work for transactions going forward.