I still get the same Slack screenshot every few months.
A client homepage that “used to feel snappy.” PageSpeed is red. The sales page takes a breath before the first paint. Someone already installed three caching plugins, a database cleaner, and a mystery “booster” from a Black Friday email. Features still work. The site still feels heavy.
WordPress is not slow because you have “too many plugins.”
It is slow because a couple of them do expensive work on every request, your page cache is fighting itself, autoloaded options grew quietly for years, and nobody measured Time to First Byte before guessing.

This is the playbook I use on client WordPress sites in 2026: measure first, name the guilty plugin with Query Monitor, keep one page-cache layer, add Redis where full-page cache cannot help, clean wp_options autoload carefully, and only then trim front-end assets so Core Web Vitals have a chance.
Start with TTFB, not another plugin
Open Chrome DevTools. Network tab. Disable cache. Reload the HTML document. Read Waiting (TTFB).
Rough ranges I use in audits:
- Under 200ms on a cached public page: healthy for most marketing sites
- 200ms to 600ms: look at hosting, edge cache headers, and whether you are actually getting a cache hit
- Over 600ms on a page that should be cached: hosting or cache configuration problem
- Over 800ms on an intentionally uncached response (cart, account, personalized page): profile PHP, SQL, and HTTP API calls before you buy another optimizer
Also check a cold view and a warm view. If warm is fast and cold is terrible, your cache layer is doing real work. If both are slow, plugins, autoload, or the database are eating the request before HTML even leaves the server.
View source on the front end and search for cache comments or response headers from LiteSpeed, WP Rocket, your host, or a CDN. If you find nothing on a public page that should be cached, fix that before debating minify settings.
Plugin count is a weak predictor
I have seen 60-plugin sites with a 240ms cached TTFB and 9-plugin sites stuck over two seconds.
What matters is cost per request:
- Blocking
wp_remote_get/ HTTP API calls during render - Unindexed or heavy
meta_querywork on largewp_postmetatables - Autoloaded options that load on every bootstrap
- Page builders or booking plugins that rebuild huge query sets on archive templates
- “Optimization” plugins that buffer the whole HTML and run regex after your host already cached the page
Audit by measurement, not vibes. Keep the features your client actually uses. Remove or replace the expensive ones.

Use Query Monitor like a profiler, not a badge
Install Query Monitor. Load the slow page while logged in as an administrator. Open the admin bar panels.
Focus on:
- Queries by Component — attributes SQL time to a plugin or theme. This ends the guessing contest.
- HTTP API Calls — exposes plugins phoning home, license checks, or remote content fetches that block TTFB.
- Hooks and overall timing — useful when the query count looks fine but PHP time is high.
Do not obsess over raw query count alone. Three hundred cheap queries can be fine. One 900ms query, or forty near-identical meta lookups, is the smell.
Common patterns I still see in 2026:
- A forms or CRM plugin doing a remote call on every page view “just in case”
- A related-posts or filter plugin joining
wp_postmetawithout indexes that match the query - A page builder loading every widget variation on templates that only need three blocks
- A security or uptime helper hitting an external API synchronously during front-end render
Once you can name the component, the fix becomes boring and specific: configure it, cache its output, replace it, or remove it.
Keep one page-cache layer
A proper WordPress performance stack still has layers:
- Page cache — store rendered HTML and serve it without bootstrapping most of WordPress
- Object cache — Redis or Memcached for options, query results, and objects on uncached requests
- OPcache — keep compiled PHP bytecode in memory
- CDN / edge — put HTML and static assets closer to visitors when it fits the site
The failure mode I see constantly is stacking three page caches: host cache + LiteSpeed Cache + WP Rocket (or W3 Total Cache) all trying to own the same HTML. Carts go stale. Logged-out banners flip wrong. Purge buttons stop meaning anything.
Pick the path that matches the server:
- LiteSpeed or QUIC.cloud: LiteSpeed Cache can talk to server-level LSCache. That is the point. On plain Apache or Nginx without LiteSpeed’s cache engine, the plugin cannot do that full-page magic the same way, even if CSS/JS helpers still work.
- Managed WordPress host with built-in edge or server cache: often you only need object cache + careful plugin hygiene, not a second full-page plugin.
- Generic VPS: one well-configured page cache (host nginx fastcgi cache, a single caching plugin, or reverse proxy) beat five overlapping ones.
If deactivating an all-in-one optimization plugin makes the site faster, believe the measurement. Those tools sometimes hook template_redirect, buffer output, rewrite HTML, add tables, and schedule cron jobs on top of work your host already finished.

