WordPress Performance – Breaking It Down by HTTP Requests

wordpress performance

WordPress can be a tricky beast as they say when it comes to web performance. Especially if you are comparing it against others running static sites. Because WordPress is based on PHP and most of the content is dynamically generated, it means you need to find other ways to optimize. In today’s post, we are going to dive into a fresh WordPress install and take it apart piece by piece, or rather by HTTP requests, to hopefully help you gain a better understanding of WordPress performance. WordPress can load a lot faster than what some people might lead you to believe!

Breaking Down WordPress Performance

In this post, we are going to first tear down a fresh install  and then afterwards make some improvements to it. Make sure to also check out our speed up WordPress guide for additional tips on improving WordPress performance. In this case study, we are running on NGINX, over HTTPS and HTTP/2. If you are starting a new website, we encourage you to take advantage of HTTP/2 right off the bat. Or check out our HTTP to HTTPS migration guide.

Understanding the basics when it comes to web performance makes it easier to apply advanced methods later.

Our fresh WordPress site is using the default Twenty Sixteen theme.

Let’s first take a look at each HTTP request that is generated out of the box, as there are a couple you can probably get rid of. So by default, we have a site with 15 HTTP requests at a page size of 135 KB. And a decent load time. Remember, as you add media and content to your site your load time will only increase, so it is better to optimize your site as much as possible first, and then add content. Also, if you are starting with a different base theme, you can apply almost everything we do below as well, although it might vary slightly.

wp twenty sixteen performance

Step 1. Disable Emojis

The first one is the wp-emoji-release.min.js file. This file is used for showing emoji characters in WordPress, since version 4.2. Unless you absolutely can’t live without emojis, we recommend this is the first thing to get rid of on a fresh install. To disable emojis you have the following to options:

1. Disable Emojis with Code

The first way to disable emojis is you can put the following code into your functions.php file.

/**
 * Disable the emoji's
 */
function disable_emojis() {
	remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
	remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
	remove_action( 'wp_print_styles', 'print_emoji_styles' );
	remove_action( 'admin_print_styles', 'print_emoji_styles' );	
	remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
	remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );	
	remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
	add_filter( 'tiny_mce_plugins', 'disable_emojis_tinymce' );
}
add_action( 'init', 'disable_emojis' );

/**
 * Filter function used to remove the tinymce emoji plugin.
 * 
 * @param    array  $plugins  
 * @return   array             Difference betwen the two arrays
 */
function disable_emojis_tinymce( $plugins ) {
	if ( is_array( $plugins ) ) {
		return array_diff( $plugins, array( 'wpemoji' ) );
	} else {
		return array();
	}
}

2. Disable Emojis with Plugin

If you prefer to use a free lightweight plugin, Ryan Hellyer has created a great “Disable Emojis” plugin for WordPress. The total size of the plugin is only 9 KB.

disable emojis

Remember, with plugins it isn’t always bad to have a lot of them running. It is more about quality of the plugin vs quantity. If a plugin is lightweight, it won’t slow your site down. Essentially all this plugin is doing is running the code we shared above. After doing this we are now left with 14 HTTP requests at a total size of 129 KB.

disable emojis http request

Step 2. Disable Embeds

Next, we will look at the wp-embed.min.js script. This has been included in WordPress since version 4.4. This is a script that auto formats pasted content in the visual editor, such as videos, tweets, etc. However, this is not really needed. A big issue with this script is that it loads on every single page, whether it is being used or not. You can still use the default embed code from YouTube and Twitter to included content, even when this script is disabled. Again we have two options:

1. Disable Embeds with Code

The first way to disable embeds is you can put the following code into your functions.php file.

// Remove WP embed script
function speed_stop_loading_wp_embed() {
if (!is_admin()) {
wp_deregister_script('wp-embed');
}
}
add_action('init', 'speed_stop_loading_wp_embed');

2. Disable Embeds with Plugin

If you prefer to use a free lightweight plugin, Pascal Birchler has created a great “Disable Embeds” plugin for WordPress. The total size of the plugin is only 3 KB and features the following:

  • Prevents others from embedding your site.
  • Prevents you from embedding other non-whitelisted sites.
  • Disables all JavaScript related to the feature.

disable embeds

After doing this we are now left with 13 HTTP requests at a total size of 128 KB. You can also see that our DOMContentLoaded and total Load time keeps decreasing as we make these WordPress performance tweaks. We are using Chrome DevTools and have caching disabled.

disable embeds http request

Step 3. Implement Caching

Notice above in all of our speed tests that the first HTML initial DOC load is quite high. Even when we enable caching in Chrome DevTools it still hovers around 180 ms. So to fix the initial HTML DOC load time, you need to implement a caching mechanism. In this case, we are going to use the free WordPress Cache Enabler plugin from KeyCDN.

first HTML doc load time

