TechEarl

Remove the WordPress Version Number (Generator Tag and Asset Query Strings)

How to remove the WordPress version number: drop the generator meta tag (and the version from feeds), why hiding it is housekeeping not security, and how to handle the ?ver= query string on core assets without breaking cache-busting.

Ishan Karunaratne⏱️ 10 min readUpdated
Share thisCopied
How to remove the WordPress version number: drop the generator meta tag and the version from feeds, and handle the core ?ver= asset query string without breaking your own cache-busting.

To remove the WordPress version number from the front end, drop this into your theme's functions.php (or, better, a small site-specific plugin). It strips the <meta name="generator"> tag from wp_head and blanks the version out of the feeds in one go:

php
add_action( 'init', function () {
    remove_action( 'wp_head', 'wp_generator' );
    add_filter( 'the_generator', '__return_empty_string' );
} );

The remove_action() line drops the <meta> tag from the page head. The the_generator filter blanks the generator string everywhere else it surfaces, which matters because the version is also emitted into your RSS and Atom feeds, not just the HTML head. That is the whole fix for the parts that are actually under your control.

What WordPress actually advertises

On a clean install, wp_generator() is hooked to wp_head at the default priority 10 and prints a single line into the front-end <head>:

text
<meta name="generator" content="WordPress 6.8" />

That is the headline leak, the one every "hide your WordPress version" guide goes after. But the version number turns up in more places than the head:

  • The feeds. the_generator runs for RSS, Atom, RDF, and the comment feeds too. View-source on /feed/ shows a <generator>http://wordpress.org/?v=6.8</generator> element. Removing the wp_head action alone leaves this untouched, which is exactly why the snippet above also filters the_generator.
  • The ?ver=X.Y query string appended to WordPress's own bundled CSS and JS (/wp-includes/css/dist/block-library/style.min.css?ver=6.8, and friends). That version comes straight from the core release number.
  • /readme.html, which ships with every install and prints the major version near the top.
  • The login screen and various other fingerprints that have nothing to do with the head.

So the generator meta tag is one signal among many. Strip it and you have tidied the most visible one; you have not made the version a secret.

How to find your current WordPress version

Before you hide it, it helps to see everywhere it shows. A few quick checks:

  • View-source on the front page and search for name="generator", the meta line covered above.
  • /readme.html at your site root prints the major version near the top.
  • ?ver= on core assets, e.g. /wp-includes/css/dist/block-library/style.min.css?ver=6.8, where the query value is the core release number.
  • WP-CLI: wp core version (add --extra for the build and locale) reports it from the server side.

Does hiding the WordPress version improve security?

No. Hiding the version is not a real security control, and it is worth being blunt about that because it is the reason most people land on this page. The generator meta tag is one fingerprint among many: the version still leaks via the ?ver= strings on core assets, /readme.html, the feeds, the REST API, and core asset hashes. Anyone running an actual scanner reconstructs it in seconds, so blanking the meta tag is security-by-obscurity, and a thin version of it.

The protection that actually matters against version-targeted exploits is keeping WordPress (core, plugins, and themes) updated. A hidden generator on an unpatched install is still an unpatched install, just one that makes an attacker spend an extra few seconds confirming what it is running. Remove the tag for tidiness and to deny a trivial signal to lazy scanners, not because it hardens anything.

How much does this actually save?

Nothing, in performance terms, and I want to be straight about that before you spend any time on it. The generator tag is a single short line of HTML. Removing it does not save a request, does not save measurable bytes, and will not move any Lighthouse metric. This is not a speed optimization.

It is also not a security control, and this is the part that gets oversold the hardest. You will read that hiding the version "protects you from hackers who target old WordPress installs." That framing is wrong in two ways. First, the version leaks in so many other places (the ?ver= strings, readme.html, the feeds, asset hashes) that anyone running a real scanner reconstructs it in seconds; security-by-obscurity barely slows them. Second, the actual protection against version-targeted exploits is keeping WordPress updated, not making people guess which version you neglected to patch. A hidden generator on an out-of-date install is still an out-of-date install.

So why do it at all? Two honest reasons. It is tidiness: a clean head and clean feeds are easier to audit, and the version number serves no visitor. And it denies a trivial fingerprint to lazy, low-effort scanners that only check the obvious meta tag and move on if it is missing. That is the whole value proposition. Treat it as housekeeping, file it alongside the rest of the wp_head cleanup pass, and do not kid yourself that it hardened anything.

Put it in a plugin, not the theme

