D
P
0
← All articles Baca dalam Bahasa Indonesia

Technical SEO, Redirects & Migrations

Auditing a 3-Hop 301 Redirect Chain That Was Hiding Across Four Mechanisms

· · 4 min read
Auditing a 3-Hop 301 Redirect Chain That Was Hiding Across Four Mechanisms

A high-traffic URL on a WordPress site I maintain started throwing a warning in the crawl report: one page was going through three back-to-back 301s before it landed.

/podcasts  →  /resources/  →  /podcast  →  /podcast/

Four hops, three redirects. Over 9,000 hits ran through this chain. Bad for SEO (link equity bleeds at every hop), bad for crawl budget, and slow for users. The site owner already had a theory: "There's no redirect plugin, so it must be .htaccess." The reasoning was simple: the owner couldn't find a redirect menu where one was expected to live.

That theory was wrong. And that mistake is the single most important lesson from this incident: redirect chains almost always have multiple owners.

Why everyone blames .htaccess first

.htaccess is the obvious suspect because it's one readable text file. But on a modern WordPress install, redirects can come from several places at once, and some of them don't appear under the Settings menu at all:

A chain forms when one mechanism's target is itself redirected by another. For example: the Redirection plugin sends /podcasts to /resources/; but /resources/ is an old page whose slug was once changed to podcast, so _wp_old_slug bounces it to /podcast; then core canonical appends the trailing slash to /podcast/. Three different owners, one chain.

Audit EVERY source before you touch anything

Before agreeing with the "it's .htaccess" theory, I audited every source that could possibly own a redirect:

  1. Tools menu → Redirection (the Redirection plugin)
  2. SEO menu → Rank Math → Redirections
  3. wp_options: permalink settings and plugin options
  4. _wp_old_slug post meta: each post's old-slug history
  5. .htaccess: manual mod_rewrite rules
  6. Theme functions.php: home-grown wp_redirect() / template_redirect hooks

Rule #1: map every hop to its owner before changing a single thing.

You can read the Redirection plugin's rules through its REST API without opening the UI:

# Read all Redirection plugin rules
curl -s "https://your-site.com/wp-json/redirection/v1/redirect" \
  -H "X-WP-Nonce: <nonce>" --cookie "wordpress_logged_in_..."

Rank Math's rules have to be edited in its UI (there's no convenient read endpoint), so open SEO → Redirections manually.

For _wp_old_slug, check the database directly:

SELECT post_id, meta_value
FROM wp_postmeta
WHERE meta_key = '_wp_old_slug';

Fix at the SOURCE of each hop instead of stacking new redirects

The biggest temptation when you see /podcasts land on /podcast/ is to create one new rule: /podcasts → /podcast/. Don't. That just adds a fifth owner and leaves the old three hops alive for other URLs.

The right move: for each hop, identify the mechanism that owns it, then fix it at the source of that intermediate hop so the chain collapses to a single 301:

Verify: one hop, not three

After fixing, prove the chain actually collapsed to a single 301. From the browser:

// .url is the final URL after all redirects are followed
fetch("https://your-site.com/podcasts", { redirect: "follow" })
  .then(r => console.log(r.url));

Or count the 301s from the command line:

# -I header only, -L follow redirects, -s silent
curl -sIL "https://your-site.com/podcasts" | grep -i "^HTTP\|^location"

What you want to see: exactly one 301 line, then 200. If you still see two or three 301s, there's a hop whose owner you haven't fixed yet.

Checklist for when you find a redirect chain

  1. Don't trust "there's no redirect plugin." Check the Tools menu and the SEO menu, not just Settings.
  2. Map every hop to its owner: Redirection, Rank Math, core canonical, _wp_old_slug, .htaccess, functions.php.
  3. Read Redirection rules via the REST API (/wp-json/redirection/v1/redirect); Rank Math via the UI.
  4. Fix at the source of the intermediate hop so the chain collapses to a single 301. Don't stack a new rule on top.
  5. Verify with fetch(...).url or curl -sIL and confirm there's only one 301.

The lesson: redirect chains are usually multi-owner. Never assume there's a single source. Map every hop to its owner first, and only then should you touch anything.