Today I learned… in code

A lot happens between "Hello World" and "Supreme Master Programmer". Here, we share little discoveries made along the way. The more frustrating something was, the more likely it is to end up here on this site!

However, there’s more work to be done! Here’s what I did to raise my Google Insights mobile score.

Fixing render-blocking JavaScript on above-the-fold content on a WordPress site using W3 Total Cache and a CDN

Let’s look at this render-blocking JS/CSS problem first:

Eliminate render-blocking JavaScript and CSS in above-the-fold content.
Your page has 8 blocking script resources and 12 blocking CSS resources. This causes a delay in rendering your page.
None of the above-the-fold content on your page could be rendered without waiting for the following resources to load. Try to defer or asynchronosly load blocking resources, or inline the critical portions of those resources directly in the HTML.

This message is followed by a list of all the JS and CSS scripts causing the render blocking, which were 8 JavaScript files and 3 CSS files in my site’s case.

To fix the blocking JavaScript files I had to do a number of things to configure W3 Total Cache. This part took a couple hours of trial and error and some steps were not covered in the guides I used (or my situation was different from theirs), so I’ve attempted to document the process as I experienced it in this guide.

First, I enabled Minify in the general W3 Total Cache settings. Go to Performance > General Settings > Minify > check the “Enable” box and select the “Manual” radio button.

Next, go to Performance > Minify to work on minify settings as they pertain to JavaScript and CSS. You’ll need the list of blocking files from PageSpeed Insights report.

Watch out! The file paths shown in the PageSpeed Insights results might be truncated. To get the full path, you have to hover over the truncated path and copy the path from the tool tip.

In Performance > Minify there are a variety of options that apply to all the script in a particular area (before head, after body begins, before end of body). In my case, code in the head tag was already minified, so I set it to “Combine only” (rather than re-minify it). I also needed to keep it blocking, or else my page filled Chrome’s console with “can’t find JQuery!” errors.

Next, under JS file management, add all of the blocking files from the PageSpeed Insights results – be sure to get the full file path, not the truncated version.

Also! If you’re using a CDN, you’ll have to change the domain in the file paths that you paste.

Instead of this:

https://your-cdn.com/wp-includes/etc

You need to use your website’s actual domain. For each path you paste, change the CDN part to be your site’s domain instead, like this:

https://yourwebsitesrealdomain.com/wp-includes/etc

Or you can remove that part of the url entirely and go with something like:

/wp-includes/etc

…which is what I did for mine:

Note: I needed to set the jquery files to embed in <head> to avoid a slew of console errors when visiting the site. As per the earlier settings, anything embedded in head is going to be blocking. I think some blocking files might be inevitable; the point of these settings is to tease out which files belong where in the load sequence.

Save settings and purge all caches, then test again in PageSpeed Insights.

Woohoo – no JS files blocking loading. I also tested the site manually, and verified that it doesn’t look like garbage and doesn’t fill the console with errors. So far, so good.

Fixing render-blocking CSS with Autoptimize

I initially set up all the CSS file paths in W3 Total Cache but ran into these two cases that I couldn’t figure out how deal with through W3 Total Cache alone:

At this point, I loaded my site and found it was using serif typefaces on buttons and it wasn’t scaling the hero (header) image correctly. To fix this, I added custom CSS to Autoptimize’s custom CSS section. This CSS gets loaded right away, so the page doesn’t get stuck waiting on the js or css to “fix” certain issues that are visible right away to a visitor.

One more thing: I also uploaded a significantly more compressed “hero” banner image jpg to the site (old size: about 350kb, new size: about 110kb).

The reward for all these optimizations:

Note that I still have one render-blocking w3tc js file. For now, I’m going to call this “good enough”, since I don’t know how to fix this last one without breaking some fundamental aspect of the site, so I’m going to move onto the expiry problems and see if I can get the score higher that way.

Fixing “leverage browser caching” with W3 Total Cache

PageSpeed Insights found a few files it thinks could leverage browser caching. These files are all .js files.

The first step is to enable browser caching in W3 Total Cache’s settings. Go to Performance > General Settings and make sure Browser Cache is enabled.

