WordPress sites are slow by default. Not because WordPress is inherently slow — it can serve tens of thousands of requests per day — but because the defaults are misconfigured and every plugin adds overhead. Here's how to fix it.
Baseline: Know Your Slow Pages
Before optimizing anything, measure:
# TTFB (Time To First Byte) from the shell
curl -w "\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
-o /dev/null -s https://example.com
# Query count from inside WordPress
define('SAVEQUERIES', true); // in wp-config.php during debug
Target: TTFB < 200ms, < 30 DB queries per page.
Object Caching with Redis
WordPress has a built-in object cache API (wp_cache_get, wp_cache_set) but it's per-request only by default — it doesn't persist between requests.
Install a persistent object cache:
wp plugin install redis-cache --activate
wp redis enable
Add to wp-config.php:
define('WP_REDIS_HOST', '127.0.0.1');
define('WP_REDIS_PORT', 6379);
define('WP_REDIS_DATABASE', 0);
define('WP_REDIS_TIMEOUT', 1);
define('WP_REDIS_READ_TIMEOUT', 1);
With Redis object caching, expensive queries (post meta, options, term relationships) are cached in-memory across requests. This alone typically cuts response time by 30-60%.
Query Optimization
The most common performance killer: WP_Query without no_found_rows:
// Bad — runs COUNT(*) even if you don't need pagination
$query = new WP_Query(['post_type' => 'product', 'posts_per_page' => 6]);
// Good — skip the COUNT(*) when you don't paginate
$query = new WP_Query([
'post_type' => 'product',
'posts_per_page' => 6,
'no_found_rows' => true,
'update_post_meta_cache' => false, // skip if you don't use post meta
'update_post_term_cache' => false, // skip if you don't need terms
]);
Page Caching
Object caching speeds up PHP execution. Page caching serves entire pages from disk — zero PHP, zero DB.
For Nginx + FastCGI:
fastcgi_cache_path /tmp/nginx-cache levels=1:2 keys_zone=WORDPRESS:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
location ~ \.php$ {
fastcgi_cache WORDPRESS;
fastcgi_cache_valid 200 60m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
add_header X-FastCGI-Cache $upstream_cache_status;
}
WP Super Cache and W3 Total Cache achieve the same thing at the plugin level if you don't control the server config.
CDN for Assets
Every image, CSS file, and JavaScript bundle should be served from a CDN. CloudFront or Bunny CDN with WordPress:
// Rewrite asset URLs to CDN
add_filter('wp_get_attachment_url', function (string $url): string {
return str_replace(site_url(), 'https://cdn.example.com', $url);
});
Database Maintenance
# Optimize all tables (removes overhead from deleted rows)
wp db optimize
# Delete post revisions older than 30 days
wp post delete $(wp post list --post_type=revision --before="30 days ago" --format=ids) --force
# Remove transients that have expired
wp transient delete --expired
Add these to a weekly cron job. WordPress accumulates tens of thousands of expired transients in wp_options over time, which slows every page that reads the options table.
Al Amin Ahamed
Senior software engineer & AI practitioner. Building things in Laravel, PHP, and TypeScript.
About me →More from the blog
One email a month. No noise.
What I shipped, what I read, occasional deep dive. Unsubscribe anytime.
Check your inbox — confirmation link sent.