The snippet works in functions.php, but I do not keep it there. Theme code vanishes the moment you switch themes, and "why is the version number back?" is an annoying thing to rediscover six months later. Drop this file into wp-content/mu-plugins/te-remove-version.php instead. Must-use plugins load automatically, before regular plugins, and survive theme switches:

php
<?php
/**
 * Plugin Name: TE Remove Version Number
 * Plugin URI:  https://techearl.com/remove-wordpress-version-number
 * Description: Removes the WordPress generator meta tag and the version string from feeds, and strips the core ?ver= from bundled assets.
 * Version:     1.0.0
 * Author:      Ishan Karunaratne
 * Author URI:  https://techearl.com
 * License:     GPL-2.0-or-later
 * Text Domain: te-remove-version
 */

add_action( 'init', function () {
    // The generator <meta> in the head, and the version in every feed type.
    remove_action( 'wp_head', 'wp_generator' );
    add_filter( 'the_generator', '__return_empty_string' );
} );

// Strip the core WordPress version from bundled CSS/JS query strings, but
// leave any other ?ver= alone (your own asset versioning stays intact).
$strip_core_ver = function ( $src ) {
    global $wp_version;
    if ( $src && strpos( $src, 'ver=' . $wp_version ) !== false ) {
        $src = remove_query_arg( 'ver', $src );
    }
    return $src;
};
add_filter( 'style_loader_src', $strip_core_ver, 9999 );
add_filter( 'script_loader_src', $strip_core_ver, 9999 );

The first block is the head and feed fix. The second block is the careful part, and it is worth reading before you ship it.

If you do not write PHP, you can get the same generator removal without touching code: a code-snippet plugin (WPCode and similar) lets you paste the first block as a managed snippet, and several security plugins ship a one-click toggle for "remove WordPress version" that does the same wp_generator removal under the hood. Just know that the toggle usually only covers the meta tag, not the feeds or the core ?ver=, so it is a partial version of what the snippet above does.

The ?ver= query string: be careful here

The version on bundled assets (?ver=6.8) is a real leak, and the obvious move is to strip every ?ver= you see. Do not do that. Versioning your own CSS and JS is genuinely useful: a changing ?ver= (ideally filemtime() of the file, so it bumps automatically on every edit) is how you cache-bust an updated stylesheet without renaming the file. Blanket-stripping every query string throws that away and leaves visitors staring at a stale cached stylesheet after your next deploy.

The closure above threads the needle: it only removes ver when its value equals the running $wp_version, so core's bundled assets lose the version while your theme's and plugins' own versioning is left completely alone. That is the version-leak fix without the cache-busting regression.

One trade-off to state plainly: WordPress core uses that same ?ver= as its own cache-buster, so stripping it from core assets means a core minor update can briefly serve a returning visitor stale cached core CSS or JS (their browser keeps the old, query-less URL until its cache expires). It is a non-issue for most sites (core CSS/JS rarely changes in a way a visitor would notice, and the cache turns over), but it is the price of removing the core version, so weigh it before you ship.

While we are here, kill an old myth. You will still find "remove query strings from static resources to speed up your site" in 2015-era speed guides, usually as a GTmetrix recommendation. That advice is obsolete. It came from old forward proxies and a handful of CDNs that refused to cache any URL containing a ?, so a ?ver= string meant the asset was re-fetched every time. Modern CDNs (Cloudflare, Fastly, every current edge) cache query-stringed URLs without blinking. Stripping ?ver= buys you no speed today. Strip the core version string for the fingerprint reason if you like, but do not present it as a performance win, because it is not one.

Verify it worked

After adding the snippet, hard-refresh the front page in a logged-out window and check the head:

text
$ curl -s https://example.com/ | grep -i 'name="generator"'
(no output)

No output means the meta tag is gone. Then check a feed, the bit most snippets miss:

text
$ curl -s https://example.com/feed/ | grep -i 'generator'
(no output)

And confirm the core assets no longer carry the version, while your own versioning survives:

text
$ curl -s https://example.com/ | grep -oE '\.(css|js)\?[^"]*ver=[^"& ]*'
(your own theme/plugin ?ver= values, but no ?ver=6.8 on /wp-includes/ files)

If the version still shows up, the usual causes are a page cache serving old HTML (purge it), or a plugin re-adding the generator on a hook that runs after your init callback. On the asset side, remember the version also feeds Lighthouse's "serve static assets with an efficient cache policy" check; removing it does not change caching behaviour, only what the URL advertises.

See also

Sources

Authoritative references this article was fact-checked against.

TagsWordPressPerformancePHPfunctions.phpSecurity

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