When WordPress becomes slow after a plugin, theme, or cache change, first check whether the slow request reaches WordPress. A cached response and a page generated by PHP are different tests. Mixing them can make a cache problem look like a hosting problem.
TTFB measures the time until the first response byte and can include connection setup, redirects, and server work. It is not a Core Web Vital. The web.dev TTFB reference gives 0.8 seconds as a rough guide, not a universal pass/fail boundary.
Keep the test conditions consistent
Record these details before comparing results:
| Detail | What to record |
|---|---|
| Page type | Homepage, product, post, archive, logged-in route, API, or another specific class |
| Test location | Same region/network for before and after |
| Request state | Anonymous, cookie-bearing, logged-in, cache-bypass, or preload |
| Cache result | Verified HIT, MISS, BYPASS, EXPIRED, or unknown from real headers |
| Website version | Commit/plugin/theme/config version and deployment time |
| Sample size | Enough repeated requests to report p50 and p95, not one fastest request |
Do not add a random query string and call it “cold” unless the production cache key treats that request like a real miss. Do not call the second request “warm” unless headers prove a cache hit.
Measure cache hits and misses separately
For each sample page:
- Record headers and timings for an anonymous request.
- Repeat without changing URL, cookies, location, or protocol.
- Identify cache status and age from the actual response headers.
- Collect a distribution for confirmed hits and confirmed misses separately.
- Compare the same conditions before and after the change. If no earlier measurements exist, say so; do not present a different page or cache state as the baseline.
- Profile origin generation only on requests proven to reach origin.
This command saves the headers and prints timings for one request:
curl -sS -o /dev/null -D headers.txt \
-w 'remote=%{remote_ip} code=%{http_code} redirect=%{time_redirect} connect=%{time_connect} tls=%{time_appconnect} starttransfer=%{time_starttransfer} total=%{time_total}\n' \
https://example.com/representative-page
Repeat the request and group timings by the cache headers. The command measures one test location; it does not measure the experience of all visitors.
Use the pattern to choose the next check
| What changed | Where to look next | What to compare |
|---|---|---|
| Confirmed edge HIT regressed | CDN route, cache storage, edge worker, connection path | Same POP/request state; HIT header; response age; timing distribution |
| MISS slow, HIT stable | Origin generation or cache-fill path | MISS header plus origin/app timing |
| HIT rate collapsed | Cache key, cookies, bypass rule, invalidation, TTL | Header distribution before/after and named rule change |
| Anonymous fast, cookie-bearing slow | Page-cache bypass, personalization, session/plugin behavior | Same URL/location; cookie set recorded; cache status differs |
| Origin generation regressed | PHP, database, object cache, theme/plugin hooks, remote calls | Confirmed misses plus profiling or query/request evidence |
| Only browser rendering regressed | Frontend assets or JavaScript, not document TTFB | Document TTFB stable; later browser milestones changed |
If the slow requests reach WordPress, inspect:
- database query count and slow queries
- uncached remote HTTP calls
- plugin/theme hooks on the request path
- object-cache hit behavior and key invalidation
- cron or queue work leaking into requests
- full-page cache exclusions and cookies
Before/after worksheet
| Sample | Version | Request state | Cache headers | Requests | Median TTFB | p95 TTFB | Notes |
|---|---|---|---|---|---|---|---|
| Product control | Before | Anonymous | Header/value | ||||
| Product affected | Before | Anonymous | Header/value | ||||
| Product control | After | Anonymous | Header/value | ||||
| Product affected | After | Anonymous | Header/value |
Repeat the same measurements after the fix and compare the median and slower requests, not only the fastest result. If document TTFB stayed stable but rendering became slower, inspect frontend assets and JavaScript. A browser-only tag runs after the document starts arriving, so it does not explain a slower server response for that document.
