SEO migration: 390 addresses, no lost rankings
A case study: 390 old addresses, 205 301 redirects, zero orphans. The inventory, the trap of the 210 attachment pages, and the launch checklist.

Rebuilding a site is the moment of greatest risk to traffic in a domain’s life. Not because the new design is worse, but because the addresses change and Google has an index full of addresses that suddenly no longer answer. Sites with years of accumulated authority lose half their traffic in two weeks and never fully recover it.
This article is the case study of migrating our own site, off WordPress onto a static platform. The figures are real, verified with a script that reads the original export rather than a hand-written list: 390 old addresses · 175 served directly · 205 redirected · 10 retired · 0 with no destination. It also includes the trap almost nobody spots, which on its own would have produced 210 error pages.
Contents
- Why migrations lose traffic
- Step 0: the inventory
- What happens to rankings when you rebuild a site
- The rule that saved the project
- The trap of the 210 attachment pages
- 301, 410, and when to use each
- Automated verification
- Why we kept the 2005 archive
- The launch checklist
- What we migrated and what we left behind
- Metadata: the one part with nothing to lose
- What to watch in the first 30 days
Why migrations lose traffic
Five causes, in order of frequency:
1. Addresses changed without a redirect. The most common and the most serious. Every indexed address that returns an error is a page lost from the index.
2. Redirect chains. A leads to B, B leads to C. It works for the visitor, but it dilutes the signal and eats into the crawl budget.
3. Forgotten addresses. The ones nobody counted: archive pages, pagination pages, old addresses left over from earlier renamings.
4. Wholesale redirection to the home page. “Anything we cannot find, send home.” From a search engine’s point of view that is a signal of a non-existent page, not a useful redirect — and you lose everything.
5. Content that did not migrate. The page exists at the same address, but with half the text. The ranking is lost because the relevance dropped.
What they have in common
All five are problems of inventory, not of technology. You cannot keep what you have not counted.
Step 0: the inventory
Before any design decision, you make the complete list of what exists.
The sources, in order of reliability
- The platform export. For WordPress, the complete XML file. It is the only source that contains everything, including old addresses remembered from renamings.
- The database. For whatever does not appear in the export.
- Search Console. What is actually indexed and what brings impressions.
- Analytics. Which pages had real traffic in the last year.
- A crawler. What is reachable through internal links.
Why one source is not enough
Each sees something different. A crawler will not find a page with no links to it that has nonetheless been indexed for years. Search Console does not show pages with no impressions. The export does not show what was deleted.
We started from the export, because it was the only source that guaranteed complete coverage of everything that had ever existed in WordPress.
What came out
390 distinct addresses. The site “had”, as everyone believed, around 180 pages.
The difference of more than 200 is explained in the section on attachment pages.
What happens to rankings when you rebuild a site
If the addresses stay the same and the content is preserved, generally nothing happens — perhaps a few days’ fluctuation during reindexing. If the addresses change and are correctly redirected with a 301, most of the authority transfers, with a period of instability lasting a few weeks. If the addresses change without redirects, the loss is large and, in many cases, permanent.
In other words: the risk is not in the new platform, it is in the continuity of the addresses.
The rule that saved the project
Ugly addresses stay ugly.
The old site had 155 project pages at addresses of the form /portfolio-items/<slug>/. That is an address generated by a commercial theme, not one anyone chose. /portofoliu/<slug>/ would obviously have been nicer.
We did not change it.
Why
- They are 155 addresses indexed for years, the deepest content on the site.
- Renaming would have meant 155 redirects, each with a small but cumulative loss.
- The gain: a nicer address no visitor would have noticed.
- The risk: losing part of the site’s only real SEO capital.
An unacceptable risk-to-benefit ratio. They stayed exactly as they were.
The rule generalised
In a migration, an address changes only if it solves a real problem: a structure that prevents growth, an address with parameters that produces duplicate content, a taxonomy used as a menu destination.
Aesthetics is not a real problem.
What we did change
| Old | New | Why |
|---|---|---|
/category/blog/ |
/blog/ |
a taxonomy archive used as a menu page |
/portfolio_category/<cat>/ |
/portofoliu/<cat>/ |
the archives became real category pages |
/acasa/ |
/ |
the home page answered at two addresses |
Three structural changes, each with a reason. The rest, untouched.
The trap of the 210 attachment pages
The discovery that justified the whole inventory effort on its own.
What they are
WordPress creates, by default, a separate page for every file uploaded to the media library. Not just the file — an HTML page containing the image, at an address below the page it was inserted into:
/portfolio-items/ambike/ ← the project page
/portfolio-items/ambike/ambike-ro/ ← the page of the image in the project
/servicii/packaging/ ← the service page
/servicii/packaging/top-realizare-concept-ambakaj/ ← the image's page
Why they are a problem
- Nobody knows they exist. They do not appear in menus, and they do not appear in the admin panel’s page listing.
- They are indexed. Google finds them in the parent page’s code.
- They appear in no manually compiled inventory.
- In a migration, they all become 404 errors.
In our case: 210 such pages. More than half the total of 390 addresses.
How we handled them
Every attachment page 301-redirects to the page it belonged to. That is the logical destination: someone landing there was actually looking for that project or that service.
The rule, generalised through an address pattern:
# An attachment page is a segment below a real page.
# The !-f and !-d guards make the rule skip any page that
# does exist in the build — each one is a directory on disk.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/.]+)/[^/.]+/?$ /$1/ [R=301,L]
Ten cases with no parent
Ten images had been uploaded directly to the library without being attached to any page. Their addresses had no logical destination.
For those we used 410, not 301 and not 404. Explained in the next section.
301, 410, and when to use each
| Code | Means | When |
|---|---|---|
| 301 | moved permanently | the content exists at another address |
| 302 | moved temporarily | rarely; in a migration, almost never |
| 404 | not found | an address that never existed |
| 410 | gone for good | it existed, it no longer does, it is not coming back |
Why 410 and not 404
Both mean “it is not here”. The difference is intent: 404 says “I cannot find it”, 410 says “it existed and we removed it deliberately”.
In practice, an address returning 410 leaves the index faster and more cleanly. An address returning 404 gets rechecked periodically, sometimes for months, and can stay reported as an error.
For deliberately removed content — the ten parentless image pages — 410 is the right answer.
Rules for 301s
In a single step. If /acasa/ led to / and an image below /acasa/ would have led to /acasa/, you have a chain. You write the rule so the image goes straight to the final destination.
To the equivalent destination, not to the home page. Wholesale redirection to / is treated as a non-existent page.
At the server level, not through HTML. A static site generator can emit pages with a meta refresh instead of redirects. It works for the visitor, but it is not a real 301. On cPanel/Apache hosting, the rules go in .htaccess and produce genuine 301 responses.
Automated verification
The most important part and the most often skipped.
Why a hand-written list is not enough
Because a hand-written list contains what you know. The problem is what you do not know — the 210 attachment pages.
What we built
A script that:
- Reads the old addresses from the WordPress export. Not from a list compiled by a person.
- Parses the rules in
.htaccessand applies them in the same order Apache applies them. Order matters: the first rule that matches wins. - Looks for the destination in the final build. Does the file actually exist?
- Reports on every address: served directly, redirected, retired, or with no destination.
The result
| Old addresses checked | 390 |
| Served directly, at the same address | 175 |
| 301-redirected | 205 |
| Retired with 410 | 10 |
| With no destination | 0 |
The reverse check
The rules that catch the attachment pages are broad. An over-greedy rule could catch a real page.
The script also checks in reverse: it runs all 189 built pages through the redirect rules without the !-f and !-d guards, and reports whether any would be caught. Result: none.
It is a check we would recommend to anyone writing general redirect rules. A rule that “catches everything that does not exist” is a rule that will, one day, catch something that does.
What cannot be checked locally
.htaccess does not apply in a local preview. After upload, every rule is checked on production:
curl -sI https://digital-art.ro/portfolio-items/ambike/ambike-ro/ | head -3
The response has to be 301 with a Location: header pointing at the right destination. You do it for a sample from each category of rule, not for all 390.
Why we kept the 2005 archive
The site has a subdomain, vechiul-website.digital-art.ro, hosting the 2005–2017 version. Static PHP files, a design from nearly two decades ago.
The natural question: why not delete it?
The data
Out of 23 clicks in 58 days across the whole domain, 12 came from the archive. More than the main site.
Of those, nine came from a single page: the write-up of a villa in Eforie Nord, with a click-through rate of 5.92% and an average position of 4.47.
What that tells us
A PHP file from 2007 brings more traffic than all ten service pages of the new site put together.
Not because it is well made. Because it is specific: it has a proper name, a place and a precise subject. And the competition on “vila monica eforie nord” is all but non-existent, where the competition on “business website design” is ferocious.
The lesson
Do not delete old content that still brings traffic, however bad it looks. Check the data first. An ugly page with a 5.92% click-through rate is worth more than a beautiful page with 0%.
We kept the archive as a separate subdomain, with the main site’s redirect rules explicitly kept out of its way — a configuration precaution worth mentioning: a carelessly written general rule can end up affecting a subdomain you were not thinking about.
The launch checklist
In the right order. The order matters.
BEFORE LAUNCH
☐ A complete inventory, from the platform export — not from a crawler
☐ Every old address has a destination: direct, 301 or 410
☐ Zero addresses with no destination — verified by script, not by hand
☐ Reverse check: no real page is caught by the general rules
☐ No redirect chains
☐ Content migrated in full — checked page by page
☐ Titles and descriptions written for every page
☐ A complete backup of the old site
LAUNCH DAY
☐ Publish
☐ Upload the redirect rules at server level
☐ Check with curl a sample of each type of rule
☐ Check the SSL certificate
☐ Check that robots.txt is not blocking anything by mistake
☐ Submit the new sitemap in Search Console
☐ Keep the old sitemap reachable for a few weeks
☐ Test the forms from a real device
☐ Check the measurement: analytics working, events recording
AFTERWARDS
☐ Watch the errors in Search Console, daily in the first week
☐ Watch the indexing
☐ Watch the performance data from real users
Why the old sitemap is kept
So that Google rechecks the old addresses and sees the redirects. It is counter-intuitive — it looks like you are sending the engine towards dead pages — but that is exactly what speeds up the remapping.
What we migrated and what we left behind
An inventory of the content, separate from the inventory of addresses. The two get confused often and they are different things: an address can survive with half its content, and the result is a lost ranking nobody connects to the migration.
What was migrated
| Category | Quantity | Treatment |
|---|---|---|
| Published pages | 17 | text kept in full |
| Blog articles | 3 | kept, at their addresses |
| Portfolio projects | 155 | kept, at their addresses |
| Words of content | ~19,300 | migrated in full |
| Frequently asked questions | 14 | kept, plus new structured data |
| Original images | 245 | reprocessed from the originals |
The rule for text: verbatim. The text is what ranks. We corrected diacritics and obvious errors; we rewrote nothing during the migration. Rewriting content is a separate project, done after the migration has settled — otherwise you no longer know what caused a change in ranking.
What was left behind
| What | Quantity | Why |
|---|---|---|
| Automatically generated image derivatives | 3,410 files, 86 MB | regenerated at build time, from the originals |
| JavaScript from the visual editor | 62 files, 40.6 MB | unused |
| CSS from the visual editor | 10 files, 12.2 MB | unused |
| Font cache | 32 files | the new site chooses its own fonts |
| A plugin’s debug log | 1 file, 2.6 MB | it should never have been public |
| Orphaned backups | 38 files | residue |
Out of 181 MB, the real content was 35 MB. The rest: artefacts.
A check worth doing
On any migration, search the file archive for extensions that should not be publicly available: log files, archives, backups, configuration files. They turn up surprisingly often, indexed.
Metadata: the one part with nothing to lose
A discovery that simplified the project.
What we looked for
We scanned the complete database for the keys that SEO plugins use to store titles, descriptions and canonical addresses.
What we found
Zero rows. The old site had never had an SEO plugin installed. No meta descriptions, no social tags, no structured data, no custom canonicals.
Why it matters
The standard risk of a migration — “preserve the titles and descriptions” — did not apply. There was no body of metadata that could be lost.
That reorients the whole project: the risk was concentrated almost entirely in the continuity of the addresses, and everything the new site added — descriptions, social tags, structured data — was net gain, not porting.
The generalisable lesson
Before planning a migration, check what metadata actually exists. If it exists, it has to be preserved carefully. If it does not, you have a simpler project than you thought and an immediate opportunity: every title and description written now is an improvement on the previous state, not a replication.
The check takes ten minutes and changes the effort estimate.
What to watch in the first 30 days
| Period | What to watch | What is normal |
|---|---|---|
| Days 1–3 | crawl errors | a few; they should decrease |
| Days 1–7 | indexing of the main pages | they appear gradually |
| Weeks 1–3 | ranking fluctuation | normal, do not intervene |
| Weeks 2–4 | organic traffic | returns towards the previous level |
| Week 4 | Core Web Vitals, real data | accumulates after ~28 days |
What not to do
Do not change anything in the first two weeks, apart from obvious errors. Ranking fluctuation is normal during reindexing. Every change made in a panic prolongs the period of instability.
When you have a real problem
- Crawl errors that increase after the first week.
- Important pages not indexed after 14 days.
- Organic traffic below 70% of the previous level after 30 days.
In any of those cases, the first check is the same: run the inventory again. It is almost always a forgotten address.
Have a site to rebuild and are worried about this part? Rightly so — it is the part where things get lost. Write to us and we will do the inventory first, before any conversation about design.
Read next: The SEO structure of a business website, WordPress or a static site and SEO in the age of AI Overviews.












