Jump to Section
Prerequisites
- A working Umbraco CMS v8 setup.
- Basic understanding of Umbraco's back office.
- Familiarity with C# and Umbraco's APIs.
Role-Based Customization of Umbraco CMS Back-Office Interface
The purpose is to provide content managers, writers, and technical teams with a simplified and clutter-free back office interface by showing or hiding specific fields and tabs.
To ensure that they only see content types and fields relevant to their role.
Include these essential namespaces
using Umbraco.Web.Editors;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.PublishedModels;
using Umbraco.Core.Composing;
Create the Composer and Component
The custom composer will append our component to Umbraco's component collection during the application's startup.
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public class HideContentPartsComposer : IUserComposer
{
public void Compose(Composition composition)
{
composition.Components().Append<HideContentPartsComponent>();
}
}
Now, create the component that will handle the logic for showing or hiding content based on the user role.
public class HideContentPartsComponent: IComponent
{
public void Initialize()
{
throw new NotImplementedException();
}
public void Terminate()
{
throw new NotImplementedException();
}
}
Register SendingContentModel event
Secondly, go to HideContentPartsComponent and set the SendingContentModel event for EditorModelEventManager as follows:
public void Initialize()
{
EditorModelEventManager.SendingContentModel += EditorModelEventManager_SendingContentModel;
}
private void EditorModelEventManager_SendingContentModel(HttpActionExecutedContext sender, EditorModelEventArgs<ContentItemDisplay> e)
{
//Restrict visibility here
}
Finding user groups for logged-in Umbraco user
To get user roles in Umbraco, you need to refer to the CurrentUser object inside UmbracoContext as follows:
IList<string> _currentUserGroupsAliasses =
e.UmbracoContext.Security.CurrentUser?.Groups?.Select(userGroup => userGroup.Alias).ToList();
Showing content fields only for the role
private void ShowFieldOnlyForRole(ContentItemDisplay contentItemDisplay, string contentTypeAlias, string propertyAlias, string userGroup)
{
if (contentItemDisplay.ContentTypeAlias.Equals(contentTypeAlias))
{
if (!_currentUserGroupsAliasses.IsNullOfEmpty() && !_currentUserGroupsAliasses.Contains(userGroup))
{
foreach (var tab in contentItemDisplay?.Variants?.FirstOrDefault()?.Tabs?.ToList())
{
if (!tab.Properties.IsNullOfEmpty())
{
tab.Properties = tab.Properties.Where(x => x.Alias != propertyAlias);
}
}
}
}
}
For example, to display the 'google manager' field exclusively for administrators, use the following method:
/* Show google manager field only for admin */
ShowFieldOnlyForRole(contentItemDisplay: e.Model, contentTypeAlias: "globalSettings",
propertyAlias: "googleTagManagerId", userGroup: "admin");

Showing googleTagManagerId field for admin role
Showing content tabs only for the role
private void ShowTabOnlyForRole(ContentItemDisplay contentItemDisplay, string contentTypeAlias, string tabAlias, string userGroup)
{
if (contentItemDisplay.ContentTypeAlias.Equals(contentTypeAlias))
{
if (!_currentUserGroupsAliasses.IsNullOfEmpty() && !_currentUserGroupsAliasses.Contains(userGroup))
{
if ((contentItemDisplay?.Variants?.FirstOrDefault()?.Tabs?.Any()).GetValueOrDefault(false))
{
contentItemDisplay.Variants.FirstOrDefault().Tabs =
contentItemDisplay.Variants.FirstOrDefault().Tabs.Where(x=> x.Alias != tabAlias);
}
}
}
}
To show the ‘SEO Settings’ tab only for the admin role execute the method as follows:
/* Show 'SEO Settings' tab only for admin role */
ShowTabOnlyForRole(contentItemDisplay: e.Model, contentTypeAlias: "globalSettings",
tabAlias: "SEO Settings", userGroup: "admin");

