Headless WordPress And Nextjs
The Mission
We were tasked with creating a system that would allow our client to spin up as many unique sites as needed under any domain and or subdomains. This site should be flexible enough to reuse page sections/templates and styles across all their sites. The resulting system would be able to spin up anywhere from 20 to 100 sites running off a single application instance, but each site would be a unique entity. Each site would not just house content but must integrate with existing backend legacy data and custom business logic to display additional dynamic content and widgets.
After playing around with many CMSs we settled on WordPress. This is not just a multi-site in the sense of subdomains or subfolders, which is a supported WordPress feature, but a Multi-Domain System. Due to this, we reached out for Nextjs to consumer WordPress APIs and augment that data with existing legacy data. Separating out the frontend from WordPress gave us the ability to leverage all that is great with WordPress while allowing for extreme flexibility and the ability to pivot on changing requirements.
The Puzzle Pieces
Once we settled on WordPress, we were tasked with integrating its multisite feature into a frontend, with our client wanting to use React. We selected on Nextjs as it provided the server-side rendering and optimizations we needed. Leveraging Nextjs’s server-side rendering and out-of-the-box build optimizations, we can use WordPress as a headless CMS and engage its APIs to get the content we needed. Using these two systems, we can spin up countless sites. Our client wanted to make sure this new system was fully dockerized, making the WordPress setup a bit more complicated. This requirement forced us to use an external MySQL database and external storage for the images.
When all was said and done, we manage to get the new infrastructure on Google Cloud leveraging the below services:
- Google Cloud Run, for our application containers
- Google Cloud Build, for our build pipeline
- Google Cloud SQL, for our database
- Google Memory Store, for application memory storage
- Google Registry Container, for our Docker Images
- Google Cloud Storage, for our WordPress Images
- Google Load Balancer, for our Domain Mapping
- Google Compute Engine, for other Legacy System Integrations
Having the whole infrastructure dockerized allows for rapid development as we were able to mimic the entire production environment locally and iterate over changes at extreme speed. We put this all behind Cloudflare CDN to offload as much as we can for both cost and performance benefits. Given this setup, a user could request domain1.com, domain2.com, or domain3.com and have them all served from the same Nextsjs application, which would call the WordPress API to fetch the content associated with that site. This communication from the Nextjs to WP is all on the server-side, allowing us to enrich the content with our client’s internal data as we could make additional calls as needed. The output would then be cached in our CDN, offloading it for future requests.
Conclusion
We faced many challenges along the way, such as performance issues and infrastructure setup. One of these challenges was efficiently serving images. We were able to offload the images to the Google Cloud bucket. Still, We needed to create a separate subdomain that remains constant across all the domains to cache them at our CDN without creating multiple copies, so our cache hit ratio remained high. We were able to leverage the Google Load Balancer to do this map as well as this WordPress plugin. Another issue was around performance. There was a small delay from our WordPress containers to our Cloud SQL database. This delay would have been acceptable in any other application, but given the magnitude of the customizations we had, this 1.2-millisecond delay caused our WordPress admin to seem slightly sluggish. This WordPress slowness is a current issue we are addressing, so tune back in for future posts to see how we overcame this challenge. Ultimately the system as a whole seems to be working great after some tuning. In a future post, we will be reviewing our maintenance strategies around Unit and End-to-End testing as well as how we manage our infrastructure alerting and error tracking.
Thank you for reading and please feel free to share using the links below! If you would like to stay up to date with our posts, you can also subscribe below.