This post has been updated for 2020 – read here: WordPress Optimization – A Comprehensive Guide
Running high traffic sites means WordPress optimization is crucial. I spend a lot of time reading, thinking, and testing configurations to constantly improve the performance of my WordPress sites, as well as the server load. When sites are getting over 100,000 visitors per month, every millisecond counts. Whether you are running a blog, enterprise site, or local business, ensuring your visitors and customers have a fast speed can make all the difference between someone who clicks away and someone who stays for a while. This post is formatted in a way which starts with the lowest hanging fruit and gets harder and more complex the farther down you read. Begin your WordPress optimization from the top and begin measuring results!
If you’re reading this and realize its simply more than you feel comfortable taking on, or want to hire a WordPress optimization expert, send me a message for hire and I’d be more than happy to speed up your website!
Last Updated: June 14, 2016
Disclaimer: This post includes affiliate links for some of the products mentioned, however, I am not being compensated to endorse any of the products.
WordPress Web Hosting
The first step in WordPress optimization is choosing a good web host.As a web developer, I’ve used and been exposed to a huge variety of web hosts. I’m ultra-picky and want the very best available for my budget. I use iWFHosting.
A lot of people running WordPress website are going to be on what’s called “Shared Hosting” plans. While these are not inherently bad, a lot of times web hosts overload the amount of customers on a single server, causing a slowdown for everyone. With the amount of sites and traffic I handle, I’m beyond the shared hosting spectrum. I run a VPS, or virtual private server. Running a VPS allows me to quickly scale on demand, as well as better manage backups and testing configurations.
Beyond Hosting – A CDN for WordPress
With a good web host selected, the next step is getting a content delivery network, or CDN setup. I ended up with MaxCDN for several reasons. The first being a lot of plugins support integration with their API. The second being their support and speed were excellent. I’ve bugged them multiple times with silly questions and their expertise has always proved worthwhile. With a Pull Zone setup, these are the ideal settings I’ve found for a WordPress site running SSL/HTTPS.
With a good server setup in place, now we can move on to actual WordPress optimization. The first step is getting some plugins in place to do some automated tasks. Then, we’re going to analyze what the WordPress site is currently loading, and then install a few more plugins and optimize the theme.
WordPress Plugins to Help Auto Optimize
Better WordPress Minify
This minifies and combines your CSS/JS files, and works with MaxCDN. Combining files equals less HTTP requests and a faster load time. Once the automatic configuration is in place and the rest of the optimization of this section is complete, you’re going to want to come back and revisit the advanced and enqueued files section to start moving scripts to the footer and test until something breaks. Moving js files to the footer means portions of the site won’t stop displaying as scripts download and render. These are the settings I am currently using on this site.
This is one of the best automatic non-configuration-required caching plugins I’ve found and used. If you have users visiting your site whom are logging in, you’re going to need the Pro version. This is a common pro feature across a lot of caching plugins. For everyone else, these are the only options you’ll need, and this is what will display in the source code:
EWWW Image Optimizer
Optimizes all of your images and PDFs into the smallest size possible without sacrificing quality. This means your assets will load much faster. The only settings I usually touch on this plugin are Deferred Optimization and I use a bit more intense optimization levels. This is so I can work on posts and upload images faster, and I know when my wp_cron (will get to this soon) runs every hour, the images will be optimized.
WordPress has an API that autosaves drafts which by default goes every 15 seconds. This plugin lets you change the frequency to every 60 seconds. There is an option to disable where it runs, but I kept it everywhere so future plugins or features aren’t affected. I could totally see myself spending an hour trying to figure out why a plugin doesn’t work, only to realize its a setting here.
Over time, junk data accumulates in the database. This plugin can automatically run an optimize and repair command every set amount of days – I do 3 days – and helps keeps database requests running smoothly. I ran an optimize command on a client’s site that had been running for several years without any maintenance and got the database size from around 90 megabytes to under 10. That’s a lot of junk. You can also use this to run automatic backups of the database.
Analyzing Your WordPress Performance
This is what a typical graph will look like as I optimize a WordPress site, testing as I go. I was already familiar with my own site, so the process didn’t take as long, but it generally takes anywhere from 2-6 hours to optimize a WordPress site before even getting to the server itself.
Going off the GTMetrix waterfall view or the Pingdom File requests view, the first thing I look for is how many fonts are being loaded. A lot of times themes or plugins load multiple themes. Your site should have a consistent brand and look, so this will accomplish several things. Removing extra fonts from loading will improve your branding, as well as reduce the number of requests for your site to load.
Next, look for any 404 errors that are popping up. Go and find out what is missing, and fix those. For example, in testing this site, I realized I had a 404 image that was causing a huge slowdown. Oops.
I like to check out the 200 response code request. This is going to be the first one in the list and the most crucial. This is also where caching will shave off a lot of time.
Keep analyzing the waterfall as you go, and take care of different items that seem out of place to you. Try playing with BWPM to get to the ideal configuration.
Remove, minify, or modify one item at a time, flush your cache, and retest. If something breaks, its easy to undo what you just changed, versus guessing over multiple items. This is the most tedious of the entire process and takes a lot of close scrutiny. You’ll also have a much better understanding of how your website works and dependencies when you’re done.
High Traffic Websites and wp-cron.php
Every time a visitor goes to your site or loads a page, wp-cron.php is triggered. This is WordPress checking to see if it needs to do anything. This includes checking for updates, scheduled posts, email notifications, or a number of other tasks. When your website is getting several thousand or more hits per day, this uses up resources unnecessarily. Disabling the default wp-cron.php will be a lifesaver.
Open wp-config.php and add the below code. I usually place new code near the debug function.
Now, login to cPanel and setup a Cron Job to hit wp-cron.php every hour. Change the username to your cPanel username and make sure the path is correct, especially if you’re on a subdomain or subdirectory.cd /home/CPANELUSERNAME/public_html; php -q wp-cron.php
Database Bloat and Revision Control
Every time you save a post, WordPress saves a version of that post in the database. These are all accessed via the Revisions interface. WordPress will keep saving every version indefinitely. I got up to 48 revisions on this post alone in writing the initial spec. Figuring out an appropriate number of revisions for your style and setting that will reduce the size of the database. I personally set mine to 7 via wp-config.php:define('WP_POST_REVISIONS', 7);
Miscellaneous WordPress Notes
Too many plugins equals a slow site – This is a false myth. I currently have 50 active plugins on this site, and another 20 or so which are inactive. I get load times in under 3 seconds, and often under 1 second.
wc-ajax=get_refreshed_fragments – This is something which will show up as a slowdown if you’re running WooCommerce or haven’t installed the Heartbeat Control plugin. Its probably a bad idea to disable completely. I run WooCommerce on this site, and the only way to speed it up significantly is to disable the ajax-cart option here: /wp-admin/admin.php?page=wc-settings&tab=products§ion=display
Remove extra fonts being loaded – If you can’t find where fonts are being loaded, or if the theme is loading extra fonts on its own, removing them via BWPM is the way to go.
cPanel WordPress Optimization
Optimize Website – This generically named setting is where you can enable compression/gzip of your content.
For the more advanced readers – Zlib for compression is another good option when configuring WHM, although I’m not sure what PHP7 support is.
While not directly related to WordPress speed, its a good idea to make sure your DKIM and SPF records under Authentication are valid. These records help fight spam and let’s other mail servers know that your e-mail is authentic.
Advanced WordPress Optimization
Alright, time to take a break, make a fresh brew of coffee, and get ready to dive into the heavier and more advanced areas of getting the most performance out of your WordPress website.
Disclaimer and notice of imminent danger: Modifying settings in WHM could very well render your enter server useless. This guide includes items which can break stuff. If you feel unsure of a setting, or want a better understanding, ask your web host support or search for more information. I am only providing a very superficial overview on many of the following items. WHM supports Dry Runs of some of these settings, particularly EasyApache – take advantage of this, even if it takes you longer.
My current setup is a VPS with 8G Ram, 4 Xeon CPU cores, SSD drive, SolusVM, CentOS 6.8, and WHM56. If your setup is radically different, you may encounter problems. Feel free to ask your web host if these settings are safe.
WHM WordPress Optimization
There is a lot to adjust within WHM. I’m going to go down the menu and just list changed settings related to WordPress performance. There are plenty of other settings you may want to change for security, or based off of a specific website environment.
If there is another setting within WHM I missed which has impacted your WordPress performance, comment with an explanation and let me know to add it. Most of the heavy lifting was done prior to this point, and now that we are in WHM/PHP configurations, I’d love to have some input from others on further performance tuning.
Again, only settings which have been changed from their default and related to WordPress optimization are listed here.
WHM Tweak Settings
gzip compression level: 6
pigz processes: 4
Kb per chunk: 128
Initial default/catch-all: Fail
Email delivery retry time: 60m
Enable BoxTrapper spam trap: Off
Enable Mailman mailing lists: Off
Enable Analog stats: Off
File upload required free space: 128MB
Piped Log Configuration:
Enable Piped Apache Logs
As of the time of writing this post, PHP7 and EasyApach4 are not quite released for production. According to support, EA4 is ready for 95% of the people. Based off outstanding bugs, I felt they didn’t affect my usage, therefor it was reasonably safe to upgrade. If you read this and you’re running WHM 58, then EA4 is ready for you!
To install EasyApache4, follow this link. If something goes wrong, you’ll want to follow the same link to uninstall.
Below is my current configuration. I did not include versions for security reasons. I’m probably using whatever is listed as the latest.
Server Modules – You might recognize the names deflate, expires, and headers from your caching plugin.
PHP – I kept PHP5.5 and PHP5.6, even though I plan on using PHP7, in case I need a fallback. I’ll phase out PHP5 in the future.
Plus a similar config for 5.6 and 5.5.
PHP Configuration / MultiPHP INI Editor
Editor Mode; Opcache Tuning opcache.revalidate_freq=0 opcache.validate_timestamps=0 (comment this out dev environment) opcache.max_accelerated_files=7963 opcache.memory_consumption=192 opcache.interned_strings_buffer=16 opcache.fast_shutdown=1
Whew! You made it to the end. Please comment if:
- This helped you in any way – post screenshots of your results from Pingdom or Gtmetrix!
- I missed something
- You have a better config to share