Speeding Up a Slow WordPress Site: The Order I Actually Work In
"Our WordPress site got slow" is one of the most common requests I get, and the instinct is usually to start with a plugin, an image optimizer, a "speed" plugin that promises to fix everything. Sometimes that helps a little. But the biggest wins almost always come from things that have nothing to do with WordPress's plugin ecosystem, and going through them in the wrong order means spending time on a 10% improvement before fixing the thing causing the other 70%.
First: is it the server, or the page?
Before touching anything, I check the time-to-first-byte, how long the server takes to start sending a response, separate from how long the browser takes to load everything after that:
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s\n" https://example.com
A TTFB over half a second on a logged-out page usually means WordPress is doing real work on every request, the database is being queried, PHP is executing, nothing is cached. A fast TTFB but a slow overall page load points toward the frontend, images, scripts, fonts, which is a different (and usually easier) problem.
If it's the server: caching, in layers
A WordPress page that's identical for every visitor (which describes most pages on most sites) doesn't need PHP and MySQL to run on every request. A page cache, whether through a plugin like WP Super Cache or, better, at the server level with Nginx's fcgicache or a similar reverse proxy cache, serves a static copy and skips PHP entirely for cached requests. This single change is often the difference between a TTFB of 800ms and 50ms, because it's the difference between "run WordPress" and "serve a file."
For the requests that do need PHP, logged-in users, anything dynamic, an object cache (Redis or Memcached) caches the results of WordPress's database queries so repeated lookups (which WordPress does a lot of, often the same query dozens of times per page) hit memory instead of MySQL:
// wp-config.php, after installing a Redis object cache plugin
define('WP_REDIS_HOST', '127.0.0.1');
define('WP_REDIS_PORT', 6379);
define('WP_CACHE', true);
And PHP's OPcache, which caches compiled PHP bytecode so the same file doesn't get recompiled on every request, should simply be enabled in php.ini, this one has no WordPress-specific configuration at all and benefits every PHP request on the server.
The database accumulates weight
WordPress's database grows in ways that don't show up until they do: post revisions (every autosave creates a new row), expired transients (temporary cached data that often never gets cleaned up), and orphaned metadata from removed plugins. None of this is dramatic on a small site, but on a site that's been running for years, it's common to find a wp_options table where the autoloaded options (loaded on every page request, regardless of whether they're needed) add up to several megabytes:
SELECT option_name, LENGTH(option_value) AS size
FROM wp_options
WHERE autoload = 'yes'
ORDER BY size DESC LIMIT 10;
Anything large here that came from a plugin that's no longer active is pure overhead on every single request. Cleaning this up doesn't require guesswork, the query tells you exactly where the weight is.
Then, and only then, the frontend
Once the server responds quickly, frontend optimization, lazy-loading images, serving modern image formats, deferring non-critical scripts, actually has a foundation to build on. Doing this first on a site with an 800ms TTFB is polishing the visible 20% while the invisible 80% (the time before the browser even starts rendering) goes untouched.
Why the order matters
Each of these steps is independently useful, but the order reflects where the time actually goes on a typical slow WordPress site: server-side caching addresses the biggest chunk for logged-out traffic, the object cache and OPcache address the cost of WordPress itself for everything else, database cleanup removes accumulated weight that affects every single page, and frontend optimization polishes what's left. Starting from the bottom of that list because it's the most visible, an image, a script, feels productive, but it's optimizing the smallest piece of the total time first.