Cache Enabler is a lightweight caching plugin for WordPress that makes your website faster by generating static HTML files to disk. This is a very fast method of caching. The plugin also focuses on HTTP/2, meaning you won’t find options for concatenation, as this can hurt HTTP/2 performance. The total size of the plugin is only 15.4 KB.

wordpress cache enabler

In the Cache Enabler plugin settings we have pre-compression checked, as well as cache minification of HTML & Inline JS.

cache enabler settings

Now, lets look at our first HTML initial DOC load again. Simply by enabling Cache Enabler, this has dropped us from 180 ms on average down to 80 ms on average. So it shaved off about 100 ms from our HTML DOC load. This is the power of what a caching plugin will do for your WordPress site. Also, our total page size dropped to 123 KB thanks to minification and again our DOMContentLoaded and total load time is lower.

cache enabler HTTP request

Step 4. Use a CDN

Now that we have our base fresh install fairly well optimized, now is the time to add a CDN into the mix. By using a CDN you can further decrease the latency by serving up the content closer to your visitors. Also, as we will show later on, there are additional benefits, such as moving towards a single HTTP/2 connection and ignoring query strings for additional caching.

Make sure to check out our in-depth posts on how a CDN works and also our getting started guide. In this post, we are going to assume you already have a CDN up and running. We are going to be using the free WordPress CDN Enabler plugin from KeyCDN to deploy our CDN. The total size of the plugin is only 6.4 KB.

cdn enabler

In the CDN Enabler settings we enable HTTPS (as we are using HTTP/2 from KeyCDN) and input our CDN URL.

cdn enabler settings

After we enable the CDN, you can see most of our assets (JavaScript, CSS, etc.) are now loading from our CDN. The total load time drops by about half, and our DOMContentLoaded time also decreases by a large amount. Notice how our waterfall, is getting nicer as we continue to optimize. Not sure what we mean by waterfall? Make sure to check out our in-depth post on waterfall analysis.

cdn wordpress performance

Step 5. Remove Query Strings

Next, you notice how every script ends in a version number? Such as ver=1.12.4 or vers=3.4.1. These are called query strings and help determine the version of the script. The problem with query strings like these is that it isn’t very efficient for caching purposes and sometimes prevents caching those assets altogether. So you have a three options here:

1. Remove Query Strings with Code

The first way to remove query strings is you can put the following code into your functions.php file.

function _remove_script_version( $src ){
$parts = explode( '?ver', $src );
return $parts[0];
}
add_filter( 'script_loader_src', '_remove_script_version', 15, 1 );
add_filter( 'style_loader_src', '_remove_script_version', 15, 1 );

2. Remove Query Strings with Plugin

If you prefer to use a free lightweight plugin, Atul Kumar Pandey has created a great “Query Strings Remover” plugin for WordPress. The total size of the plugin is only 1.5 KB.

query strings remover

3. Cache and Ignore Query Strings with a CDN (Recommended)

The third option and this is the recommended method is that if you using KeyCDN, we have an option to actually ignore query strings and cache the assets regardless. This feature is enabled by default on all zones. This means you don’t need to use code or a plugin for this optimization, it is all handled by the CDN. If for some reason you need to disable it, it can be done under the advanced features on your zone.

cdn query string

Step 6. Host Google Fonts

Next, if we look closer we can see there are 4 requests being generated to fonts.gstatic.com. And this is to load Google fonts, which is included in the default WordPress theme. In our example, it is loading different font weights for Merriweather and Montserrat.

https://fonts.googleapis.com/css?family=Merriweather%3A400%2C700%2C900%2C400italic%2C700italic%2C900italic%7CMontserrat%3A400%2C700%7C&subset=latin%2Clatin-ext

https://fonts.gstatic.com/s/montserrat/v7/IQHow_FEYlDC4Gzy_m8fcoWiMMZ7xLd792ULpGE4W_Y.woff2

https://fonts.gstatic.com/s/merriweather/v13/RFda8w1V0eDZheqfcyQ4EOgdm0LZdjqr5-oayXSOefg.woff2

https://fonts.gstatic.com/s/montserrat/v7/zhcz-_WihjSQC0oHJ9TCYPk_vArhqVIZ0nv9q090hN8.woff2

It always better to reduce the number of external DNS lookups and also focus on having a single HTTP/2 connection if possible. Every external lookup introduces its own set of latency issues, content download times, TLS negotiations, etc. So what we are going to do is move the Google fonts to our CDN. This way they load from the same place as the rest of our assets.

You can check out our in-depth tutorial on how to migrate Google Fonts to your CDN. This can also be used to simply host them directly on your web server as well, if you aren’t using a CDN. We quickly download the following Google fonts from https://google-webfonts-helper.herokuapp.com and host them on our server in a folder called “fonts.”

