UPDATE Dec 8th 2013: I’ve updated the plugin even more. Read about it in part 2.
UPDATE Dec 3rd 2013: While testing the plugin on a few installations, I discovered a couple of bugs. If you downloaded the plugin on Dec 2nd 2013, you may want to try the improved version available below.
I’ve been working a lot with WordPress lately and doing so I’ve sometimes needed to trouble shoot slow WordPress installations. Naturally, I’ve googled for things like “wordpress performance”, “wordpress is too slow” and similar phrases. Almost always, those searches will take me to a page listing the top-10 things you should do to speed up your WordPress website. Those lists of tips are usually quite good, you’ll typically learn that you should install a caching plugin, clean up your database and get rid of unneeded plugins etc. Mostly quite useful information…. but with some important exceptions.
Installing a caching plugin such as W3 Total Cache will often solve most of your performance problems as long as you have mostly a “read only” website. However, if your website is inherently slow when used without any caching, your users will notice it and suffer from it whenever they do anything that can’t be cached as easily, like posting comments or doing custom searches. The most scary example I’ve experienced was an e-commerce website that was screaming fast as long as you were just browsing products (good) but was terribly slow when adding things to the cart (bad), entering a coupon code (worse) or checking out (flat out terribly bad). In that case, it didn’t matter much that the front page got a 90/100 score on Google Speed since the users had a terrible experience just as they were about to place their orders. So sometimes, a WordPress site need performance beyond what you can get from a good caching plugin.
Maybe it’s time for a little clarification. When people talk about performance it’s common that a few important concepts are mixed up. For the remainder of this post, when I say performance I mean the time needed to create the main HTML document that WordPress generates and that IS the page. Specifically, I don’t talk about the size of or number of other resources (images, css-files, js-files etc) that your page needs. Those are almost always static and the webserver will seldom require the PHP scripting engine to serve them to your users, and if your webserver actually is too slow, static files can easily be moved to a CDN anyway.
When a user requests a page from (or makes an Ajax call to) your Wordpres site and that request can’t be cached, the entire WordPress system needs to initialize in order to generate the response. For the sake of argument, let’s divide the response generation process into two phases:
- Internal WordPress init. In this phase. WordPress will load itself into the PHP process memory, it will set up the database connection and read various options from the database. It will initialize your theme, meaning it loads the theme’s function.php into memory and allow it to register the hooks it want. It will also load the main php-file from all your active plugins and they will also typically register some hooks.
- Theme processing When phase 1 is ready, your theme will be called into action. If it’s a standard post or page, Wordpres will typically load your single.php or page.php and let it execute it’s code. That code will call internal WP functions such as ‘wp_head()’ or get_bloginfo() to do it’s job and sometimes, calling an internal function will call back into your theme’s function.php, it all depends on the theme.
During these two phases, you really don’t have a lot of information about what WordPress spends the most time with and that makes it terribly difficult to know what you can do to optimize it. I found this very frustrating so at one point, I started hacking a few of the files in WordPress core in to insert debug information about what it’s doing. Specifically, I was inserting profiling code into wp-settings.php like this:
require( ABSPATH . WPINC . '/version.php' ); // <--- existing line $profiledata['post_require_version.php'] = microtime(TRUE); // <--- my line
Then in my footer.php, I’d output the content of the $profiledata array into HTML to review it. Naturally, modifying core files like that gets messy quite fast. You can easily break the entire site by accident and any changes will be overwritten on the next WordPress upgrade. So even if I believe that I was gathering useful information this way, I needed to do it cleaner. So, (since this is WordPress) I wrote a plugin, I now have a working plugin that will do the following using a bunch of Ajax calls from an admin-page:
- Copy wp-settings and wp-config into a separate plugin folder
- Rewrite wp-settings and wp-config so that they contain profiling code as shown above and some modified path information.
- Via a special bootstrap php file, load wordpress using the modified versions of wp-settings and wp-config and at the end, output the profile data using json
- Submit the data back to the server for storage, and render an HTML table with all the profiling data.
This is what it looks like:
And the complete content of the analysis can be downloaded here (tab separated text)
One interesting thing is that this is not limited to just displaying internal WordPress load time analysis, if you want to, you can add additional profiling statements into your own theme code and have them displayed in the same table. I’d even say it’s the preferred thing to do. One thing that I’ve seen so far is that in a lot of cases, the WordPress internal stuff takes roughly 40-55% of the total load time, so to get the full story of what happens during load time.
I’ve just finished writing this plugin so it’s really quite rough at the moment. It’s not been tested with a lot of WordPress versions and the UI is not at all what I’d want it to be. I’m in the process of adding it to the WordPress repository, should you want to look at it before that, feel free to download it from here:
Feedback, comments questions? Use the comments below.
Testing some WordPress installations I have running for customers, NextGen Gallery and Event Manager stand out a bit as quite expensive at load time.
To their defense, the plugin is currently only measuring how long time it takes to load the initial PHP file, not how much time that each individual plugin spends in the init action, where most plugins typically do additional initialization.