What the Queries

I’ve never been a fan of IDEs, complex debugging tools with breakpoints, variable watch lists and all that fancy stuff. var_dump() and print_r() have always been my best friends.

Recently I was playing around with the caching arguments in WP_Query, trying to combine that with update_meta_cache() while sticking wp_suspend_cache_addition() somewhere there in the middle, and it quickly became a mess, so I wanted to know what queries am I actually running under the hood.

I came up with this little piece, which I think I’ll use more often from now on:

// Assuming SAVEQUERIES in set to true.
$GLOBALS['wpdb']->queries = array();

// All the magic goes here

var_dump( $GLOBALS['wpdb']->queries );

This gives you a nice list of SQL queries that were triggered only by that magic code in between. Works great when you need a quick sanity check on all those caching arguments, priming meta or term caches, splitting queries and whatnot.

Obviously it empties the initial set of queries, so anything in Debug Bar, Query Monitor, etc. will no longer be accurate.

What’s your favorite way to keep track of queries?

An Alternative to @import in WordPress Child Themes

Using Child Themes in WordPress is a great way to modify an existing theme, however the CSS @import directive is slower than it has to be, so you should try and avoid it. Here’s why.

If it takes 200ms to load the child theme’s stylesheet, and 200ms to load the parent theme’s CSS, a modern web browser should take approximately 200ms to load both of them, because modern browsers load assets in parallel.

Unfortunately this is not true for CSS @import. Let me quote Google:

The browser must download, parse, and execute first.css before it is able to discover that it needs to download second.css.

Which means that instead of 200ms, with @import it’ll take the web browser approximately 400ms to load both stylesheets. Here’s a typical child theme’s CSS:

/**
 * Theme Name: My Child Theme
 * Template: parent-theme
 */
@import url(../parent-theme/style.css);

/* My Child Theme CSS */

We can drop the @import statement, and make good use of functions.php and the wp_enqueue_style() function:

// Faster than @import
add_action( 'wp_enqueue_scripts', 'my_child_theme_scripts' );
function my_child_theme_scripts() {
    wp_enqueue_style( 'parent-theme-css', get_template_directory_uri() . '/style.css' );
}

And we don’t need to re-declare dependencies because the child theme’s functions.php is loaded before the parent theme’s. Unless, of course, the parent theme uses a different action priority, in which case we should just match it.

That’s +1 to our PageSpeed score :)

High Performance WordPress

A co-worker and friend of mine Iliya Polihronov gave this talk earlier this year at WordCamp San Francisco 2012. He walked through an optimal server configuration for a high-performance WordPress environment, including nginx, php-fpm, APC and memcached. His notes are on SlideShare.

I’ve been running an nginx and php-fpm configuration for over a year now, with a VPS from MediaTemple. I tried quite a lot of different configurations, including Batcache, W3 Total Cache, Varnish and more. I found that WP Super Cache with nginx and php-fpm works really well for my setup, where I have just over ten sites in a multisite environment, running on 512M of memory.

After watching Iliya’s talk and the performance improvements possible by APC, I have decided to give it a go some time later this year. My codebase is quite small, so I think I’ll manage to survive with much less than 32M dedicated to APC.

I’d also really love to run the Memcached Backend for WordPress’ object cache, but unable to at the time of writing, since one of my sites in the network has over a thousand “posts” published every day, but accessed only once or twice in their life time. If you’re wondering, they’re Twitter profiles for Foller.me.

As much as I’d like to avoid that, I’ll have to move the site out from the network, instead of hacking the Memcached plugin to avoid caching, based on a domain, which I think is also possible. I’ll keep looking into other solutions, and probably blog about how I solved that later.

In addition to the tools Iliya talked about, I’d like to mention one called ab, or the Apache server benchmarking utility. It has quite a few options to test and benchmark your (not necessarily Apache) web server performance.

