Some problems seem to be simple at first, but then take a while to find a good solution. Some applications like headless WordPress not only require technical functionality, but also content editing capabilities that go beyond “simple” data input forms and displaying them.
Context: Let’s build an eLearning platform
Let’s take the example of an eLearning or “learn management” platform. When faced with the challenge of designing such a system, we had to consider different requirements.
On this eLearning platform, teachers should be able to create courses with rich content – text, images, videos, custom widgets – you name it – and of course have the ability to maintain and edit content with an intuitive and easy to use user interface.
For the students, the users of the platform, it should both offer learning content as well as management functionalities, such as tracking my progress, collaborating with others and managing my courses. Last but not least, as developers, we wanted to use a modern software stack that allowed us to efficiently create a well-functioning and easy to maintain product.
Technology choices: use the power of WordPress to save time and provide a great editing experience?
So, what technology do you choose? A common approach would be to create a Single Page Application (SPA) using your frontend framework of choice. In our case, this would have been React in combination with TypeScript with a Backend API connected to an SQL/NoSQL-Database doing the heavy lifting.
However, for this project, the interesting challenge was that we wanted to offer a rich set of content editing functionalities which is already available in different Content Management System (CMS), and we certainly did not want to reinvent the wheel. Ideally, we could use an existing CMS and benefit from its features, ongoing maintenance and plug-in ecosystem. The obvious first choice for a CMS is WordPress, as it is by far the most used. WordPress powered 37% of all web sites in 2019 with a huge user base and ecosystem.
The choice is WordPress
However, as great as WordPress is for content-creating users, it is unpleasant for developers to work with. On the one hand, the programming language PHP has become a bit dated and lacks the developer tooling support of other languages. However, the far bigger issue is WordPress’ approach of mixing configuration with content in one database. As developers, we are used to working with “develop”, “staging” and “production” systems and deployments in order to achieve a reliable live version of a platform where functionality updates are automatically deployed after being thoroughly tested and validated.
This is notoriously hard with WordPress, as you cannot always separately deploy functionality updates (e.g. creating a new login page) without transferring the database as well. This means, that if you have a live system where your users are actively creating and working on content, you are bound to recreate certain changes you validated on staging a second time on the live system, which is both a time consuming and manual process.
Getting the Architecture Right
The good thing is, you can work around these issues and create a quite powerful symbiosis, combining the best of two worlds.
The overall architecture of our headless WordPress approach:
We decided on the following system architecture:
- Students see and use a React Single Page Application (SPA) which displays learning content and allows them to manage their learning progress and account.
- All data is served by an API. Since we went for a full stack TypeScript approach, we are using NestJS here. The API handles authorisation, and user-profile functionalities, and serves as a caching server to expose the learning content…
- … which is served by a WordPress instance via API. Teachers directly use the WordPress admin interface to directly create and update content using the WordPress Gutenberg Editor – giving them a powerful tool to work with and saving us the effort of implementing a solution of our own.
The key to this setup is that WordPress is used for what it is great at – creating content. We let our API backend handle the rest of the functionality. This makes the WordPress installation easy to maintain and deploy, taking away many of the pain points you would usually have.
Let’s dig down deeper and have a look at what WordPress looks like at an API-Level. Thankfully, recent versions of WordPress come with a REST-API built in, so you don’t need an extra plugin to get started.
WordPress API Structure: Everything Revolves Around a “Post”
The core WordPress data structure is a Post. A post can be a classical blog post, but it can also be a static page or custom content as in our case. Let’s have a closer look at a post via the API. If you want to play around with a local WordPress installation, I recommend you use a Docker-C
compose setup as described here.
Going to localhost:8080/wp-json/wp/v2/posts, you will see all posts published on your installation. Besides the title, modified date, author, slug and so on, the post itself is rendered as HTML inside the content.rendered attribute.
What is important to note here is that while you get HTML, you need to take extra care about the styling. Normally, one would use a WordPress theme to apply a certain style and design to a page. Since we are now using a separate frontend, we need to take care to have appropriate styles for <h>, <p> etc defined in our SPA.
There is a little trick though
If you are working with the default Gutenberg editor, you can already do quite a bit of the layout (e.g. paragraphs, quotes, two-column layouts and similar). This layout manifests as wp-block-* CSS classes in your content’s HTML. In order to display these attributes correctly, you can just include the default blocks stylesheet generated by WordPress. In our experience, there have been very few clashes with our custom styles when using this stylesheet.
Now, we can get a post’s content and style it accordingly, which offers us the base functionality to work with WordPress as a headless CMS. However, we are not limited to exchanging HTML.
Imagine we not only want to display the course content, but also to have a nice teaser-text and a thumbnail image for each course. This is where ACF (Advanced Custom Fields) comes into play. ACF allows you to specify additional fields and rule where to attach them. This means we can configure WordPress to require authors to add a teaser-text and a thumbnail image. Conveniently, these fields are exposed directly in the post API as well, making it easy to work with:
Consequently, in our frontend application, we only need to look up the field values and can readily use them to build a custom “course preview” react component. With this approach, we can extend WordPress to be an easy to use source of structured content consumed by our system.
Deployment and Lifecycle Considerations
Finally, let me share a few words about the deployment of such a system. While there is little discussion about how to deploy the API-Server and React SPA (we use a develop/staging/production deployment flow), the lifecycle of our WordPress content-API can be debated.
One approach would be certainly to have three WordPress instances being deployed, and then transferring code + configuration by transferring database dumps between these three deployments.
However, depending on your exact use case, another viable approach might be to have only two instances: a “live” WordPress instance that is used to serve content to both the staging and production deployment, and a “testing” instance to test major WordPress changes.
Under the assumption that content changes do not require frequent WordPress modifications, you could use the live instance to serve live and testing content (which can be separated – e.g. by using different post categories inside WordPress), and only use the testing instance if you need to validate that certain bigger changes do not break the live system. This would greatly reduce the amount of database transfers you need to perform, while only having a slightly increased risk for the production system.
This blog post is just the beginning and we have barely scratched the surface of what is possible. You can go way further and customise the editing experience by starting to create custom blocks for the WordPress “Gutenberg” editor or start to integrate complete page-building tools such as Elementor.
All things considered, when used correctly, WordPress is a powerful tool that is part of a modern and efficient development workflow. It offers a great editing experience for content creators, and by using its API with a headless approach to serve content to your application, you can also create complex applications that are a delight to use for your end-users.
I hope that with this post I have given you a few ideas on how to start your next content-heavy development project. If you want to learn more or have a project in mind, contact us for a first personal consultation.