Redis (or Memcached) for the traffic page cache cannot touch
Full-page cache helps anonymous readers. It does not save:
- wp-admin
- WooCommerce carts and checkouts
- membership or account areas
- personalized dashboards
- any request that bypasses the page cache on purpose
That is where a persistent object cache earns its keep. With Redis on the same host and a proper object-cache.php drop-in, option reads, term lookups, and repeated query results stay in memory instead of hitting MySQL every time.
Practical notes:
- Prefer Redis when your host supports it cleanly; Memcached is fine when that is what you already have.
- Set a
maxmemorypolicy such asallkeys-lru. A full Redis with no eviction can start missing silently and feel slower than no object cache. - Watch hit rate. Persistently low hit rates usually mean something is writing noisy keys or your working set does not fit memory.
- Flush object cache after big option cleanups or plugin removals so you are not debugging ghosts.
MySQL 8 removed the old query cache. Guides that still tell you to tune query_cache_size are outdated. For WordPress, the replacement is object caching plus better queries.
Audit wp_options autoload before you delete anything
Every WordPress request loads autoloaded options into memory early. A decade of plugins can leave hundreds of small rows. WordPress 6.6 improved autoload handling with clearer values (on, off, auto, and related) and a guard around very large single options, but it does not retroactively tidy legacy clutter.
Before you touch production:
- Back up the database.
- Measure total autoload size and the largest keys.
- Identify rows left by plugins you already removed.
- Disable autoload or delete only what you can prove is safe.
- Flush object cache and re-measure uncached TTFB.
Autoload cleanup is high leverage on uncached responses. It is also a great way to break a license, a redirect rule, or a feature flag if you delete by vibes. Be boring. Be reversible.
Transients and orphaned options from uninstalled plugins are fair game after confirmation. Active plugin settings are not.

