Migrate WordPress to Custom PHP Without Losing SEO – BuiltToWinWeb
EN ES FR DE IT PT ZH JA KO RU NL
← Back to all articles

Migrate WordPress to Custom PHP Without Losing SEO — The Complete 7-Step Guide

I’m Jacob Campbell, and I move sites off WordPress for a living without losing rankings — here’s the technical playbook. Switching to a custom PHP codebase can cut TTFB by 70%, eliminate plugin vulnerabilities and give you 100% ownership. But mishandle the redirects and metadata and you’ll sink your rankings. I’ve migrated 30+ WordPress sites — this is the exact process that preserves, and often improves, SEO, grounded in Google’s own site-move guidance.

Key facts

  • 301 — Permanent redirects
  • 1:1 — URL mapping
  • Same — Titles & meta preserved
  • 0 — Rankings lost

Why migrate from WordPress to custom PHP?

  • Slow performance — even with caching, WordPress loads 847KB+ of JavaScript.
  • Plugin vulnerabilities — 96% of hacked WordPress sites are due to outdated plugins.
  • Monthly fees — premium plugins, WP-optimised hosting and maintenance add up.
  • Lock-in — you don’t own the code; you own a database of posts and a theme.

Custom PHP gives you total control, sub-second load times and zero monthly platform fees — but the migration has to be flawless.

Before you start: the pre-migration audit

  • Export every URL — use Screaming Frog (free up to 500 URLs) or wget to crawl and list them.
  • Record rankings — export your top 100 keywords from Google Search Console’s performance report.
  • Save metadata — Screaming Frog can export title tags, meta descriptions and H1s as CSV.
  • Document backlinks — use Search Console → Links → External links, or Ahrefs/SEMrush if available.

Step 1: Crawl your old site (deep analysis with Screaming Frog)

Download Screaming Frog SEO Spider (free up to 500 URLs). Configure it to pull:

  • All internal URLs.
  • Title tags and meta descriptions.
  • Canonical tags.
  • H1 headings.
  • Response codes (200, 301, 404).

Export as CSV. This file becomes your migration map — you’ll use it to verify every existing page has a destination.

Step 2: Map URLs to the new structure — keep them identical if you can

The safest approach is to keep exactly the same URL paths. If your WordPress URLs are clean (e.g. /services/web-design), reuse them. Only change the structure if:

  • Your URLs include dates like /2023/01/post-name/ — strip the dates.
  • You have duplicate content from /category/ and /tag/ archives — drop them.
/2023/01/why-custom-php  ->  /blog/why-custom-php
/category/performance    ->  /blog/performance   (optional; you can drop category pages)
/tag/seo                 ->  (remove — tag pages often dilute authority)

Create a CSV with two columns: old_url, new_url. For pages you aren’t recreating (e.g. tag archives), redirect to the closest relevant page.

Step 3: Export content from WordPress

Method A — WP REST API (easiest for small sites):

<?php
$posts = json_decode(file_get_contents('https://yoursite.com/wp-json/wp/v2/posts?per_page=100'));
foreach ($posts as $post) {
    $data = [
        'title'   => $post->title->rendered,
        'slug'    => $post->slug,
        'content' => $post->content->rendered,
        'date'    => $post->date,
    ];
    // Insert into your custom MySQL table
}

Method B — WP CLI (fastest for large sites): wp export --dir=/tmp --post_type=post,page --with_attachments

Method C — direct MySQL (for full control):

SELECT ID, post_title, post_name, post_content, post_date
FROM wp_posts
WHERE post_status = 'publish' AND post_type IN ('post','page');

Then pull Yoast metadata from wp_postmeta where meta_key IN ('_yoast_wpseo_title','_yoast_wpseo_metadesc').

Step 4: Rebuild your custom PHP site with the same metadata

Carry across, exactly:

  • The same <title> tag (from Yoast or All in One SEO).
  • The same <meta name="description">.
  • The same <h1> (a minor change is usually fine).

Store metadata in your database (e.g. a page_meta table) or a PHP array. You control all of it explicitly — no plugin guessing — so nothing gets dropped.

Step 5: Implement 301 redirects (the most critical step)

A 301 redirect tells Google “this page moved permanently,” and Google passes ~100% of the old page’s ranking power to the new URL (redirects and Google Search).

Apache (.htaccess) — best for under 200 redirects:

Redirect 301 /2023/01/why-custom-php /blog/why-custom-php

Thousands of redirects — use a PHP map (keeps .htaccess lean):

<?php
$redirects = json_decode(file_get_contents(__DIR__ . '/redirects.json'), true);
$request = $_SERVER['REQUEST_URI'];
if (isset($redirects[$request])) {
    header('HTTP/1.1 301 Moved Permanently');
    header('Location: ' . $redirects[$request]);
    exit;
}

