How to Reach a PageSpeed of 100
Welcome to part two of our series on Google PageSpeed. In the first episode, I optimized the PageSpeed of my site’s then theme, MySiteMyWay’s Construct. I managed to get to 70 Mobile and 86 Desktop.
However, with MySite’s closure, I chose a new theme and reached a 100 PageSpeed for Mobile and Desktop. It took me about 12 hours of extra effort to accomplish this. Now, my site’s performance is one of the fastest WordPress sites I’ve seen in a long time—check it out. Browsing’s almost instantaneous.
In this tutorial, I’ll walk you through how I accomplished this and what I learned about WordPress and Google PageSpeed. For much of the day I worked on it, I thought I might top out in the 90s. I was surprised a bit when it jumped suddenly to 100 for Desktop—and there were just a few details left to maximize Mobile.
For those that don’t know, Google PageSpeed is a free tool that assesses the performance and usability of your website for mobile and desktop platforms. It’s extra important because Google uses it in determining key elements of our SEO ranking, i.e. how high we appear in their search results.
If you want more background about the benefits of increased site speed, read Moz’s Why Site Speed Optimisation Should Be Part of Your SEO Strategy. It highlights, “…several case studies have shown faster loading pages strongly correlate to higher revenue.”
Google and WordPress Don’t Make This Easy
Ultimately, optimizing my PageSpeed took a lot of time and effort and left my site vulnerable to future plugin and Google script updates. A lot of this work is quite confounding, detail-oriented and time-consuming. It’s also a bit crazy-making and mind-numbing. Thanks, Google.
A static site usually has one file with CSS and JS includes that can be easily minified and combined. WordPress is a lot more complex. So much is created dynamically through WordPress’s—ahem—less than perfect architecture.
It can take time to find where files are being created, whether they are in the themes or plugins, and how to address these issues. It turns out that when you have seven plugins including JavaScript files and you want to minimize and combine them into one include while allowing regular plugin upgrades, it’s quite a challenge in the WordPress world of constantly changing themes and plugins.
This makes a lot of developers sad:
Image credit: My photo from Picasso Museo in Paris. Could now be called “Sad Developer Confronting PageSpeed of Mobile 55 / Desktop 62”
That said, let me encourage you by showing how I did it (you don’t have anything useful to do today, do you?). Keep in mind, your site’s needs may differ from mine a bit.
Before we get started, please remember, I do try to participate in the discussions below. If you have a question or topic suggestion, please post a comment below or contact me on Twitter @reifman. I’m interested in your experience with WordPress and PageSpeed.
The Foundational Steps to PageSpeed 100
Selecting a New Theme
If you’re in the market for a new WordPress theme and want to evaluate PageSpeed, you may be surprised that the scores for well-known themes often run in the 60s and 70s but also up to the 90s. Here are a couple of articles assessing themes and PageSpeed via ColorLib and WPMU. In any case, I expected higher.
Just as an example of industry expectations, The New York Times website scores 53/55 for me, far below 100.
The PageSpeed of various themes is greatly affected by the number and size of JavaScript files and CSS they use, the number of images used and their size, and the approach of their mobile implementation, i.e. typically responsive nowadays. Some creators don’t seem to look at their PageSpeeds as they build.
Array Themes Medium
For this tutorial, I’m going to focus on improving my personal website, JeffReifman.com. I chose Medium by Array Themes for a few reasons.
The first was its baseline speed. Medium scores Mobile 74 and Desktop 89 to start from their demo server. While this was already slightly better than I had maximized Construct to, it was a more modern theme and there were a lot of remaining optimization steps I could try. I hoped to bring PageSpeed into the high 80s or low 90s.
Also, given the growth of mobile readership, I wanted to move away from relying on sidebars—especially for advertising placement (I hope to write about my new revenue directions in our ongoing Google DFP series). The Medium theme does a good job of folding the left sidebar into a responsive menu and concealing its right sidebar.
Medium’s Initial PageSpeeds
Here was the initial PageSpeed for the demo of Medium (demo hosting is never tightly optimized). It was actually encouraging to see it had lots of unaddressed issues because it showed that it was better than my optimized Construct before extra effort was applied and similar tasks I knew to perform to maximize its score:
Here are more of the issues:
And more:
And the user experience challenges, which were more localized:
Finally, here is its demo Desktop score:
Encouraged by the foundation score, I purchased and installed the Medium theme on my server and got to work.
Keep in mind that changing themes can be quite complicated. For me, replacing, eliminating and updating built-in shortcodes from the Construct theme took the most time, and I’m not fully done, e.g. dropcaps, pullquote variations, buttons, tabs and page-based navigation menus. My drive for 100 pushed me to trudge ahead regardless. How to Perform Mass Search and Replace in WordPress offers some good solutions for finding and replacing shortcodes.
While this tutorial won’t guide you through exact steps for raising your site’s PageSpeed to 100, it will guide you through a lot of the possible solutions and identify common roadblocks. There’s another great generalized resource I’ll share at the end.
Cornerstones of Performance in WordPress
I did contact ArrayThemes a bit about the sub-100 demo performance of the Medium theme. They sent an excellent response:
The PageSpeed optimization test should be taken with a grain of salt … our demo is being dinged for not caching, but we don’t actually need caching on our demos … PageSpeed suggestions aren’t entirely accurate or exemplary of the performance of a theme. It will depend entirely on your setup, server, caching and other optimizations you decide to make.
This makes a perfect launching point to reviewing the common foundational elements for WordPress performance. All of the areas of performance below address underlying PageSpeed scores, not completely but the basics.
Caching
WordPress caching is critical for performance, and I’ve regularly written about my favorites: W3TC and Varnish Cache, e.g. Optimizing WordPress with Varnish and W3 Total Cache.
It turns out that there are a handful of plugins designed to help you take on the challenge of efficient caching. Here are two of the best that I tried:
- Minit: A WordPress plugin to combine CSS and JavaScript files.
- Dependency Minification: Automatically concatenates and minifies any scripts and stylesheets enqueued using the standard dependency system.
Image credit: WordPress Tavern
Both were helpful, but neither quite removed barriers for me related to PageSpeed, such as embedding CSS within my <head>
tag to remove PageSpeed problems; in other words, this plugin won’t likely get you all the way to 100 PageSpeed. I found Dependency Minification to be efficient and helpful, but its lack of flexibility made me walk away.
Ultimately, I would repeatedly return to W3 Total Cache and find new more powerful ways to press it for performance. It’s not perfect and definitely has some UX bugs, it worked well in enough ways for me to find my path with other approaches to PageSpeed 100.
In the end, I chose only one new plugin which made it easy to remove PageSpeed problems with Disqus—I’ll review this further below.
Content Delivery Networks (CDN)
Another service that’s critical is a content delivery network. Earlier I wrote about Accelerate Your Content Delivery With KeyCDN at Envato Tuts+ and then decided to switch to them as a customer.
In the end, there are a variety of CDNs you can choose from, such as CloudFlare and RackSpace to name a few.
Image Optimization
Recently, I began experimenting with KeyCDN’s new Optimus image optimization service and WordPress plugin. There’s a small possibility it’s run by robots built with old Apple Lisas and Macs:
It works well, but another popular alternative is WP-Smush, an older plugin with more than 300,000 users.
Eliminating Render Blocking
If you have a large variety of files that need to be loaded to style (CSS) and activate (JS) the functionality of your web page, most browsers will slow down after four resources are requested in parallel.
Here’s an example of the CSS render blocking complaint in PageSpeed:
This can be a hard WordPress item to eliminate due to the theme and plugin architecture. We’ll come back to it.
What Steps Ultimately Pushed My Site to 100?
Targeted Optimization Approaches
If you’ve done all the major basics above, improving your PageSpeed with WordPress turns out to require significant effort and can be quite time-consuming.
Let’s go step by step through the identified problem areas and the ways I solved them. In truth, I did a vast amount of experimenting with different tools and approaches. I regularly dropped one approach and returned to another. My solution turned out to be a fairly well-managed patchwork of solutions. The path was not direct Yoda.
Minification of HTML, JavaScript and CSS
For example, here’s how you minimize HTML within W3 Total Cache:
Bundling JavaScript at the End of the Page
Similarly, it’s easy to minimize JavaScript in W3 Total Cache. Note below that I’m instructing W3TC to embed the compressed file not in the <head>
but instead just before </body>
. Delaying JavaScript may improve your PageSpeed score.
Minimizing Combined CSS From Themes and Plugins
Because both themes and plugins use JavaScript and CSS, it takes a bit of work to minimize them together and combine them into a single file (and that’s not even enough for PageSpeed, which I’ll discuss further below).
In order to block plugins from loading their own CSS and instruct W3TC to load compressed and combined versions, you need to find the plugin’s handle for the CSS file (distinct from filenames) and add code to your theme to interrupt the plugin loading instructions. Then, enter the path to each CSS file within the W3TC dialog box above to be loaded with the others.
Blogger Justin Tadlock offered some guidance explaining how to ask WordPress not to load the CSS files that my plugins had enqueued for loading. The answer is to deregister them and then load a combined file on your own.
Here’s my Table of Contents plugin enqueuing its JS and CSS files:
/** * Register and load CSS and javascript files for frontend. */ function wp_enqueue_scripts() { $js_vars = array(); // register our CSS and scripts wp_register_style( 'toc-screen', $this->path . '/screen.min.css', array(), TOC_VERSION ); wp_register_script( 'toc-front', $this->path . '/front.min.js', array('jquery'), TOC_VERSION, true ); // enqueue them! if ( !$this->options['exclude_css'] ) wp_enqueue_style("toc-screen"); if ( $this->options['smooth_scroll'] ) $js_vars['smooth_scroll'] = true; wp_enqueue_script( 'toc-front' );
Following Tadlock’s suggestion, I deregistered my plugin includes in my theme’s functions.php, starting with the CSS—you have to find the references used by the plugin developer:
add_action( 'wp_print_styles', 'my_deregister_styles', 100 ); function my_deregister_styles() wp_deregister_style( 'toc-screen' );
I manually created a combined CSS files with those three plugin stylesheets. Then, I asked W3TC to minify and combine that file into its own mega-stylesheet as shown above.
Optimizing CSS Loading for PageSpeed
W3TC may combine all my theme and plugin files, but PageSpeed still doesn’t like seeing even one CSS include (so much for good HTML development practices):
I ultimately loaded nine CSS files (only seven shown below). Firstly, you have to find plugin handles for CSS and deregister them in your theme as described above. Then, you have to point them all to W3TC.
While there are several ways to get a minified version of all of these, I actually just grabbed W3TC’s compressed file. I removed all of the caching query arguments, e.g. ?cbe3w2
, with search and replace in TextEditor. I’m still a loyal TextMate user, but it actually had huge delays and hangs whenever I tried to navigate a minified CSS file. So TextEditor helped me edit these files individually. Apologies to purists, I haven’t moved on to Sublime yet.
While it worked for me to paste my minified CSS into my header, I later needed to change it to dynamically get the contents of CSS files and echo them into place.
<![endif]--> <style type="text/css"> <?php $css = file_get_contents('/mypathtowp/wp-content/themes/medium/includes/styles/combined.min.css'); $css2=file_get_contents('/mypathtowp/wp-content/themes/medium/includes/styles/osd-social.css'); echo $css.$css2; ?> </style> <!-- add js class -->
Once I added another plugin for social sharing, pasting no longer worked and I had to separate the files with the above mechanism. This also provides more flexibility for the future. Google PageSpeed never sees this, and my Varnish cache conceals any slowdown of including two files.
Ultimately, I configured all of my CSS files in W3TC, made copies of the compressed files, and then turned off this include feature:
One shortcoming of W3TC is that it repeatedly shows annoying error messages even though you are deliberately using it in an unusual way.
When moving CSS files out of plugin directories, make sure you set correct relative paths to images and so on for operating from the site’s root directory. I had a lot of situations where images wouldn’t load until I found where to resolve these things. I’ll share an example in the Troubleshooting section below.
Caching External Scripts in the Browser
Amusingly, Google’s PageSpeed complains if you load its JavaScript libraries externally. I received demerits for external scripts related to Flickr, Disqus and Google Analytics:
This turned out to be quite a big obstacle and requires a lot of time and complexity to fully resolve these issues.
Removing Flickr Embed Problems
First, I had recently returned from a trip to India and put individual blog posts with Flickr-embedded photos on the home page. My Medium theme quickly scrolls through a number of posts, so PageSpeed complained about all of them.
After observing that PageSpeed complained both about Flickr-hosted embedded image sizes (at various pixel counts) and seeing these external JavaScript demerits, I returned to self-hosting optimized images on my site. They still link to Flickr for my ongoing India album.
This is a good example of how trying to use a powerful third-party service with the simple purpose of embedding photos kills your PageSpeed score. Flickr hasn’t done an optimal job of helping WordPress users solve this. Just as an example, they would need to:
- offer embedded sizes that keep PageSpeed’s image optimization happy (possibly as separate export options compromised for your PageSpeed—Flickr’s about image quality)
- publicize the JavaScript code in an easy manner to integrate into WordPress and W3TC combined files
Self-Hosting External JavaScript Files
With my remaining Google files, the best solution was to locally host a copy of scripts for Analytics and DFP and use cron scripts to regularly update them on a server.
First, I stopped using my Google Analytics plugin and manually added modified code to my theme’s header:
//... <!-- add js class --> <script type="text/javascript">document.documentElement.className = 'js';</script> <!-- add custom GA --> <script> (function(i,s,o,g,r,a,m)function()[]).push(arguments),i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) )(window,document,'script','/wp-content/themes/medium/includes/js/external/analytics.js','ga'); ga('create', 'UA-37244292-1', 'auto'); ga('send', 'pageview'); </script> <?php wp_head(); ?> </head>
Notice I changed the paths to my local copies of the scripts. Then, I made local copies of the scripts for Google Analytics and Google DFP, and shortly after my browser caching was resolved in PageSpeed except for Disqus.
Solving the Disqus Plugin Loading Problem
I’m not sure exactly whether it’s for security or multi-platform support or pure “cleverness”, but Disqus and other providers like Flickr seem to obscure the actual files they are loading with other files. This makes optimizing PageSpeed much more difficult and often unsolvable.
Admittedly, I spent two to three hours trying different approaches to optimize the Disqus plugin—nothing worked for me.
Ultimately, I uninstalled the Disqus plugin and installed Disqus Conditional Load:
While it’s meant to do a lot of things, it also makes it possible to optimize PageSpeed with installation.
Suddenly, PageSpeed’s Leverage Browser Caching demerits were gone. Kudos to DCL!
Fixing the Tap Targets
PageSpeed often complains about links too closely spaced in mobile devices. I experimented with a few approaches and ultimately just stopped displaying tags on mobile devices.
If I spend more time, I can probably improve their UX and pass with PageSpeed.
<?php if( is_page() ) else ?> <ul class="meta"> <li ><span><?php _e( 'Category: ', 'medium' ); ?></span><span><?php the_category( ', ' ); ?></span><br /></li> <?php if (!wp_is_mobile()) ?> <!-- not mobile --> <?php $posttags = get_the_tags(); if ( $posttags ) ?> <li><span><?php _e( 'Tag: ', 'medium' ); ?></span> <?php the_tags( '', ', ', '' ); ?></li> <?php ?> <?php ?> <!-- end not mobile --> <?php if( is_single() ) ?> <li><?php previous_post_link( '%link', __( '<strong>Previous Post: </strong>', 'medium' ) . '%title' ); ?></li> <li><?php next_post_link( '%link', __( '<strong>Next Post: </strong>', 'medium' ) . '%title' ); ?></li> <?php ?> </ul> <?php ?>
Troubleshooting
Missing Images From Compressed and Combined CSS
The ArrayToolkit Plugin, which displays follow icons in the right sidebar, stopped working for me. It took me a while to sort out which paths needed to be coded with absolute paths to make it work.
Ultimately, I found and replaced these paths with corrected relative paths to the original plugin directory:
// Had to put path in plugin css @font-face font-family: 'array'; src: url('./fontello/array.eot'); src: url('./fontello/array.eot#iefix') format('embedded-opentype'), url('./fontello/array.woff') format('woff'), url('./fontello/array.ttf') format('truetype'), url('./fontello/array.svg#array') format('svg'); font-weight: normal; font-style: normal;
Broken JavaScript
I still have one problem I need to resolve. My new tabs plugin (Construct had built-in tabs) stopped working along the way. I just need to spend time debugging it, but it should be fairly easy to sort out.
Choosing the Best Minifier
I experimented with YUI Compressor with W3TC to compress my JavaScript and CSS files. Instead of leading to increased speed, everything kind of broke.
If you’re interested in figuring out what I did wrong, you can install Java and YUICompressor like this:
#good luck sudo apt-get install openjdk-6-jre cd /usr/local/lib sudo wget https://github.com/yui/yuicompressor/releases/download/v2.4.8/yuicompressor-2.4.8.jar
Please post in the comments if you know how to make it play well with WordPress.
In Closing
After this second round of work on the new theme, everything worked out better than I’d hoped. I was never sure I’d reach my optimal goal.
My Final PageSpeed Scores
I scored 100 PageSpeed for both Mobile and Desktop. Even more noticeably, my site was running super-fast—faster than I’ve ever had a blog run before. I’m very curious to see how inbound search traffic and readership activity reacts to the faster scores and performance over the next few months.
Here are my final PageSpeed scores, first Mobile:
And now Desktop:
Desktop reached 100 first, and I had to go back and finish some adjustments (addressing tap targets) to get Mobile there.
And again, the speed of the site makes it worth a quick visit. If you know of other commercial websites running at 100 PageSpeed, please share them in the comments. I’d enjoy seeing them.
Just as one example of SEO changes, my popular essay on dating jumped to third ranked on mobile results under “Seattle dating” (not on desktop yet.) This tells me that perhaps stories on major sites beating it have poor mobile PageSpeeds, because it’s not easy.
To maximize my site’s PageSpeed, I had to make a number of adjustments to my theme, which will now create dependencies on changes to external scripts and updates to the theme and plugins. Now that I’m done with my short-term goal, I have work to do to organize my systems to more easily manage this.
Cron for External Files
Soon I’ll need to go implement that cron script to synchronize my self-hosted Google scripts for Analytics and DFP.
Here’s a company that provides a simpler approach to using Analytics without PageSpeed being penalized, fixing the last point on Google PageSpeed Insights. I’d rather not rely on other third parties.
Managing Theme Updates
I’ll also need to better track Medium’s theme updates and integrate changes. Building a child theme from my changes might also ease this process. Mostly I’ll be looking for changes that overwrite mine, updated (or additional) JavaScript and CSS files.
Managing Plugin Updates
Similarly, when plugins update, I’ll need to watch for the same kinds of updates. It may help me to better organize my use of GitHub with WordPress plugins. I already use it for my theme.
Automation
I may want to spend some time writing scripts to track which JavaScript and CSS files are in use with the updated theme and plugins, download them to my server, and minimize and pack the appropriate files to link or include.
SSL
Finally, one of my surprises is that SSL is not required to achieve a PageSpeed of 100. This somewhat makes sense but highlights that a variety of different components may affect your Google search ranking. I’ll be writing about implementing Let’s Encrypt’s free SSL with WordPress soon.
What’s Next?
If you’ve enjoyed this but want to read a more general tutorial that doesn’t go as deeply into specifics that may or may not apply to you, KeyCDN’s Google PageSpeed Scoring 100/100 with WordPress is an excellent complementary piece. I’ve also written a sponsored piece about their CDN at Envato Tuts+ (Accelerate Your Content Delivery With KeyCDN) and went on to continue with them as a customer.
In the future, I’ll be looking at a few more enhancements to improve my site’s overall performance. These include:
- Review the individual PageSpeed of my most popular posts such as Amazon Marketplace Fraud Made Easy (currently 97), to ensure they are all running at 100. As in this example, it’s often just embedded image size(s) which perturbs PageSpeed.
- Improving management of my theme and plugins to sustain these optimizations as easily as possible as updates arrive, e.g. tracking changes to JS and CSS files in updates, keeping copies of external JS files like Analytics updated, re-compressing updated files, etc.
- Upgrading my server to PHP7. The upgrade promises nearly 2x performance improvements. It’s not simple to upgrade prior to the bundled Ubuntu release, but it’s not too difficult.
- Upgrading my server to Varnish4. The upgrade requires some reworking of configuration files, and I’m unsure of its performance improvement and compatibility with W3 Total Cache, but I’m willing to give it a try.
- Explore KeyCDN’s CacheEnabler for serving more efficient Webp images to Chrome users. Webp file sizes are significantly smaller but not yet supported by Safari. I’m actually quite excited about improving the user experience with this.
If you have questions, please post them below. Or, you can contact me on Twitter @reifman. Please check out my Envato Tuts+ instructor page to see other tutorials I’ve written, such as Cloning WordPress in Linux (in 90 seconds).