TechEarl

Clean Up wp_head in WordPress: Remove the Header Bloat

What WordPress prints in wp_head by default, which tags and scripts are safe to remove, and one must-use plugin that strips the emoji, shortlink, feed, oEmbed, and version bloat in one place.

Ishan Karunaratne⏱️ 12 min readUpdated
Share thisCopied
What WordPress outputs in wp_head by default, which tags and scripts are safe to remove, and a single must-use plugin that strips the emoji, shortlink, feed, oEmbed, and generator bloat.

To clean up wp_head, remove the default emoji script, shortlink tag, feed links, oEmbed discovery links, version meta, and RSD link with remove_action() in a must-use plugin, keeping only what your site actually uses.

A default WordPress install prints a surprising amount into the <head> that a given site never uses: emoji detection scripts, a shortlink tag, RSS feed links, oEmbed discovery links and a script, a version <meta>, and more. None of it is huge on its own, but it adds up to output you are shipping to every visitor for features most sites do not need. Cleaning it up is standard housekeeping on any WordPress build I do.

This is the overview. Each item below has a focused article with the full snippet, the gotchas, and the verification steps; here I want to show you the whole picture at once, be honest about what it does and does not buy you, and give you one must-use plugin that does the lot.

What WordPress prints in wp_head, and what is safe to remove

Here is the default output worth knowing about, what each piece is for, and whether removing it is safe on a typical site.

OutputWhat it is forImpactSafe to remove?
Emoji detection script + stylesPolyfill so old browsers render emojiBytes onlyYes, modern browsers render emoji natively
rel=shortlink tag + Link: headerThe ?p=123 short URLBytes onlyYes, almost nothing consumes it
Feed <link> tagsRSS/Atom discoveryBytes onlyOnly if you do not publish feeds
oEmbed discovery links + wp-embed.jsLets other sites embed your postsBytes onlyYes, keep the consumer, drop the provider
<meta name="generator">Advertises the WordPress versionBytes onlyYes, but it is cosmetic, not security
RSD / EditURI linkXML-RPC client discoveryBytes onlyYes, if you do not use XML-RPC clients
Dashicons stylesheetAdmin icon fontReal requestYes, for logged-out visitors only
jQuery MigrateCompatibility shim for old jQuery codeReal requestOnly if nothing on the site needs it

The pattern across all of them: WordPress ships these on by default for the widest-possible compatibility, and most individual sites use none of them. The job is to remove what your site does not need, not to blindly strip everything.

One thing the head also prints that you must not remove: the canonical tag (rel_canonical) is load-bearing for SEO, so leave it in place; the prev/next adjacent-post links (adjacent_posts_rel_link_wp_head) are the safe ones to drop if you do not want them.

How much does cleaning up wp_head actually save?

I will be straight, because a lot of "speed up WordPress" content oversells this. Most of these items are bytes, not requests. Removing the emoji script, the shortlink, the feed tags, the oEmbed links, and the version meta together trims a few KB of head output and a little main-thread parse time. No single Lighthouse metric will jump.

The two items that are real requests, and therefore the only ones with a measurable page-speed effect, are the Dashicons stylesheet (if your site loads it for logged-out visitors) and jQuery Migrate (if it is being enqueued). Everything else is tidiness, reduced attack surface, and crawl hygiene rather than load time.

So why bother? Because a clean head is easier to audit, the removed feed and /embed/ URLs stop wasting crawl budget on thin duplicate pages, and you take genuinely unused features off the site. It is the right baseline. But if the site is slow, the head is not your problem. Caching, image sizing, and your slowest plugins and queries are, which is why this guide links out to the real WooCommerce speed levers and to tracking down ACF query bloat at the end. Clean the head because it should be clean; fix the database because that is what makes the site fast.

The five cleanups, each with its own guide

These are the focused articles. Read the one you need for the full code, the priority gotchas, and the verification.

  • Disable WordPress emojis. Removes the emoji detection script, the polyfill, and the inline styles. The classic first cleanup.
  • Remove the shortlink. Drops the rel=shortlink tag and the matching Link: HTTP header (the part most snippets forget).
  • Remove feed links. Strips the RSS/Atom discovery tags, and optionally kills the /feed/ rewrite rules and redirects the URLs.
  • Disable oEmbed. Turns off the provider (discovery links, wp-embed.js, REST route, /embed/ URLs) while keeping your pasted YouTube and Twitter embeds working.
  • Disable Dashicons on the front end. Dequeues the admin icon font for logged-out visitors, the one item here that removes a real CSS request.

A few more worth knowing (briefly)

These do not each need a full article, but they belong in the same cleanup pass.

The version meta. WordPress prints <meta name="generator" content="WordPress 6.x"> in the head. Remove it with:

php
remove_action( 'wp_head', 'wp_generator' );

Be honest about why, though: this is cosmetic, not a security measure. The version leaks in plenty of other places (the ?ver= query string on core CSS and JS, readme.html, the REST API), so removing one <meta> tag does not hide your version from anyone determined. Remove it for tidiness, not because it hardens anything. For the full set of places the version shows up and how to handle the asset query strings without breaking your cache-busting, see removing the WordPress version number.

The RSD / EditURI link. This is the XML-RPC client-discovery link:

php
remove_action( 'wp_head', 'rsd_link' );

Note that its old companion, the Windows Live Writer manifest link (wlwmanifest_link), was removed from WordPress core in 5.6 (November 2020), so on any modern install you no longer need to remove it; it is already gone. The RSD link is still emitted today, and you can drop it if you do not use XML-RPC desktop clients.