What does your WordPress environment look like? Which caching plugins and techniques do you use? Are you planning to try something, or is your setup working well for you? Share your thoughts via the comments section. Thanks for reading!

Otto on Caching in WordPress

Otto describes why neither page caching, nor persistent object caching are part of the WordPress core, and why they probably never will be. The main reasons are the way WordPress is architected, and the way it is used by the majority.

If you’re a person writing a blog that gets less than 1000 hits a day, caching ain’t going to do much for you.

And my favorite, about why object cache doesn’t (and probably shouldn’t) use the database for persistent storage:

Trust the MySQL query optimizer, it’s smarter than you are.

Get an Expired Transient in WordPress: Good Idea or Crazy Talk?

I wonder if there’s an easy way to get an expired transient in WordPress? Now, for this to make sense I guess I should provide a little more context, so here it goes :)

The Transients API is an extremely easy way to cache parts of your WordPress code, that may be CPU/memory intensive, or rely on a third-party server and so on. A great example is grabbing a tweet from Twitter and caching it for a few minutes, so that we don’t query the Twitter API on every page load. So in theory:

if ( false === ( $tweet = get_transient( 'my_latest_tweet' ) ) ) {
    $tweet = get_my_latest_tweet(); // Queries the Twitter API
    set_transient( 'my_latest_tweet', $tweet, 60*60 );
}

Is a great way to cache my latest tweet for an hour. Perfect, but there’s a problem. The code above will work well for 60 minutes. When the transient expires, it will have to spend time again to fetch the tweet, thus impacting your page load time. Once every 60 minutes.

Suppose Twitter is being slow today and taking 2 seconds to respond back, and suppose I want to cache the tweet for 5 minutes, not an hour. This means that every 5 minutes, somebody will have to wait two extra seconds for my page to load. Suppose I’m querying the Flickr API, the Facebook API and fetching a few RSS feeds too, that will all add up to the page load time, to that unlucky person who visited my site, when the cache was expired. Bummer!

Is there a solution? I don’t know, but I can think of one — always serve cached data, even if it’s expired. That way visitors will never have to wait extra when you’re speaking to third party servers and APIs. I can think of a way to accomplish this by fetching the new data in a different request, transparent to the user.

Like an asynchronous request with jQuery (aka AJAX) to a special action that would revalidate expired cache. Crazy talk? Here’s the scenario:

  1. You visit your page when caches are empty, you don’t see the tweet.
  2. An async jQuery request is fired to the server which grabs the latest tweet and caches it, this happens behind your back.
  3. You refresh the page and you see the tweet from cache. Yey!
  4. Ten minutes have passed, cache is expired, but not trashed. You visit your page, you see the old tweet from (expired) cache.
  5. An async request in the back fetches a new tweet from Twitter and replaces the one expired.
  6. You refresh the page and you see the (new) tweet from cache. Yey!

So in steps 1, 3, 4 and 6 you’re always serving what’s in cache, whether it expired or not, even if it’s empty (first step) so you’re serving as fast as possible. Steps 2 and 5 happen behind your back, they don’t impact page load time, and they never return anything back. You won’t see them happening unless you’re looking at your Netwok tab in Chrome’s developer tools or Firebug.

Now, suppose Twitter is down. The visible steps are not impacted, because they return stored data, they don’t have to fetch it from Twitter. The hidden steps will fail, but your visitors will never know, since they’ll be still seeing the old tweet fetched some time earlier, right?

This can easily be done with the Options API but hey, transients are already a great tool for caching. Wouldn’t it be even easier if transients never actually expired? And a function to fetch such an expired transient, get_expired_transient perhaps? :)

Okay, that’s just off the top of my head, it’s quite late so, sorry if I’m totally on the wrong track. Let me know if there’s an easier solution, or maybe a caching plugin that already does this. Object caching can benefit too by the way. Share your thoughts in the comments section below!

Google Analytics Proxy with Nginx

