· Updated

WordPress Links Not Working After a Migration? Fix Them

Migrated WordPress links not working? Fix permalinks, URLs, and redirects, then find every remaining broken link.

Quick fix: start with the symptom you have

If all internal WordPress links started returning 404s after a migration, go to Settings → Permalinks and click Save Changes. That flushes WordPress’s rewrite rules and is the fastest fix for the common “homepage works but every post or page 404s” problem. Clear any site or host cache afterwards, then test an old post in an incognito window.

If that does not fix it, use this quick diagnosis before changing anything else:

What you see Most likely cause Fix first
Homepage works, but posts and pages 404 Permalinks or server rewrite rules were not rebuilt Save Permalinks; then check .htaccess or nginx rewrite rules
Links send visitors to the old domain home, siteurl, or hardcoded URLs still use the old domain Update WordPress URLs and run a serialization-safe search-and-replace
Images are broken but pages load Upload paths or old media URLs did not move cleanly Verify wp-content/uploads, then replace old media URLs
Only old bookmarks and backlinks 404 Old URL structure changed Add permanent 301 redirects from each old path or pattern
Pages work but assets show security warnings Old http:// URLs remain after moving to HTTPS Replace insecure URLs and clear caches

Just migrated a WordPress site? Run a free broken-link check with SitesRadar to scan its internal links, SSL, and DNS health before you hand it back to the client. No signup required.

Start here: what’s actually broken

You moved a WordPress site — new host, new domain, or you changed the permalink structure — and now links are 404ing. Before you touch anything, figure out which kind of broken you’re dealing with, because the fix is different for each:

  • Internal links 404ing (blog posts linking to other pages on the same site): almost always a permalink structure change or a domain change with unmigrated hardcoded URLs.
  • Images and media not loading: usually a path mismatch — the wp-content/uploads structure didn’t move cleanly, or URLs are still pointing at the old domain.
  • External links to your site are dead (backlinks, bookmarks, search results): the URL structure changed and there’s no redirect mapping old paths to new ones.
  • Mixed content warnings / broken assets over HTTPS: leftover http:// references in content or settings after moving to SSL.

Each of these has a specific cause and a specific fix below. Skip to the section that matches what you’re seeing, but read the “why” section first if you have a few minutes — it’ll save you from fixing the same problem twice.

WordPress builds URLs from a permalink setting (Settings → Permalinks), and it’s easy to end up with a different structure after a migration — especially if a new host or new theme setup wizard reset it, or if you deliberately changed from /?p=123 to /%postname%/ or restructured categories into the URL. Every internal link that was hardcoded to the old pattern (as opposed to generated dynamically by WordPress functions like the_permalink()) breaks immediately, and so does every external bookmark or backlink pointing at the old paths.

Domain changes

Moving from a staging subdomain to a live domain, or from an old domain to a new one, is the single biggest cause of migration link rot. WordPress stores the site URL in two places — siteurl and home in the wp_options table — but that’s not the whole story. Content authored in the classic editor or Gutenberg often contains hardcoded absolute URLs: a link typed as https://oldsite.com/services instead of a relative /services. Changing the options table doesn’t touch those; they’re baked into wp_posts.post_content as literal text, and they’ll keep pointing at the old domain until someone does a search-and-replace across the database.

Media and upload path mismatches

The wp-content/uploads directory is organized by year and month (/uploads/2024/03/photo.jpg), and image URLs in your content reference that exact path — often as an absolute URL, not a relative one. If the migration didn’t preserve the folder structure exactly, or if you moved to a new host with a different uploads path (some managed hosts remap this), every image reference embedded in old posts breaks even though the files themselves may have transferred fine.

Mixed content after adding HTTPS

If the migration included moving to HTTPS (common when switching hosts, since many now provision SSL automatically), any content still referencing http:// URLs for images, scripts, or embeds will either 404, get blocked by the browser as mixed content, or silently downgrade security warnings in the console. This is separate from broken links technically, but it shows up in the same symptom bucket: things not loading that should.

Guessing which pages are affected wastes hours. You want a full inventory before you start fixing anything, because search-and-replace and redirects both work best when you know the complete scope up front.

Manual spot-checking (fine for tiny sites, unreliable at scale)

Clicking through your own nav and a handful of blog posts will catch the obvious stuff, but it won’t catch orphaned older posts, image references buried in old content, or backlinks from other sites — which are exactly the links most likely to be pointing at a URL structure that no longer exists. Treat manual checking as a sanity check, not your primary method.

Crawlers

A site crawler (Screaming Frog, Sitebulb, or similar) will walk every internal link and report status codes, which is the right tool if you want a full technical audit including redirect chains, orphaned pages, and image link status. The tradeoff is setup time and a learning curve if you haven’t used one before, and most have limits on the free tier that matter for larger sites.

