WordPress themes and plugins: what slows a site
Themes and plugins decide most of a WordPress site's speed. How core loads their files, how to find the heavy ones, and how to remove, limit or replace them.
In this guide
Why they matter most
WordPress core is small compared with what is added to it. The WordPress Advanced Administration Handbook says a theme has a huge impact on performance, and a fast lightweight theme performs much more efficiently than a heavy, graphic-laden one. It says the same about plugins, and that deactivating and deleting unnecessary ones is a significant way to improve performance.
The 2025 Web Almanac points the same way. Its CMS chapter reports that WordPress sites span a wide range of results, and that the differences come from configuration more than from core limits.
A theme or plugin can cost speed in two places:
- On the server. Its PHP runs on every request, it asks the database questions, it may call other servers, and it may schedule background tasks.
- In the browser. It adds styles, scripts, fonts and images, and it can make the page's structure larger.
The two are separate. A plugin can be light in the browser and heavy on the server, or the other way round.
What core does to help
Recent WordPress versions have features that reduce the cost, as long as the theme or plugin takes part. These come from the core source:
- Block styles on demand. Block themes load a separate stylesheet for each core block, and only when the block is on the page. Classic themes get the same behavior from version 6.9, unless a site turns it off.
- Script loading strategy. Since version 6.3,
wp_enqueue_script()accepts astrategyofdeferorasync, and a choice to print the script in the footer. Version 6.9 added afetchpriorityoption. - Inlining small styles. A theme can opt in to have small stylesheets printed inline instead of fetched. The limit is 40,000 bytes in total since version 6.9.
- Version numbers. Enqueued files get a version in their address for cache busting. If the version is
false, WordPress uses its own version number. If it isnull, none is added.
These help only when the theme or plugin uses them. Most of the work below is finding the ones that do not.
Step 1: measure on a copy
Do the testing on a staging copy, or at a quiet hour. Use three pages: the home page, a typical post or product page, and a page with a form.
For each, record the same things before you change anything:
- the Lighthouse or PageSpeed Insights result, as the median of several runs (see why PageSpeed scores change);
- the number of requests and the total size of JavaScript and CSS;
- the server response time, which the Document request latency insight shows.
Change one thing at a time, then measure again.
Step 2: list what each plugin and the theme add
WordPress prints files with their origin in the address. A plugin's files live under /wp-content/plugins/<plugin name>/, and the theme's under /wp-content/themes/<theme name>/. That makes them easy to group.
- Open the page, open DevTools, and go to the Network panel.
- Reload and type
pluginsin the filter box. Note the plugin names, how many files each adds, and their sizes. Then typethemes. - Open Coverage (see unused code) to see how much of each file ran.
- Repeat on a page where the plugin's feature is not used. A contact form plugin that loads its files on a page with no form is a typical finding.
On the server side, WordPress can save every database query when SAVEQUERIES is set to true, as the handbook's wp-config page explains. Tools can use this record to show which function ran each query. Use them on a copy, not on the live site.
Turn them off one at a time
The handbook suggests selectively disabling plugins to measure their effect. On the copy, deactivate one plugin, measure the three pages, reactivate it, and move to the next. Keep a table. A plugin that adds 300 milliseconds to the server response, or a megabyte of script, stands out at once.
Watch for dependencies. Some plugins need others, and switching one off can hide the real cost or break a page. Look at the page, not only at the numbers.
What the numbers mean
| What you see | Likely cause | What to do |
|---|---|---|
| Many files from one plugin on every page | The plugin loads its assets sitewide | Look for a setting to load only where used. If there is none, limit it with code or replace it. |
| A slow server response on only some pages | A plugin that runs queries or calls other servers on those pages | Disable it on the copy and compare. Ask the plugin's developer about the query. |
| A very large page structure | A page builder, or a theme with many wrapper elements | See page builders and the DOM size guide |
| Large JavaScript from sliders, animations or pop-ups | Features you use once, loaded everywhere | Remove, simplify, or load only on the pages that use them |
| Several font files | A theme and plugins each loading fonts or icon sets | Reduce the families and weights. See web fonts |
| jQuery and its plugins everywhere | Older plugins that depend on it | See removing jQuery before you try to change it |
Choosing a theme
- Compare with a default theme. On the copy, switch to a theme that ships with WordPress and test the same page. The difference is a rough measure of what your theme adds. Content that uses the theme's own shortcodes or blocks will look different, so judge the numbers, not the design.
- Prefer a block theme or one that uses core's loading features. Block themes get styles on demand by default.
- Be wary of themes that do everything. Sliders, animation libraries, icon packs and many font choices are loaded or bundled "just in case". Turn off what you do not use in the theme's settings.
- Keep custom code in a child theme or a small plugin. Edits made directly in a theme or plugin are lost when it updates.
Choosing and judging plugins
A plugin deserves its place when:
- it loads its files only on the pages where its feature is used;
- it loads scripts with
deferor in the footer, and does not depend on libraries you do not need; - it does one job, or has modules you can switch off;
- it does not call another server on every page view, and does not run heavy tasks on visitors' requests;
- it is maintained. The plugin's readme lists the WordPress version it was tested up to and the PHP version it requires. An old plugin on a current site is a risk for speed and security.
A plugin that fails these tests may still be worth keeping. The question is whether the feature is worth the cost, and whether a lighter route exists. A native block, a few lines in a child theme or a smaller plugin often does the same job.
Fixes, in order
- Delete what is inactive or unused. An inactive plugin does not run, but it is still code to maintain and secure.
- Replace the heavy ones. Choose a lighter plugin or a core feature.
- Configure. Switch off modules and features you do not use inside large plugins.
- Limit to the pages that need it. Some plugins and performance plugins can stop a file from loading on selected pages. In code, use the hook that prints assets and the conditional functions, such as
is_page()orhas_block(). - Load the rest late. Use
deferorasync, and the footer. - Update. Keep core, the theme and plugins current, as the handbook advises, and keep PHP current too.
Here is the code version of step 4. The handle is shown in the page source, because WordPress prints scripts with the id <handle>-js and styles with <handle>-css:
add_action( 'wp_enqueue_scripts', function () {
if ( ! is_page( 'contact' ) ) {
wp_dequeue_script( 'contact-form-plugin' );
wp_dequeue_style( 'contact-form-plugin' );
}
}, 100 );And for your own script, ask for defer and the footer:
wp_enqueue_script(
'my-widget',
get_stylesheet_directory_uri() . '/js/widget.js',
array(),
'1.0.0',
array(
'strategy' => 'defer',
'in_footer' => true,
)
);Dequeuing can break a feature that depends on the file, such as a form that needs its script. Test the page after each change. If you are not comfortable with code, use a plugin built to unload assets, or ask a developer.
Mistakes to avoid
- Counting plugins instead of weighing them. Twenty small, quiet plugins can cost less than one large one.
- Testing on the live site. A mistake costs customers.
- Removing a plugin without a backup. Some leave settings behind, and some break content that uses them.
- Fixing speed by adding plugins. Every optimization plugin is also code that runs on every request. Add one only when it solves a measured problem.
- Editing the plugin's own files. The next update erases the change.
Check your own page
Run the free audit and look at Reduce unused JavaScript, Reduce unused CSS and 3rd parties. Match each large file to a plugin by its address. Start with the biggest one that is loaded on a page that does not need it.
Sources
- Optimization and Editing wp-config.php in the WordPress Advanced Administration Handbook: the effect of themes and plugins, testing by disabling,
SAVEQUERIES. - WordPress core source: functions.wp-scripts.php (
wp_enqueue_scriptand itsstrategy,in_footer,fetchpriorityand version options), script-loader.php (block styles on demand and inline styles) and theme.php (block themes' defaults). - CMS chapter, Web Almanac 2025: variation among WordPress sites.
Start here
Free website audit
Live Google data for any public page: mobile and desktop.
Mobile + desktop · Lighthouse lab test · Real-user Chrome data when Google has it
Rather have this done for you? WordPress speed · Book a call