← Writing

Your marketing site is the fossil record of your product's first architecture

ChiroSimple's WordPress site wasn't just a marketing site — it was the original SaaS, a 245-sub-site multisite where every customer once had their own subdomain. Migrating it down to a single clean site meant database surgery, WP-CLI forensics, and a PHP time machine.

On this page

Every product company eventually looks at its marketing site and asks why it’s so weird. Why the hosting is set up like that, why the DNS has those records, why the database is so large for a site with a dozen pages.

The answer is almost always the same: the marketing site is the fossil record of the product’s first architecture. It’s where the earliest version of the business calcified.

ChiroSimple is a good example. Today it’s a Flutter app — iOS, Android, web — backed by Firebase. But the original product was WordPress. Not “the marketing site was WordPress”: the product itself. Every customer clinic got their own sub-site on a WordPress multisite, on their own subdomain. That was the EHR, version one.

The product outgrew that architecture years ago. The multisite didn’t go anywhere. It kept serving the marketing pages from the main site while quietly carrying 245 customer sub-sites of legacy data underneath — every one of them a fossil.

This is the story of digging the marketing site out of that stratum.

What we were actually dealing with

On paper, the task was “clean up the WordPress site.” In practice, the inventory looked like this:

  • A WordPress multisite install with 245 sub-sites, only one of which — the main site — still mattered.
  • A Divi-based theme, with page content stored as Divi shortcodes inside post content.
  • Hosting on cPanel/HostGator, with deploys done by hand.
  • A PHP version that had been pinned to 5.6 for compatibility with the old stack, while the host’s modern handlers were 8.2 and 8.4.

None of this is exotic. It’s what a decade of “don’t touch it, it works” looks like.

Rule one: archive before you delete

The 245 sub-sites were dead weight for the marketing site, but they were also customer history. Before any surgery, the whole thing got archived — 608 MB of customer sub-site data, preserved intact and set aside. The goal of a migration like this is a smaller live footprint, not destroyed records.

This step is boring and it is not optional. The moment you start database surgery on a multisite, you will delete something you didn’t understand. The archive is what makes that survivable.

Database surgery: multisite to single site

WordPress multisite doesn’t store sub-sites as separate databases — it multiplies table sets inside one database, with network-level tables holding the site registry. “Converting” to a single site isn’t a toggle; it’s extraction.

The approach that worked: rather than trying to strip 245 sub-sites out of the existing database in place, build a clean single-site database and move the main site’s content into it. The old multisite database stays untouched as part of the archive; the new database contains only what the marketing site actually needs.

Deploys to the host went over rsync into a cPanel jailshell — not glamorous, but scriptable and repeatable, which is the property that matters when you’re going to iterate on a live host.

The forensics: where did the hero images go?

The unglamorous middle of the project was a category of bug I’d describe as content that exists but doesn’t appear. Hero images gone. FAQ sections rendering empty. Pages that looked fine last year, hollow now.

The instinct is to assume data loss. The discipline is to check the database first. Using WP-CLI to pull the raw post content and read the Divi shortcodes directly, the content was demonstrably all still there. So the failures had to be in the rendering path — and there turned out to be several, stacked:

  • The image optimizer’s lazy-loading was rewriting image markup and, in some configurations, never swapping the real image in.
  • Caching was serving pages rendered under one broken configuration long after the configuration changed — every fix had to be evaluated through a cache-clearing ritual before you could trust what you were seeing.
  • PHP handler mismatches were the deepest layer: content authored under PHP 5.6 being rendered by 8.2/8.4 handlers, with theme code hitting constructs that had changed or vanished across four major PHP versions. Some pages broke outright; others degraded quietly, which is worse.

Each layer masked the others. The lesson that generalizes: when content vanishes on an old WordPress site, you are almost never looking at one bug. You are looking at a stack of independently-broken rendering layers, and you have to peel them in order — raw content first, then plugins, then cache, then runtime.

SSL and subdomain archaeology

A multisite that once served 245 customer subdomains leaves debris in DNS and SSL configuration: wildcard records, per-subdomain certificates, routing rules whose reason for existing left the company years ago. Part of the migration was walking that configuration and asking, for each rule, whether anything still depended on it — archaeology more than engineering. The safe order is to make the main site independent of the wildcard machinery first, and only then start removing it.

The cutover: two directories and a rename

The final cutover used the oldest trick in shared hosting, and I’ll defend it: build the new site in a parallel directory, then swap public_htmlpublic_html_old.

It isn’t blue-green deployment. But it has the one property a risky cutover needs: rollback is a single rename, executable in seconds, requiring no tooling and no thought under pressure. On a cPanel host, that’s as good as it gets — and knowing your rollback is trivial changes how calmly you execute everything else.

What I’d tell you to take from this

If you inherit a strange marketing site, assume it used to be something else, and find out what — the answer will explain most of the strangeness and tell you where the bodies are buried. Archive ruthlessly before deleting anything. When content disappears, read the database before mourning it. And make your rollback so simple you could do it half-asleep, because cutover night is exactly when you’ll be half-asleep.

The site that came out the other side is just a marketing site now — small database, current PHP, no fossils. The fossils are in a 608 MB archive where they belong.

← All writing Book a call →
Book a call → WhatsApp