← Back to Home

The Smallest Fix Set to Pass WordPress Core Web Vitals

WordPressCore Web VitalsLCPINPCLSSpeculation Rules APIPerfmattersperformance

Disclosure: This post includes one affiliate link (Perfmatters) — signing up through it gives you a first-year discount. It does not bias my review; I provide both a "no paid plugin" path and a "use a paid plugin" path below, you pick.

Why Fix Core Web Vitals Now

Google officially replaced FID with INP (Interaction to Next Paint) in March 2024. According to corewebvitals.io's CrUX-powered Technology Report from late 2025, only about 44% of WordPress sites pass all three Core Web Vitals on mobile — meaning more than half of WordPress sites fail Google's "good user experience" bar.

The "Good" thresholds (based on the 75th percentile of real-user data):

For real users, LCP is "how long until I see something," INP is "how snappy does it feel when I click," and CLS is "does content jump around while I'm trying to read it."

Diagnose First: Use PageSpeed Insights for Real Data

Don't guess. Open https://pagespeed.web.dev/, enter your URL, and run both Mobile and Desktop. Focus on three blocks:

1. "Discover what your real users are experiencing" — This is CrUX 28-day rolling real-user data. If all three are green here, real users are already happy and you're optimizing beyond the threshold.

2. "Diagnose performance issues" — This is Lighthouse's lab simulation. It tells you exactly which element is hurting LCP, which JS is blocking INP, which image is missing dimensions and causing CLS.

3. The "Audits" list — Sort by the red and orange items, then group by "fix cost":

Trivial cost (almost free):

Medium cost (config changes):

High cost (likely requires code changes):

The "smallest fix set" below covers the first two groups only, no PHP theme code touched, suitable for 90% of WordPress sites.

Four Most Common LCP Root Causes

Root 1: Hero image is not preloaded, browser discovers it too late

Symptom: PageSpeed shows "LCP element: " with "LCP image was not preloaded."

Fix: Add a preload hint in functions.php or your theme's header.php inside .

fetchpriority="high" is the key — it tells the browser "this image beats everything else." If your hero is the WordPress featured image, you can inject it dynamically with a theme hook:

add_action('wp_head', function() {
    if (is_singular() && has_post_thumbnail()) {
        $img = wp_get_attachment_image_src(get_post_thumbnail_id(), 'full');
        if ($img && $img[0]) {
            echo '';
        }
    }
});

Don't over-preload. Only preload the LCP element image. Preloading 5 images = saturating bandwidth and slowing down first paint.

Root 2: Hero image is PNG/JPG, not WebP/AVIF

Symptom: PageSpeed flags "Serve images in next-gen formats."

Fix: Use ShortPixel, Imagify, or WordPress's built-in converter (5.8+). WebP is 25-35% smaller than JPG; AVIF is 40-50% smaller. My workflow: upload original → Imagify auto-converts to WebP at 80% quality → frontend uses element to fall back by browser support.

Root 3: Responsive images missing srcset

Symptom: Mobile loads a 1920px desktop image, wasting bandwidth.

Fix: WordPress 4.4+ automatically adds srcset to images in the Media Library. **Check whether your theme actually outputs the srcset attribute** — many custom themes strip it for "image rendering control." Restore it via functions.php:

add_filter('wp_calculate_image_srcset', '__return_true');

Or use Perfmatters's "Remove Unused Image Sizes" combined with "Responsive Images" option.

Root 4: Render-blocking CSS synchronously loaded in

Symptom: PageSpeed flags "Eliminate render-blocking resources"; CSS files are synchronously loaded in .

Fix: Move non-critical CSS (comment form styles, contact form styles, footer styles) to the bottom of and load asynchronously.

The fastest path: Perfmatters's "CSS" tab, check "Remove Unused CSS" (it generates critical CSS from Chrome Coverage data) and defers the rest. Or Autoptimize's "aggregate + async" feature.

Three Most Common INP Root Causes

INP's biggest culprit is long main-thread JavaScript tasks. PageSpeed's report names the exact file blocking how many milliseconds.

Root 1: Third-party scripts synchronously loaded in

Symptom: Google Analytics, Facebook Pixel, Hotjar, and ad scripts all synchronously load in , each blocking the main thread 50-200ms.

Fix: Add async or defer attributes. async runs as soon as downloaded (order not guaranteed); defer runs after HTML parsing (order preserved). **For INP, defer is usually better** — it yields the main thread to first paint.

Batch-defer in functions.php:

add_filter('script_loader_tag', function($tag, $handle) {
    if (is_admin()) return $tag;
    $scripts_to_defer = ['ga', 'gtag', 'fbevents', 'hotjar'];
    foreach ($scripts_to_defer as $s) {
        if (strpos($handle, $s) !== false) {
            return str_replace(' src', ' defer src', $tag);
        }
    }
    return $tag;
}, 10, 2);