Then, go to the actual Browser Cache section of the plugin. As per the guide, I ensured these boxes were checked:

Set expires header

Set cache control header

Set entity tag (eTag)

Set W3 Total Cache Header – this one was not already checked for me

Enable HTTP (gzip) compression

(I re-ran the PageSpeed Insights test at this time just in case that one checkbox was all it took. Alas, there was no change in the results.)

The next thing I did was scroll down a little bit to the CSS & JS section. My “expires header lifetime” was set to 172800, which is way less than the recommended 604800 (2 weeks) the guide recommends. I saved that change, cleared cache, and ran the test again.

Now I have just three files with unsuitable caching times:

Alas, two of the remaining files are out of my hands: they are Google Analytics’s own .js files. After reading this guide to browser caching Google Analytics, I decided not to try to cache the analytics js file myself. Doing so would require manually updating it periodically. Even the guide’s author says they don’t recommend this method. That’s fine by me.

But how about this emoji js file? I don’t use emojis on my site, so I wouldn’t mind removing them and reaping a small page speed boost.

Normally, removing them is as simple as adding these two lines in your site’s functions.php:

Fixing the “flash of unstyled content”

A new problem has been introduced by all this work: now my page looks unstyled for half a second or so while it’s loading.

I used this tool: Critical Path CSS to identify a the “minimum” CSS needed to make the “above the fold” content look good (it’s a huge block, I’m sure a human could produce something more elegant but for now, it’ll do).

I put this CSS into Autoptimize’s “above the fold” CSS section and the flash of unstyled content seems to look better now, though I still see the fonts looking bad before the preferred “open sans” style comes into effect.

Done… for now

At this point, I’ve gotta call it good enough for now. My site’s score went from 8/100 to about 62/100. I still have a one blocking JS file that I don’t know what to do with and two files from Google Analytics with unsuitable cache expiration times.

That referrer, cdn1-mycompany.netdna-ssl.com, isn’t allowed to serve this file. But there’s an easy fix: you can whitelist the CDN itself in the CDN.

The fix: whitelist the CDN itself

In MaxCDN, go to Pull Zones > Security > Whitelist.

You might already have yourdomain.com in here. What you need to add is the domain your CDN files are pulled from.

In my case, that was a domain that took the form of cdn1-mydomain.netdna-ssl.com, but you can find out what yours is by looking in the Network tab while you try to load your site. Look for a red-colored error message and open the Headers.

Anyway, the fix is as easy as adding the domain to this list of whitelisted domains and waiting a few minutes (for me it was about 10 minutes). Reload your website and the Font Awesome icons should now appear.

Note: You will probably need to Purge All Caches, too, once the time has passed to actually see the change in your browser (I use the dropdown in the WP toolbar).

My W3 Total Cache settings

(Just in case it’s useful to someone else trying to debug this problem)

My W3 Total Cache settings are set to upload .css, .tff, .otf, .woff, and .woff2 files.

Provided again as text so you can copy/paste.

wp-includes file types to upload:

*.css;*.js;*.gif;*.png;*.jpg;*.xml

Theme file types to upload:

*.css;*.js;*.gif;*.png;*.jpg;*.ico;*.tff;*.otf;*.woff;*.woff2

This is a pretty specific configuration issue but hopefully it’ll help someone else out there!

This guide was written after I completed the process of hooking up MaxCDN to my Digital Ocean hosted WordPress blog.

This wasn’t a straightforward process, partially due to my own errors and partially because I was using WP Super Cache which I’m pretty sure just doesn’t cooperate with MaxCDN for reasons I may never understand. However, I now have it working so here’s my guide to everything I did.

Why I wanted a CDN: To speed up my top money-making property, which is also my slowest because it’s got long articles and lots of images.

I chose MaxCDN because it seemed to have a lot of good reviews and at about $10/month was reasonably priced.

Setting up MaxCDN with W3 Total Cache and a custom CNAME on Digital Ocean

I signed up and was disappointed to see that the URL MaxCDN gave me by default included the business name I used when I signed up. I wanted cdn.mysitename.com, but by default MaxCDN gave me cdn1.mybusinessname.netdna-cdn.com. MaxCDN calls this the “branded domain” and you can use it as-is, but I would guess most people want to customize it.

