Skip to content

Case study

WordPress to Astro rebuild

Around thirty pages of Elementor WordPress rebuilt as a static Astro site, reviewed page by page against the original, now live in seven languages.

Overview

A retail software company wanted off Elementor. Their own technical lead described what existed as a page-builder site put together by a previous employee, and what he wanted instead as “a very basic developer-friendly static site” that his team could keep editing without a page builder in the way.

Around thirty pages, Swedish as the default language and English alongside it, with Norwegian and Finnish expected later.

What I own

The whole rebuild: the component system, the content and localisation model, the forms and their mail path, and the preview deployment used for review throughout. The client’s technical lead ran the reviews and deployed the final result himself.

Complexities tackled

I inventoried the site before quoting, and found the shape nobody had stated. My first pass listed ten pages; the client’s list had around thirty. Reading through all of them turned up something more useful than the count: three different content sections, case studies, guides and blog posts, were the same template wearing different names. That collapsed a large part of the work into one component set, and it is why I went back and asked for the budget to be raised rather than absorbing the difference quietly. It was raised.

Page-builder markup cannot be translated, only replaced. Elementor emits deeply nested containers with inline styles and its own breakpoint system. Porting that markup gives you the same tangle in a new framework and none of the speed. Every section was rebuilt as a component instead.

Deciding when to fix the original and when to copy it. One case-study page contradicted the visual language of the whole site. Rather than silently normalising it I asked whether it was intentional, and it was: a deliberate match to that customer’s brand. Elsewhere the original had genuine layout bugs, and a large-screen behaviour it never handled. The answer I got shaped the rest of the project: improve where it is clearly better, never worse than the original. So the max-width behaviour got fixed, and the deliberate outlier stayed.

Replacing SMTP before it failed in production. The proof of concept sent mail over SMTP from serverless functions. That combination fails intermittently and confusingly, because every invocation pays a fresh connection handshake inside a function designed to start and die quickly. I proposed an HTTP mail API instead and explained why in terms of the execution model rather than preference. It was accepted, and the forms have not been a source of trouble since.

Shipping the interface before the plumbing, deliberately. I put the pages live with forms unfinished so design feedback could start while I was still building functionality. When the technical lead pulled the repository and audited it properly, he found real problems: duplicate POST requests firing several times per submission, an undocumented environment variable, production mail code commented out behind a temporary address, and failing lint. All fair. I said which of them I already knew about rather than presenting them as surprises, and cleared the list inside a day.

Knowing when to stop improving. Partway through I was redesigning things the brief did not ask me to touch. I said so in writing, stopped, and finished the scope, on the reasoning that once a baseline exists every later change is cheap and before it exists nothing is.

Outcome

Both milestones approved. The technical lead’s closing note: the mail paths work as expected, the linter is clean, and the links check out. The client asked how to leave a rating a month after the contract closed, which is why there is no review attached to it.

The client discarded the WordPress site and put this build into production. It is what serves the company’s site today, on their own domain, with no page builder left in it.

It also outgrew what I handed over, which is the part I am most pleased about. I built it for two languages, with Norwegian and Finnish named as likely later additions. It now serves seven, and every one of them is delivered by the same build I wrote rather than a fork or a rewrite. The routing and content model were designed so that adding a language is adding content, and that is how it has been used since.

Stack

Astro with content collections and i18n routing, TypeScript, Tailwind CSS, static output, an HTTP mail API for the forms with localised confirmation emails, deployed to Vercel for review.

Working on something similar?

Tell me what you are building and what is in the way. I will tell you honestly whether I am the right person for it.

Start a conversation

Last updated: