topdj.ie.
Rebuilding a wedding DJ's site from WordPress to a custom Next.js build.
Galway wedding DJ · Next.js 16 · TypeScript · Tailwind v4 · 2026
- client
- Alan Geraghty, wedding DJ, Galway & the West of Ireland
- role
- Solo: audit, content migration, visual identity, design system, frontend build

the problem
Couples choose a wedding DJ on trust and feel. The old WordPress site had the right content: real testimonials, blog posts and gallery photos. But it was buried under a theme that looked like every other DJ site, plugin weight, and a custom scroll library that hijacked the page. The job was to keep everything true about the business and throw away everything generic.
The brief: replace the ageing WordPress site with a fast custom build. Real content only, a distinctive identity, and no CMS.
the process
Audit the live site before touching code
I went through the existing site in a real browser session and noted structure, content and pain points. Its custom scroll library intercepted normal scrolling, so I had to drive the page through
document.scrollingElementdirectly just to inspect it. That was a useful reminder of what the new build should not do.Extract the real content, not a rewrite of it
I pulled the content from a WordPress XML export (WXR). Generic XML parsers choked on WordPress's non-standard CDATA handling, so I wrote a Python extractor using BeautifulSoup plus targeted regex. It recovered six real testimonials and three full blog posts. It also caught a data bug where a literal “Company Name” placeholder had been concatenated into the testimonial attributions, and stripped it out. Every word on the new site comes from the business.
Model content as typed data instead of a CMS
Testimonials, the set list and blog posts live in
lib/content.tsas typed TypeScript, with the gallery in its own data file. There's no database or admin panel to patch, and no runtime CMS calls. The compiler catches a missing field before a visitor ever would. For a small business whose content changes a few times a year, that was the right trade-off.Build an identity from the subject, not from a UI kit
Instead of the usual neon and “DJ” icon cards, the site runs on a dark ink base with cream type and two accents, gold and pink, that alternate through the night's running order. Manrope carries display and body text, with Caveat as a handwritten accent. The hero leads with a photo of a real crowd, not an illustration.
Reframe services as a running order
Wedding DJ services are usually a grid of icon cards. Couples think in terms of the night: ceremony, drinks reception, first dance, the floor filling up, last song. So the services section is written as the evening's running order. It's the same information, organised the way the customer already thinks.
Build component-first, with a written handoff
I built the core components first (Header, Hero, MeetTheDJ, SetList, WeddingJourney, Testimonials, CTABand, Footer) and assembled Home and About from them. The remaining pages were written up in a handoff file: a gallery with a lightbox, a contact form with an API route stubbed for Resend, static blog routes via
generateStaticParams, and a privacy page. Anyone, or any AI agent, could pick the build up without re-deriving decisions, and those pages have since been built.Make migration debt visible, not hidden
WordPress media was temporarily served through
remotePatternsinnext.config.tsand flagged as an explicit TODO. It's since been moved into the repo and the remote pattern removed. Every page has to pass a pre-delivery checklist:npm run build,npm run lint, a 375px mobile viewport check, and a review of the nav collapse behaviour.
identity snapshot
The client's palette and type, shown as they are on topdj.ie.
Ink
#11100F
Cream
#F7F4EE
Gold
#D9A441
Pink
#E83D78
display + body
Manrope
The moment the night properly begins. Reading the room and building the energy, one last singalong before the night winds down.
accent
Caveat
Handwritten asides, used sparingly.
how AI was used
AI tools helped with the donkey work: browser inspection, writing the extraction script, scaffolding components, and continuing the build from the handoff file. The decisions were mine:
- Content: real content only, nothing generated.
- Identity: the palette and type pairing.
- Structure: the running-order reframe.
- Architecture: no CMS.
Every step had a human checkpoint: reviewing the extracted data, catching the placeholder bug, and signing off each component against the identity.
where it is now
A distinctive, fast, CMS-free site built entirely from the business's real content. Built so far:
- Home, About, Gallery, Contact, Blog, FAQ and Privacy
- Five county landing pages (Clare, Mayo, Midlands, Roscommon, Sligo) with matching guides
- The blog, grown from the three migrated posts to eight
- All media moved off WordPress and into the repo
Next: retire the old WordPress install.