If you want something lighter — no software install, just a URL and a few minutes — the free checker at SitesRadar will crawl a site’s links, SSL, and DNS health and flag what’s broken, which is a reasonable first pass to confirm scope before you decide whether a full crawler audit is warranted.

Google Search Console

Search Console’s Coverage report (under Indexing → Pages) will show you 404s that Google has actually encountered while crawling your site, which is valuable because it reflects real-world traffic and backlink patterns you might not think to check manually. It’s slower to update than a live crawl — Google needs to recrawl to notice a fix — but it’s the best signal for which broken URLs matter most in terms of search traffic and existing backlinks, so prioritize fixes here alongside whatever a crawler turns up.

Server logs (if you have access)

If your host gives you access to raw access logs, grep for 404 and look at the referrer field — it’ll tell you exactly which broken links are actually being clicked, which is useful for triaging when you have limited time and a long list of 404s to work through.

How to fix it

Once you know the scope, fix in this order: database-level content fixes first, then redirects for anything you can’t fully clean up, then manual link updates for the stragglers.

Search-and-replace URLs in the database

If the root cause is hardcoded absolute URLs — old domain, old permalink structure baked into post content — a database search-and-replace is the direct fix. Don’t do a raw SQL UPDATE with REPLACE() on wp_posts directly; WordPress serializes some data (widget settings, some plugin options) as PHP serialized arrays, and a naive string replace corrupts the length prefixes in that format and breaks the site. Use a tool that’s serialization-aware.

WP-CLI’s search-replace command handles this correctly:

# Dry run first — always
wp search-replace 'https://oldsite.com' 'https://newsite.com' --dry-run

# Then actually run it
wp search-replace 'https://oldsite.com' 'https://newsite.com' --all-tables

# If you also changed permalink structure, e.g. removing a category prefix
wp search-replace '/category-name/2024/' '/2024/' --dry-run

--all-tables matters because URLs can be embedded in options, postmeta, and some plugin tables, not just wp_posts. If you don’t have shell access to run WP-CLI, most managed hosts and plugins like Better Search Replace do the same job through a UI, with the same serialization-safety.

Back up the database before running this against production, even after a clean dry run — a dry run tells you what would change, not that every change is safe for every edge case in your specific content.

Set up 301 redirects for anything you can’t rewrite

Search-and-replace fixes your own site’s internal links, but it does nothing for external backlinks and bookmarks still pointing at the old URLs — those need a redirect. This also covers cases where you deliberately changed the permalink structure and want old URLs to keep working rather than being fully replaced everywhere.

Using the Redirection plugin (WordPress admin), you can map old-to-new patterns including wildcards, which is the easier path if you’re not comfortable editing server config directly, and it gives you a log of which redirects are actually being hit — useful for confirming you caught the traffic that matters.

If you’d rather handle it at the server level, an .htaccess example on Apache:

RewriteEngine On
RewriteRule ^old-category/(.*)$ /new-category/$1 [R=301,L]
Redirect 301 /old-page/ https://newsite.com/new-page/

Or the nginx equivalent:

rewrite ^/old-category/(.*)$ /new-category/$1 permanent;
location = /old-page/ {
    return 301 https://newsite.com/new-page/;
}

Use 301 (permanent), not 302, so search engines transfer ranking signal to the new URL rather than treating it as a temporary detour — this matters for preserving whatever SEO equity the old URLs had accumulated.

After search-and-replace and redirects, there’ll usually be a handful of links that need manual attention — links inside navigation menus, widgets, or page builder content that wasn’t touched by the database replace because it’s stored in a format the tool didn’t parse, or links that point to pages that were genuinely restructured (not just moved) and need a different destination, not just a domain swap. Go through your crawler’s report or Search Console list and update these by hand; there usually aren’t many left once the bulk fixes are done.

Preventing this on the next migration (or the next content change)

The underlying fix is to stop authoring hardcoded absolute URLs in content going forward — link internally with relative paths or WordPress’s own linking tools where possible, so a future domain or permalink change doesn’t require another database sweep. That’s a process fix, not something you can retroactively apply to years of existing posts, so the practical safety net is catching breakage early rather than preventing it entirely.

That means recurring monitoring, not a one-time check after this migration. A link check that runs on a schedule — daily or weekly, depending on how often content changes — catches new 404s from future plugin updates, theme changes, or someone accidentally deleting a page, long before a client or a search engine notices. This overlaps with the same discipline you’d use for general site health monitoring — see the client site down triage checklist for the broader picture of what to watch beyond just links, since a site that’s fully “up” can still be quietly leaking traffic and trust through broken links that nobody’s actively looking for.

For the broader practice of catching those silent homepage, metadata, DNS, and link regressions, see website change monitoring for client sites.

If you’re managing sites for multiple clients, the real cost of broken links isn’t the fix — it’s the lag between when they appear and when someone notices, often a client complaint or a drop in organic traffic weeks later. Whatever tool you use, the goal is closing that gap.

← More from the SitesRadar blog