Perfect 100/100 PageSpeed Score With WordPress

A long time ago I worked on a theme called Elementary for my Jekyll blog. The goal was simple, to create a website that just works, and works fast. In fact, I’ll just paste the line from the readme of the GitHub repository.

This is my personal blog’s Jekyll template that I’ve been optimizing for performance, accessibility, usability, readability and simplicity in general.

I personally do not approve of personal blogs bloated with hundreds of kilobytes of trackers and analytics code, and hence, this is an attempt at creating something that I’d be comfortable with using on my website.

The goal was accomplished. I managed to get a perfect score on many of the pages. But I wanted to write more and while on the go, and plaintext editing on phones is a pain. Then the other problem was to add it to git and push it. In short, working with a static blog from an Android phone wasn’t easy.

That’s when I moved to WordPress. I ported the theme to Elementary-WordPress, which is essentially the same theme but in a WordPress shell. It worked really well, but the problem was all the bloat that WordPress sends to the frontend. For a while I didn’t care enough. I was still serving a fast website, albeit with Jquery, emojis and other code that wasn’t getting used anywhere else.

Today, that changed. I finally took some time to optimize the website and got back my perfect 100/100 PageSpeed score. Here’s how I did it.

Table of contents

  1. Disable jQuery
  2. Disable wp-embed
  3. Disable block library CSS
  4. Disable emoji
  5. Serve fonts from same domain
  6. Use font-display: optional property
  7. Use an in-memory page cache like Memcached
  8. Fix conflicting cache strategies
  9. Use a CDN for asset delivery
  10. TODO: Inline all CSS and Javascript

Disable jQuery

If your website isn’t ancient, there’s a good chance you’re not using it. If some plugin you’re using is using jQuery, consider alternatives. It will save you ~30KB and an HTTP request. Adding the following to the functions.php should do it.

function jquery_dequeue() { 
  wp_deregister_script( 'jquery' );
}
add_action( 'wp_enqueue_scripts', 'jquery_dequeue' );

Disable wp-embed

The following snippet from this answer needs to be added to functions.php

function wp_embed_dequeue() {
  wp_deregister_script( 'wp-embed' );
}
add_action( 'wp_footer', 'wp_embed_dequeue' );

Disable block library CSS

*Sigh* This goes into the functions.php

function remove_wp_block_library_css(){
  wp_dequeue_style( 'wp-block-library' );
}
add_action( 'wp_enqueue_scripts', 'remove_wp_block_library_css' );

Disable emoji

I found some nice code to disable a whole bunch of unnecessary actions from this guide here: https://kinsta.com/knowledgebase/disable-emojis-wordpress/#2-disable-emojis-in-wordpress-with-code

Serve fonts from same domain

If you’re not super keen on using the smart browser detection functionality that Google Fonts offers and are happy only supporting modern browsers, simply downloading the font files and linking them with @font-face can save an additional DNS and HTTP request.

Use font-display: optional property

I’m using font-display: optional; CSS property on my @font-face and it pushed my PageSpeed score over the top. Essentially it prevents the CLS, or Cumulative Layout Shift metric of Core Web Vitals from getting affected due to page shifting due to slow loading of font files.

Read more about it here: https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display

Use an in-memory page cache like Memcached

Building pages to serve the users is expensive as it involves the database, but isn’t something that needs to be done for every visitor visiting the same page. A plugin like W3 Total Cache coupled with a Memcached instance (could be running on the same server as the website) could enable caching of pages among other resources in memory, reducing the load on the server and improving performance for cache-hit pages.

memcached

Fix conflicting cache strategies

I’m using W3 Total Cache plugin that helps minify and cache CSS and JS files. But I wasn’t seeing any minification happening. Upon some reading, it turns out that CloudFlare’s minification conflicts with W3 Total Cache’s. Disabling it on CloudFlare’s side fixed the non-minification problem for me.

Use a CDN for asset delivery

Once the thing to deliver is optimized, it is a good idea to optimize the delivery pipeline as well. Since my server is in the same country as me, it is easy to make a mistake of thinking every visitor of the website is seeing a 50 milliseconds time to connect to the server. The further the user is from the origin server, the longer it could take.

Hence, an global CDN like CloudFlare should be used which can serve static content from its edge node physically closest to the visitor.

TODO: Inline all CSS and Javascript

It doesn’t go beyond 100, but I’d still like to improve it further. For one, the little bit of CSS and JS that does exist doesn’t have to need two additional HTTP requests. Inlining that bit will mean that blog posts without an image, which for me are most of them, will get served in only three HTTP requests; the document, the font file and the favicon. Pretty cool, huh?

Conclusion

I’m pretty pumped about the 100/100 score. WordPress has a reputation for being slow and bloated, but with some simple optimizations, it starts performing like how you’d expect some text on a page to perform like.

Thank you for reading!