Within this tutorial, you will learn about the three different patterns that you can use to model page hierarchy within Contentful CMS. Modeling website hierarchy within a headless CMS is definitely more complicated compared to a traditional CMS.

In a traditional CMS, you will get access to a page tree. This tree will allow you to create pages using various templates in order to build up your website structure. Within a headless CMS, the content modeling process is different.

Within a headless CMS, there is no page tree. Obviously, you can use a headless CMS to power a website... so this raises the question... what's the best way to model menus and the structure of a website within Contentful?

Get this architectural decision wrong and your website might be very clunky to use. Get it right and you will be recognized as a complete legend by your content editors. If you are interested to learn how to master Contetnful, read on 🔥🔥🔥

One of the main content modeling paradigms within a headless CMS is the ability to model content that is separated from its presentational context. The benefit of this separation is being able to define content that can be reused anywhere.

On most projects, you will sill likely will want to power your website from Contentful, however, without the classic page tree, how do you model the site structure?

Topics and Assemblies

To answer this question, you need to understand some Contetnful specific jargon, Topics and Assemblies

using technical jargon that no one understands... aA 'topic' is an abstract logical representation of a type of content. In real terms, this could mean modeling a product, a video, or a news item. These are all examples of what Contentful deems as a topic.

Within the Contentful UI, you will never see the word topic itself. The idea of a topic is just a theoretical construct. Within the CMS, you will still create a content model and entries as normal. As long as you do not use a reference field on that content model, Contentful defines this as a topic! This is all very Zen thinking, Ommm.....

An assembly is a content model that references other content models! Again, an assembly is still just a content model that you create within the CMS the same as any other. When you add a reference field to a model that allows editors to reference another model, it theoretically can now be considered an assembly!

If the reference field only defines a one-to-one mapping, it's considered a fixed assembly. If the reference field allows for multiple references, it should be referred to as a flexible assembly! These terms are a little silly, however, when you need to define a website structure, you should map out what are topics and assemblies.

Website Structures

In order to model the website page hierarchy you can either create an assembly or, you can create a content type specifically designed for managing a page structure. The route you pick will be based on the website's planned hierarchy type. Whenever you model a website or an app you will need to structure your content in one of three ways:

  • Hierarchically: Classic parent/child relationship
  • Linear: All pages sit directly under the homepage
  • Webbed/networked: When pages can live in multiple areas within a site. A good example of a webbed can be found on most e-commerce site tags. A men's shirt details page might live under New, Mens, and Sale landing pages at the same time

When it comes to modeling hierarchy within Contentful, there are three main architectural approaches that you can implement. Two of the approaches involve defining the relationship on the page itself and the third option involves defining the hierarchy in a separate content type.

The two patterns that involve defining the relations on the page itself are called bottom-up or top-down. In the bottom-up approach, you would create a content type called Page. On Page, you define a reference field called parentPage (or something similar). On the parentPage property, you will need to add two validations. One validation is to make the property mandatory. The second validation is to restrict the editors to only be able to reference other models of type Page from that property.

Applying this pattern will mean that whenever an editor needs to create a new content page they will be forced into defining its hierarchy relationship before they can save the page. By enforcing this pattern, you will create a map from the current page back to the homepage.

The benefit of this approach is that you can query the API with a specific slug and then get access to its parent. You can then query the parent and get access to its parent. You can then repeat the process until you get back to the homepage.

There is an alternative variation to the bottom-up pattern. This variation makes sense when you need to model an area that is not so hierarchal in nature. Instead, the hierarchy is more webbed (also known as networked in nature). A typical example where this need can crop up is within an e-commerce store or a news area. Imagine your site had two top-level landing pages called New and Travel. You need a news item to appear in both.

A different solution to model this type of relationship is to change the intention of the parentPage property from a single-page picker to a multi-page picker instead. Using a Categories property, an editor could define a relationship between the current content item and one or more categories.

If you want to implement this pattern, I recommend that you build some flexibility into the design so that your categories can be accessed and rendered easily from anywhere within your site. To do this, you will need to define a new content type that will be used to represent the different categories. I would typically name this new content item Category. This new content type will be used as a bridge between the top-level landing page and the related items. This abstracted gateway will provide you with a means for accessing the related content from anywhere in your solution easily.

To implement this pattern, on your top-level landing page model, you can define a reference field so an editor can associate the current page with an item of type Category. From the individual news item page, using the Categories picker editors can also associate individual articles with as many categories as they like. With the relationships defined, in the code, you can then query for content that is related to the specific Category content type.

It is also possible to reverse this pattern so an item holds information about its children instead. This type of relationship is known as a top-down relationship. On each page, instead of defining a field to set the parent relationship, you include a property to map the allowed child relationships.

To implement a top-down pattern, within the Page content type, add a reference field called ChildPages. In terms of configuration, you should set ChildPages to be optional. You should also set the reference fields to allow editors to pick from many pages. Finally, do not forget to restrict the field so that editors can only reference pages.

The biggest issue with this top-down approach is trying to determine the route back home in code. In this pattern, it is easy to query the CMS and get the children of the page, however, figuring out where the current page lives within the overall site hierarchy is more complicated. This complexity tends to be the reason why the bottom-up pattern tends to be more favored. In general, I would say favor top-down where you can avoid deep nesting. If your site is mainly based on landing pages that all sit directly underneath the homepage and editors only need to create direct children, this pattern can make sense.

The final way of modeling hierarchy is to define the hierarchy relationship outside of the page content model. In this pattern, you create a specific content model just in order for an editor to define the hierarchy. By creating a separate content type to specifically model hierarchy, you can decouple your structured content from presentational concerns. This type of pattern is useful when your hierarchy is more webbed or networked. For example, in an e-commerce store, you might have an item of clothing (a topic) that appears under multiple top-level categories like menu, sale, and new. Using a specific model just for hierarchy will allow you to add the same bit of clothing into all three areas!

For developers moving from a more page-centric CMS, all of these patterns will likely feel clunky. It can definitely get a little frustrating when you may need to make multiple API calls just to render something simple like a breadcrumb menu. This is why modeling structured content within a headless CMS tends to be slightly more complex compared to modeling content within a page-centric CMS.

Modeling hierarchy within a solution that allows content to be agnostic from the presentation layer will always involve some type of compromise. The trade-off of having decoupled content that can be reused in multiple places is extra complexity modeling hierarchy. Within a page-centric CMS solution, the trade-off is content re-usability. How do you share content created in a page tree so that content can be shared in multiple areas easily? Neither approach is better than the other because each architecture has an opposing conflict.

My overall tip is that when modeling hierarchy, it is best to define the relation types first. Remember, that in Contentful terminology a content type that can reference other content types is referred to as an assembly. A content type that is set to only allow a single item to be referenced is known as a fixed assembly and a content type that allows for multiple references is known as a flexible assembly. When planning your hierarchy keep these different types in mind as it will help to clarify things. Also, just to state the obvious, it is also possible to use a combination of these patterns throughout your site.

When it comes to modeling page structure in your solution you need to consider your website's hierarchy first. After that, you need to consider if you want to model the relationship on a per-content-item basis or if you want to create a specific content type to model your items. Finally, you can then implement a solution.

As you can see with headless there is a trade-off between reusable content and hierarchy. Headless CMS allows for content to be reused more easily, however, the trade-off is that you will need to consider how to model hierarchy in more detail. Happy Coding 🤘