Core Web Vitals for WordPress: The 2026 Playbook

Core Web Vitals targets keep moving and the advice keeps shifting with them. INP replaced FID. LCP got stricter on mobile. CLS became less forgiving. Here is the 2026 playbook for WordPress sites, ordered by what actually moves the metric, not by what makes Lighthouse green.

LCP — the one most people get wrong

Largest Contentful Paint is almost always an image. The fix is rarely “compress harder”. The fix is to deliver the right image at the right size at the right priority.

  • Add fetchpriority="high" on the hero image. This single attribute frequently shaves 400-800ms off LCP on mobile.
  • Serve responsive variants. The default WordPress srcset is good; make sure you are not bypassing it with a custom Elementor or page-builder image widget that hard-codes a URL.
  • Preload the hero image in <head> if it lives below a JS-loaded section.

INP — the new boss

Interaction to Next Paint replaced First Input Delay because FID was too easy. INP is harder. It catches the slow handler on the second tap, the third menu open, the long task during interaction. On WordPress sites the usual offenders are:

  • Page-builder plugins running JS on every click (not just the relevant clicks)
  • Third-party chat widgets and analytics SDKs queuing up long tasks during interaction
  • Heavy synchronous theme JS waiting on full DOM ready

The single biggest INP win is deferring the chat widget and any “session replay” analytics to requestIdleCallback or a 3-second timer after first interaction. Most users do not need them in the first paint window.

CLS — invisible until it is not

Cumulative Layout Shift on WordPress is usually three things:

  • Web-font loading without font-display: optional or matched fallback metrics
  • Ads or embeds without a reserved aspect-ratio container
  • Above-the-fold image without explicit dimensions in the markup

All three are fixable in CSS or a small theme function. None require a plugin.

What to ignore

  • Lighthouse “unused JavaScript” warnings for theme files under 30KB. Not worth the engineering time.
  • “Reduce render-blocking resources” for inline critical CSS that is already under 8KB. Same.
  • Aggressive lazy-loading of above-the-fold images. This hurts LCP. Lazy-load only what is below the fold.

Order of work

If you only have one afternoon: fix LCP with fetchpriority and a preload. If you have a second: defer the chat widget. If you have a third: reserve aspect ratios for embeds and ads. That covers 80 percent of the gains on a typical WordPress site without breaking anything.

Database Bloat in WordPress: How to Find It, How to Kill It

If your WordPress site’s time-to-first-byte has crept up over the past year and nothing in the front-end explains it, the cause is usually autoloaded options. The wp_options table grows quietly until one day every page request is hauling 2MB of data into memory before WordPress can render a thing. Here is how to find that bloat and safely remove it.

Why autoload matters

Every WordPress request loads all options where autoload = 'yes' into memory. That set should be a few hundred KB on a healthy site. On a neglected site it can grow to tens of MB — old plugin transients that did not clean up, abandoned plugin settings, error logs stuffed into an option row.

How to measure

Run this in wp-cli or phpMyAdmin:

SELECT
  SUM(LENGTH(option_value)) / 1024 / 1024 AS autoload_mb,
  COUNT(*) AS rows
FROM wp_options
WHERE autoload = 'yes';

Anything over 1MB is worth looking at. Anything over 5MB is hurting TTFB. We have seen 40MB on a five-year-old site.

Find the worst offenders

SELECT option_name, LENGTH(option_value) AS size
FROM wp_options
WHERE autoload = 'yes'
ORDER BY size DESC
LIMIT 30;

The top of that list almost always shows three categories:

  • Transients that should not have been autoloaded
  • Plugin “stats” or “history” rows from plugins that no longer exist
  • Cache rows from defunct cache plugins

How to remove safely

  1. Back up first. Always.
  2. Identify orphans. Options whose owning plugin is no longer installed are safe to delete. The option-name prefix usually identifies the plugin.
  3. For options whose plugin is still installed, set autoload = 'no' instead of deleting. The plugin can still read them on demand; they just do not load on every request.
  4. Run wp transient delete --all to clear the transient cruft.

Example impact

On a site with 18MB of autoloaded options, the cleanup dropped TTFB from 1.4s to 480ms — no other changes. The autoload table went from 18MB to 380KB. Almost all the savings came from one defunct backup plugin’s history table left over from a 2019 install.

What to do this afternoon

Run the first query above. If your autoload_mb is over 1, schedule a 30-minute cleanup. If it is over 5, do it today. This is the single highest-leverage TTFB optimisation on most older WordPress sites and it has nothing to do with caching.

How I Cut WP-Admin Load Time by 60 Percent (Without Disabling Plugins)

If wp-admin feels slow, the instinct is to disable plugins one by one until it speeds up. That is a long afternoon and usually answers the wrong question. The actual reason wp-admin is slow is rarely the plugin itself — it is what the plugin does on admin hooks. Here is the audit that cut admin load time 60 percent on the site I tested, with all plugins still active.

The diagnosis

WordPress fires admin_init, admin_menu, and admin_enqueue_scripts on every admin page load. Anything a plugin hangs off those hooks runs every time you load any admin screen — even if you are on a screen that has nothing to do with that plugin. A plugin that makes an outbound HTTP request on admin_init to check for updates is adding network latency to every page in your dashboard.

How to profile in 10 minutes

Install Query Monitor temporarily. Load wp-admin/index.php. Switch to the “Hooks & Actions” panel. Sort by time spent. The top three offenders are almost always:

  • An update-check that fires an external HTTP call on every admin request
  • A backup or security plugin pre-loading its dashboard data
  • A page-builder plugin loading its asset manifest globally instead of on its own screens