Showing SEO Settings tab only for admin role
Show content tab only for specific roles
To make ‘SEO Settings’ tab visible only for both admin and editor roles, execute the method as follows:
ShowTabOnlyForRoles(contentItemDisplay: e.Model, contentTypeAlias: "globalSettings",
tabAlias: "SEO Settings", userGroups: new []{ "admin", "editor" } );
private void ShowTabOnlyForRoles(ContentItemDisplay contentItemDisplay, string contentTypeAlias, string tabAlias, string[] userGroups)
{
if (contentItemDisplay.ContentTypeAlias.Equals(contentTypeAlias))
{
if (!_currentUserGroupsAliasses.IsNullOfEmpty() && !userGroups.IsNullOfEmpty() && !_currentUserGroupsAliasses.Any(cug=> userGroups.Any(ug=>ug == cug)))
{
if ((contentItemDisplay?.Variants?.FirstOrDefault()?.Tabs?.Any()).GetValueOrDefault(false))
{
contentItemDisplay.Variants.FirstOrDefault().Tabs =
contentItemDisplay.Variants.FirstOrDefault().Tabs.Where(x=> !x.Alias.Equals(tabAlias));
}
}
}
}
Show list of tabs only for specific roles
To make ‘SEO Settings’ and “Content” tab visible only for both admin and editor user groups, execute the method as follows:
ShowTabsOnlyForRoles(contentItemDisplay: e.Model, contentTypeAlias: "globalSettings",
tabAliases: new []{ "Content", "SEO Settings"} , userGroups: new []{ "admin", "editor" } );
private void ShowTabsOnlyForRoles(ContentItemDisplay contentItemDisplay, string contentTypeAlias, string[] tabAliases, string[] userGroups)
{
if (contentItemDisplay.ContentTypeAlias.Equals(contentTypeAlias))
{
if (!_currentUserGroupsAliasses.IsNullOfEmpty() && !userGroups.IsNullOfEmpty() && !_currentUserGroupsAliasses.Any(cug=> userGroups.Any(ug=>ug == cug)))
{
if ((contentItemDisplay?.Variants?.FirstOrDefault()?.Tabs?.Any()).GetValueOrDefault(false))
{
contentItemDisplay.Variants.FirstOrDefault().Tabs =
contentItemDisplay.Variants.FirstOrDefault().Tabs.Where(x=> !tabAliases.Contains(x.Alias));
}
}
}
}
Helper Extensions
We'll include an extension method to streamline the code.
using System.Collections.Generic;
public static class CollectionsExtensions
{
public static bool IsNullOrEmpty<T>(this ICollection<T> collection)
{
return collection == null || !collection.Any();
}
}
Working HideContentPartsComponent implementation
public class HideContentPartsComponent: IComponent
{
IList<string> _currentUserGroupsAliasses;
public void Initialize()
{
EditorModelEventManager.SendingContentModel += EditorModelEventManager_SendingContentModel;
}
private void EditorModelEventManager_SendingContentModel(HttpActionExecutedContext sender, EditorModelEventArgs<ContentItemDisplay> e)
{
_currentUserGroupsAliasses = e.UmbracoContext.Security.CurrentUser?.Groups?.Select(userGroup => userGroup.Alias).ToList();
/* Show google manager field only for admin */
ShowFieldOnlyForRole(contentItemDisplay: e.Model, contentTypeAlias: "globalSettings",
propertyAlias: "googleTagManagerId", userGroup: "admin");
/* Show 'SEO Settings' tab only for admin role */
ShowTabOnlyForRole(contentItemDisplay: e.Model, contentTypeAlias: "globalSettings",
tabAlias: "SEO Settings", userGroup: "admin");
}
private void ShowFieldOnlyForRole(ContentItemDisplay contentItemDisplay, string contentTypeAlias, string propertyAlias, string userGroup)
{
if (contentItemDisplay.ContentTypeAlias.Equals(contentTypeAlias))
{
if (!_currentUserGroupsAliasses.IsNullOfEmpty() && !_currentUserGroupsAliasses.Contains(userGroup))
{
foreach (var tab in contentItemDisplay?.Variants?.FirstOrDefault()?.Tabs?.ToList())
{
if (!tab.Properties.IsNullOfEmpty())
{
tab.Properties = tab.Properties.Where(x => x.Alias != propertyAlias);
}
}
}
}
}
private void ShowTabOnlyForRole(ContentItemDisplay contentItemDisplay, string contentTypeAlias, string tabAlias, string userGroup)
{
if (contentItemDisplay.ContentTypeAlias.Equals(contentTypeAlias))
{
if (!_currentUserGroupsAliasses.IsNullOfEmpty() && !_currentUserGroupsAliasses.Contains(userGroup))
{
if ((contentItemDisplay?.Variants?.FirstOrDefault()?.Tabs?.Any()).GetValueOrDefault(false))
{
contentItemDisplay.Variants.FirstOrDefault().Tabs =
contentItemDisplay.Variants.FirstOrDefault().Tabs.Where(x=> x.Alias != tabAlias);
}
}
}
}
private void ShowTabOnlyForRoles(ContentItemDisplay contentItemDisplay, string contentTypeAlias, string tabAlias, string[] userGroups)
{
if (contentItemDisplay.ContentTypeAlias.Equals(contentTypeAlias))
{
if (!_currentUserGroupsAliasses.IsNullOfEmpty() && !userGroups.IsNullOfEmpty() && !_currentUserGroupsAliasses.Any(cug=> userGroups.Any(ug=>ug == cug)))
{
if ((contentItemDisplay?.Variants?.FirstOrDefault()?.Tabs?.Any()).GetValueOrDefault(false))
{
contentItemDisplay.Variants.FirstOrDefault().Tabs =
contentItemDisplay.Variants.FirstOrDefault().Tabs.Where(x=> !x.Alias.Equals(tabAlias));
}
}
}
}
private void ShowTabsOnlyForRoles(ContentItemDisplay contentItemDisplay, string contentTypeAlias, string[] tabAliases, string[] userGroups)
{
if (contentItemDisplay.ContentTypeAlias.Equals(contentTypeAlias))
{
if (!_currentUserGroupsAliasses.IsNullOfEmpty() && !userGroups.IsNullOfEmpty() && !_currentUserGroupsAliasses.Any(cug=> userGroups.Any(ug=>ug == cug)))
{
if ((contentItemDisplay?.Variants?.FirstOrDefault()?.Tabs?.Any()).GetValueOrDefault(false))
{
contentItemDisplay.Variants.FirstOrDefault().Tabs =
contentItemDisplay.Variants.FirstOrDefault().Tabs.Where(x=> !tabAliases.Contains(x.Alias));
}
}
}
}
public void Terminate()
{
EditorModelEventManager.SendingContentModel -= EditorModelEventManager_SendingContentModel;
}
}
Common pitfall and workaround when hiding properties/tabs in Umbraco
However, not everything works beautifully, as the Umbraco documentation says.
Wojciech Tengler noticed a bug.
When submitting content, hidden properties might unexpectedly save as empty values.
To prevent this, instead of just hiding the properties, consider changing the view.
Here's an example in pseudo-code:
var tabAlias = "tabAliasToHide";
foreach(var variant in model.Variants) {
var tabsToHide = variant.Tabs.Where(t => t.Alias.Equals(tabAlias));
foreach(var tab in tabsToHide) {
foreach(var propety in tab.Properties) {
propety.View = "/App_Plugins/CustomPropertyEditorViews/PropertyWithoutAccess.html";
}
}
}
Conclusion
Umbraco's extensible nature means it can be tailored to specific requirements, as demonstrated by this role-based visibility control.
By understanding and leveraging Umbraco's events and APIs, you can create an intricate content control system that enhances productivity, security, and user experience.
You can modify or extend the above code as needed, and I recommend exploring the Umbraco events if you need more advanced back-office workflows.
📚 For more tips and updates, don't forget to browse our blog. 👩💻👨💻