My business name and my website name are not the same and I didn’t want to expose the former in the latter. (They don’t tell you they’ll use your business name this way when you sign up, nor do they let you change it once you opened your account. Ugh.)

Fortunately, you can set up a custom domain and use that instead, and my steps below include that process.

Step 1:Enter your custom domain into the pull zone settings. Go to Pull Zones > Settings and fill in the Custom Domains field with cdn.yoursitehere.com (or cdn1.yoursitehere.com, or whatever you prefer. The important thing is that all three parts of the url are present.)

Step 2: Get into Digital Ocean’s record management. Inside Digital Ocean’s droplet management page, go to Networking and then go to Domains. Click the magnifying glass next to the domain you’re adding this CDN to to get into its records. More help adding/editing domain records in Digital Ocean.

Look in Networking, Domains

Step 3: Add a CNAME record to your droplet’s domain. If you want cdn1.yourdomain.com, fill the form out like this:

Enter Name: cdn1

Enter hostname: cdn1.yourdomain.netdna-cdn.com (the “branded” domain that Digital Ocean gave you by default)

Be sure to click the Create CNAME Record button to actually add it to the list of records.

Assuming nothing else is conflicting (you didn’t leave your DNS hooked up to CloudFlare like I did, you don’t have a competing www.yourdomain.com record like I did, etc), this should happen in 20 minutes or less.

At first, I was using WP Super Cache and every time I turned on the CDN feature my site’s styling and images disappeared. I fought with this for a while, got good and frustrated, then tried W3 Total Cache like MaxCDN suggests and WOW – it was like night and day. I followed MaxCDN’s tutorial and basically, it just worked. Be sure to whitelist your site’s IP (go into Terminal or command prompt and ping www.yoursite.com to get your site’s IP if you don’t know it, or look in Digital Ocean’s droplet list).

If everything’s working, you should be able to load your site (yoursite.com) at its usual url (not the cdn url) and look in the network tab of your browser to see responses coming in from the CDN url (cdn.yoursite.com).

Fast way to check: right click any image on your site and view it in another tab. Its url should be your cdn’s url.

If you don’t have any images, you can see this in Chrome by right clicking to Inspect and then click over to the Network tab before loading your site. Hover over some resources (like .css resource) and you should see cdn1.yourdomain.com.

You should also start to see improvements to your page’s load time immediately.

If you don’t see the changes right away: While the cdn1.mysite.com changeover was observable right away on the computer I was working on, it wasn’t on my laptop. The cause seems to be the computer’s own DNS settings. By switching my laptop’s DNS settings to Google’s, I was able to see the most up-to-date (ie: not cached) version of the website.

(Alternatively, waiting a while – up to a day – should resolve it with no changes to your computer.)

Pingdom results, before and after MaxCDN

Here’s a couple of “before” load times on my website, taken less than a minute apart and both from New York City. The thing I often notice on Pingdom’s Website Speed Test is how much variance there can be in load time across multiple tests when all other factors remain the same (location testing from, time of day, etc).

Site speed: before

Here, there’s a huge difference in load time just on these two “before” tests.

The kind of extreme difference in load time seen above is why I like to run several Pingdom tests when collecting my “before” data before making a change that I think should effect load time. Here’s another test, this one from San Jose, California.

Site speed: after

Whoo! Look at that, down to <2 seconds since turning on MaxCDN:

Here’s an even faster one, best one I saw in my several tests:

And one from San Jose:

So far I like MaxCDN. Their online support is very responsive. I sent a detailed plea for help on a Sunday afternoon in the U.S. and had a (reasonably) customized response within an hour. Their documentation is plentiful and thorough. They include many examples and their screenshots are up-to-date with their current interface.

The real test will be in seeing if getting the site speed down to ~2 seconds has any noticeable effect on the site’s Google rank and total conversions (sales).

CDN Traffic Boost?

Totally unscientific study here, but my site’s traffic pulled out of a slump as soon as my CDN hookup went live. (March 17 is just beginning as I post this update.)