WordPress powers a huge share of the web, and it can be very fast. When it is slow, the cause is rarely WordPress itself. It is usually some mix of cheap hosting, no caching, too many plugins and a heavy theme or page builder. Here is what to fix, in the order that matters.
1. Start with hosting
If your server takes more than a second to respond, no plugin can fully fix it. Check Time to First Byte in PageSpeed Insights. If it is high on every page, the server is the bottleneck.
- Run a currently supported PHP version. Newer PHP releases are significantly faster than old ones.
- Choose hosting with server-level page caching and an object cache such as Redis.
- Put the site behind a CDN so visitors get pages from a location near them.
2. Turn on full-page caching
Without caching, WordPress runs PHP and database queries to build every page on every visit. With caching, most visitors get a ready-made HTML file. Use your host's built-in cache if it has one; otherwise a single, well-configured caching plugin. Never run two caching plugins at once.
3. Audit your plugins
The number of plugins matters less than what each one does. One badly built plugin can add more load than twenty light ones. Install Query Monitor temporarily to see which plugins add slow database queries, scripts and styles.
- Deactivate and delete plugins you no longer use.
- Replace heavy all-in-one plugins with lighter ones that do only what you need.
- Stop plugins loading their scripts on pages where they do nothing, such as a form plugin on every page.
add_action( 'wp_enqueue_scripts', function () {
if ( ! is_page( 'contact' ) ) {
wp_dequeue_script( 'contact-form-7' );
wp_dequeue_style( 'contact-form-7' );
}
}, 100 );4. Be honest about page builders
Visual page builders are convenient but often generate deeply nested HTML and load large CSS and JavaScript files on every page. If your theme is the problem, a lightweight block theme using the core block editor is usually much faster. If a rebuild is not an option, disable unused builder modules and widgets in the builder's settings.
5. Use what WordPress already does for you
- Images: WordPress adds responsive srcset, lazy-loading and, since version 6.3, fetchpriority high to the image it predicts is the LCP element. Make sure your theme does not override this.
- Modern formats: WordPress 6.5 added support for uploading AVIF images, alongside WebP.
- Speculative loading: since version 6.8, WordPress prefetches pages a visitor is likely to open next, so clicks feel almost instant. It is on by default for logged-out visitors on sites with pretty permalinks.
If your hosting can handle it, you can make speculative loading more aggressive by prerendering likely next pages instead of just prefetching them.
add_filter( 'wp_speculation_rules_configuration', function ( $config ) {
if ( is_array( $config ) ) {
$config['mode'] = 'prerender';
$config['eagerness'] = 'moderate';
}
return $config;
} );6. Fix images at upload
- Resize photos before uploading. A 6000-pixel photo is wasted on a 1200-pixel layout.
- Use an image optimization plugin or your CDN to convert to WebP or AVIF automatically.
- Check that the main image above the fold is not lazy-loaded by your theme or a plugin.
7. Clean up the database
Years of post revisions, expired transients and leftover plugin tables slow down queries. Limit revisions in wp-config.php and clean old data periodically, always after taking a backup.
define( 'WP_POST_REVISIONS', 10 );What to skip
- Stacking several optimization plugins that do the same job. They conflict and can make things slower.
- Aggressive minify and combine settings without testing. They are a common cause of broken layouts.
- Chasing a perfect 100 lab score. Aim to pass Core Web Vitals for real users first.
The fast path
LightLoader works alongside your caching setup: it handles image priority, script deferral and layout reservation from one tag, without another plugin to configure. Add it to your theme header or with a header-scripts plugin.
<script src="https://app.lightloader.com/api/loader.js?token=YOUR_TOKEN" async></script>