Case Study · In progress · Wedding photography · 2026

A WordPress wedding-photography site, rebuilt static. Performance 45 → 90.

This case study is published in-flight. The rebuild is shipped and the Lighthouse numbers are real, but the AI-grounding instrumentation and the conversion-impact data aren't in yet. The process is the story for now — we'll add the outcomes layer when the measurement lands. Same standard as Miabella: nothing claimed that isn't instrumented.

Client
Shinepics
Vertical
Wedding photography
Status
Built · measuring
Stack
WordPress → Static HTML · Cloudflare Pages
Hosting
£0 / month
01 · The justification

The before / after, on the same machine, minutes apart.

The two screenshots below are PageSpeed Insights runs against the live WordPress site and the rebuilt static version, captured within a single minute of each other on the same Lighthouse engine. Same content. Same brand. Same photos. Different stack.

Before · WordPress · shinepics.co.uk Perf 45
Google PageSpeed Insights mobile report for shinepics.co.uk dated 21 May 2026, showing a Performance score of 45 (red), Accessibility 100, Best Practices 96, and SEO 92.
PSI · mobile · shinepics.co.uk · 21 May 2026 · 15:15
After · Static HTML · shinepics.pages.dev Perf 90
Google PageSpeed Insights mobile report for shinepics.pages.dev dated 21 May 2026, showing a Performance score of 90 (green), Accessibility 100, Best Practices 100, and SEO 100.
PSI · mobile · shinepics.pages.dev · 21 May 2026 · 15:16
Performance 45 → 90 · +45 Accessibility 100 → 100 Best Practices 96 → 100 · +4 SEO 92 → 100 · +8

The Performance lift is the headline number — almost exactly double — but the three other panels going to 100 is what closes the door on the entire category of agency excuse that says all-green isn't realistic on a working site. It is. We did it with the same photos and the same words.

02 · The process

Nine steps, in the order they happen.

The procedure below is how we do every WordPress extraction. The order matters: ship an empty framework first, then put content into it, then iterate to score — not the other way around. Building content on top of bloat then trying to optimise the bloat away is the trap most rebuilds fall into.

  1. Export every page and post as JSON.

    Pull the canonical content out of WordPress as structured data — titles, body copy, image references, dates, categories — not as rendered HTML. Once it's JSON, the source of truth is portable and the rest of the rebuild can treat WordPress as a one-time data dump.

  2. Strip the WordPress bloat, nested CSS, and Elementor div soup.

    Page-builder output is the single biggest reason these sites score 45 on Performance. Forty-deep div nesting, six layers of inline-style overrides, megabytes of CSS where dozens of kilobytes would do. The rendered HTML gets reduced to the actual semantic content — headings, paragraphs, lists, images — and everything else is dropped.

  3. Build a clean framework: header, footer, empty body.

    The chrome (nav, footer, base styles, head metadata) is built as reusable HTML partials with nothing in the body yet. This is the architectural shell — small, fast, accessible — that the content will eventually drop into.

  4. Ship the empty framework. Test it with no content.

    Deploy the shell to a staging URL before any content lands. Run Lighthouse against it. If the empty framework doesn't already score 100 across the board, the framework is wrong — fix it now, before any content is on top of it to obscure the diagnosis.

  5. Build the brand identity — fonts, colours, max font sizes.

    Pick the typeface(s), define the colour tokens, set the type scale ceiling. Doing this as a discrete step — rather than letting it drift in via page-by-page decisions — is what keeps the system coherent and the font payload small. One pass, written down, then applied.

  6. Build a single test page with real content.

    One representative page, not the homepage. Take a real article or service description from the JSON export and lay it out using the brand identity. This is the first time content meets the framework — the test page exposes anything the empty-framework Lighthouse run couldn't see.

  7. Test the test page. Real device, real network throttling.

    PSI mobile, real-device check, accessibility tree review, screen-reader pass. The test page is the canary — if anything is going to fail at scale, it fails here first, in isolation, where the fix is cheap.

  8. Tweak until SEO, Accessibility and Best Practices are 100 each.

    Those three panels are non-negotiable. Performance is allowed to vary slightly with content weight (a gallery-heavy page genuinely is heavier than a text page), but the other three are pass/fail and the only acceptable mark is 100. Iterate the test page until it's there.

  9. Cull. Audit every weight on the page.

    Do we really need the font at 700 when we already have the same family at 800? Is every font local, or are we still calling Google Fonts? Are we loading a JavaScript library for one feature we could implement in ten lines? Every byte is justified or removed. The case for keeping anything has to be made — the default is to drop it.

03 · Why this matters

Two pieces in Writing argue the principle this build demonstrates.

The Shinepics rebuild is a worked example of two arguments we've already made in long form. The before/after is the proof; these are the why.

04 · Still to come

Four more layers, all in flight.

The nine-step process above is the rebuild. The four items below are everything that happens around the rebuild — keyword discipline going in, pre-deploy verification, post-deploy observability, and adversarial stress testing. Each one is a piece of operational kit we run for ourselves; each one will get its own write-up as it stabilises.

Pre-buildPreFlight

How we decide what keywords to include.

The discipline that runs before a single page is written. Which queries we're actually trying to win, which we deliberately won't pursue, and why most "SEO keyword research" outputs are noise.

Pre-deployPreCommit

How we confirm a page is ready before it goes live.

The checklist that runs against every page before it ships — Lighthouse thresholds, accessibility-tree review, schema validity, link integrity, payload audit. Pass the gate or the commit is rejected.

Post-deployBot Observability

What we do after it's live.

Watching which bots crawl what, how often, and from where. AI-grounding traffic looks different from search-engine traffic, and treating them as the same line in a log is how you miss the change.

HardeningRedTeam

How we stress the site adversarially.

Deliberately try to break the things we just built — prompt-injection against schema, broken-state rendering, hostile referrer chains, malformed bot requests. If we don't find the failure modes, an attacker (or a misbehaving crawler) will.

Each of those four becomes a writeup of its own once we're confident the practice is replicable rather than situational. The Shinepics case study will be updated with results from each as the data lands.