I have a personal blog where I document my learnings on various web technologies.
I have been blogging since last 4 years and I recently optimised the blog to load way faster than it did before.
My Blog was getting getting the PageSpeed score on Google PageSpeed of Around 35 for Mobile and 50 for Desktop. That's pretty bad in terms of user experience and also for SEO in general.
With some tips and tricks to improve the page speed, the website get's the PageSpeed score more than 90 for desktop.
Screenshot of Google PageSpeed Score
Screenshot of GTMetrix Report
Although there are tons of article on the web on improving the page load times, Many of them are too generalised and doesn't offer practical solutions.
In this article I am sharing few steps that I took to improve the website page speed.
1. Combine and Minify Multiple CSS and JS Files
Problem :
I use different CSS and JS plugins in my blog that includes Bootstrap, Font-Awesome, PrismJS, Modernizr, AppearJS, EasingJS.
Previously, There used to be a separate call to the server for each of the Asset and some of the CSS and JS files were not minified.
I tried different plugins to Minify and Combine the CSS and JS but none of them worked exactly how I wanted it to work and instead the plugins added the overhead on page load speed.
Solution :
Since I used to Laravel way of doing things. I figured out that Laravel Mix (A wrapper library for WebPack) could work perfectly for my use-case.
I installed Laravel Mix and Combined and Minified the CSS and JS using it's easy to use API.
This is the simple code to combine and minify all CSS and JS inside webpack.mix.js
mix.styles([
'writing/framework/googlefonts/lora.css',
'writing-child/assets/framework/bootstrap-4/css/bootstrap.css',
'writing/pluginstyle.css',
'writing/style.css',
'writing-child/style.css',
'writing-child/assets/css/prism.css',
'writing-child/assets/css/jquery.mCustomScrollbar.min.css',
'writing-child/assets/css/fontawesome-5.min.css'
], 'writing/css/all.css');
mix.scripts([
'writing/js/modernizr.js',
'writing/js/lazysizes.min.js',
'writing-child/assets/framework/bootstrap-4/js/bootstrap.min.js',
'writing/js/conditionaljs/appear.js',
'writing/js/conditionaljs/easing.js',
'writing/js/conditionaljs/basic_script.js',
'writing-child/assets/js/prism.js',
'writing-child/assets/js/jquery.mCustomScrollbar.concat.min.js',
'writing/assets/js/custom-child.js'
], 'writing/js/all.js');
This code compresses and joins all CSS and JS into a single file named all.css
and all.js
for javascript.
Inside the functions.php of Wordpress Theme, Wherein all the scripts and stylesheets gets enqueued. I now have a two entries one for my CSS and one JS.
wp_enqueue_style('all', get_template_directory_uri() . '/css/all.css', array(), 1.0);
wp_enqueue_script( 'all', get_template_directory_uri() . '/js/all.js', array(), 1.0);
Sweet, Isn't It?
2. Removed Unwanted CSS & JS
Problem : Shipping unused JavaScript or CSS is a common problem in web development. Paid Themes in Wordpress Includes CSS and JS for each and every customer and customisation possible.
The theme I was using was having tons of lines of CSS and JS for the Sidebar's, Widgets and Components which I was never going to use in my Blog.
Solution: Unfortunately there is no easy solution for this. I spend some hours looking at the CSS and JS Files and manually removing the code which I knew my blog is never going to utilise.
One Tool that I found useful is UnCSS-Online
This tool is simple, copy and paste your page's HTML source code and along with that paste the CSS which you want to purify.
This online tool will detect and let you know what part of CSS is being unused, so that you know if it's safe to remove it.
Another Tool that I used is a built-in Tool in Google Chrome Browser to check the Code Coverage.
Here are the steps to check your Code Coverage.
- Open your website in Google Chrome.
- Open Developers Tool and Navigate to Sources Tab.
- Click on the Coverage Link on the Footer Panel.
- It will ask to reload the page to start capturing the code coverage.
- Reload the page and you can now see Total Bytes and Used Bytes for all of the CSS and JS files on your page.
3. Uninstalled Unwanted Plugins
Problem : All activated Plugins on your Wordpress site contribute to page load times. If you have variety of plugins this is going to cause problems to your PageSpeed.
The problem with Plugins and Themes for me is that they cater to variety of requirements since they have variety of requirements from their Customers.
When you install a Popular Wordpress Plugin, with it you also install the Code on your website which is a customisation need for other customers and not yours.
Solution : I analysed each of my installed plugins and checked if I really need it and if yes can there be a simpler solution for it that can be done with few lines of Code myself.
For example : I used a Paid plugin named WP-Rocket (In the hope to speedup the website), Since I did not got the desired results from it. I uninstalled it and wrote a custom code to combine and minify my CSS and JS (Described in Step 1)
Similarly I used a plugin to Lazy Load the images, instead I included a jQuery library Lazy Load Remastered to do its job. (Described in Step 5)
4. Moved to a Better Host
One of the important factors in improving page load times to is to reduce the Initial Server Response Time.
Initial Server Response Time is Time to First Byte, the time that it takes for a user's browser to receive the first byte of page content.
Although It depends on a lot of factors and that includes Plugins, Themes, Database Size, Server Specification etc.
Improving the response time also depends on the Web Host you choose. My website was hosted on Bluehost and then I shifted to SiteGround, With the exact same configuration I found SiteGround providing me better response times to the website.
It takes anywhere from around 150ms to 500ms for blank Wordpress System to FireUp, and Google PageSpeed considers anything less than 600ms a good server response time. (Refer https://web.dev/time-to-first-byte )
That means that we have a really short window to time to load up Themes and Plugins after Firing up of Wordpress to get into the Green section of Google PageSpeed.
SiteGround does a good job of reducing the initial server response time.
Here are the screenshot from a fresh website that I hosted on SiteGround that has blank database and uses default theme.
If you are new to Blogging and Hosting, Here is an in-depth article I wrote to help you get started.
Beginners Guide to Start Blogging with Wordpress
5. Enhanced Theme to Load Faster
Problem : I used a paid theme for my Blog and although it served the purpose of Look and Feel. It was bloated with lot of customisation code.
There was code for Instagram, Pinterest Widget, Code for Collapsable Sidebar, Code for Sidebar Widgets and tons of other things which I don't require
Solution : Again, there is no easy solution for this.
I opened the functions.php
file and removed each and every customisation code that I don't require and won't need in the future.
Note: This hampers the ability to update the future releases of the Theme since I directly made the changes in core files. But this is the trade-off I made for better speed and minimal code to maintain.
6. Removed Wordpress Comments Section
Problem : Few of my Posts have around 80 comments on the post. Which is great, but this really slows up the page to fetch Gravatar images, getting comments from the database and also it bloats up the Html DOM.
Solution : I am replaced default wordpress comment system in favour of Disqus. Comment migration to Disqus is simple and I have also have installed a plugin to conditionally load the Disqus comments.
That means if the user really wants to read the comment or add a new comment he can choose to load up the comment section by clicking on a button.
7. Cleaned Database Tables
Problem : I currently have 300 blog posts in my database. Each one of those had some kind of revisions in the database which I was of no use to me.
Also when you uninstall a plugin, Most of the times it leaves some residue data in the database.
Solution : It's great idea to frequently clean up the database.
There are variety of free plugins that you can install to perform the database cleanup for Free. Once the job is done I removed that plugin as well.
8. Added Asset Cache Policy
Problem : Browser doesn't cache the static Assets for longer period if you don't specify the Cache policy.
That results in refetching the content from the server and leads up to slower website.
Solution : By Specifying the Cache Policy for Static Assets (CSS, JS, Images etc.) you tell the Browser to cache the files for Specific number of days. Browsers will then cache these files on the user’s computer.
I added cache policy for my Static assets in .htaccess file by utilising the mod_expires module.
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access 1 year"
ExpiresByType image/jpeg "access 1 year"
ExpiresByType image/gif "access 1 year"
ExpiresByType image/png "access 1 year"
ExpiresByType image/svg "access 1 year"
ExpiresByType image/webp "access 1 year"
ExpiresByType text/css "access 1 month"
ExpiresByType application/pdf "access 1 month"
ExpiresByType application/javascript "access 1 month"
ExpiresByType application/x-javascript "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType image/x-icon "access 1 year"
ExpiresDefault "access 2 days"
</IfModule>
9. Reduce Image Size & Lazy Load Images
Problem : Too many images of high file size were effecting the page speed.
Solution : I converted most of my pages images that appear frequently (Logo, Footer Author Image, etc.) to webp
format. webp is desired format for the browser these days and it compresses the image.
Also I utilised the Lazyload plugin to load the images only when user scrolls to that position.
It works absolutely great since in the first user request there are no images to be load and once user starts reading the article the images gets loaded in the background.
Here is the custom function written to utilise this plugin in Wordpress.
function five_balloons_filter_lazyload_images( $content, $type = 'ratio' ) {
if ( is_feed()
|| intval( get_query_var( 'print' ) ) == 1
|| intval( get_query_var( 'printpage' ) ) == 1
|| strpos( $_SERVER['HTTP_USER_AGENT'], 'Opera Mini' ) !== false
) {
return $content;
}
$respReplace = 'data-sizes="auto" data-srcset=';
$matches = array();
$skip_images_regex = '/class=".*lazyload.*"/';
$placeholder_image = apply_filters( 'lazysizes_placeholder_image',
'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' );
preg_match_all( '/<img\s+.*?>/', $content, $matches );
$search = array();
$replace = array();
foreach ( $matches[0] as $imgHTML ) {
// Don't to the replacement if a skip class is provided and the image has the class.
if ( ! ( preg_match( $skip_images_regex, $imgHTML ) ) ) {
$replaceHTML = preg_replace( '/<img(.*?)src=/i',
'<img$1src="' . $placeholder_image . '" data-src=', $imgHTML );
$replaceHTML = preg_replace( '/srcset=/i', $respReplace, $replaceHTML );
$newClass = 'lazyload ';
$pattern = '/class="([^"]*)"/';
// Class attribute set.
if ( preg_match( $pattern, $replaceHTML, $matches ) ) {
$definedClasses = explode( ' ', $matches[1] );
if ( ! in_array( $newClass, $definedClasses ) ) {
$definedClasses[] = $newClass;
$replaceHTML = str_replace(
$matches[0],
sprintf( 'class="%s"', implode( ' ', $definedClasses ) ),
$replaceHTML
);
}
// Class attribute not set.
} else {
$replaceHTML = preg_replace( '/(\<.+\s)/', sprintf( '$1class="%s" ', $newClass ), $replaceHTML );
}
$replaceHTML .= '<noscript>' . $imgHTML . '</noscript>';
array_push( $search, $imgHTML );
array_push( $replace, $replaceHTML );
}
}
$content = str_replace( $search, $replace, $content );
return $content;
}
add_filter( 'the_content', 'five_balloons_filter_lazyload_images' );
10. Defer Loading of Javascript
Problem : By default JavaScript blocks DOM construction and thus delays the time to first render. This adds to the page load time until the javascript is executed.
Solution: If the javascript that you are working with isn't critical to load before other DOM elements,
The loading and execution of javascript may be deferred until after the initial render or other critical parts of the page have finished loading.
Doing so can help reduce resource contention and improve performance.
To prevent JavaScript from blocking the parser it's recommend to use the HTML async
or defer
attribute on external scripts. For example:
<script async src="my.js">
Here is the WordPress function I wrote to achieve the same.
/** Defer parsing of javascript */
function defer_parsing_of_js( $url ) {
if ( is_user_logged_in() ) return $url; //don't break WP Admin
if ( FALSE === strpos( $url, '.js' ) ) return $url;
if ( strpos( $url, 'jquery-' ) ) return $url;
return str_replace( ' src', ' defer src', $url );
}
add_filter( 'script_loader_tag', 'defer_parsing_of_js', 10 );
In this function I add defer to all the script tag except jQuery
which is required for my pages to render correctly.
11. Removed Unwanted External Scripts
Problem : Once I analysed the scripts being loaded in the Network tabs of Developer console. I noticed some scripts which are not useful or aren't relevant for my use-case.
Solution : I added custom functions in my functions.php
file of Wordpress to remove those scripts.
//Remove Gutenberg Block Library CSS from loading on the frontend
function smartwp_remove_wp_block_library_css(){
wp_dequeue_style( 'wp-block-library' );
wp_dequeue_style( 'wp-block-library-theme' );
wp_dequeue_style( 'wc-block-style' ); // Remove WooCommerce block CSS
}
add_action( 'wp_enqueue_scripts', 'smartwp_remove_wp_block_library_css', 100 );
/** Remove Contact Form 7 CSS unless required */
function rjs_lwp_contactform_css_js() {
global $post;
if( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'contact-form-7') ) {
wp_enqueue_script('contact-form-7');
wp_enqueue_style('contact-form-7');
}else{
wp_dequeue_script( 'contact-form-7' );
wp_dequeue_style( 'contact-form-7' );
}
}
add_action( 'wp_enqueue_scripts', 'rjs_lwp_contactform_css_js');
/** remove WP-Embed */
function my_deregister_scripts(){
wp_deregister_script( 'wp-embed' );
}
add_action( 'wp_footer', 'my_deregister_scripts' );
That's all about the major steps that I performed to improve the PageSpeed score.
What's Next ?
In terms of page loading time my blog is still not where I want it to be. I have planned out creating a custom minimal theme which fits my UseCase to remove all the unwanted php code, and JS and CSS assets.
Feedback / Suggestions ?
Let me know if you find these tips useful. Also, did you have any other such tips that you performed to decrease the page load time and get a good score in Google Page Speed Index.
Please share it in comments.
Top comments (6)
Great job on the optimization.
That being said, this illustrates what I wrote about here really well.
Is there any particular reason you're staying on WordPress instead of using something lighter?
Wordpress ecosystem (Personal knowledge, Plugins, etc.) works got really well for my UseCase and I haven't found the motivation to move all my data to a newer system. Which platform are you using?
Makes sense!
For my blog, I will be moving from Bludit to Saisho which is an engine I made (You can see it in action on my second rant-dump).
For knowledge I also use a DIY system which I briefly wrote about here.
Hello, I would like to thank you for sharing this productive blog post. I would like to share with you one place wich helped me with my nursing career development when I was in troubles. Luckily when adressed them they helped me to upgrade my career options.
Hello, I appreciate reading this blog post. Having a well-written blog needs a lot of time and resources. When I was at college I used to have one personal blog where I shared my life experience. Nevertheless, it happened so that I needed an assistant with my analysis essay, and one of my subscribers recommend me one place where I managed to buy analysis essay and everything was so great
There are lots of essay writing services available currently, I want to recommend this one. Here you can buy dissertation papers