Skip to content
McGinnPublishing
All case studies
Meridian PressIndependent academic publishing2025

A 40,000-title catalogue that loads like a single page

Eleven years of accumulated WordPress debt, a print catalogue that had outgrown its template, and an editorial team of 200 who could not ship a landing page without a developer.

Headless WordPressDesign systemsPerformance engineering
p75 Largest Contentful Paint
0.6sp75 Largest Contentful Paintwas 4.8s
Engaged time on feature pages
+68%Engaged time on feature pages
Editors shipping without a ticket
200Editors shipping without a ticket
Titles migrated, zero downtime
40kTitles migrated, zero downtime

01The constraint

Meridian Press had grown from a four-person typesetting shop into the largest independent academic publisher in the country. Their WordPress install had never been migrated: 312 active plugins, a theme forked four times, and a plugin catalogue page that took eleven seconds to render on a good connection. Every marketing request went through a two-week queue.

02What we did

We split the platform into three concerns. WordPress keeps the catalogue, the editorial workflow and the 200-person user base — unchanged, because it was never the problem. A public GraphQL layer exposes a curated schema of 40,000 titles, each with a normalised product record, related-work graph and full-text search index. Next.js renders it: category and product pages statically with tag-based revalidation, search and account as dynamic routes, everything else streamed. The book page became the design system's centre of gravity, which is where it should have been all along.

03What changed

The catalogue page went from 11.4 seconds to 480 milliseconds at the 75th percentile. Engaged time on long-form features rose 68% in the first quarter, largely because pages stopped arriving halfway down a scroll. The internal tool that used to take a developer two weeks is now a form. Median time-to-publish fell from nine days to under four hours.

In detail

Meridian's catalogue is the business. Roughly 74% of their sessions begin on a title page, and every one of those sessions used to compete for a single PHP process on a shared host in Reading.

What we found in week one

The plugin audit returned 312 active plugins, 41 of them with no update in over two years and 9 with known unpatched vulnerabilities. Two were writing to the same option row, which meant that occasionally the theme would render a stale price. This is not unusual. It is the normal condition of a WordPress install that has been in production for eleven years.

The origin was not slow because the code was bad. It was slow because a page had to be assembled, from scratch, for every single visitor, on hardware that was already two generations behind.

The rendering decision, route by route

We wrote an architecture decision record for every route in the build. It is the document we would hand to any team taking this over, and it is short enough to read:

  • Title pages — statically generated, revalidated by tag on publish. A catalogue page changes when a price or a cover does.
  • Category and series pages — static, revalidated on any change to a member of the collection.
  • Search and autocomplete — dynamic, backed by Algolia. Never static, because the result is unique to the visitor.
  • Long-form features — static shell, streamed body. The headline and hero paint immediately; the article streams in behind it.
  • Account and basket — dynamic, no-store. Correct and unavoidable.

What the editors noticed

The thing that changed Meridian's relationship with its own website was not the speed. It was the release. Previously, a landing page required a plugin update, a CSS override and a deploy. Now a campaign page is a collection of blocks the marketing team can assemble from a library that engineering built once.

Median time from brief to live went from sixteen working days to two. Nobody on the editorial team now needs to file a ticket.

Migration

Forty thousand titles, eleven thousand legacy URLs from a 2009 structure, and eight years of accumulated authority. We exported, transformed and re-imported in a rehearsal against a copy of production, then diffed both datasets field by field until they matched. The redirect map was generated from the old sitemap and then verified by crawling both systems — 11,043 URLs, 11,043 verified mappings, zero orphans. Cutover happened behind a proxy at 02:00 GMT and traffic was moved in three stages over six hours.

Organic sessions dipped 1.8% for ninety minutes during the switch and were back above baseline within four days.