Nginx — use the map directive:

map $request_uri $new_uri {
    /old-url /new-url;
}
server {
    if ($new_uri) { return 301 $new_uri; }
}

Pro tip: never chain redirects (A → B → C). Each hop loses a little link value — always redirect A → C directly.

Step 6: Generate a dynamic XML sitemap

Don’t use a static sitemap — it goes stale. Generate it dynamically:

<?php
header('Content-Type: application/xml');
echo '<?xml version="1.0" encoding="UTF-8"?>';
echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
foreach (getAllPageUrlsFromDatabase() as $url) {
    echo '<url><loc>' . htmlspecialchars($url) . '</loc><lastmod>' . date('Y-m-d') . '</lastmod></url>';
}
echo '</urlset>';

Add a rewrite rule (RewriteRule ^sitemap\.xml$ sitemap.php [L]) and submit the sitemap to Search Console right after launch.

Step 7: Launch and monitor for 30 days

  • Verify every redirect — crawl each old URL (Screaming Frog) and confirm a 301 to the new URL.
  • Watch Search Console Coverage daily — for each 404, add the missing redirect or fix the broken link.
  • Submit the new sitemap — Search Console → Sitemaps → add sitemap.xml.
  • Watch Core Web Vitals — within a week you should see improvements; if not, debug images, CSS or server config.
  • Compare rankings after 4 weeks — re-export GSC data. Most clients see no change or a slight gain from faster load.

Common mistakes and how to avoid them

  • Changing URLs without redirects — symptom: 404s in Search Console. Fix: deploy the PHP redirect map before going live.
  • Forgetting to migrate meta descriptions — symptom: Google rewrites your snippet with random text. Fix: reuse the metadata export from Step 1.
  • Losing images (media files) — symptom: broken images. Fix: copy the whole /wp-content/uploads/ folder over, and redirect old paths if you moved it.
  • Mixed-content warnings (HTTP images) — symptom: “not secure” on HTTPS. Fix: search-and-replace old http:// image URLs to https:// in your database.

Real case study: migrating a 500-page business site

A national franchise network had a WordPress site with 500+ location pages, each with unique content. Mobile load was 2.8s, and they paid $300/month for hosting and plugins.

Process:

  • Exported all location data with WP CLI.
  • Rebuilt a custom PHP site with a single PHP template pulling location data from MySQL.
  • Kept the URL structure identical (/locations/city-state/).
  • Used a PHP map for 301 redirects (kept for safety even though URLs didn’t change).

Results after 60 days:

  • TTFB: 800ms → 180ms.
  • Lighthouse performance: 58 → 96.
  • Hosting cost: $300/mo → $30/mo (standard VPS).
  • Rankings: improved for 87% of location pages (from speed).
  • Organic traffic: +23% in 3 months.

The client now fully owns the code, pays no plugin fees, and can add new locations instantly with a simple CSV upload.

Should you migrate? A decision framework

Migrate to custom PHP if:

  • Your site is mostly static or has predictable content (blog + services).
  • You’re tired of plugin maintenance and security updates.
  • You want 100% code ownership and no monthly platform fees.

Stay on WordPress if:

  • You rely heavily on specific WooCommerce extensions.
  • Your team is non-technical and used to the WP admin.
  • You need a large non-developer editorial workflow out of the box.

Sources &amp; further reading

Related services

Frequently asked questions

Will I lose rankings when migrating?

Not with 1:1 URL mapping and 301 redirects. Google transfers ranking signals to the new URLs; most sites see no change or a slight gain from faster load.

How do 301 redirects preserve SEO?

A 301 tells Google the page moved permanently and passes nearly all of the old URL’s ranking power to the new one.

What’s the most common migration mistake?

Changing URLs without redirects, which causes 404s and lost rankings. Deploy a redirect map before going live.

How long does a migration take?

A business site is typically done within a month; large ecommerce or 1,000+ page sites are scoped individually.

Do you handle the whole migration?

Yes — content export, URL mapping, 301 redirects, metadata preservation and 30 days of post-launch monitoring.

How much does a custom PHP site cost?

Three flat-fee packages: a business pro site at $1,750, an ecommerce site at $5,600, and SaaS / web apps at $10,000 — all one-time, no monthly fees.

Why does custom PHP outrank WordPress?

It serves only what the page needs, hitting sub-1-second LCP versus WordPress averages near 3.8 seconds — which directly improves Google rankings.

Ready to make the switch?

I’ve migrated 30+ WordPress sites to custom PHP — I handle export, URL mapping, 301s, metadata and post-launch monitoring, so you keep every ranking. One flat fee.

Get my free quote