Root 2: Theme or page builder ships bloated JS

Elementor, Divi, and Avada load 200-500KB of JS on every page even when you don't use their widgets.

Fix, ordered by recommendation:

Root 3: WordPress 6.8+ Speculation Rules API not enabled

WordPress 6.8 (released April 2025) integrated Chrome's Speculation Rules API into core, enabled by default in prefetch mode — the browser prefetches the next page's HTML/data when the user hovers a link. When the user actually clicks, the target page is nearly instant.

eagerness: moderate is the key — the browser only prerenders after the user has hovered for 200ms, so it doesn't waste resources during fast scrolling. eagerness: conservative (prerender on click) is more resource-friendly but feels less instant.

Note: Speculation Rules API only supports Chromium (Chrome 109+, Edge 109+, Opera 95+). Firefox and Safari don't support it yet. If 70%+ of your traffic is Chrome, this API can improve LCP and INP simultaneously because "the next page is already in memory."

Three Most Common CLS Root Causes

CLS is fundamentally "page elements load late and push the content above them down."

Root 1: Images/videos/iframes missing width/height

Symptom: Before the image loads, the browser doesn't know its size; once it loads, it suddenly pushes content below it down.

Fix: In the HTML5 era, add width and height attributes to every (CSS width/height don't count — it must be HTML attributes):

...

WordPress-uploads output width/height by default, but check whether your theme outputs them — some "lazy load" plugins strip them.

Root 2: Web fonts cause FOIT/FOUT

Symptom: Browser first renders text in a fallback font, then swaps to the Web font when it downloads; line height changes, pushing content down.

Fix: Use font-display: optional or font-display: swap plus size-adjust:

@font-face {
  font-family: 'Inter';
  src: url('inter.woff2') format('woff2');
  font-display: swap;
  size-adjust: 100%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}

size-adjust and the override properties are the 2026 best practice — they make the fallback font **visually as close as possible** to the Web font, so the swap doesn't shift content.

Root 3: Ad slots and embeds without reserved space

Symptom: Ad container is empty (height 0); ad loads and suddenly pushes content down.

Fix: Hardcode height on the ad container:

Speed Up "Next Click" Too: Speculation Rules Production Config

A full "medium-aggressive" Speculation Rules config (paste into theme header.php or inject from child theme's functions.php):

This config:

30-Minute Minimum Fix Checklist

Sorted by cost, 5-10 minutes each, complete in 30 minutes:

1. Switch from a page builder theme (if you're on Elementor/Divi/Avada) — single biggest gain.

2. Convert images to WebP (use ShortPixel/Imagify to batch process Media Library) — one-time, permanent benefit.

3. Add Speculation Rules script (paste code above) — one JS line, cross-page navigation feels instant.

4. Defer third-party scripts (GA/Pixel/Hotjar) — 5 lines of PHP.

5. Add size-adjust to web fonts (per CSS above) — 10 lines of CSS.

6. Audit image width/height attributes (check theme output) — may require theme edit.

7. Reserve space for ad slots (hardcode height) — 3 minutes.

8. Enable Perfmatters Remove Unused CSS + Script Manager (paid plugin, one-time config) — 1 hour but largest single gain.

Validation

After changes, do two things:

1. Wait 30 days before re-checking CrUX — PageSpeed Insights' "Real Users" tab is a 28-day rolling average. You won't see effects immediately. Give Google time to collect new data.

2. Check Search Console → Experience → Core Web Vitals — here you see Google bucket each URL into "Good / Needs Improvement / Poor." Tackle the "Poor" list one by one.

Cost of This Set

If you want Perfmatters to save config time, 👉 Check it on Perfmatters.io (affiliate link) — first-year discount applies.

Related Reading

Together, these three pieces (back-end cache + database + front-end Core Web Vitals) complete the "front-to-back loop" of WordPress performance optimization.

📌 This article was AI-assisted generated and human-reviewed | TechPassive — An AI-driven content testing site focused on real tool reviews

🔗 Recommended Tools

These are carefully selected tools. Using our affiliate links supports us to keep producing quality content:

☁️ DigitalOcean Cloud ⚡ Vultr VPS 📚 WordPress Books 🔍 WordPress SEO Books 🌐 Web Hosting Books 🐳 Docker Books 🐧 Linux Books 🐍 Python Books 💰 Affiliate Marketing 💵 Passive Income Books 🖥️ Server Books ☁️ Cloud Computing Books 🚀 DevOps Books ⭐ MiniMax Token Plan 🔍 Cloud Search
← Back to Home