WP 301 Redirects: Doing It Right in WordPress

wp 301 redirects

Handling wp 301 redirects looks like a solved problem — install a plugin, paste two URLs, done. It usually is. But WordPress gives you three different places to put a redirect rule, they interact badly, and the choice matters a lot once you pass a few hundred rules or start a real migration.

A 301 tells search engines a URL has moved permanently, so ranking signals consolidate onto the destination. WordPress makes those changes constantly: you rename a post slug, restructure categories, switch permalink formats, or merge two thin articles. Every one of those actions strands a URL that people and crawlers still request.

Where WordPress lets you put redirects

Three layers, in order of how early they run:

  • Server config.htaccess on Apache, or the nginx server block. Runs before PHP starts. Fastest by a wide margin.
  • Plugin — rules stored in the database, applied during the WordPress request lifecycle.
  • Theme or custom code — a template_redirect hook in functions.php. Flexible, and the easiest to forget about later.

The performance gap is real. A server-level redirect costs a few milliseconds and no database queries. A plugin redirect boots WordPress, loads plugins, queries the database, and only then sends the header. On a busy site with thousands of legacy URLs, that difference shows up in your crawl rate and your response times.

Built-in behavior you already have

Before adding anything, know that WordPress redirects on its own. Change a post’s slug and WordPress stores the old one as _wp_old_slug post meta, then redirects the old URL to the new one automatically. This works for posts and pages, and it is why some slug changes never seem to break anything.

It has limits. It does not cover category or tag slug changes, permalink structure changes, deleted posts, or anything outside the post type system. WordPress also has a “guess” behavior that redirects near-miss URLs to the closest match, which is helpful for typos and occasionally sends someone somewhere strange.

Do not build a strategy on it. The old-slug redirect only survives as long as that post meta does, and bulk database cleanups, migrations between hosts, and some optimization plugins delete it. If a URL matters — it has backlinks, or it ranks — record the mapping somewhere you control rather than trusting an automatic behavior you cannot inspect from the admin screen.

Plugin route: when it is the right call

For most sites, a redirect plugin is correct. Editors can add rules without touching a config file, you get a log of 404s to work from, and the rules are visible in the admin instead of buried in a file nobody opens.

Redirection remains the most widely used option and is free; Rank Math and Yoast Premium both include redirect managers, which is convenient if you already run one of them. Whichever you pick, use the features that matter: bulk CSV import for migrations, 404 logging so you can find broken URLs from real traffic, and regex support for pattern-based rules.

Where plugins start to hurt is scale. Several thousand rules evaluated in PHP on every request is a measurable tax, and some plugins store 404 logs indefinitely until the table is tens of millions of rows and your database backups take an hour. Cap the log retention on day one.

There is a subtler cost too. Plugin redirects run inside PHP, which means they are usually bypassed by full-page caching — the cache serves the old URL directly and the redirect never fires, or the cache stores the redirect response and serves it to everyone. Both behaviors surprise people. If you run a page cache, test your redirects as an anonymous visitor with a cold cache, not while logged into wp-admin.

Server route: for migrations and large maps

When you are moving a whole site or handling more than a few thousand rules, put them in the server config. On Apache, keep custom rules above the # BEGIN WordPress block — anything inside that block is rewritten whenever you save permalinks, and your rules will vanish silently:

# Custom redirects — keep above the WordPress block
Redirect 301 /old-post/ https://example.com/new-post/

RewriteEngine On
RewriteRule ^old-category/(.*)$ /new-category/$1 [R=301,L]

# BEGIN WordPress
# ...

On nginx — which many managed WordPress hosts run — .htaccess is ignored entirely. Rules go in the server block and need a config reload, which usually means a support ticket on managed hosting. Factor that turnaround into your migration schedule.

The loops WordPress causes

Redirect loops on WordPress have a short list of usual suspects, and the “too many redirects” error almost always traces to one of them.

The first is a site URL mismatch. Settings → General must have the WordPress Address and Site Address matching exactly what your server enforces — same protocol, same www or non-www. If the server forces HTTPS and the setting says http://, you get an infinite bounce. Locked out of admin? Set them in wp-config.php:

define('WP_HOME', 'https://www.example.com');
define('WP_SITEURL', 'https://www.example.com');

The second is a CDN SSL mismatch — Cloudflare on “Flexible” SSL requesting your origin over HTTP while the origin redirects HTTP to HTTPS. Set SSL to Full or Full (Strict).

The third is two systems owning the same URL: a plugin rule and an .htaccess rule both firing on the same path, each pointing at the other’s source. Pick one layer per migration and stick to it.

A migration sequence that holds up

  1. Crawl the existing site and export every URL before you change anything.
  2. Pull the top URLs by clicks from Search Console over the last twelve months, and the URLs with external backlinks. Those get hand-checked mappings.
  3. Build the old-to-new map in a spreadsheet, mapping each URL to its closest genuine equivalent. Redirecting hundreds of retired pages to the homepage is treated as a soft 404 and passes nothing — use 410 where there is no equivalent.
  4. Import in bulk, either via the plugin’s CSV import or as generated server rules.
  5. Save permalinks once after the change so WordPress regenerates its rewrite rules.
  6. Test, then update internal links so your own navigation points at final URLs rather than through redirects.

Testing every rule you add

Do not verify redirects in a browser. Browsers cache 301 responses hard and will show you behavior the server stopped sending days ago. Ask the server:

curl -sIL https://example.com/old-post/ | grep -E "HTTP/|location"

One 301 followed by one 200 is correct. Two 301s is a chain. A 302 means the plugin defaulted to temporary — check its settings, because some do.

At scale you need a crawler that follows every hop across the whole site, since chains and loops are invisible one URL at a time. SEO Rocket’s technical audit crawls full sites — verified past 900 pages — and reports evidence per issue instead of a count: the exact URLs, redirect targets, titles, and tags, so you can trace a bad rule back to its source. It does not install plugins, deploy redirects, or edit your server config. It also pairs PageSpeed and Core Web Vitals lab metrics with real-user field data, which is where the latency of PHP-level redirects becomes visible.

After launch, expect a dip. Traffic commonly softens for two to four weeks while Google recrawls and reassigns signals, and daily movement of two or three positions in that window is normal noise. Keep the redirects permanently — old links keep sending real people long after Google has finished re-indexing.