The REST API discovery link. WordPress prints a <link rel='https://api.w.org/'> tag (via rest_output_link_wp_head) plus a matching Link: HTTP header (via rest_output_link_header) so clients can discover the REST API. You can remove both:

php
remove_action( 'wp_head', 'rest_output_link_wp_head' );
remove_action( 'template_redirect', 'rest_output_link_header', 11 );

Be honest about what this does: it only hides the discovery hint. It does not disable the REST API, which still answers at /wp-json/. If your goal is locking down the API, this is cosmetic; you need real REST authentication or endpoint restrictions, not a removed <link>.

jQuery Migrate. WordPress loads jquery-migrate as a compatibility shim for themes and plugins still using jQuery APIs removed years ago. If nothing on the site needs it, you can stop it loading:

php
add_action( 'wp_default_scripts', function ( $scripts ) {
    if ( ! is_admin() && isset( $scripts->registered['jquery'] ) ) {
        $scripts->registered['jquery']->deps = array_diff(
            $scripts->registered['jquery']->deps,
            array( 'jquery-migrate' )
        );
    }
} );

This one needs testing, because removing Migrate breaks any code relying on the old APIs it patches. Load the site with the browser console open and watch for jQuery errors before you keep it. The full jQuery Migrate guide covers how to spot the JQMIGRATE deprecation warnings and confirm it is safe to drop.

The block-library CSS. Gutenberg enqueues wp-block-library on the front end. You will see advice to dequeue it for speed, but be careful: if your content uses any block markup (most sites do now), removing it breaks block layout. Only consider it on a site whose front end genuinely uses no blocks, and verify visually. For most sites, leave it. I walk through exactly which handles to dequeue and when it is actually safe in removing the wp-block-library CSS.

One must-use plugin that does the lot

Rather than scatter these across functions.php, I keep the whole cleanup in a single must-use plugin. Drop this into wp-content/mu-plugins/te-wp-head-cleanup.php. It loads automatically, before regular plugins, and survives theme switches:

php
<?php
/**
 * Plugin Name: TE wp_head Cleanup
 * Plugin URI:  https://techearl.com/clean-up-wordpress-wp-head
 * Description: Trims the default WordPress head bloat: emojis, shortlink, feeds, oEmbed provider, version meta, and RSD link.
 * Version:     1.0.0
 * Author:      Ishan Karunaratne
 * Author URI:  https://techearl.com
 * License:     GPL-2.0-or-later
 * Text Domain: te-wp-head-cleanup
 */

add_action( 'init', function () {
    // Emojis.
    remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
    remove_action( 'wp_print_styles', 'print_emoji_styles' );
    add_filter( 'emoji_svg_url', '__return_false' );

    // Shortlink: the head tag and the HTTP header.
    remove_action( 'wp_head', 'wp_shortlink_wp_head', 10 );
    remove_action( 'template_redirect', 'wp_shortlink_header', 11, 0 );

    // oEmbed provider: discovery links and wp-embed.js (keep pasted embeds working).
    remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );
    remove_action( 'wp_head', 'wp_oembed_add_discovery_links', 4 ); // WordPress 6.9+
    remove_action( 'wp_head', 'wp_oembed_add_host_js' );

    // Version meta and the RSD link.
    remove_action( 'wp_head', 'wp_generator' );
    remove_action( 'wp_head', 'rsd_link' );
}, 9999 );

// Dashicons: drop only for logged-out visitors (the admin bar needs it).
add_action( 'wp_enqueue_scripts', function () {
    if ( ! is_user_logged_in() ) {
        wp_dequeue_style( 'dashicons' );
        wp_deregister_style( 'dashicons' );
    }
}, 100 );

I have left the feed-URL removal and the /embed/ redirect out of this combined file on purpose, because both touch rewrite rules and need a flush, and both depend on decisions specific to your site (do you publish feeds? do you want /embed/ redirected?). Add those from the feed links and oEmbed articles if you want them. This base plugin is the safe, no-flush-needed core of the cleanup.

Why a must-use plugin and not the theme

The same reason it applies to every snippet here: theme code disappears when you switch themes, and rediscovering why a tag came back six months later is a waste of an afternoon. Files in wp-content/mu-plugins/ load automatically, cannot be deactivated from the dashboard by accident, and survive theme changes. For a developer-controlled site that is exactly the behaviour you want for infrastructure-level tweaks like head cleanup. The same logic is why I keep the emoji disable in a must-use plugin rather than functions.php.

Verify the whole thing

After activating, hard-refresh a single post in a logged-out (incognito) window and grep the source for the usual suspects:

text
$ curl -s https://example.com/sample-post/ | grep -iE 'emoji|shortlink|oembed|generator|dashicons|application/rss'
(no output)

An empty result means the head is clean. Then check the HTTP headers for the shortlink one:

text
$ curl -sI https://example.com/sample-post/ | grep -i 'rel=shortlink'
(no output)

If anything survives, the usual causes are a page cache serving old HTML (purge it), a missed hook priority (the shortlink header at 11 and the oEmbed discovery link at 4 on WordPress 6.9+ are the two that bite), or a plugin re-adding output after your init callback runs.

See also

Sources

Authoritative references this article was fact-checked against.

TagsWordPressPerformancePHPwp_headPage Speedfunctions.php

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts

AI for WordPress SEO: The Playbook

The SEO-role playbook for AI on WordPress sites: internal link audits, schema generation, content-gap analysis, redirect audits, title/meta rewrites, technical SEO triage, and AI-search citability. Plus what stays human.