Themes, builders, and features that cost every view
Plugin bloat is only half the story. Theme and builder choices show up in both TTFB and front-end vitals.
Patterns that keep showing up:
- Mega themes shipping every demo feature on a five-page brochure site
- Builders that store layout as giant serialized post meta and query more than the template needs
- Related content modules that run complex meta queries on every single post
- Live chat, heatmap, and A/B snippets injected sitewide from three different tags
- Sliders loading five image sizes and two animation libraries above the fold
I do not tell every client to rebuild in a custom block theme tomorrow. I do ask: which features are used weekly by real users or the business, and which are demo leftovers? Cutting unused builder modules often recovers more than another minify toggle.
If you are on the block editor path, lean into lean templates, patterns you actually need, and fewer global assets. If you are stuck on a builder, constrain templates, disable unused extensions, and make sure archives are not running the same heavy queries as singular product pages.
Front-end work after the server is honest
Once TTFB is under control, front-end performance stops being theater.
Priorities that usually matter:
- Serve modern image formats (WebP/AVIF where appropriate) at the sizes you actually display
- Lazy-load below-the-fold media; do not lazy-load your LCP image
- Load only the CSS/JS the template needs; dequeue plugin assets on pages that never use them
- Be careful with “combine everything” on HTTP/2 or HTTP/3 hosts; critical CSS and delayed JS help more than giant concatenated blobs when done poorly
- Host fonts intentionally; avoid tricks that also hurt CLS
- Delay third-party tags until interaction or idle when the business can accept it
Autoptimize and similar tools can help minify and optimize CSS, JS, HTML, and Google Fonts when you do not already have that covered. They are not a substitute for page caching, and they should not fight a host-level optimizer.
Core Web Vitals still map cleanly to this stack:
- LCP cares that the server answers quickly and the hero asset is ready
- INP cares that main-thread JS is not flooded with third-party and builder scripts
- CLS cares that fonts, banners, and embeds do not shove layout around
Server fixes feed LCP. Asset discipline feeds INP and CLS. Do both.
A practical 2026 audit order I actually use
When a WordPress site feels slow, I resist the plugin store and run this sequence:
- Measure cached and uncached TTFB, plus a field or lab Core Web Vitals snapshot.
- Confirm cache headers and that only one page-cache owner exists.
- Install Query Monitor and name the top components by SQL and HTTP time.
- Check autoload size and leftover options from removed plugins.
- Add or verify Redis/Memcached for admin, cart, and logged-in traffic.
- Disable or replace the one or two expensive plugins after a staging test.
- Trim theme/builder extras that never ship in the real information architecture.
- Then optimize images, fonts, and third-party tags.
- Re-measure. Keep the change that moved the needle; revert the rest.
That order protects features. You are not deleting the booking plugin on day one because a blog post said “use fewer plugins.” You are proving whether that booking plugin costs 12ms or 240ms per request.
Staging, deploys, and the “it broke checkout” fear
Performance work fails when it is reckless.
Use staging that mirrors PHP version, object cache availability, and the same major plugins. Test:
- Homepage and a heavy archive
- A singular post or product with real media
- Cart add, cart update, checkout start (for commerce)
- Login and a common wp-admin screen
- Any membership gate or form that emails someone
Purge page cache and object cache between experiments so you are not comparing a warm hit to a cold miss and calling it science.
When you must keep a heavy plugin, mitigate instead of pretending:
- Load its assets only on the templates that need it
- Cache expensive shortcode or block output with a transient or object-cache key that invalidates on the right events
- Move remote API work to cron or async jobs when the UI can tolerate it
- Replace a chat widget that loads on every page with a click-to-load button on contact routes
Clients care that features survive. Your job is to keep the feature and remove the tax.
Hosting still matters
No plugin audit saves a starving CPU on shared hosting with noisy neighbors and no OPcache headroom.
In 2026 I still ask:
- Is PHP modern and supported (and not an abandoned 7.x leftover)?
- Is OPcache enabled with enough memory?
- Is there a real page cache path before WordPress bootstraps?
- Can we run Redis on the same region as the app?
- Are HTML cache purges wired to publish, update, and menu changes?
- Is the CDN purging the same URLs WordPress thinks it published?
LiteSpeed Enterprise with LSCache remains an excellent architecture when available because cached HTML can be served before PHP wakes up. Cloudflare or another CDN helps global readers when HTML caching rules match your cookies and cart exceptions. Neither replaces fixing the plugin that runs a one-second remote call on every miss.
What I tell clients in plain language
Your site is not failing because WordPress is “old.”
It is failing because the request path got crowded: too many owners of caching, too little measurement, and a few features that cost more than they return.
We keep the features that make money or save staff time. We measure the rest. We give the server one clear cache story. We stop autoload and remote calls from taxing every visitor. Then the design and content work you already paid for can feel as fast as it looks in Figma.
Checklist you can run this week
- Record cached and uncached TTFB for home, a post, and a template that should bypass cache
- Confirm a single page-cache owner and correct cache-hit headers
- Run Query Monitor on the slowest template; write down the top three components by time
- List HTTP API calls during front-end render; remove or defer blockers
- Measure
wp_optionsautoload size; clean only proven leftovers after backup - Enable Redis/Memcached with an eviction policy; retest cart/admin
- Disable one expensive plugin or builder module on staging; compare numbers
- Optimize the LCP image and delay non-essential third parties
- Re-check LCP, INP, and CLS after server work, not before
Closing
WordPress performance in 2026 is not a shopping trip.
It is a diagnostic habit: TTFB first, Query Monitor second, one cache layer, object cache for the uncached path, careful autoload hygiene, then front-end polish. Do that and you can cut bloat without gutting the features your client refuses to lose.
If you want the longer companion threads on interaction metrics and modern front-end work, I have also written about INP and Core Web Vitals and keep shipping practical web performance notes on darshanpanchasara.com/blog.