---
title: What happens when you change a WordPress slug
description: WordPress already redirects a changed post slug automatically, no plugin needed. How it works, and the real gaps — pages, moves, media, permalink structure.
pubDate: 2026-08-08
source: https://wpproadmin.com/guides/change-wordpress-slug-redirect/
---

Most advice about a WordPress permalink redirect starts the same way: change a slug, then go install a redirect plugin before every inbound link and bookmark turns into a 404. Skip that step. For the case that trips people up the most — renaming a published post — WordPress has already done it for you. Change the slug, click Update, and core quietly remembers the old one and sends visitors from the old URL to the new one with a real 301. No plugin involved.

That's not the whole story, and the parts core leaves out are exactly where "install a plugin" advice usually starts pointing in the wrong direction. This guide shows the built-in redirect actually happening, explains the mechanism behind it, and then walks through the real gaps — verified against WordPress's own source, not guessed at — so you know precisely when the built-in behavior is enough and when it genuinely isn't.

## Watch WordPress redirect the old URL

Try it on any published post. Open it in the editor, click the permalink under the title, and change the slug — from `/blog/old-post-title/` to `/blog/new-post-title/`, say. Click Update.

<!-- screenshot: post editor permalink field open for editing, showing the slug about to be changed -->

Now visit the old URL directly, the one you just retired. Don't search for the page — type the old address into the browser, or run `curl -I` against it. WordPress doesn't 404. It answers with a 301 and lands you on the new URL.

<!-- screenshot: terminal or browser output showing a 301 response (or a browser address bar landing on the new URL) after requesting the old permalink -->

That's the entire built-in behavior in action. No setting to enable, no plugin to install first. It only took a slug change and a single click.

## How the built-in redirect actually works

The mechanism is two functions, both in WordPress core, both older than most of the redirect plugins that get recommended instead of them.

The first runs the moment you save the change. `wp_check_for_changed_slugs()` is hooked to `post_updated` (and `attachment_updated`), and it compares the new `post_name` against the one that was just overwritten. If they differ, and the post is published, it stores the previous slug in a `_wp_old_slug` post meta entry. A post can collect several of these across repeated renames, and if you ever rename it back to a slug it used before, WordPress notices and removes that stale record rather than leaving a dangling one behind — the same instinct that stops a duplicated page from silently inheriting its original's URL; see [duplicating a page in WordPress](/guides/duplicate-page-wordpress/) for what actually happens when a copy is published with a reused slug.

The second runs the moment someone hits a 404. `wp_old_slug_redirect()` is hooked to `template_redirect`, and on every 404 it checks whether the requested slug matches a `_wp_old_slug` value for a post of the right type. If it finds one, it looks up that post's current permalink and calls `wp_redirect( $link, 301 )` before WordPress ever renders the 404 template. Visitors and crawlers never see the missing page — they're redirected before the 404 fires.

Both functions have shipped in core since WordPress 4.9.3, which is why "you need a plugin for this" is such persistent, and wrong, advice for the ordinary case.

## Where a WordPress permalink redirect still needs help

Everything above is real, and it's also incomplete on purpose — `wp_check_for_changed_slugs()` explicitly limits itself. Here's what it leaves out, straight from the parts of core that decide who gets a redirect and who doesn't.

**Pages don't get this at all.** The published-post check in `wp_check_for_changed_slugs()` also excludes any hierarchical post type, and `page` is WordPress's hierarchical post type by default. Rename a page's slug and nothing gets written to `_wp_old_slug` — there's no record for `wp_old_slug_redirect()` to find later, so the old URL just 404s. The redirect function makes the same exclusion from its own side: it checks `is_post_type_hierarchical( $post_type )` before it even looks for a match, with a comment in core's source that says plainly what it's doing — "Do not attempt redirect for hierarchical post types." This is the biggest gap, because pages are exactly the URLs people are most careful about changing: top-level marketing pages, service pages, anything with external links already pointing at it. A page's real identity is its row and ID, not its slug — the same principle behind [editing a published page without taking it offline](/guides/edit-published-page-without-unpublishing/), where merging a rewrite back into the original only works because the ID and URL never move.

<!-- screenshot: editing a Page's slug in the block editor, next to a note that this rename gets no automatic redirect -->

**Moving a page to a different parent breaks its URL too, silently.** A hierarchical permalink is built from the whole ancestor chain — `/services/plumbing/` becomes `/emergency/plumbing/` if you move the page under a different parent, even though `post_name` never changed. `wp_check_for_changed_slugs()` only fires when the slug itself changes, so a pure reparenting move doesn't even trigger the check, on top of pages being excluded anyway. The path changes, nothing gets recorded, and the old URL is simply gone.

**Media file URLs never redirect, no matter what.** Renaming an attachment's slug touches its attachment *page* — the WordPress-generated page some themes build around an image — and that page does get old-slug tracking, since `attachment_updated` calls the same function. It does nothing for the actual file: the address under `/wp-content/uploads/...` that your `<img>` tags, your CDN, and every page embedding that image actually point at. That's a filesystem path, not a routed slug, and nothing in WordPress watches it for changes. Uploading a replacement image is a related but different problem — see [replacing an image in WordPress without breaking links](/guides/replace-image-wordpress-same-url/) for the full version.

**Changing the permalink structure is a different, bigger problem.** Everything above is about one post's slug. Switching Settings → Permalinks from, say, "Plain" to "Post name," or adding or removing a date prefix, rewrites the URL of every post and page on the site at once. `wp_old_slug_redirect()` only ever compares a single stored slug string against a single request; it was never built to redirect a whole site's URL pattern in one pass. That's a site migration, not a slug change, and it's out of scope here.

## When a redirect plugin is still the right call

None of this means a redirect plugin is pointless — it means the built-in behavior already covers one specific case well, and the plugin is for what's actually left over:

- **Page slugs and page moves**, since core excludes hierarchical post types entirely — this is the gap that affects the most people.
- **Permalink structure changes**, where you need to map an old URL pattern to a new one across the whole site, not one post at a time.
- **External inbound links you have to preserve on your own terms** — a marketing campaign URL, a link from someone else's site, a printed address you can't get changed, or content moving between domains — where you want a rule that isn't tied to WordPress's own slug history at all.

For the ordinary case — renaming a published post — installing something is solving a problem WordPress already solved for you in 2017. Save the plugin for the cases above, where core genuinely has nothing to offer.

## What WP Pro Admin does here

[WP Pro Admin](/) doesn't ship a slug redirect feature — we looked at building one and cut it, because for the case that matters most, core already does the right thing without asking you to install anything. The promise we do make is the same one behind [why we don't put ads in your dashboard](/no-ads/): nothing quietly changes on your site that you didn't ask for.