In this tutorial, you will learn about the different ways of dealing with global settings within Umbraco V8. Global settings are a staple of pretty much every single CMS project I have ever worked on. Feature flags, header and footer settings, sitewide meta-data, all these settings need to be stored somewhere in the CMS, the question is where?
Out-of-the-box Umbraco does not provide any mechanisms for developers to deal with global settings. It will be up to you to decide where you want to install these settings. Within this tutorial, I will propose three solutions that you can use:
- The Homepage Settings Pattern
- The Settings Page Pattern
- The Settings Block Pattern
The Homepage Settings Pattern
The homepage settings pattern is by far the most common pattern used in almost every CMS. In this pattern, all global settings are stored on the homepage document-type. Normally a tab, or, a section is created on the homepage document-type called 'Settings', or, something equally as imaginative. The settings sections primary purpose is to be a general placeholder for all site wide settings. You can see this pattern applied in the majority of the starter-kits. For example, if you check out the Fanoe starter kit you will see this pattern in action.
There are both advantages and disadvantages of the homepage settings pattern.
Advantages:
- You do not need to create any additional document-types
- The homepage is easy to access anywhere in code
Disadvantages:
- Homepage bloat
- Hard for content editors to understand the homepage
- Performance
The main disadvantage of this pattern may not be too noticeable when the website is first launched. When a website launches you may only need a handful of properties. To see where the issues might occur let us look to the future. Imagine the site has been live for 5 years. It is impossible to predict exactly how a site will change over time, however, we all know it will. Re-designs will occur. New components will be required. The project team will change. When refactoring code, keeping track of what settings relate to what features will become a burden and a chore. It is easy to forget to clean up a setting that is no longer used.
To make things worse, there is also a risk associated with removing properties from the homepage. Imagine removing a setting that you think is obsolete. Unbeknownst to you, this particular setting is used on the menu. Removing the setting in production breaks the menu. The consequence of a broken menu is that the whole site breaks. I have seen several live production websites being taken down due to this exact issue over the years, so be careful while refactoring and using this pattern. As refactoring properties from the homepage is risky, even developers with the best of intentions can be hesitant to maintain settings on the homepage.
The code to access settings on the homepage can be done using the IUmbracoContextFactory
. In this approach my recommendation is to create a service that you inject into your route-hijacked controllers, like this:
The code above uses the Umbraco ModelsBuilder. The Home
model was generated by the model builder based on a document-type called 'Home' within the CMS.
Settings Page Pattern
An alternative approach to storing settings on the homepage is to create a document-type specifically used for storing global settings. The settings page is usually located outside of the website hierarchy as a child of the root node. In terms of relationships, this could also be referred to as a sibling of the homepage. The Umbraco content-tree structure in this pattern would look like this:
- Root
- Home
- Page 1
- Page 2
- Settings
This pattern definitely has more advantages than disadvantages. The advantages include:
- Settings can be more easily refactored
- No page-load impact on the homepage
- Decoupled architecture
While the main disadvantages being:
- An additional document-type needs to be created
The settings-page can be accessed in code using DescendantsOrSelf()
, like this:
Note The code above assumes site settings document-type is called 'settings page'.
It is also possible to add the settings page as a child of the homepage. I would advise against this though. In this pattern the CMS content-tree would look like this:
- Root
- Home
- Page 1
- Page 2
- Settings
First, the page could accidentally be indexed and returned within the search results, second, the menu may pick it up and reference it in the primary navigation, finally, it could even appear within the site-map. Global settings should never be publicly accessible and ensuring the setting-page sits outside the main content tree will prevent this from happening.
Settings-Block Pattern
The settings-block pattern is a variation of the settings page pattern. As of Umbraco V8.9, Umbraco now ships with a new property called the block-list editor. For this discussion, the important concept to grasp is the usefulness of a block. Blocks within the block list editor are created from normal document-types. A document-type become a block when the 'Is Element' checkbox is selected. A block can contain all the same properties as any other document-type. This means that you can use a block to store your settings! What's better is you can group related settings into separate blocks. blocks. These blocks can then be added to a settings page that has a block-list editor defined within it.
The benefit of this third pattern is the layer of abstraction it provides. Closely related global-settings can be added into different blocks. These blocks can then be added to the setting page. As time progresses blocks can easily be added and removed. New settings blocks can be created when new features are being built. This will help make it easier to manage settings.
Blocks provide a more robust process for maintaining global settings. Batching related settings into specific blocks will give more flexibility. If a batch of settings become obsolete that one block can be deleted. Being able to add and remove blocks like this follows the open/close principle in SOLID. Settings can be added without modifying the behaviour of the existing system. This will make maintaining global settings in the future easier. Another added side-effect of having global settings split across multiple blocks will prevent a monolith from occurring. To get started with the settings-block you would use this code:
Within a controller, a setting from a block can be accessed like this:
Where FeatureFlags
is a block added into a block-list-editor, simple!
You can see this working, in my V8 sample site here. Happy Coding!