This guide explains how the Soames site is built, how to run it locally, and how changes reach production. Soames is a headless WordPress setup: WordPress is the content backend, and a static Astro front end is built from it and served on a CDN. There is no PHP running on the public site — only pre-rendered HTML, CSS, and JavaScript.
Architecture at a glance
- WordPress (headless CMS) — authors content and exposes it over the WPGraphQL API. Not publicly browsed; it only serves data at build time.
- Astro front end — at build time it fetches content from WordPress and generates a fully static site.
- Netlify — builds the Astro site and hosts the static output.
- Cloudflare — sits in front of Netlify for DNS and TLS.
Flow: WordPress → WPGraphQL → Astro build (Netlify) → static HTML → Cloudflare → visitor.
Repositories and packages
- soames-astro-theme — the shared Astro theme, published to npm. It provides the Astro integration, page routes, React components, the shortcode parser, the WordPress data layer, and the component-override (“shadow”) resolver.
- soames-site — the site instance. It consumes
soames-astro-themeas a versioned npm dependency and holds site-specific configuration and overrides. This is what deploys to production. - soames-wordpress-plugin — the companion WordPress plugin. It registers the
docscontent type, the Soames settings screens, a REST settings endpoint, GraphQL fields for the hero header settings, and the automatic rebuild-on-publish behavior.
The WordPress backend
Content is fetched over WPGraphQL. The Soames plugin adds the pieces the front end relies on:
- Docs — a self-registered
docscustom post type. The/docs/landing is a card grid; individual articles render in prose with a docs sidebar. (This article is adocsentry.) - Soames Settings — site assets (logo, favicon, company name, contact blurb), the front-end URL, the page that drives the
/docs/hero, and the rebuild hook (see below). - Hero fields — four per-page meta fields drive the hero header:
heroTitle,heroCaption,heroBackgroundImage, andoverlayOpacity, all exposed onPageandPost. Each resolves tonullwhen unset and the theme owns the fallbacks: the title falls back to the post title, the background image to the featured image and then a placeholder, and the opacity to0.6. The caption has no fallback — unset means no caption is rendered. A page’stitleandexcerptare therefore reserved for the document title and meta description, not the hero.
Running it locally
Work in the soames-site repository.
- Use Node 22 (an
.nvmrcis provided; runnvm use). Older Node versions are too old for Astro. - Create a
.envfile with the WordPress endpoints (see.env.example; use HTTPS so the static output has no mixed-content references):WORDPRESS_GRAPHQL_URL=https://your-wordpress-host/graphql WORDPRESS_BASE_URL=https://your-wordpress-host - Install and run:
npm install npm run dev # http://localhost:4321 - Production build locally:
npm run build # outputs to dist/ npm run preview
Customizing the theme (component overrides)
Astro has no built-in component shadowing, so the theme provides it with a resolver. Theme files are imported as @theme/<path>; a site overrides any of them by creating a file at the matching path under src/overrides/.
src/overrides/components/Footer.tsx → replaces the theme's components/Footer.tsx
src/overrides/layouts/Base.astro → replaces the theme's layouts/Base.astro
src/overrides/styles/… → site-specific styles
This is whole-file replacement, resolved at build time, with no change at the import site — the direct successor to Gatsby component shadowing.
Publishing content → automatic rebuild
Because the site is static, content changes only appear after a rebuild. The Soames plugin triggers one automatically:
- Publishing, updating, or unpublishing a post, page, or doc schedules a rebuild.
- Rapid edits are coalesced into a single build that runs after your changes settle, so the build always reflects the final content.
- The change is typically live about a minute after you publish.
- A manual Deploy now button (Soames Settings) forces a rebuild — useful after changing menus or Site Assets.
Deploy pipeline
- Continuous deployment: Netlify is connected to the
soames-siterepository and rebuilds on every push tomain. Build settings live innetlify.toml(build command, publish directorydist, Node 22). The WordPress endpoints are provided as Netlify build environment variables. - Content rebuilds: in addition to code pushes, WordPress publishing triggers a build via a Netlify build hook (above).
- DNS & TLS: the domain is served through Cloudflare in front of Netlify, with full end-to-end HTTPS.
Updating the theme
soames-site depends on a published version of soames-astro-theme. To ship a theme change:
- Merge the theme change and bump its version.
- Push a version tag (e.g.
v0.1.1) — CI publishes the package to npm. - In
soames-site, update the dependency to the new version and push; Netlify rebuilds with the updated theme.
For quick local theme iteration without publishing, temporarily link the theme (e.g. npm link or a local file dependency) instead of the npm version.
Gotchas
- GraphQL and the WAF: some WordPress installs’ web application firewall blocks GraphQL requests whose first field is
pagesorposts. The data layer aliases the root field (for examplewpPages: pages) to avoid this; keep that pattern when adding queries. - Use HTTPS for the WordPress endpoint so image and asset URLs in the static output are HTTPS (no mixed-content warnings on the live site).
- Node version: always build and run with Node 22.
- Deploy the plugin whole: ship all plugin files together — a partial update can leave the editor and server sides out of sync.