Are you looking for an efficient way to store raw data about products, stock, people, books, or anything else? A headless content management system (CMS) might just be the solution you need. In this article, we'll look at how to structure a headless CMS-based website and design the content model to support your goals.
The first step in every headless CMS-based project is the information architecture, which refers to your data model. There are two common patterns for designing the model: a model built around raw data and a model that represents concepts like pages and their content.
Headless CMS can be used for storing raw data about products, stock, people, books or whatever else. But it can also hold information about the structure of pages on a website. Without sacrificing the benefits of a headless approach - we can also provide users with familiar and easy-to-use tools to control the appearance of their content and foster reuse of existing material. In this article, we will look at an approach to how to structure headless CMS-based websites and design the content model to support these goals.
Information architecture
What comes first in every headless CMS-based project is the information architecture. This means - your data model. There are 2 common patterns for designing the model:
- Model built around raw data, e.g. products and stock
- Model that also represents concepts like pages and their content.
While the first approach is absolutely correct, the second can easily become an anti-pattern of a headless CMS application. Let’s look a bit deeper into pros & cons of both.
Raw data pattern
In the raw data pattern, we take great efforts to eliminate (or at least greatly reduce) any signs of the presentation layer in our data model. Some models we might see in a project would be:
- product
- invoice
The purpose behind doing this is to make it easier to repurpose data for various channels. By removing the HTML or other forms that dictate how content should be displayed, it becomes simpler to reuse the same content on different devices. This is one of the primary advantages of using headless CMSs. However, there are some drawbacks to this approach. The headless CMS essentially acts as a minimal front-end to a database, which may not be ideal for content editors. All of the descriptions of how the content is displayed must be defined in code, which means any changes to the website's appearance require a developer's involvement. This lack of control is not what customers expect from platforms like Wix, WordPress, or Adobe Experience Manager, where they want some degree of control and the ability to make changes without needing to engage development teams constantly.
Visual model
Quite the opposite approach, one which tries to address the need to easily perform changes on the website, is to include a description of the visual representation of our content in the headless data model. What we might find in a project that follows this path is, for example:
- page
Depending on the features provided by the headless CMS - content editors may have quite a bit of control over how the content is structured and rendered on a page. For example, Flotiq offers a block editor that allows authoring page sections using structured content blocks.
This approach, unfortunately, is very close to a headless CMS anti-pattern. Content stored in pages structured this way will likely be unusable in any channel except a website. Let’s look at an example page object, represented in JSON:
{
"title": "About us",
"url": "/about-us",
"keywords": "company information",
"header": "<h1>ACME company information page</h1>",
"mainContent": "<h2>Company history</h2><img src=\"/media/team-photo.jpg\" alt=\"Our team in 2022 has grown to 20 people!\"/><p>Our company has been founded in 1999, just before Y2K.</p>",
"footer": "<span style=\"font-size:8pt\">Call us at +1 (123) 456-789</span>"
}
Now - this will be easily rendered in a web browser, but what about a watch? Or what if you would like to send the company history information to a mobile phone in a text message? You will have to strip all the HTML, possibly removing some important information (like the contents of the alt attribute in the example above). Actually, you won’t even be able to reuse the information about company history on another page of your website - you would have to copy the entire page and only then start making adjustments. You will end up with a similar situation when using visual website builders.
Headless visual pattern
A sweet spot can be found between the 2 models above. A way to keep both - the editors wanting some flexibility and influence on the presentation layer and orthodox headless purists - happy. Let’s consider a specific example of a website selling tea. The basic data type, in this case, would be:
- product
- order
and providing this to content editors via a Headless CMS will allow them to easily add and update products as well as track orders. A very simple product detail page might look similar to the following (the code examples below are incomplete but are inspired by Next.js components):
export default function Product({ product }) {
return (
<div style="background-color: green">
<h1>{product.name}</h1>
<img src="{product.image}"/>
<span><b>Price</b>{product.price}</span>
<button>Buy</button>
</div>
)
}
That’s really straightforward. But will a content editor happily clone a Git repo, open up an IDE and change the background color of this page? Nope. So can we do anything about it?
Defining the architecture
In some cases, this might be an iterative process, but it usually starts with a simple question - what do you expect to update on the site, and how frequently will you do it? Based on the answers to these questions you will end up creating more or less complex content architecture. To address the situation in the example above - one might include in their content model (on top of the product and order content types) a productCard the model defined like this:
- productCard
and the component would instantly become:
export default function Product({ product, productCard }) {
return (
<div style="background-color: {productCard.cardBackground}">
<h1>{product.name}</h1>
<img src="{product.image}"/>
<span><b>Price</b>{product.price}</span>
<button>Buy</button>
</div>
)
}
This mix of content types originating from the raw data model and ones more related to the visual representation is really powerful if you think about it. Let’s consider that on our website, we also have a number of informational pages which describe the process of growing tea, packaging it and brewing it. Our UI designer created a modern minimalistic design based on 2 kinds of sections:
Sections' mockup
Content in these sections is text and a related image, but we already know there will be situations when the editors might want to visually emphasise some of these descriptions. How could we organize this in a headless CMS? Let’s look at an example:
- section
- page
In the section content type we’ve identified several important patterns:
a) sections can have the image on either side but otherwise are the same,
b) background color should be changeable by the editors,
c) heading text should be split from the rest to simplify the presentation.
For the page content - we chose to compose the content of links to existing section objects (Flotiq supports relations/linking between objects of different content types). This way, sections can be used on different pages, and editors can even decide what goes on which page and in what order.
export default function Section({ props } ) {
return (
<div style="background-color:{props.backgroundColor}; display:flex">
<div style="order: {props.variant == "leftTextRighImage" ? 1 : 2}">
<h1>{props.heading}</h1>
<span>{props.content}</span>
</div>
<div style="order: {props.variant == "leftTextRighImage" ? 2 : 1}">
<img src="{props.image}"/>
</div>
</div>
)
}
export default function Page({ page }) {
return (
{page.sections.map((section) => (
<Section section={section}/>
))}
)
}
Data in Flotiq
The example above can be implemented in Flotiq very quickly. Here are our content type definitions first.
Section
Content type definition of a section
Page
Content Type Definition of a page
Objects
Example section
Once the CTDS are in place, we can start creating content. Here’s an example section:
and a page could be like this:
A page reusing existing section objects
Summary
The primary advantage of headless CMS systems is that they separate data from its presentation, making it easier to repurpose the content for various channels. However, this division can cause problems with the authoring process and slow down development. On the other hand, prioritizing the presentation aspect can lead to a data model that does not allow for content reuse. By following the headless visual pattern, we can organize our content logically, map it onto code such as React components, and provide content editors with the ability to affect the presentation without requiring changes to the code.
By following this practical guide, you can successfully structure your content in a headless CMS to suit your needs without sacrificing the benefits of a headless approach.
Happy structuring!