Trim WordPress page weight: scripts, styles and plugins
Most of a WordPress page's weight is plugins loading files on pages that do not use them.
Written by Hamza Ahmad Aslam. Updated . One of the page weight guides.
The thresholds
- HTML over 150 KB is a warning, over 400 KB a problem.
- More than 5 render-blocking scripts in the head is a warning, more than 10 a problem. Scripts with
defer,asyncortype="module"are not counted. - More than 8 stylesheets is a warning, more than 15 a problem.
- More than 4 outside hosts serving scripts is a warning, more than 8 a problem.
- More than 20 plugins loading files on the page is a warning.
- Images without width and height, the emoji script and jQuery Migrate are noted, and more than 5 undimensioned images becomes a warning.
Scripts in the head
A plain <script src> in the head stops the page drawing until the file has downloaded and run. Since WordPress 6.3 a script can ask to be deferred when it is registered:
wp_enqueue_script(
'my-script',
get_theme_file_uri( 'js/my-script.js' ),
array(),
'1.0',
array( 'strategy' => 'defer', 'in_footer' => true )
);For plugin scripts you cannot edit, a performance plugin's defer setting does the same job. Test the page afterwards: a script that others depend on must still load before them.
Stylesheets
Each stylesheet in the head blocks rendering. Many belong to plugins that enqueue on every page, like a form plugin whose form is only on the contact page. Find the handles in Query Monitor's Styles panel, then remove them where they are not used:
add_action( 'wp_enqueue_scripts', function () {
if ( ! is_page( 'contact' ) ) {
wp_dequeue_style( 'some-plugin-style' );
wp_dequeue_script( 'some-plugin-script' );
}
}, 100 );Images without width and height
Without dimensions the browser does not know how much room to leave, so the text jumps as each image arrives. WordPress adds width and height to images in post content. Theme templates that print <img> by hand are the usual gap; wp_get_attachment_image() writes the dimensions for you.
The emoji script
Browsers draw emoji themselves. The script WordPress adds to support very old ones can go:
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'wp_enqueue_scripts', 'wp_enqueue_emoji_styles' );jQuery Migrate
A compatibility layer for code written against old jQuery. If it loads, something on the site may still need it. With it loaded, the browser console shows JQMIGRATE warnings naming the old calls; when a full click through the site shows none, remove it on the front end:
add_action( 'wp_default_scripts', function ( $scripts ) {
if ( ! is_admin() && isset( $scripts->registered['jquery'] ) ) {
$jquery = $scripts->registered['jquery'];
$jquery->deps = array_diff( $jquery->deps, array( 'jquery-migrate' ) );
}
} );Third-party hosts
Each outside host costs a DNS lookup and a new connection before its file even starts. Tag managers add more hosts after the page loads. Keep the ones that earn their place and remove the ones left from old campaigns.
A heavy HTML document
Large inline CSS from page builders, inline SVG icons repeated on every card, and big blocks of JSON printed into the page are the usual causes. Move shared CSS into cached files and use an SVG sprite or icon files.
Check the fix
Rerun the check. Then open the page in your browser's developer tools, Network panel, with the cache disabled, and compare the number of requests and the transferred size with before.
Check a site for this
Other fixes
- Hide the WordPress version numberThe version shows in the page's generator tag and in the stock readme.html. Both can go in a few minutes.
- Stop the WordPress REST API listing user namesThe users endpoint answers anonymous requests with account slugs, which are usually the login names.
- Turn off XML-RPC in WordPressxmlrpc.php still answers. Unless Jetpack or a publishing app needs it, block it at the server.