Being a Front-end developer by life choice, I obsess over a lot of things when it comes to the web. Some things are little and have no effect on the end-user like proper indentation and combing, or alphabetizing, my CSS properties. Some are really big and important, like performance and accessibility.
Granted, if you view source on this page you probably won’t see much of that because this is a WordPress theme and a lot of the code is out of my hands at the moment. PS: Viewing source on pages is another hobby of obsessed front-end developers.
One thing that has been bothering me for a very long time is the load time of my WordPress sites, and I had to do something about it. Here is a detailed list of things I did to speed up my WordPress properties. Note: Most of these things are just general best practices, but some are very specific to my site. I will point them out, but it’s important you take the time to tweak your own.
First order of business was changing my web host. For almost 10 years, I have been on the same server. It started out with a Reseller plan on Autica, and the service was great. I remember before I signed up with them, calling them at odd hours of the night to test their tech support to make sure they were responsive and they always answered the phone. I was really happy with them and felt like my dreams of being a freelance web developer, selling my clients hosting services, was going to come true. It never did, of course. Over the years the ownership has changed too many times. Currently, the company is called Midphase. They were just too slow for me. I had problems with mail servers being blacklisted all the time. The decision to change finally came last year, as my account was compromised and malware installed on every domain. They said it was an FTP issue, that my computer was probably compromised and thats how the FTP password was attained. All very plausible, since FTP passwords transfer in the clear. The only problem was that I hadn’t FTP’d in a few years. As a matter of fact, none of my current computers had an FTP client installed.
Doing some serious research, I started to fall in love with the idea of administering my own services. Not for resale, but so I can have control over every aspect. I didn’t want to deal with old versions of PHP, SQL, Apache, etc., or not having access to configurations I needed. I finally decided to get an account with DigitalOcean (DO) and trying building a platform focusing on NGINX. DigitalOcean has a great community with step-by-step tutorials on how to get up and running.
Being my own admin means I get to experiment with the latest versions of things, and having the ability to take snapshots as a backup before any big changes is a big help. On this instance, I have installed and enabled HTTP/2 to take advantage of greater speeds. Wow, what a difference! If at all possible, I highly recommend you upgrade to HTTP/2.
Next step was to have DNS routing properly set up. The DO tutorial suggested having a CNAME record for WWW but I instead chose to have an ANAME for WWW. This reduces one additional DNS lookup. To be honest, this is more of a geeky thing, as the DNS lookups are really only in terms of ms. I think if DNS lookup times are your biggest issue, then you are doing pretty good. Still, shaving as many ms as possible are important to me. I used DNSstuff to test my configuration and make sure everything was good.
Browsers will one day be requiring that all sites be served via HTTPS. Google will give a higher ranking to sites that employ secure HTTPS. It’s also a requirement for HTTP/2. Getting a certificate is no longer hard, or an expense, thanks to Let’s Encrypt. Once again, following a simple tutorial from DO, I was able to generate the necessary certificates on my server and enable on all my sites. I used Mozilla’s SSL Config Generator to get the right configuration. Once you have everything in place you can use Qualys SSL Labs to test everything.
Now, if you don’t know, you are probably wondering how this is related to performance. Well, besides the fact that it is required for HTTP/2, if your cipher suites are not configured in the optimal order you may end up using an encryption that is slower than others. Worse than that, but not performance related, is that you may end up using a less secure encryption and actually opening up yourself to exploits, and really defeating the purpose of using HTTPS in the first place. As I mentioned in the DNS section above, we are really talking in terms of ms here, so if TLS/ SSL encryption is your biggest performance issue, you are doing pretty good. I have a performance budget in mind that I want to meet, and shaving as much time off as possible is important to me.
W3 Total Cache
Most discussions about WordPress performance start with the W3 Total Cache (W3TC) plugin. I followed a bunch of different sites with recommended settings and was just not happy with the results. Understanding that my server setup is special (probably bad/ incorrect) I decided I would just disable everything and try each setting one at time until I get the best results. I recommend the same for you.
I tried out all the caching systems that W3TC integrates with: APC, eAccelerator, and XCache. They were all easy to install/ uninstall on my DO droplet (DO’s version of an instance) so I was able to test each of them. In the end, I get the best results from XCache. I was surprised myself considering the popularity and community around APC but I have no alliances here. The results were all the proof I needed. You mileage may vary, so test all you can to get the best.
With the two options for DB caching between Memcached and Redis, I researched enough to decide that trying out Redis would be the best way to go. Unfortunately, I did not do so well as it ended up slowing everything down considerably. I ended up uninstalling Redis and, to be fair, I did not spend enough time trying to figure it out. I have a couple of follow up tasks to try out when I get more time, and giving Redis another go is one of them.
Result: XCache, via W3TC
W3TC General Settings
As mentioned above, between all of the Opcode caches supported by W3TC I got the best results from XCache. Unfortunately, using XCACHE was killing my page load times. I was able to cut this in half by using enhanced disk caching. This resulted in a 200% increase over XCache.
Result: Disk: enhanced
This section is really important to me, as a big part of front-end performance is in proper asset delivery. Unfortunately, no matter how much I tried I just could not get the right combination for W3TC. There was always some JS error I had to deal with, and every time a plugin is updated you need to update the minify settings. With some plugins embedding scripts, it was also hard to manage dependency order.
Frustrated with all this, I decided to disable this W3TC’s Minify option and use a separate plugin. I tested quite a few and I was very happy to find Autoptimize, which did HTML, JS, and CSS concatenation/ minification, including embedded scripts. Autoptimize settings as follows:
|Optimize HTML Code?||Checked|
|Keep HTML comments?||Unchecked|
|Also aggregate inline JS?||Enabled||Big improvement over W3TC|
|Exclude scripts from Autoptimize||Default (no change)|
|Add try-catch wrapping?||Unchecked||Luckily I didn’t have any errors, but wrapping JS in try-catch blocks disables JS engine optimizations in most browsers. I don’t think that is such a big deal for a WordPress blog, but I hate to think of doing anything with a negative impact.|
|Optimize CSS Code?||Checked|
|Generate data: URIs for images?||Unchecked||This used to be a best practice, but not any more. Avoid inline data uri’s.|
|Remove Google Fonts?||Checked||This was huge. Google Font’s would sometimes add an extra 2 seconds to total page time. I disabled custom fonts here, and just rocked with good ol’ Arial as a font. There was hardly any visual impact. Big win.|
|Inline and Defer CSS?||Unchecked||Didn’t have the time to fully configure this. Will definitely need to do so when I enable HTTP/2|
|Inline all CSS?||Checked||A bit of a controversial move. I ran the risk of increase the total kweight of the rendered page, but with all the various caching involved it wasn’t such a big hit. This is huge, as I remove a request and now rendering will not be blocked while trying to load external CSS even if it is completely concatenated/ minified. I still feel pretty icky about this and I think I will revisit this again. Still, I can’t deny I got the best results with this turned on.|
|Exclude CSS from Autoptimize||admin-bar.min.css||Removed dashicons.min.css as this resulted in a separate file/ request on every page.|
|CDN Base URL||Default (blank)||No CDN being used here. Yet.|
|Save aggregated script/css as static files?||Checked||Luckily my server supported this. Exactly why I choose DigitalOcean so I can control these things.|
It is said that HTTP/2 makes the need to concat files unnecessary, but I am just not there yet. I will have to test out this theory some day.
Result: Disabled W3TC, used Autoptimize
Once again, I got the best performance from using XCache here. It was kind of surprising, but again, numbers do not lie.
Surprisingly, I had to turn this off. No improvement from XCache or disk.
I have this turned off as well. My caching headers and GZIP is enabled via my NGINX configuration. I suggest you find your best settings based on your needs.
Result:Disabled, handled via NGINX config
CDN, Reverse Proxy, Monitoring,
I am not currently using any of these features so they are disabled.
Network Performance & Security powered by CloudFlare
I had high hopes for Cloudflare. Truth is, they killed my pageload times. DNS added around 1000ms and assets (JS/CSS) being served via their “CDN” could take up to 4000ms. I turned them off and never looked back. Your mileage may very.
Most of my WordPress sites are very image heavy. This is where the largest amount of time is spent so it is important that image delivery is optimized.
Compressing your images is extremely easy to do and makes a huge difference. I originally compressed all my images using WP-Smush but found that Imagify gave me an additional savings. Some of the image file sizes are bigger than I prefer but this has more to do with the format I created/ saved them in. Images are killing me!
Another important trick to saving bandwidth is to lazy load images until they are actually in the viewport. This is especially important for smaller screens, as images towards the bottom of the page may never be viewed but they will still download, eating up your bandwidth and increasing page times. I found a great plugin for this, a3 Lazy Load, and it was the only I could get to work with my version of WordPress/ theme. Highly recommend you use some kind of lazy load plugin.
Update: Something about WordPress 4.4 killed the ability to lazy load images. I tried everything I could find on the web to solve this. No other plugins worked. Big bummer! Thank God that HTTP/2 is saving my butt here.
In the end, after all the experimentation, I am very happy to report I was able to hit my desired performance budget. My sites now load between 480ms and 1.1s, cold cache. Pingdom score is 99/100. Google Pagespeed actually docked me for THEIR assets not caching/ loading properly so I ignore their score of 78. Is that fair?
Even though I am pretty happy with my results, there are still a few things that I want to try once I have more time.
- Try out Redis again.
- Revisit inline CSS
If there is anything I want you to get from this, it’s that you have to experiment with the best settings for your particular configuration/ site. It can be time consuming, but the payoff is satisfying.
Hopefully this was help. Do you have any recommendations? Post in the comments and let’s get speeding!