How to speed up WordPress by tweaking your page header

When WordPress generates a webpage, it adds a lot of information unseen by the user. Much of this appears between the <head> tags in the code, and asks the browser to interpret information in a certain way, or load additional files and resources. While some of these are useful (such as style.css, which turns raw words into a stylish website), others are not. Some could even compromise the security of your site.
Each resource that’s requested slows your website a little. If you’re on fast broadband or 5G, you might not notice. Those condemned to slow mobile connections, data limits, poor service or other restrictions may come to hate you for it.
It makes sense to remove anything your theme or site doesn’t use, even if all it does is shave a third of a second off the loading time, and saved a user a few kb on their data plan.
In this post, I’ve outlined the resources I’ve suppressed from this site, and the code I’ve used. You can include the code either in your functions.php file or your own plugin. It’ll get updated from time to time as WordPress develops.
First, some basics.
For much of what follows I’m using two function called “remove_action” and wp_deregister_script. If you know how these works, you can skip this section.
remove_action
When WordPress assembles a page, it triggers various “actions” to bring together its different parts. Developers create functions, then “hook” them to the action so when the action happens, their function runs. The action “wp_head” handles much of what you see in the <head> on your site.
Just as we can add a function to an action, so we can take it away. That’s what remove_action does. It takes three parameters: the name of the action, the function we want to remove and a priority.
To remove something from our header, we need a single line of code:
remove_action('wp_head','something_to_remove',10);
wp_deregister_script
When a web page loads, it’ll also call on a collection of files with names like style.css and jquery.js. These are “scripts” and add styling and functionality to the bare bones of a page. These are added to a page through a process called “enqueueing”, where the script is first registered and then enqueued.
To remove these scripts you have to deregister them using wp_deregister_script. This takes them out of the queue. The script takes a “registered name”, which can be hard to come by.
wp_deregister_script('script_name');
I usually wrap all my wp_deregister_script calls in a single function rather than calling each individually.
function remove_unwanted_scripts () {
// I remove all the unwanted scripts WordPress is determined to load.
wp_dequeue_style( 'style_name_1' );
wp_dequeue_style( 'style_name_2' );
..
}
add_action( 'wp_enqueue_scripts', 'remove_unwanted_scripts');
Adding the code to your site
Any code to changes the headers should go in your site plugin or functions.php file outside of any functions, although you can wrap it in logic. For example, you might only want to load the emoticons when someone has edit rights. The priority is usually set to a high number to ensure you trigger remove_action after add_action. Otherwise it has no effect.
Words of caution
Functions are linked to specific actions. You must have the same combination of action and function as used to connect them together. If you don’t, WordPress ignores your instruction.
Also, be wary of removing things. You can break your site if you remove too much, or if a plugin or theme updates and suddenly requires the scripts and functions you’ve removed.
How to remove emoticons.
The lowest hanging fruit is emoticon support. If you’re not accepting comments or don’t want smiley faces plastered across web pages, you can remove these.
There are two parts to this: an embedded set of styles, and embedded JavaScript. Both have to be removed.
remove_action('wp_head', 'print_emoji_detection_script',10);
remove_action('wp_print_styles', 'print_emoji_styles',10);
Disable the REST API
The REST API lets external apps access the content on your site, either to update show it. An example could be if you have a mobile app that lets people buy from your Woocommerce site.
From a security standpoint, it’s a good idea to switch it off if you’re not using REST. Remember some plugin and theme developers use it, which may stop functionality from working. If this happens, you can either select a different product, or switch it on.
remove_action('wp_head', 'rest_output_link_wp_head',10);
Remove JQuery
JQuery is a library of Javascript tools and functions often used by WordPress developers to simplify coding. Most themes and plugins, and the Gutenberg editor, use JQuery.
However, there is a growing movement to remove JQuery from websites because it takes up unnecessary resources. For example, on this site JQuery is used for one specific purpose for visitors – lazy loading the images.
Removing JQuery requires the following code.
wp_deregister_script('jquery');
For Gutenberg users
WordPress 5 introduced the controversial “Gutenberg” editor. It also introduced yet more resources to load, some of which are less than useful.
Disable external editors
WordPress lets you manage your content using tools other than Gutenberg. These work through two interfaces called RSD and WLW. If you’re only using Gutenberg you can remove both.
remove_action('wp_head', 'rsd_link',10);
remove_action('wp_head', 'wlwmanifest_link',10);
Remove inline styling
Gutenberg introduced “inline styling” into the editor. You can add all manner of “tweaks” to your content, from changing font sizes to colors and backgrounds. All exciting new ways to break your brand and create headaches for months or years down the line.
These tweaks are added to individual web pages using inline styles: additional CSS inserted into the head of the page.
To remove it, you need to dequeue “global-styles”.
wp_dequeue_style( 'global-styles' );
Remove Block Libraries
Gutenberg also introduced “blocks”, and came with a collection of default stylings. This loads yet another stylesheet, and can have some unexpected consequences if you’ve defined your own styles.
If you’re confident you’ve styled all the blocks you’ll ever need, you can remove this as well.
wp_dequeue_style('wp-block-library');
Canonical and short links
A “canonical link” tells a search engine which URL is the preferred one when indexing the page. This is useful if the page is a duplicate, or can be accessed through different URLs. SEO plugins will usually override this functionality, so you can leave it in place. If you want to remove it, use the following code:
remove_action('wp_head', 'rel_canonical',10);
Short links are abbreviated URLs which used to be easier to share in emails or on social networks when text length was a constraint. For example, the URL to this page is <URL>, but you can also access it through <URL?id=>. I prefer to remove this.
remove_action('wp_head', 'wp_shortlink_wp_head',10);
Block embedding your content
Ombed is an open standard that embeds your content into another website. If you’ve pasted a link to Twitter in a post and seen the Tweet appear, that’s Ombed at work.
WordPress allows other people to embed your content in their sites using the same method. However, few sites use this feature, and many have restrictions in place that may even block your content from being embedded.
Disable Ombed for your site using this code.
remove_action('wp_head', 'wp_oembed_add_discovery_links',10);
remove_action('wp_head', 'wp_oembed_add_host_js',10);
Note: this doesn’t stop you from embedding Tweets, YouTube videos etc in your content.
Disable RSS Feeds
RSS feeds are a simple way of showing users what content is available on your site. Depending on their software, they might also flag when new content is available. However, they lose all the styling and branding you’ve created, may not show images, and it isn’t used widely.
I’ve disabled RSS feeds on my site using this code:
remove_action('wp_head', 'feed_links',10);
remove_action('wp_head', 'feed_links_extra',10);
Remove prefetching
Prefetching is a technique to speed up browsing when the user clicks on a link. When your page loads, the web browser looks at the links and finds the IP address of the domain. It cuts a second or two out of the delay between clicking a link and the page loading. There are some issues with this approach, not least domains inside scripts might be missed.
WordPress explicitly asks the browser to prefetch specific domains in the “dns-prefetch” tag in <HEAD>. Most of the time the only domain declared is s.w.org – the WordPress.org domain.
Remove it with this code:
remove_action('wp_head', 'wp_resource_hints',10);
Hide the WordPress Version Number
WordPress likes to broadcast which version you’re running. This can be a security issue, and it’s usually advised to suppress this information.
remove_action('wp_head', 'wp_generator',10);
Remove backward capability for JQuery
As JQuery develops, so it leaves a trail of legacy code that may not work correctly. To prevent this from crashing your site, WordPress loads a library called JQuery.migrate. As long as you’re keeping WordPress, and its themes and plugins, up to date you shouldn’t need it.
Disabling it requires more complicated code than seen previously as it has to be cleaned out of WordPress completely. The following code works on my sites, and was contributed by SwissSpidy.
function dequeue_jquery_migrate( $scripts ) {
if ( ! is_admin() && ! empty( $scripts->registered['jquery'] ) ) {
$scripts->registered['jquery']->deps = array_diff(
$scripts->registered['jquery']->deps,
[ 'jquery-migrate' ]
);
}
}
add_action( 'wp_default_scripts', 'dequeue_jquery_migrate' );
Older WordPress
There are some outliers that occasionally appear in <head>, depending on how old your version of WordPress is.
The following code removes various links to posts in <head>. If your version of WordPress is based on Gutenberg you can ignore these.
remove_action('wp_head', 'start_post_rel_link',10);
remove_action('wp_head', 'index_rel_link',10);
Robots
WordPress defines a default “robots” instruction which is applied to every page. If you want to be more nuanced and create your own robots tag, use the following to remove the default. You can also use it if you’ve installed an SEO Plugin that’s left duplicate robots tags in your code.
remove_action( 'wp_head', 'wp_robots', 1 );
Adding some logic
Removing functionality from WordPress, particularly in admin, carries the risk you’ll break something. I suggest you wrap these instructions in some logic that disables them on the public facing website and leaves them active in the administration screens.
To do this, use:
if ( !is_admin() ) :
// All the commands
endif;
Bottom line: it’ll get worse
The more plugins and blocks you add to your site, the more resources your web pages will demand. Each new .css or .js file is another file to download and a slight slowing of your site. This will impact both SEO and the usability, particularly for mobile users or those in areas with limited broadband.
You can limit the damage to some extent by removing anything you don’t need from your headers. What I’ve outlined is the basics that work on my site. You may want to experiment and find out what works best for yours.