Here’s a quick tip! If you need to serve a specific script, stylesheet or any other file from your own domain, you can easily proxy it with nginx. A good example is the ga.js file for Google Analytics. Here’s how I proxy it with nginx, in the server context:

# Google Analytics Proxy
rewrite ^/ga.js$ /ga/ last;
location /ga/ {
        proxy_pass http://www.google-analytics.com/ga.js;
        break;
}

This rewrites the ga.js filename to the /ga/ pseudo-directory, in the context of which I can use the proxy_pass directive to fetch the file from Google. This way I have total control over the file that’s being served and especially the HTTP headers, which I was after in the first place.

You can repeat the trick with basically any file, but keep in mind that each one is a little extra load on your server, so add a caching layer where possible.

Varnish and Preview Posts in WordPress

I wrote earlier that I started playing around with Varnish here on my site and that post has a little snippet that strips all incoming and outgoing cookies (except the admin of course.) Today I stumbled on a problem where I had no permission to preview a post I was drafting in WordPress and they all turned 404’s when I tried to.

I first thought Varnish was stripping out the preview query string but I was wrong, the problem was that WordPress knew I was logged in and editing the post when I were in the admin panel, but when I tried to preview it on the front end Varnish was stripping out my login cookies, hence it didn’t display my draft post.

Here’s a snippet for vcl_recv and vcl_fetch that should go before the unset cookies statement which passes the request to the web server if preview=true is found in the request URL.

if (req.url ~ "preview=true") {
	return(pass);
}

Restart the Varnish service and voila! Your cookies aren’t stripped out anymore and you can now preview your posts and pages. Do note though that if somebody manually types in the preview query string in the browser, they’ll by-pass Varnish as well.

Varnish and WordPress Comment Cookies

I wrote before that I’ve been running some experiments with Varnish lately. Not that I have huge traffic here but I’ve always used my own website to test things out. As I wrote earlier, the problem with WordPress and Varnish is that WordPress relies on cookies which create cache misses on Varnish and in that previous post I shared a snippet on how to strip all incoming and outgoing cookies, which hopefully solves one problem.

The second problem now is that cookies are disabled throughout the whole website (except the admin section of course) so if you’ve got commenters on your website, their browsers will no longer save their names and e-mails, so they’ll have to type them in every time they want to leave a comment. I agree it’s a pain, which is why I was searching for a solution, which turned out to be quite simple — handle it all on the client side using javascript.

So I wrote a little plugin which you can download and use. It simply enqueues a javascript file if the request is a singular page and comments are open. It passes in some cookie constants used by WordPress. The javascript itself hooks onto the submission of the comment form to create cookies and restores the form fields upon page load.

Note that the plugin can fail if you’re rendering your comment form differently (with different DOM IDs) from WordPress, and don’t forget to purge.url your Varnish cache after activating!

My website is now super-fast with Varnish

My website is now super-fast with Varnish — an open source HTTP accelerator which sits on top of your HTTP servers and serves your cached pages.

It didn’t take me longer than 20 minutes to get Varnish up and running on my Ubuntu VPS, and a few more minutes to set all my nginx configurations to port 8080, bringing Varnish to port 80. The problem with WordPress however, is that it heavily relies on cookies, resulting in almost no cache hits with Varnish. Here’s a little snippet for your Varnish configuration file that removes all cookies and still leaves your admin dashboard accessible:

# Remove all cookies sent to web server except for wp-login and admin
sub vcl_recv {
	if (!(req.url ~ "wp-(login|admin)")) {
		unset req.http.cookie;
	}
}

# Remove all cookies sent by web server except wp-login and admin
sub vcl_fetch {
	if (!(req.url ~ "wp-(login|admin)")) {
		unset beresp.http.set-cookie;
	}
}

Anyhow, even if you don’t look for the wp-login and wp-admin and clear out all cookies sent back and forth, you could still access your admin panel by asking for it directly from your webserver, i.e. from port 8080 (or however you have configured it) which will bypass Varnish.