Page speed and user experience have become increasingly important in the recent past since Google announced its plans to roll out the Core Web Vitals update in 2021.
This update is going to count in Google search ranking which should explain the rather overwhelming interest by website owners to optimize their sites before this deadline.
I’m one such owner, and in the past month I’ve been optimizing my WordPress sites with some reasonable success.
I thought I’d share my experiences optimizing WordPress which as we know, often sacrifices performance in favour of usability and features.
It’s from these merits that it gets it reputation of being “heavy” – a fair description, but one which shouldn’t necessarily condemn your site to poor performance.
NOTE: This is going to be a very long post. I’ve however structured it in a thematic way using the table of contents below which you can use to jump to the topic that interests you.
Read more: How to make money with WordPress?
Not all WordPress Sites are Created Equal
It should be noted that the recommendations I provide here are of a general nature. Not all WordPress sites are created equal, so what may work for one site may not necessarily work for another.
Unfortunately, the Core Web Vitals don’t take note of this nuance and therefore all sites are expected to meet its “standards” irrespective of design, features and amount of traffic.
Thus, an e-commerce site running WooCommerce is expected to perform just as good as a small WordPress blog.
It’s here where the issue of scale comes into play. You really need to spend money on what really counts, otherwise you risk overkilling your performance goals.
However, as a general rule of thumb we can safely surmise that the larger the site, the bigger the “optimizing budget”, both in terms of time and money.
So if you’ve a small site such as my blog the truth is that you can achieve good results on a very tight budget. For example, while not to discount its benefits, but you most certainly may not need a VPS or a dedicated server.
Some good affordable hosting might actually be more than adequate for your site’s needs. But how do you ascertain that? That’s really the question.
Finding the Root Cause Behind a Slow WordPress Site
The most consideration before you begin optimizing your site is to first identify and understand where the problem lies. Only then can you allocate your resources efficiently, be it in either resolving it completely or at least mitigating its effects.
The problem could lie in your hosting, your WordPress set-up, or both.To do this, you got a few tools at your disposal:
This is the go-to page performance analyzer not because it’s inherently the best, but merely because its powered by Google, and they happen to be the ones calling the shots.
The availability of real world data is however a hit or miss depending on the amount of traffic your site receives. You may therefore want to test your more popular pages to increase your chances of getting this data.
GTmetrix used to be powered by the open-source Yslow analyzer, but now relies on Lighthouse for testing. Results may however not equal those of PageSpeed Insights since:
- there’s a difference in the location of the test servers (PageSpeed Insights doesn’t disclose their test server locations)
- the two use different Lighthouse versions which produce slightly different scores (for instance, at the time of this writing, GTMetrix is using Lighthouse 7.4.0 while PageSpeed Insights is using version 8.0.0)
The first reason however outweighs the latter. Server location impacts performance more since the further away it’s from your users the slower it will be (that is, unless you’re using some global CDN).
As such, if your site receives traffic predominantly from one country or region, GTMetrix and other tools that allow adjusting server locations may prove more accurate for testing.
Note however that the free GTMetrix plan only supports testing the desktop version of your site and only includes a handful of test locations. You’ll need a Pro account to test the mobile version and get access to more locations.
- Chrome DevTools
You can test your site using Lighthouse straight from your browser by going to Chrome’s Developer tools and selecting the Audit tab.
This is the full suite of Lighthouse so in addition to the Performance score it gives you options to also audit Best Practices, SEO and Accessibility metrics, all of which are not included in the Pagespeed Insight report.
Make sure you’re using the latest version of Chrome for more accurate results. You can also use Chromium browser for testing if you mind using Chrome.
This is also from Google tool and likewise uses Lighthouse for auditing. Measure however gives you the full Lighthouse report similar to the one in Chrome DevTools.
This is a more advanced tool that is geared towards testing for performance as opposed to usability as it’s the case with Lighthouse. Nevertheless, it does provide the Core Web Vitals scores in its report.
As such, it may prove more useful compared to the rest of the tools here if you want a more in-depth report about your website performance.
It’s auditing has options for different test locations, variable connection speeds, mobile browsers, video previews, waterfall and multiple tests.
All these options should allow you to better pinpoint what’s actually slowing your site in addition to better simulating the experience of your traffic from various locations at different speeds.
It also includes a useful security scale that shows you how secure your website is.
This is a relatively new auditing tool from the fellows behind the WordFence security plugin. Unlike all the other tools here, this one focuses more on testing your page’s performance from various locations globally.
As such, if your site receives very diverse traffic, this one will give you a better picture of what you need to improve on.
Performance Optimization Recommendations
After you’ve conducted assessments with the above tools, you should at least have an idea what’s slowing your site down.
A good place to start with are the Top Issues that GTMetrix lists or the Opportunities and Diagnostics suggestions PageSpeed Insights provides.
I’m now going to address how to resolve or at least mitigate some common WordPress performance issues that you may have encountered based on my experiences doing the same.
1. Optimize Server Performance
A high Time to First Byte (TTFB) indicates that your server is slow to respond. No amount of page optimization will resolve this issue, however you may be able to somewhat lessen its effects by doing so.
The only long-term way of resolving this issue is getting good fast hosting. That may mean a lot of things for different people: Managed WordPress Hosting, a VPS, Cloud Hosting, Dedicated Hosting or even your good old Shared hosting.
The key thing here is in identifying a good host for your budget and your site’s needs, as more resources will not necessary equal better performance if the servers are poorly maintained and support is poor.
With that said, here are some general recommendations you should consider when choosing a good server for WordPress:
1.1 Use SSD Hosting
SSDs are much faster than the traditional HDDs.SSD hosting however costs more, as such ensure you get space that’s just adequate for your website needs. Quality over quantity is the far more cost-effective approach here.
HDD hosting costs less, and for that reason you may be attracted to it simply because it has more GBs, however, you should consider whether the extra space is worth trading off for slower performance, more so if it’s space that you’re never going to utilize.
You’d be surprised to learn that 1GB SSD space is more than adequate for some sites (e.g bronchure sites, small blogs). For instance, this blog is hosted on a 3GB SSD plan, and currently it’s using slightly over a quarter of that entire space.
1.2 HTTP/2 Enabled Servers
This is good to have if your site has many HTTP requests, which is typical of most WordPress sites.
1.3 Choose Closest Server Location
Always go for hostig that allows you to select servers that are nearest to your traffic to reduce latency. If this is not feasible, connsider using a CDN.
1.4 Use the Latest Supported PHP version
PHP is the backbone of WordPress. If you’re on a shared hosting environment, use a host that provisions the latest PHP versions (7.3 and above).
It’s not only essential for your site’s security, but its well documented that the 7.X versions handle requests faster than the old PHP versions.
1.5 Consider Web Server Used
The main web servers used by hosts include Apache, Nginx and LiteSpeed (or its open source derivative called OpenLiteSpeed.
Of these, LiteSpeed is usually reported to be the fastest. Benchmarks from its company even claim that it is 12 times faster than Nginx and 84 times faster than Apache when loading WordPress.
While I’m no Sysadmin, from an end-user’s perspective I can attest to it being very responsive as it’s what my host uses for all my sites.
It’s main selling point however is that it pairs really well with the LiteSpeed Cache WordPress plugin (LSCWP) which manages your cache and does a host of optimizations (more on this later) without needing other plugins.
Choosing a Fast Web Host
So how do you identify a web host that best meets your needs? Reviews are admittedly your best option here, but where you get them is far more important.
As a rule of thumb, user reviews based on first-hand experience are preferable to the millions of blog reviews out there. Unfortunately, a significant portion of online reviews are merely interested in getting affiliate revenue than on giving you an accurate picture.
On this point, beware of any EIG hosts who tend to feature prominently on these reviews despite having subpar performance in relation to their prices.
One place I can however recommend for sourcing user reviews and recommendations is on web hosting forums such as Reddit’s Web Hosting Subreddit.
On these kinds of platforms, you’ll get firsthand experiences that are far less susceptible to tampering due to moderation and other discerning users.
With that said, there are also some hosts that give you a money-back guarantee which essentially allows you to test run their hosting.
This is perhaps the most ideal way of going about it as you get to deploy your site onto their hosting and should you not be pleased with their performance you can always get your money back.
It’s however rare that you’ll have to do this as more often than not this indicates they’ve confidence in the quality of their product.
2. Use Lightweight Theme and Plugins
Here are some recommendations when choosing theme and plugins for your WordPress site:
2.1 Use Fast Modular Themes
A poorly coded or bloated theme is no good for performance. Always use an optimized theme that is modular. This way you can enable only the features that you need as opposed to having everything loading in the frontend.
Some good fast themes I’ve used that are modular include GeneratePress & Neve.
2.2 Use Minimal Plug-ins and Lightweight Alternatives where Possible
It’s better to use one plugin that has a lot of functionality as opposed to using many plugins each doing a separate function.
This is because most plugins that work on the frontend load their own CSS and JS which only adds up the size of your page and the number of requests.
The LiteSpeed Cache plugin (LSCWP) for example handles cache, CSS/JS optimizations, image optimization, database optimisation and CDN all under one roof. Ordinarily, one would have had to use a separate plugin for each one of these functions.
Jetpack is another good example of this as it has a lot of functions which are segmented into modules. It gets a lot of flak but my experience using it has been quite smooth.
One only needs to enable the needed modules and overall this will have a negligible impact on your performance compared to using several plugins.
2.3 Use a Lightweight Related Posts Plugin
JetPack’s related posts module deserves a special mention here as it’s very lightweight compared to its competition.
Unlike other plugins that have to do a lot of database queries on your server to generate the related posts, this module does this heavy lifting on JetPack servers which reduces the workload on your site.
2.4 Use External Services to Manage Subscriptions
Doing this will reduce the load on your site and mail server. Furthermore, sending out email subscriptions via your hosting mail server is not recommended for the simple reason that it may prove to be unreliable (marked as spam etc.).
JetPack Subscriptions is a worthy consideration if your needs are modest. For managing huge lists you can look into services such as MailPoet, MailChimp etc.
2.4 Avoid Nulled Themes and Plugins
This is not only unethical to the actual developers, but is also a significant security risk to your site. For all we know, nulled themes and plugins could be bundled with malware that can steal your site’s data, or that can use your site to commit unsavory stuff such as sending out spam.
3. Keep Requests low
PageSpeed Insights will usually recommend you keep your request counts low and transfer sizes small if detects a high number of HTTP requests.
Ideally this shouldn’t be a problem provided you’re using a HTTP/2 enabled server which allows for concurrent requests to be sent on the same connection. This allows for the resources to be downloaded faster by the browser, which in turn improves your page loading speed.
If you’re however on a HTTP/1.1 server that sends requests sequentially, keeping the requests low can significantly improve your speed.
Nevertheless, even if you’re using a HTTP/2 server, your website’s speed stands to benefit from having fewer and smaller sized requests.
This is especially true in situations where you’ve many external request as its the case for advertisements, web fonts, embeds and analytics requests. Ads are especially woeful in this regard as they’ve to load a lot of scripts and media, all of which significantly increase the number of requests.
Here are some few recommendations on reducing your number of requests:
3.1 Keep Plugins to a Minimum
Keeping this sort of plugins to a minimum will potentially reduce the number of requests. If they’re unavoidable, consider the next tip.
3.2 Remove Unused CSS/JS
Unfortunately, some plugins tend to load their resources site wide rather than on the specific post types or pages they’re needed. This could partly explain why you are getting the unused CSS/JS issue when you audit your pages in PageSpeed Insights.
A good example of this is the popular Contact Form 7 which loads its JS and CSS on all pages regardless of the fact that most people usually use it only once, typically in their contact pages.
What that means is that two redundant requests are added to all posts where there’s no form used and this needlessly increases their total page sizes. Even the developer acknowledges this limitation and provides some workarounds.
Now, Contact Form 7 is far from being an exception on this account. A lot of plugins behave similarly. Another good example of this is the popular visual builder called Elementor.
Fortunately, it’s possible to unload (dequeue) unused resources so that the requests are reduced and your page leaner. The easiest way to do this is to use an optimization plugin like Asset Cleanup.
With Asset cleanup you can unload resources on a conditional basis which reduces the likelihood of you breaking your site. If you unload a required resource some functionality may not work as intended or at all for that matter.
The conditions include site wide (i.e unloads everywhere), by post types (e.g. posts or pages only) or on a specific post or page.
Here are two examples of what you may want to unload just to give you an idea of how it works:
- You use Contact Form 7 on your contact page only: unload C7 CSS & JS on all post types except Pages, then unload on individual static pages.
- You use Elementor only on a custom post type: unload all Elementor resources on all other post types (posts, pages)
It should however be noted that while in WordPress Admin, Asset cleanup may list resources that are actually not being loaded in the front-end. So ideally, you should confirm the redundant requests by inspecting the network requests for each post type (when logged out or incognito) using the Network tab available in Chrome’s and Firefox’s Developer Tools.
3.2 Keep External Requests to a Minimum
External requests are in most cases unavoidable. This is because most of them originate from services you’ve opted to integrate into your site.
The usual suspects here include analytics services such as Google Analytics, Ad Networks like Google AdSense, Media.Net or Ezoic, web fonts like Google fonts and CDNs that host common third party scripts.
The best you can do here is to just remove services that are not an essential for your site or switch to lighter or better optimized alternatives.
For instance, if you’re only interested in knowing the amount of traffic your website gets (no user metrics), you may not need Google Analytics. A plugin (e.g. Stats if you’re already using JetPack) or you may consider using lighter and more privacy-friendly alternatives like Cloudflare Web Analytics or Plausible.
As for fonts and third party scripts, you can opt to localize them so that they’re served directly from your server.
This will however not reduce the number of requests though it’s beneficial in cases where the external server is slow, where the resource itself is not optimized (e.g a script is not minified/compressed) or when you need to further optimize it for your needs (e.g. make it inline or combine it with other scripts).
Litespeed Cache plugin has a localization feature which makes localizing popular external scripts super easy.
NOTE: You don’t need to be using Litespeed server to do optimizations with the Litespeed Cache plugin. The only thing you cannot use are the page caching options.
3.3 Disable Unneeded WordPress Features
As I said earlier, not all WordPress sites are created equal. Based on that premise, some core WordPress features may prove superfluous for some sites.
In that case, we can disable them, which should in turn reduce the number of requests and total page size.
Asset Cleanup comes in handy here as it can help you disable some of these features site-wide with just a switch of a toggle. One can also unhide core files from the assets list in order to remove the WordPress resources on a conditional basis.
Example of scenarios where you may consider disabling some core WordPress features include:
- You don’t use Gutenberg blocks (using classic editor): unload the block library (/wp-includes/css/dist/block-library/style.min.css) site wide
- You don’t use Comments on your blog or use an external service like Disqus or Facebook comments: unload the comment reply script (/wp-includes/js/comment-reply(.min).js) site wide
- You don’t embed content from other sites: Disable oEmbed (/wp-includes/js/wp-embed.min.js) site-Wide
- You don’t use Emoji on your site: remove the WordPress.org Emoji (/wp-includes/js/wp-emoji-release.min.js) site wide. The browser default Emoji will be used instead if needed.
3.4 Combine CSS / JS
Combining CSS and JS into one huge file is not absolutely necessary as its benefits are negligible if you’re using HTTP/2.
Combining JS may also cause issues, since some scripts don’t play well when combined with others.
Nevertheless, from experience I can attest to getting better scores after combining some CSS and JS. The key thing here is to test and avoid combining problematic scripts (e.g JQuery).
For instance, CSS and JS resources from the theme can be easily combined with little problems. Small CSS and JS scripts from plugins are also quite benign and I’m yet to experience issues with them.
After combining scripts, make sure to check the browser console to weed out any problematic scripts. You can then exclude them from combining in whichever plugin you’re using. Again, the Litespeed Cache plugin does both of these functions.
Now, it’s imperative that combining is done as the final step; it’s the reason I put it as the last recommendation in this section as we don’t want to combine unoptimized or worse, unnecessary resources.
3.4.1 Combined CSS/JS files taking too much space?
Thorough tests should be conducted if you opt to combine external and inline CSS/JS resources. This is because a small difference in the CSS/JS generated for each page (e.g a query string), will mean a combined CSS/JS file will be generated for each post or page.
This is not a big issue for site with a few posts or pages however for larger sites with hundreds to thousands of posts this will create a lot of combined CSS/JS files which will take up a lot of hosting space not to mention overwork the server every time a purge is done.
If you run into this situation, narrow down the unique code in the pages by comparing two combined CSS/JS file using a tool like Diff Checker then exclude the specific CSS/JS in your optimization plugin’s combine settings.
Based on my experience, I can confirm this issue seems to be caused mostly by inline JS from particular plugins.
Case in point is my favorite anti-spam plugin Antispam Bee that generates a unique identifier for all comment sections which means that a combined JS is generated for each posts should its inline script not be excluded.
4. Optimize HTML/CSS/JS Delivery
After you’ve only the necessary CSS/JS loading on your pages, the next thing to do is optimize how they’re delivered and processed by the browser.
PageSpeed Insights and the other performance tools really come in handy here as they clearly point out specific issues that you need to fix in this regard. The common ones that pop up are:
- Unminified Resources
- Render blocking JS/CSS
- Large layout shifts
Here are some ways to fix these issues:
4.1 Minify CSS/JS/HTML
Minifying compresses these files so that their transfer sizes are reduced. This works by removing spaces and comments which are not essential.
You can minify your HTML, CSS and JS files on-site using various plugins incuding such Litespeed Cache, Asset Clean up, WP Rocket etc. or you can do it on a CDN such as Cloudflare.
Ideally, you should only use one plugin to do the minifying. Likewise, if you decide to do minification on a CDN, don’t do use a plugin for the same. You can test between the two and see which produces the smaller sizes.
Some JS files that are not critical to the rendering of the above-fold content are sometimes loaded before the HTML. This slows down the painting of the above fold elements which gives you poor FCP and LCP scores.
4.3 Load CSS Asynchronously
Just like the JS in the previous point, some CSS files that are not critical may slow down the painting of your page. You can resolve this issue by minifying the CSS and loading it asynchronously.
What this does, is that it loads the CSS at the same time with the HTML. Ordinarily, the browser will load the CSS in the header before proceeding with the rest of the HTML in the body.
As a result, your page will load faster, however you may briefly see unstyled HTML content as the page initially loads. This brings us to the next point.
4.4 Inline Critical CSS
The phenomena I just described is usually referred to as Flash of Unstyled Content (FOUC).
Fortunately, we can fix it by including the CSS that’s needed for the above the fold content (that is, the critical CSS) within the HTML itself. This is what we mean when we say to inline the critical CSS.
To do this, you need to generate critical CSS (CCSS) for your pages. However, since different post types tend to be styled differently, each may require a separate CCSS file.
In some cases, some pages of the same post type are also different in which case a separate CCSS is needed for each post.
Litespeed Cache is the one plugin that I’m aware of that handles all this automatically for you. The plugin generates the CCSS on their QUIC cloud servers for each post type (or individual posts if defined) and sends them back to your site where it automatically inlines them when a page is loaded.
This will significantly improve your page speed, however I’ll be quick to point out that CCSS may not be necessary for all sites.
For instance, I don’t need it for this blog as I have no issues with render blocking CSS. However, on a different site I had this issue pop up due to the design of its custom post type which I managed to resolve by generating CCSS for it.
4.5 Fix Large Layout Shifts
The Cumulative Layout Shift (CLS) indicates whether your page has elements that shift around after they’ve been loaded. CLS is part of the Core Web Vitals and a score of less than 0.1 is the minimum.
The CLS score is one of the more problematic ones to resolve. The reason for this is that I’ve noticed some themes are designed without taking this into account, which ultimately means that there’s very little you can do until the theme developer fixes the issue.
Nevertheless, there are those that are within your control to fix. They include:
4.5.1 CLS from Advertisements
Ads are a huge culprit for CLS as they push the content down to create room to display on.
For AdSense, you can fix this by using fixed size ad units and reserving space for them accordingly. On the other hand if you’re using responsive ad units, you can customize the ad code by specifying the shape (rectangle, horizontal) and the maximum height and then reserving space for them accordingly.
It’s also worth noting that the CLS impact from Ads is highest when they’re placed high above the fold. Minimizing the number of ads in this position by shifting them lower may therefore also help in resolving this issue.
4.5.2 CLS from Images
WordPress by default now lazy load images which may cause CLS issue for image. This is especially true for images that are above the fold such as logos.
To prevent this, you can define the dimensions for the logo and/or exclude the logo from lazy loading (ideally, it should be very small).
For other images, you can create responsive image placeholders using a plugin like Litespeed Cache. This will reduce layout shifts as the placeholder will have reserved space for the images before it gets loaded.
4.5.3 CLS from Embeds and Iframes
Just like Ads, you can reduce the layout shifts caused by embeds by reserving spaces for them. Additionally, you can also lazy load iframes (WordPress now supports this) to reduce the number of requests when the page is loaded initially.
4.5.4 CLS from Fonts
PageSpeed Insights usually recommends that we ensure text is visible during web font load. To do this, it suggests we set the font-display attribute to Swap which tells the browser to uses a fallback font (a system font like Arial/Roboto) to show the text while the web font is downloaded.
The problem with this however is that it causes a flash of unstyled text (FOUT) as the font is being swapped (after all, the fonts while the same size are “shaped” differently) which in turn causes some layout shifts. I know, it’s ironical that a supposed fix brings about another issue.
Anyway, to minimize this particular effect web.dev suggests we preload our web fonts which I’ll cover in the next section.
5. Optimize Fonts
The performance overhead from fonts comes exclusively from downloading external fonts. As such, the biggest performance optimization one can achieve in this regard is in evaluating the need for an external font in the first place.
Here are some recommendations to optimize font display and delivery.
5.1 Consider using System Fonts
If your website’s design demands the use of a font style that cannot be replicated by a system font, then by all means use a web font.
On the other hand, if readability is your only concern, a system font will suffice in most cases. Usually all a system font (e.g. Arial, Helvetica) needs is some minor adjustment in terms of font size, weight and line height to be the winning candidate.
Now, I’m not suggesting we all use system fonts, as such a thing would render the web rather bland. This recommendation is only for those who are finding web fonts are significantly impacting their page speed.
Besides, not all web fonts can be replaced by system ones which is the case for icon fonts like Font Awesome that load just the same way as normal fonts.
5.2 Use Swap font-display
If you’re getting the recommendation to ensure text remains visible during web font load, that means the text in your page remains invisible until the web font is downloaded and rendered. This phenomenon is usually called Flash of Invisble Text (FOIT).
To fix this, consider using the Swap font-display property which instructs the browser to fallback to a system font (e,g Arial, Helvetica, Roboto) while the web font is being downloaded. Once it’s done downloading, the web font is swapped in to replace the system font. You can do this automatically using various optimization plugins.
Unfortunately using the Swap property may inadvertently cause the aforementioned FOUT. At this juncture it would almost seem one is forced to weigh which between FOUT and FOIT is the lesser evil. Fortunately there is one last solution for us: preloading fonts.
5.3 Preload External Fonts
Normally, the font-face declaration that specifies the web font to be used is located in a CSS file, which means the browser has to process it before it can show any text on the page.
In this brief waiting period, users may get a FOIT before the text can be displayed for elements that are above the fold (e.g a text logo in the header) which in turn may cause some layout shifts once the font is downloaded and rendered.
A way out from this situation while minimizing the risk of FOUT that may be caused by the Swap font-display property is to preload the font.
Preloading a webfont instructs the browser to start downloading a font before its discovered for rendering. What this means is that by the time the browser is processing the CSS file the font will already have been fetched thereby reducing FOIT/FOUT.
You can use plugins like Asset Cleanup or WP Rocket to easily preload your font files. You have two ways of preloading: you can preload the actual font files (woff) from your server or the font’s CSS from a CDN like Google Fonts. Asset Cleanup can do both, I’m not sure about WP Rocket.
For the former solution, you can download the web fonts on your server using a plugin like OMGF that allows you to host Google Fonts locally.
5.3.1 Only Preload Necessary Fonts
Preloading adds extra requests which may impact performance. Therefore, you should ideally only preload critical fonts that are used in rendering the above the fold content such as titles, logos and body text.
For most sites, this will usually amount to either one or two fonts. Other fonts below the fold can pretty much wait.
More reading: https://web.dev/optimize-webfont-loading/
6. Optimize Images
Images are usually the largest elements that have to be downloaded when loading most web pages. As such, it’s essential that image are optimized in size to prevent them from heavily impacting load time and usability. Here are some recommendations on how to do this.
6.1 Always Compress Images before Uploading
If possible always compress your images before uploading them into WordPress. These not only saves precious load time but also server space.
There are plenty of online and offline image optimization tools you can use for this task. For offline I personally recommend RIOT which I’ve been using for years now to batch optimize mostly JPGs though it does also support PNGs and GIFs.
For PNG however, I recommend using pngquant which is much faster and outputs better quality images.
On the other hand, if you typically upload many images and have no time to do manual optimization, you may opt instead for an automated service from plugins such as LiteSpeed Cache and Smush.
Personally, I do both as it’s my experience from using LiteSpeed’s image optimization service that not all images get reduced in size. This way my manually optimized provides a fallback should the service be unable to optimize it further down.
Note: If it’s essential that the quality of the images is maintained (e.g. for a gallery), then it’s better to focus more on how those images are displayed.
A good strategy here is to only display optimized thumbnails when the page is loaded, and only provide the full resolution image at the user’s discretion.
6.2 Use WebP replacement (for supported browsers)
The WebP image format provides the smallest image sizes in relation to quality. It’s only undoing however is that it’s not supported by older browsers. Other than that it’s a great substitute to JPGs and PNGs and its something worth considering for media heavy sites.
The compatibility issue with unsupported browsers can however be easily remedied by using fallbacks in traditional formats.
To accomplish this, ideally you shouldn’t upload the images in WebP instead you want an image optimization service to handle both the optimization of images in traditional formats to WebP and the subsequent replacement.
This is for instance how Litespeed Cache plugin does its WebP replacement: it pushes the uploaded images to their servers and optimizes them in the original format as well as creating a WebP format if this option is enabled.
Whichever of the images is the lowest is then used in the frontend. The original images can also optionally be backed up.
In most cases the WebP wins however I’ve seen instances where my pngquant optimized PNGs have smaller sizes (screenshots mainly). In any case, should the WebP be used, a fallback to the other format is included for incompatible browsers.
6.3 Lazy Load Images
WordPress now lazy loads images by default which should speed up load times significantly. If you however don’t like its global implementation you may opt for an alternative like LSWCP which allows you to fine-tune the lazy loading.
For instance, you may want to set lazy load exceptions for important images that are above the fold e.g logos. You may also want to generate placeholders for lazy loaded images to avoid text shifting as the image loads.
6.4 Disable Unnecessary Image Sizes
As you know, WordPress automatically generates some additional image sizes when they get uploaded. It uses this images in different places in your dashboard (e.g thumbnails) or template when it’s not ideal to load the full resolution image size.
This works well for most WordPress sites however as I said not all sites are created equally. Some sites or templates may have no use for this additional sizes likely because the design is explicitly set to use some specific image sizes.
In this situation it’s preferable to disable the unwanted image sizes not only to avoid them taking up server space, but also the server resources needed for generating them.
If not for that, then use it as a precaution to keep WordPress from loading image sizes you don’t want, which brings us to the more potentially pernicious issue that srcset creates.
6.5 Disable srcset to Explicitly Define Images
srcset is an attribute that specifies available image sizes for a browser to pick the best one according to the device’s resolution. It’s been available by default since WordPress 4.4.
This attribute is useful for responsive sites as it allows different image size to be used while delivering the best possible quality.
For instance, a full size image will only be displayed in large displays while mobile devices will display the medium or large sizes. This save bandwidth and speeds up page load times in mobile devices.
Again, for most sites this is a perfectly sound approach. The problem however arises when a particular image size has been specified and because of srcset the browser overrides the image by choosing what it finds best for the current resolution.
This behavior becomes more apparent when dealing with large resolution images.
Let me give you a personal example for better understanding: there’s a site I was developing where I needed a particular image size to be loaded as a background image.
The size I had chosen in this particular case was the default large size (1024×1024) which reduced my high resolution images (1280×1920) into 683×1024. I expected this to be used on all devices regardless of their resolution.
Here’s what happened instead: on a desktop with a resolution of 1280×1024, the 683×1024 image was loaded by Firefox. However, on an Android device with a resolution of 720×1280, a larger image with dimensions of 1024×1536 was being loaded by Chrome Mobile.
This peculiar image was actually from srcset and what I hadn’t factored in were the extra images sizes that WordPress generates quietly with no option to disable them. They include:
- Medium Large – 768px
- 2x Medium Large – 1536px
- 2x Large – 2048px
- Scaled – 2560px
In this particular case, Chrome chose the medium large (1024×1536) since the resolution of 683×1024 was lower than what the device was capable of. However, this image was much larger in size and consequently slowed down the page load times on mobile.
This case illustrates perfectly the downside of srcset. The rule of thumb therefore is if you must use a specific image size for your design, make sure to disable the other sizes you’re not using.
You have two ways of going about this: you can either disable WordPress from outputting the srcet attribute entirely, or you can disable the extra image sizes and keep only those you need.
To disable srcet you can use the Disable Responsive Images Complete plugin by Jeff Starr. To disable the extra images sizes you can use the Disable Media Sizes plugin by the same developer or the snippets he provides in his blog post.
I also recommend reading the post itself as well as this one on srcset as he gets deeper into what I’ve glossed over here.
7. Optimize Videos
A good fast server is crucial if you’re serving video content from your WordPress site. This is however not practical in most cases.
A far better approach is to instead embed video from streaming sites that already have powerful servers and global CDNs.
Embedding video not only saves plenty of server space but also allows one to provide video content in different qualities that adapt automatically to the users device and bandwidth – two things that contribute immensely to a good user experience when streaming.
The other benefits are that embedding allows one to further optimize how it works by:
7.1 Lazy Load Video Embeds
Like images, you can lazy load video embeds by simply lazy loading iframes. Doing this will postpone the requests needed to load the embed until when the video comes into the view, hence reducing the number of initial requests.
7.2 Load Embeds on Demand
Embedding videos does not always mean that all users are going to watch them. In such cases, all the additional requests needed to load the embed prove wasteful whilst adding to the page size.
To avoid this scenario, the video embedding can be deferred to the user using an on-demand approach. This is usually accomplished by using an optimized image of the video (e.g a thumbnail) that has a play button which triggers a script to load the embed when clicked.
A YouTube video embed is for instance very heavy, however using this approach its size can be reduced significantly. You can do this on WordPress manually using a script and some CSS as shown on Digital Inspiration.
Alternatively, if you use Elementor you can create an on-demand embed very easily by choosing the Image Overlay option. You only have to specify the video thumbnail, and Elementor will do the rest.
Even better, this works not just with YouTube embeds but also Dailymotion, Vimeo and Self-hosted videos. For an example of this, check my homepage’s YouTube channel section.
8. Optimize Ads Delivery
The internet runs on advertisements and this blog is no exception. These ads present a unique challenge as they’re served by third parties from external servers. Consequently, there’s little one can do with regards to their optimization beyond controlling how and where on the page they get served.
Whatever the course action, remember that it must be in accordance with the ad networks’ policy otherwise you may risk losing the monetization.
8.1 Serve Fewer Ads
The lesser the number of ads, the less the number of requests and the smaller the size of page. This of course assumes that the ads in question are loaded with the page. Different ad network work differently, but most behave this way.
Displaying fewer ads in this regard is perhaps more essential for above the fold content. Nevertheless, I realize this may be problematic for most publishers as these tend to perform better overall, in which case displaying smaller sized ads is the next best option.
8.2 Use Lazy Loaded Ads
Some ad networks lazy load the ads in the same way images are lazy loaded on WordPress. In this set-up, the ads only start loading when they come into view. As a result, all ads below the fold get deferred and don’t impact the initial page load due to fewer number of requests.
8.3 Reserve Space for Ads to Minimize CLS
Typically, ads always load after the other HTML content on the page. This means they will push this content down if no space is reserved for them. Consequently, you may get content layout shift (CLS) warnings as explained earlier in the article.
A quick simple solution for this is to reserve space for the ads using CSS.
Ad Inserter is a good plugin that can help you do this without tinkering with code – you just have to specify the height for the ad code in its settings, e.g. for a 300×250 banner you can set its block to a height of 250px with a margin of 10px above and below for clearance.
It’s important that caching comes as the final step as preferably you want only the optimized assets to be cached. On WordPress you can activate caching by simply using one of the many caching plugins available.
As with most plugins, some are entirely free while others are either premium with limited free versions. Some popular choices include:
- LiteSpeed Cache WordPress Plugin – an all-in-one free cache and optimization plugin that is designed for sites running on LiteSpeed Servers. The optimization functions however work with other kinds of servers such as Apache and NGINX.
- WP Fastest Cache – Freemium
- WP Rocket – Premium
Ideally, you want to use a caching plugin which does also optimization (minification of HTML/JS/CSS, critical CSS generation, CSS/JS Combine etc.) as this makes it easier to manage their cache.
A good example of this which you may find you often have to do is purging old cache for images and CSS/JS when you make stylistic or functional changes to your site.
If this is not possible, make sure that whatever plugins you choose to use don’t have the same functions enabled.
So for instance you can use one plugin just for caching and the other for optimization. I have done this personally with good results on an Apache server by using WP Fastest Cache for caching and Litespeed Cache plugin for the optimization of CSS/JS, images and fonts.
Some other things you may want to consider with regards to caching include:
9.1 Enable Object Cache
Object cache is used for caching results of database queries. Implementing object cache can therefore significantly improve your site’s speed, especially if it happens that your site makes frequent database queries.
What happens with object cache is that a visitor triggers a database query and its result is cached for a specified period (e.g 360 seconds).
Subsequent visitors who now trigger the same query within this period are served the cached result which skips the time-consuming database query, hence faster page load times for them.
The downside to Object Cache however is that its implementation may be completely outside your reach. This is because it needs to be implemented at the server level by your host using an Object Cache system such as Redis, Memcached or LSMCD.
Some hosts do have one of these systems implemented but this usually rare. You may have to check with your hosts or request them. Once it’s implemented you can connect it to a plugin like Litespeed Cache to manage the Object Cache in WordPress.
9.2 Enable Browser Cache
Most cache plugins include this option by default. Browser cache allows you to cache static content in the browser cache folder so that repeater users don’t have to re-download these assets on every visit.
As you can imagine, speed-wise this is incredibly useful for sites that get a lot of repeat direct traffic such as those with huge followings.
Now, if you do enable browser cache, the one thing you can’t overlook is the Time to Live (TTL) time i.e the expiry period of the cache.
Sites that don’t get frequent updates (i.e not content, but static content like CSS, JS, Images) can get away with longer TTL times such as 1 year (31536000 seconds). For sites with frequent updates, a minimum TTL of 1 week is usually recommended.
10. Cloudflare Integration
You can make use of Cloudflare to secure and speed up your WordPress site with their CDN and security features. The free plan is sufficient for most sites, however if you’re running a bigger site its worth considering their paid plans with extra features.
As a CDN, their Edge servers that can be found across strategic global locations will cache your sites static content and thereby speed up your site for users that are far away from your host’s server location.
With that said, Cloudflare’s free plan does not cache your site’s HTML so using it as a CDN will not necessarily speed up your site if your site is slow either due to your WordPress setup (themes etc) or an origin server with slow response times (high TTFB times).
In such cases, consider resolving the root causes of the problem before on-boarding your site on Cloudflare. Otherwise, it will act merely as a bandage solution that may slightly improve your performance if not degrade it further.
The latter point however is something you should consider regardless of your current performance. Cloudlfare speeds up most sites, but it’s also known to slow some others depending on the features you’ve opted to use.
As such, testing is of key importance since what works for one site may not necessarily work for another on a completely different server.
Most of the conflicts however usually stem from their security features, such as issues with falsely detecting WordPress cron jobs as bot traffic and problems with Auto-renewal of SSL certificates in the origin server.
Here are some Cloudlfare performance features you can test with your WordPress site:
10.1 Enable Brotli Compression
Brotli compression reduces the size of your site’s static content which helps speed up load times. You may however find that your caching plugin has an option for Gzip compression which is the older more established format used across the web.
So which one should you use? Go for Brotli as it has a better compression ratio that produces up to 25% smaller sized files compared to GZip. In any case, Brotli is widely supported by all major browsers.
You can activate Brotli in Cloudflare’s Speed app under the Optimization settings.
10.2 Auto Minify HTML/CSS/JS
You can find out the size of the CSS, JS and HTML files by going to the Network tab in your Browser’s Developer Tools then loading a page. Remember to purge the cache before each test.
10.3 Rocket Loader
You can however also just defer JS on WordPress using an optimization plugin as we discussed earlier. Don’t use both, otherwise you may run into issues.
My experience with Rocket Loader is usually hit or miss. I’ve seen it slightly improve the load times of some pages as well as slightly slow down some others when compared to LiteSpeed’s JS deferring option.
Regardless, I still prefer the onsite option, as it at least allows one to set exceptions. Rocket Loader offer’s no configurable options, which means if you run into issues using it, the only solution is to turn it off.
Railgun is used for caching dynamic content that changes frequently, which happens to be the norm for WordPress sites. To use it, however, your host needs to install a software on the server.
It seems some hosts have it installed but they don’t advertise this fact. At least that was the case for my host who had it installed for the server this site was on once upon a time.
I had no issues using Railgun until the time when I changed servers and started experiencing intermittent 524 errors.
The cause for this turned out to be Railgun which was still enabled in Cloudlfare but the new server didn’t support it. So always make sure to deactivate Railgun whenever changing servers.
10.5 Cache HTML
Cloudflare doesn’t cache HTML by default as this falls under the category of dynamic content. They however provide a paid product for WordPress sites called Automatic Platform Optimization (APO) which makes this possible.
With this plugin, the entire WordPress is cached and served from their Edge servers which significantly improves page load times, specifically the Time to First Byte time (TTFB) metric.
This admittedly gets around issues of slow server response times however with a monthly subscription of $5 monthly for APO, some may argue that migrating to a faster hosting is a far more cost-effective if not the only sustainable solution.
For those that can’t afford APO or the Pro plan, another workaround exists that makes use of the Cache Everything page rule or Cloudflare workers.
Implementing this is a little complicated, but thankfully there are two plugins that can help you in setting this up. One is WP Cloudflare Super Page Cache that is still being maintained, while the other is Cloudflare Page Cache which hasn’t been updated for a while now.
I’ve used the latter on one of my sites and can confirm that the TTFB did indeed improve by using the worker. The methodology is actually explained on Cloudflare’s blog, so there’s nothing shady about implementing HTML cache this way.
I hope you find this article useful in optimizing your WordPress sites for your users. A lot of time and research went into compiling this information, however it’s possible that I may have overlooked an important topic or made a mistake somewhere. As such, your corrections and suggestions are much welcomed to improve this article.