Most WordPress speed guides tell you to install a caching plugin and call it a day. That advice isn't wrong — it's just incomplete, and it ignores the 80% of performance problems that caching alone won't fix.
I've run the same staging-to-production performance pipeline on hundreds of WordPress sites. The pattern is always the same: a site owner reads a generic checklist, checks off the obvious boxes, and still wonders why their Largest Contentful Paint (LCP) is sitting at 4.2 seconds. The problem isn't effort — it's that the checklist was written for a fictional average site.
This post is my actual workflow. I'll cover the changes that consistently produce measurable improvements in Core Web Vitals, with real config examples and the reasoning behind each decision. No fluff.
Measure First, Optimize Second
Before touching a single setting, get a baseline. I use three tools together because each one sees something the others miss:
- WebPageTest (webpagetest.org) — run from a location close to your real users, on a cable connection, with a cold cache. This is your ground truth.
- Google PageSpeed Insights — captures field data from the Chrome User Experience Report (CrUX). If your real users are on mobile 3G, lab scores are lying to you.
- Query Monitor plugin — installed temporarily on staging. Shows you database query counts, slow queries, and hook timing.
Write down your baseline LCP, Total Blocking Time (TBT), and Cumulative Layout Shift (CLS). Every change you make should move at least one of these numbers. If it doesn't, revert it.
Fix Your Hosting Before Anything Else
I'll say the quiet part loud: no amount of optimization compensates for bad hosting. If your server is responding in 800ms before a single byte of HTML arrives, you're fighting with one hand tied behind your back.
Time to First Byte (TTFB) under 200ms is the target. Check it with curl:
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s\n" https://yoursite.com
If you're consistently over 400ms, the optimization conversation starts with your host, not your plugins. Managed WordPress hosts like Kinsta, WP Engine, and Cloudways (on a properly sized droplet) routinely hit sub-150ms TTFB on warm cache. Shared hosting at $3/month typically doesn't.
Once your TTFB is acceptable, everything else in this post compounds on that foundation.
Caching: Layers Matter More Than Plugin Choice
Everyone argues about which caching plugin to use. That's the wrong argument. The layers you cache matter far more than whether you picked WP Rocket, W3 Total Cache, or LiteSpeed Cache.
Page cache is the obvious one — serve pre-built HTML instead of running PHP + MySQL on every request. All the major plugins do this.
Object cache is where most sites leave performance on the table. WordPress's default object cache is non-persistent: it dies at the end of every request. Add a persistent backend — Redis or Memcached — and you eliminate hundreds of redundant database queries per page load.
On a VPS or managed host that gives you Redis access, add this to wp-config.php:
define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_DATABASE', 0 );
Then install the Redis Object Cache plugin by Till Krüss. Check the dashboard widget — you want a high hit ratio (above 80%) within a few hours of enabling it.
Browser cache headers tell returning visitors to reuse assets. Your server config should be setting Cache-Control: max-age=31536000, immutable on versioned static assets. If you're on Nginx:
location ~* \.(js|css|png|jpg|jpeg|gif|ico|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
Image Optimization Is Not Just Compression
Images are almost always the single biggest contributor to page weight, but compression is only part of the story.
Format matters first. WebP delivers roughly 25-35% smaller files than JPEG at equivalent visual quality. AVIF is even better but browser support is still catching up (as of mid-2025, about 94% global coverage on caniuse.com). Serve WebP as your default, AVIF where supported, and keep JPEG/PNG as fallback.
ShortPixel and Imagify both handle format conversion on upload. I've been using Imagify on client sites since 2022 — it's fast, the API is reliable, and the bulk optimization queue doesn't time out on large media libraries the way some competitors do.
Lazy loading is on by default in WordPress 5.5+, but it doesn't help your LCP image — which should load eagerly. Find the image that appears above the fold on mobile and make sure it has loading="eager" and, better yet, a <link rel="preload"> in your <head>:
<link rel="preload" as="image" href="/wp-content/uploads/hero.webp" fetchpriority="high">
FetchPriority is supported in Chrome 102+ and Safari 17.2+. It tells the browser to prioritize this resource in the fetch queue. On most sites I test, adding this tag alone drops LCP by 300-600ms.
Serve correctly sized images. A 2400px wide image displayed at 400px is wasting bandwidth. WordPress generates multiple sizes on upload, but your theme needs to use srcset and sizes attributes correctly. Check with WebPageTest's "Image Analysis" tab — it'll flag oversized images explicitly.
JavaScript: The Real Culprit Behind High TBT
Total Blocking Time correlates directly with how much JavaScript is blocking the main thread during page load. The fix isn't always "remove JS" — it's about when and how it loads.
Defer non-critical scripts. Any script that doesn't affect above-the-fold rendering should have defer or async. In WordPress, you can add defer via wp_script_add_data():
add_action( 'wp_enqueue_scripts', function() {
wp_enqueue_script( 'my-script', get_template_directory_uri() . '/js/app.js', [], '1.0', true );
wp_script_add_data( 'my-script', 'defer', true );
});
Note: defer only works on scripts without async. If you're using a plugin that injects scripts without these attributes, WP Rocket's "Delay JavaScript Execution" feature or Flying Scripts plugin can apply them globally.
Audit your plugin JS footprint. Install Asset CleanUp or Perfmatters and look at what's loading on each page type. Contact form scripts loading on every page when you only have a form on /contact/ is extremely common and completely unnecessary.
Watch for render-blocking third-party scripts. Google Tag Manager, chat widgets, and ad scripts are frequent offenders. Load them after the load event when possible, or use a facade pattern (a static placeholder that loads the real script on user interaction).
Database Optimization: The Slow Leak
WordPress databases accumulate garbage over time. Post revisions, transients, spam comments, and orphaned metadata add up. On a site that's been running for three or more years, I've seen wp_options tables with 50,000+ rows of autoloaded data — that's loaded into memory on every single page request.
Check your autoloaded options size:
SELECT SUM(LENGTH(option_value)) as autoload_size
FROM wp_options
WHERE autoload = 'yes';
Anything over 1MB is a problem. Over 3MB is a crisis. The culprits are usually deactivated-but-not-cleaned plugins and poorly coded ones that store large serialized data as autoloaded options.
WP-Optimize handles routine cleanup (revisions, transients, spam) well. For the autoload audit, you'll need to get into the database directly and identify which options are bloated. Sometimes the fix is as simple as deleting options from a plugin you uninstalled two years ago.
Also limit post revisions. Add this to wp-config.php:
define( 'WP_POST_REVISIONS', 5 );
Five is enough for any reasonable workflow. The default (unlimited) is not.
CDN and Critical CSS: The Finishing Layer
A CDN moves your static assets closer to your visitors. Cloudflare's free tier is a legitimate option for most sites — it handles CDN, basic DDoS protection, and HTTP/3 support out of the box. For assets specifically, BunnyCDN is cheaper than most competitors at $0.01/GB and has excellent global PoP coverage.
Critical CSS is the technique of inlining the CSS required to render above-the-fold content directly in the <head>, then loading the full stylesheet asynchronously. It eliminates render-blocking CSS and directly improves LCP and First Contentful Paint.
Generating it manually is tedious. WP Rocket's "Optimize CSS Delivery" does it automatically. So does the free plugin Autoptimize combined with the Critical CSS service at criticalcss.com. Test carefully after enabling — complex themes sometimes break.
One more thing on CDN: make sure you're using HTTP/2 or HTTP/3. HTTP/1.1 limits parallel connections per domain, which is why the old advice was to use multiple CDN subdomains for assets. HTTP/2 multiplexing makes that unnecessary. Check with:
curl -I --http2 https://yoursite.com 2>&1 | grep -i "HTTP/"
If you're still on HTTP/1.1, talk to your host. There's no good reason to be in 2025.
Putting It Together: My Actual Priority Order
When I take on a new site, this is the sequence I follow — not alphabetical, not by plugin category, but by expected impact per hour of work:
| Priority | Action | Expected Impact |
|---|---|---|
| 1 | Fix TTFB (hosting or server config) | High — everything compounds on this |
| 2 | Add persistent object cache (Redis) | High for dynamic sites |
| 3 | Optimize and correctly size images, add WebP | High — usually biggest payload |
| 4 | Preload LCP image with fetchpriority | Medium-High — direct LCP improvement |
| 5 | Defer/delay non-critical JS | Medium — reduces TBT |
| 6 | Enable page cache | Medium — lower if host already caches |
| 7 | Clean up autoloaded options | Medium — often overlooked |
| 8 | Implement Critical CSS | Medium — improves perceived load |
| 9 | Add CDN for static assets | Low-Medium — depends on audience geography |
| 10 | Set long-lived browser cache headers | Low — helps returning visitors |
The table isn't gospel. A content-heavy site with enormous images will see more from step 3 than step 2. A WooCommerce store with complex queries will see more from step 2. Measure, then prioritize.
The One Thing to Do Tomorrow
If you take nothing else from this post: run WebPageTest on your site right now, with a cold cache, from a server location that matches your primary audience. Look at the waterfall. Find the single largest file or the single longest request. Fix that one thing.
WordPress site speed optimization tips are most useful when you apply them in response to what your data is actually showing — not in the order some blog post listed them. The waterfall doesn't lie.
If you want to go deeper on the hosting side of this equation, my managed WordPress hosting comparison breaks down TTFB benchmarks across the major players with real test data. And if you're running WooCommerce specifically, the WooCommerce performance optimization guide covers the database and caching nuances that general WordPress advice tends to miss.
Start with the measurement. Everything else follows.