merriweather-v13-latin-700.woff
merriweather-v13-latin-700.woff
merriweather-v13-latin-700italic.woff
merriweather-v13-latin-700italic.woff2
merriweather-v13-latin-900.woff
merriweather-v13-latin-900.woff2
merriweather-v13-latin-900italic.woff
merriweather-v13-latin-900italic.woff2
merriweather-v13-latin-italic.woff
merriweather-v13-latin-italic.woff2
merriweather-v13-latin-regular.woff
merriweather-v13-latin-regular.woff2
montserrat-v7-latin-700.woff
montserrat-v7-latin-700.woff2
montserrat-v7-latin-regular.woff
montserrat-v7-latin-regular.woff2

Because we are using the CDN Enabler plugin already, these fonts then are immediately copied to our CDN. To use them, we then have to disable Google fonts in our WordPress theme and apply the styles to our internal CSS stylesheet. This will vary based on whatever theme you are using. If you can’t figure out how to disable Google fonts on your current theme, feel free to ask your theme developer.

As you can see, we are now down 12 HTTP requests since we no longer have to query Google’s stylesheet. And our fonts are now loading from the CDN. You can see that our DOMContentLoaded and total load time also continue to drop. Every optimization we make has a crucial impact on performance.

https://cdn.themewood.com/fonts/montserrat-v7-latin-700.woff2

https://cdn.themewood.com/fonts/merriweather-v13-latin-regular.woff2

https://cdn.themewood.com/fonts/montserrat-v7-latin-regular.woff2

google fonts cdn

Step 7. Disable Gravatars

As you can see we are almost down to a single HTTP/2 connection with no external DNS lookups. The only thing left is that call to gravatar.com. Thankfully they are using HTTP/2 now, but unless you really want avatars, you can disable them.

gravatar http request

This can easily be remove by un-checking the “show avatars” in the discussion setting of your WordPress dashboard.

show avatars

By removing the call to gravatar.com we are now down to 11 HTTP requests and are using a single HTTP/2 connection for external assets on our CDN.

single http2 connection

And if we un-check the “disable cache” option in Chrome DevTools we can see for repeat visits the website loads very fast!

cached chrome devtools

WordPress Performance – In Summary

As you can see, when you break down a site by individual HTTP requests it helps you to understand better what is causing delays and how you can improve upon WordPress performance. You can then take this knowledge and apply it to bigger sites and more advanced WordPress themes. We have seen these simple techniques mentioned above even help bring WordPress themes like Avada (which is known for being very large) to load times of under 650ms!

Related Articles

WordPress Performance – Breaking It Down by HTTP Requests was last modified: October 13th, 2016 by Brian Jackson
  • Another great article by Brian! Love the step-by-step tutorial to reduce HTTP requests.

  • If you want to improve frontend performance and still support emojis via WordPress’ script you can roll it into your own global JavaScript file using a task runner like Gulp or Grunt. Here’s an example using Gulp https://github.com/kingkool68/zadieheimlich/blob/master/gulpfile.js#L17-L33

    Of course you also have to prevent the scripts you’ve bundled together from being rendered on the front end. To do that you can filter them like so https://github.com/kingkool68/zadieheimlich/blob/master/functions/scripts-styles.php#L66-L85

    While we’re at it, why not serve a more modern version of jQuery to modern browsers with compatibility fallbacks for older browsers. Using conditional comments we can serve jQuery 2.x to everyone and jQuery 1.x to IE8 and below. https://github.com/kingkool68/zadieheimlich/blob/master/functions/scripts-styles.php#L87-L121 I’m sure no one cares about IE8 but it doesn’t hurt anything to do it this way.

    On a final note I wouldn’t highlight the file size of WordPress plugins. It is irrelevant and like comparing the quality of literature based on the number of pages in a book.

  • Luke Cavanagh

    Awesome post, some very handy tips.

  • Et Veritas Liberabit Vos

    Why you make a custom cache plugin and not use for example W3 Total cache which have complete features without autoptimize? There is a specific reason? Your is better? Thanks

    • Have you been following the news around W3 Total Cache?!

      • Et Veritas Liberabit Vos

        Nope… Where I can find ? Thanks

    • Cache Enabler is a much more lightweight caching solution that has also shown to provide faster loading times. With this plugin you also have the ability to deliver WebP images which W3 currently does not support.

      • Et Veritas Liberabit Vos

        I am not sure why all my comments are deleted ? What is wrong ?

    • Luke Cavanagh

      W3 Total Cache can get pretty complex to deal with, as well as causing certain issues. Using Cache Enabler with Autoptimize is a solid option.

  • HTTP requests should be less in number. The page loading time of a website matters a lot. You have provided some great tips,

    But disabling an avatar can be quite awkward. People want to see who you are. But as you have suggested, it depends on the need.

    Most of the scripts sends the HTTP request. It’s necessary to remove the strings.
    ~Ravi

  • Does WordPress CDN Enabler need a KeyCDN account? Or should i simply install and activate it? I am currently using a different CDN.

  • Great article! The Emojis now come also with a DNS prefetch, which can be disabled by adding this line:

    add_filter( ’emoji_svg_url’, ‘__return_false’ );

  • Nice article. Very handy and amazing tips.

Share This