I've lost count of how many WordPress sites I've looked at where the owner installed 4 speed plugins on top of each other hoping something would stick. One caching plugin, one minification plugin, one image optimizer, one "speed booster" thing nobody's heard of. And the site is somehow slower than before because the plugins are fighting each other.
Here's the thing about WordPress and Core Web Vitals: it's not fundamentally slow. A clean WordPress install with Twenty Twenty-Five theme will pass every CWV metric easily. The problems start when you add themes, plugins, page builders, and content without thinking about performance. Which is, you know, what everyone does.
So let's go through this piece by piece.
Why WordPress Sites Specifically Fail CWV
WordPress has a few unique problems that sites built from scratch don't have:
- Plugin bloat: Every plugin adds its own CSS and JS files. 25 plugins can mean 25 extra HTTP requests on every page load, even on pages that don't use those plugins
- Page builder overhead: Elementor, Divi, and WPBakery generate massive HTML structures and CSS files. A single Elementor page can have 2000+ DOM nodes and 200KB of CSS
- Unoptimized images: WordPress lets you upload 5MB photos straight from your phone and serves them as-is. No compression, no resize, no WebP conversion unless you install a plugin for it
- Cheap hosting: A $3/month shared hosting plan with 200 other sites on the same server. Your TTFB is already 800ms before WordPress even starts processing
- Theme feature bloat: Premium themes load Google Fonts, icon fonts, slider scripts, parallax libraries, and animation frameworks whether you use them or not
Step 1: Fix Your Hosting (If TTFB Is Over 600ms)
Before you touch anything else, load your site and check the TTFB in Chrome DevTools (Network tab > click the main document > Timing > "Waiting for server response"). If it's over 600ms, your hosting is the problem and no plugin will fix it.
Hosting Tiers for WordPress Performance
Avoid: GoDaddy shared, Bluehost basic, Hostinger shared (TTFB: 800ms-2s)
Decent: SiteGround GoGeek, A2 Turbo (TTFB: 200-400ms)
Good: Cloudways (DigitalOcean/Vultr), Kinsta, WP Engine (TTFB: 100-250ms)
Switching from a $5/month shared host to a $15/month Cloudways VPS cut TTFB from 1.2s to 180ms on a client WooCommerce site. That single change dropped LCP from 4.5s to 2.1s without touching anything else.
Step 2: Set Up Proper Caching
Caching means your server doesn't rebuild the page from scratch on every visit. The first visitor gets a freshly-built page, and everyone after gets the cached copy in milliseconds.
WP Rocket (Recommended)
WP Rocket is the most popular premium caching plugin and it handles most CWV-related optimizations in one place. Here are the important settings:
- Cache tab: Enable mobile caching, enable caching for logged-in users (if appropriate)
- File Optimization: Enable Minify CSS, Combine CSS, Minify JavaScript, Defer JavaScript
- Media: Enable LazyLoad for images AND iframes. BUT go to the "Excluded images" field and add your above-the-fold images (hero, logo) so they're NOT lazy loaded
- Preload: Enable sitemap-based preloading and enable preload links
- CDN: Connect to Cloudflare or BunnyCDN
Free Alternative: LiteSpeed Cache
If your host runs LiteSpeed server (most modern hosts do), LiteSpeed Cache is free and incredibly capable. It handles page caching, image optimization, CSS/JS minification, and CDN integration. Turn on everything in the optimization tab, exclude hero images from lazy loading, and you're 80% of the way there.
Step 3: Fix Your Images (The Biggest LCP Win)
Images are the #1 cause of slow LCP on WordPress sites. Here's the complete image fix process:
Install an Image Optimizer
Use ShortPixel, Imagify, or Smush Pro. They all do roughly the same thing: compress existing images and convert new uploads to WebP automatically.
My preference is ShortPixel because it has a generous free tier (100 images/month) and handles WebP conversion cleanly. But honestly, any of them work. Just pick one and don't install two.
Stop Lazy Loading the Hero Image
WordPress 5.5+ added native lazy loading to all images. Which is great for below-the-fold images and terrible for your hero image. The hero is your LCP element and lazy loading it adds 200-500ms to your LCP.
Fix it in your theme's functions.php:
// Remove lazy loading from the first image on every page
add_filter('wp_img_tag_add_loading_attr', function($value, $image) {
static $count = 0;
$count++;
// Skip lazy loading for the first 2 images (hero + maybe logo)
if ($count <= 2) {
return false;
}
return $value;
}, 10, 2);
Or if you use WP Rocket, just go to Media > LazyLoad > "Add excluded images" and paste the CSS class of your hero image container.
Add fetchpriority to Your Hero Image
WordPress 6.3+ automatically adds fetchpriority="high" to the first content image. But if your
theme uses a background image or a custom image tag, you might need to add it manually. Check your LCP
element in PageSpeed Insights and make sure it has fetchpriority="high".
Step 4: Clean Up CSS and JavaScript
This is where most WordPress sites have the biggest room for improvement. Your page is probably loading CSS and JS from plugins it doesn't need on that specific page.
Asset CleanUp (Free Plugin)
Asset CleanUp lets you see every CSS and JS file loading on each page and disable the ones that page doesn't need. For example:
- Contact Form 7 loads its CSS and JS on every page. Disable it everywhere except the contact page
- WooCommerce loads its scripts on blog posts. Disable WooCommerce scripts on non-shop pages
- Slider Revolution loads on every page even if only the homepage has a slider
This alone can remove 5-10 render-blocking resources from most pages.
Remove Unused Google Fonts
Many themes load 4-6 Google Font weights when you only use 2-3 of them. Go to Customize > Typography and make sure you're only loading the font weights you actually use. Each extra weight is another ~20KB download.
Step 5: Fix CLS on WordPress
WordPress CLS issues usually come from a few predictable places:
Images Without Dimensions
If your theme outputs images without width and height attributes (some older themes
do this), add them manually or use this filter:
add_filter('wp_get_attachment_image_attributes', function($attr, $attachment) {
if (empty($attr['width']) || empty($attr['height'])) {
$image = wp_get_attachment_image_src($attachment->ID, 'full');
if ($image) {
$attr['width'] = $image[1];
$attr['height'] = $image[2];
}
}
return $attr;
}, 10, 2);
Ad Containers
If you run AdSense or any other ad network, wrap your ad code in a container with min-height set
to the expected ad size. A 300x250 medium rectangle should have a container with
min-height: 250px.
Font Loading
Make sure your Google Fonts are loaded with &display=swap in the URL. Most modern WordPress
themes do this already, but check your page source for fonts.googleapis.com URLs and verify the
display parameter is there.
Step 6: Elementor and Divi Specific Fixes
Elementor
- Go to Elementor > Settings > Performance
- Enable "Improved CSS Loading" (loads CSS per widget instead of one massive file)
- Set "CSS Print Method" to "External File"
- Enable "Optimized DOM Output" if available in your version
- Avoid nesting more than 3 sections deep
- Use Elementor's built-in lazy loading for background images
Divi
- Go to Divi > Theme Options > Builder > Advanced
- Enable "Static CSS File Generation"
- Enable "Critical CSS" if available
- Minimize the use of custom CSS in individual modules
- Use Divi's Performance Options to defer JS and CSS
Step 7: WooCommerce Specific Fixes
WooCommerce sites have unique challenges because product pages load a lot of scripts for cart functionality, variations, galleries, and checkout:
- Product images: Use ShortPixel or Imagify to auto-convert product images to WebP. Set WooCommerce image sizes in Customize > WooCommerce > Product Images to match your actual display sizes, not the original upload size
- Disable cart fragments: WooCommerce runs an AJAX call on every page load to update the mini-cart. If you don't use a mini-cart, disable it with a plugin like "Disable Cart Fragments" to save a round-trip
- Lazy load product galleries: Product image galleries below the fold should be lazy loaded. But the main product image (the LCP element on product pages) should NOT be lazy loaded
The WordPress CWV Checklist
The Full WordPress Fix Checklist
1. TTFB under 600ms (upgrade hosting if needed)
2. Page caching enabled (WP Rocket, LiteSpeed Cache, or similar)
3. Images compressed and converted to WebP
4. Hero image NOT lazy loaded and has fetchpriority="high"
5. CSS and JS minified and deferred
6. Unused plugin assets removed per-page (Asset CleanUp)
7. All images have width and height attributes
8. Ad containers have min-height set
9. Google Fonts loaded with display=swap
10. CDN configured for static assets
11. No more than 1,500 DOM nodes per page
12. Page builder performance settings enabled
FAQ
Why does my WordPress site fail CWV when my hosting dashboard says it's fast?
Hosting dashboards measure server uptime and basic response, not front-end performance. Your server might respond in 200ms but if WordPress then loads 2MB of CSS, 30 JavaScript files, and a 4MB hero image, the user-facing performance is terrible. Always measure from the user's perspective with tools like PageSpeed Insights or VitalsFixer.
Do I need WP Rocket or is a free caching plugin enough?
For basic sites, a free plugin like LiteSpeed Cache or W3 Total Cache is fine. WP Rocket's advantage is that it combines caching, JS deferring, image lazy loading, and critical CSS in one place with sane default settings. If you're comfortable configuring multiple free plugins separately, you can get similar results without paying.
Will switching themes fix my Core Web Vitals?
Maybe. If your current theme loads 500KB of unused CSS and half a dozen JavaScript libraries you don't need, switching to a lighter theme (GeneratePress, Astra, Kadence) can make a huge difference. But if your images are 3MB each and you have 30 plugins, a theme switch alone won't save you.
How many plugins should a fast WordPress site have?
Quality matters more than quantity. Five well-coded plugins can be lighter than one bloated page builder. But as a rough guide, most fast WordPress sites have 15-20 active plugins. If you're above 30, start auditing. Deactivate each plugin one at a time and run PageSpeed to see which ones are actually hurting performance.
Check Your WordPress Site's Vitals
Get a detailed breakdown of your LCP, CLS, and INP scores with specific WordPress fix recommendations. Takes 30 seconds.
Analyze My WordPress Site Free →WordPress performance a mess?
Our engineers specialize in WordPress Core Web Vitals. WP Rocket config, Elementor cleanup, WooCommerce image optimization, plugin audits. 48-hour turnaround, money-back guarantee.
View Expert Fix Service →