To remove the WordPress shortlink, drop this remove_action() block into your theme's functions.php (or, better, a small site-specific plugin). It stops the <link rel='shortlink'> tag printing in the <head> and removes the matching Link: HTTP header:
add_action( 'init', function () {
remove_action( 'wp_head', 'wp_shortlink_wp_head', 10 );
remove_action( 'template_redirect', 'wp_shortlink_header', 11, 0 );
} );That is the whole fix. The first line clears the tag from the page source; the second clears the header, which is the part most snippets on the web forget. Both have to go or you have only half-removed it.
What the shortlink actually is
The WordPress shortlink is the ?p=123 style URL that WordPress advertises for every post and page, resolving to the same content as your pretty permalink. It surfaces in two places.
First, a tag in the <head> on singular views:
<link rel='shortlink' href='https://example.com/?p=123' />Second, an HTTP response header on the same requests:
Link: <https://example.com/?p=123>; rel=shortlinkThe feature dates back to WordPress 3.0 and was meant for sharing tools and services that wanted a compact URL. In practice almost nothing consumes it now: social platforms shorten links themselves, and you are far more likely to share the real permalink. So for most sites the shortlink is two pieces of output advertising a URL you would rather people did not use, because the ?p=123 form is a second, uglier address for a page that already has a clean canonical one.
How much speed does this actually save?
Almost nothing, and I want to be honest about that up front. This is a tidiness and canonicalisation change far more than a performance one.
The head tag is a few dozen bytes. The HTTP header is a few dozen more. You are not removing a request, a stylesheet, or any JavaScript, so no Lighthouse number will move in a way you can see. What you actually get is:
- One fewer line in your page source and your response headers.
- One fewer alternate URL (
?p=123) being advertised for content that already has a canonical permalink, which is the part I care about. A site that hands out two addresses for the same page is doing duplicate-URL housekeeping it does not need to.
If you are auditing a site for a clean <head>, this belongs on the list next to disabling the emoji scripts and removing the unused feed links. If you are trying to make a genuinely slow page fast, it is not where your afternoon should go. See the broader wp_head cleanup guide for where these small wins fit, and optimising WooCommerce for the levers that actually move load time.
Put it in a plugin, not the theme
The snippet works in functions.php, but theme code vanishes the moment you switch themes, and "why did that tag come back?" is an annoying thing to rediscover later. Drop this into wp-content/mu-plugins/te-remove-shortlink.php instead. Must-use plugins load automatically, before regular plugins, and survive theme switches:
<?php
/**
* Plugin Name: TE Remove Shortlink
* Plugin URI: https://techearl.com/remove-wordpress-shortlink
* Description: Removes the rel=shortlink tag from wp_head and the matching Link: HTTP header.
* Version: 1.0.0
* Author: Ishan Karunaratne
* Author URI: https://techearl.com
* License: GPL-2.0-or-later
* Text Domain: te-remove-shortlink
*/
add_action( 'init', function () {
// The tag in the page <head> on singular views.
remove_action( 'wp_head', 'wp_shortlink_wp_head', 10 );
// The Link: <...>; rel=shortlink HTTP response header.
remove_action( 'template_redirect', 'wp_shortlink_header', 11, 0 );
} );That is the same two lines with a real plugin header on top, so it shows up in the must-use list with a name and a source rather than as an anonymous file.
If you already run a head-cleanup or SEO plugin, you probably do not need this snippet at all. Perfmatters, WPCode, and Yoast's crawl-optimization settings all expose a shortlink toggle, so flip that instead of adding code that does the same thing twice.
The priority detail people get wrong
This is the same trap as every "remove a core action" snippet, and the shortlink has two priorities to get right, not one.
WordPress registers the two callbacks like this in wp-includes/default-filters.php:
add_action( 'wp_head', 'wp_shortlink_wp_head', 10, 0 );
add_action( 'template_redirect', 'wp_shortlink_header', 11, 0 );remove_action() only matches when the priority you pass equals the priority the action was added with. The head tag is added at the default 10, so removing it works with or without the explicit 10. The header is the one that bites: it is added at priority 11, so remove_action( 'template_redirect', 'wp_shortlink_header' ) with no priority defaults to 10, does not match, and silently leaves the header in place. You strip the visible tag, think you are done, and curl -I still shows rel=shortlink. Pass the 11.
Does removing the shortlink break the ?p=123 URL?
Removing these two actions stops WordPress advertising the shortlink. It does not disable the underlying wp_get_shortlink() function or the ?p=123 URL itself, which still resolves (and should, since old shares may rely on it). That is the right behaviour: you are removing the promotion of an alternate URL, not breaking a URL that already exists in the wild. If a plugin you use genuinely wants shortlinks, leave this off for that site.
Verify it worked
After adding the snippet, hard-refresh a single post and check two things.
The page source, searched for shortlink:
$ curl -s https://example.com/sample-post/ | grep -i shortlink
(no output)And the response headers:
$ curl -sI https://example.com/sample-post/ | grep -i 'rel=shortlink'
(no output)Both empty means it is fully gone. If the header still shows up, it is the priority 11 bug above. If the tag is still there, the usual suspects are a page cache serving old HTML (purge it) or a plugin re-adding the action on a hook that runs after your init callback.
See also
- Clean Up wp_head in WordPress: the overview of every default tag, script, and link WordPress prints in the head, and which ones are safe to remove
- Disable WordPress Emojis to Speed Up Your Site: the related head-script removal, a few lines in the same must-use plugin
- Remove WordPress Feed Links: strip the RSS/Atom
<link>tags WordPress prints for feeds you do not publish - How to Optimize WooCommerce: where the real speed levers are once the cosmetic head items are ticked off
Sources
Authoritative references this article was fact-checked against.
- wp_shortlink_wp_head(): WordPress Developer Referencedeveloper.wordpress.org
- wp_shortlink_header(): WordPress Developer Referencedeveloper.wordpress.org
- remove_action(): WordPress Developer Referencedeveloper.wordpress.org