The fixes that worked

  1. Throttle plugin update checks. The standard pattern is once per 12 hours, but many plugins re-implement their own check on every admin load. A small mu-plugin that short-circuits pre_http_request for the update endpoints, except every six hours, is the single biggest win.
  2. Defer dashboard widgets. Plugins that add their own widget to the WP dashboard often query their entire data set on load. Disable the widget if you do not use it; many plugins respect a filter to skip widget registration.
  3. Constrain asset enqueueing. The page-builder case can be fixed with a current_screen check that dequeues the plugin’s heavy assets on screens it does not own.

Measurable result

On the test site (38 active plugins, shared host), wp-admin dashboard TTFB went from 1.8s to 0.7s. Plugin list page went from 2.4s to 0.9s. Editor screens were unchanged because the plugins involved already only loaded on their own screens — that is the discipline you want to find.

What to do this afternoon

Add Query Monitor. Load wp-admin/index.php three times. Note the top three hooks by time. Pick the one that surprises you most and fix that one. If you do nothing else for a week, that single change usually accounts for half of the perceived “wp-admin is slow”.

You almost never need to disable plugins. You need to find out which ones are not respecting the admin context.

WordPress 6.8 Performance Wins: What Actually Made My Sites Faster

WordPress 6.8 shipped a handful of real performance improvements that mostly happened under the hood. Not all of them moved the needle on production sites. Here is what actually did, measured across 47 sites we manage, with the boring honest result for each.

The wins that showed up in the data

  • Improved wp_query caching for archive pages. Across our sample, archive TTFB dropped 12 to 28 percent without any code changes. Bigger wins on sites with deep taxonomy queries.
  • Reduced autoloaded options on fresh installs. Saves a few hundred KB of wp_options reads per request. Modest, but cumulative on shared hosting.
  • Faster admin asset enqueueing. Editor screens loaded 200-400ms faster on average. Real if you spend time in wp-admin.

The wins that did not

  • “Improved emoji handling.” Saved 20ms on requests that did not have emoji. Did nothing measurable on requests that did.
  • Block editor “fast preview” mode. Editor felt faster subjectively. Lighthouse scores on the public site unchanged.

What we changed in response

Three concrete actions after rolling out 6.8 across the fleet:

  1. Stopped manually caching archive queries in two custom plugins. The core cache now does it correctly. Removed about 400 lines of code.
  2. Audited autoloaded options on every site. The 6.8 changes made the threshold for “this matters” lower, not higher. We trimmed 60 to 200 autoloaded entries per site on average.
  3. Re-baselined Core Web Vitals. LCP and INP both improved slightly on most sites with no other changes. Worth refreshing your baseline so you do not chase ghosts in subsequent optimisation work.

What to do this week

Update if you have not. Then run wp transient delete --all and wp cache flush to make sure the new cache logic is starting from a clean slate. Re-measure Core Web Vitals 48 hours after. Most sites get a free 5-15 percent on LCP from the archive-cache improvements alone.

6.8 is a quiet release, not a flashy one. That is usually the kind that pays off in maintenance budget over the next year.

Image Optimization on WordPress: The WebP and AVIF Workflow That Stuck

Three years of WebP, two of AVIF, dozens of tested plugins. The image-optimisation workflow that stuck across our entire client portfolio is short, boring, and effective. Here is what it is, and what stopped working that we used to recommend.

The workflow

  1. Resize at upload to a maximum of 2400px on the longest edge before any further processing. Most uploads are 5000+ from phones and the extra resolution does nothing.
  2. Compress to WebP automatically with a server-side conversion. Quality 80 is the sweet spot. Below 70 is visibly worse on photos. Above 85 is wasted bytes.
  3. Generate AVIF for the hero image only. AVIF compresses better than WebP but encoding is expensive. Doing it for every image bloats your media library; doing it for the LCP image specifically pays off.
  4. Serve responsive variants via WordPress’s built-in srcset. Do not override it with a CDN URL trick that loses the responsive behaviour.
  5. Lazy-load below-the-fold images with loading="lazy". Skip the above-the-fold image — lazy-loading the LCP hero hurts your Core Web Vitals.

What stopped working

  • JPEGtran-style optimisers as a standalone strategy. They squeeze 10-15 percent out of a JPEG; switching to WebP saves 30-40 percent. The compression is no longer where the win is.
  • CDN-based automatic conversion with no local fallback. Worked great until the CDN had an incident and every image on every site went 404 for 90 minutes. We now keep the original on origin.
  • Aggressive lazy-loading with native attribute alone. Browser support is great, but native loading="lazy" can fire late and cause LCP regressions on slow connections. We now use it everywhere except the hero.

The stack

We use ShortPixel as the conversion service (any of the modern image-conversion plugins work equivalently — ShortPixel, Imagify, EWWW). Configuration: WebP for all, AVIF for the hero only, originals preserved. CDN at the edge with WebP/AVIF content negotiation. WordPress core handles the srcset.

The measurement

Median image weight on the homepage of a typical client site, before and after:

  • JPEG, no compression: 1,840 KB
  • JPEG, optimised: 1,520 KB
  • WebP @ 80: 740 KB
  • AVIF @ 80 (hero only): 510 KB

The format change is roughly 2x the savings of compression alone. Combine both and Core Web Vitals usually go from “Needs Improvement” to “Good” on the image score, no other changes.

Boring, working, stable. That is what we wanted three years ago and that is what we have now.