Episerver settings tab

In Episerver projects there are at least two options to set your site settings. The most common ones are: use a settings page (which does not have a view nor it is navigable) or use the Start Page. We tend to use the second option because the reference to the start page is easy to get using ContentReference.StartPage. However, both solutions present problems. For the first case, you have a page which is part of your site tree structure which is not ideal. For the second case , you can easily clutter the start page with a lot fields which are not part of the start page at all and can cause issues when you try to update only the start page content.

During an Episerver Dev Happy Hour meeting, we were presented with an alternative that I think everyone should use and it solves all these issues at once. The main idea is to create a new tab in the assets pane where you can have all your settings and inside that tab you can add settings base items for each site. Similar to the way I explained in this post about creating non common content types.

In this post we are going use some code of the Episerver Foundation project (no cms, it is the commerce version) where this is implemented and explain how can you migrate your previous settings from the start page or settings page to this new approach.

First, we are going to copy all the code that is under the /src/Foundation.Cms/Settings/ folder from the Episerver Foundation project and put it in a Settings folder in your project. Just do not forget after copying the files to rename the namespace to your corresponding project.

After copying all files, try to compile your project to see if the new code causes errors. It should not, but just in case. We will also need to copy the lang file settings_en.xml which can be located under the directory /src/Foundation/lang/ to your lang directory

Now, we need to initialize the settings service using structure map. For this, you can add it to your structure map initialize class or use the following initialization module. The main goal here is that you could use the settings service by dependency injection via the settings service interface.

using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.ServiceLocation;
using Foundation.Cms.Settings;

namespace Foundation.Cms.Initialization
{
    [ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
    public class Initialize : IConfigurableModule
    {
        private IServiceConfigurationProvider _services;

        void IConfigurableModule.ConfigureContainer(ServiceConfigurationContext context)
        {
            _services = context.Services;
            _services.AddSingleton<ISettingsService, SettingsService>(); // Added as singleton
        }

        void IInitializableModule.Initialize(InitializationEngine context)
        {
            context.InitComplete += delegate
            {
                context.Locate.Advanced.GetInstance<ISettingsService>().InitializeSettings();
            };
        }

        void IInitializableModule.Uninitialize(InitializationEngine context)
        {
            // Do nothing
        }
    }
}

With everything initialize and set we can start working on the settings base items that we want to add. For that, we need to create a model which is going to inherit from the SettingsBase class. In this example, we are going to add two models; one for labels and the other one for site structure. You can locate these models anywhere you want. We recommend to locate them under Features/Settings directory.

using System.ComponentModel.DataAnnotations;
using EPiServer.DataAbstraction;
using EPiServer.DataAnnotations;
using Foundation.Cms.Settings;

namespace Foundation.Cms.Feature.Settings
{
    [SettingsContentType(DisplayName = "Label Settings",
        GUID = "c17375a6-4a01-402b-8c7f-18257e944527",
        Description = "Site labels settings",
        SettingsName = "Site Labels")]
    public class LabelSettings : SettingsBase
    {
        [CultureSpecific]
        [Required]
        [Display(Name = "Play Button", Description = "Play Button",
            GroupName = SystemTabNames.Content, Order = 10)]
        public virtual string PlayButton { get; set; }

        [CultureSpecific]
        [Required]
        [Display(Name = "Pause Button", Description = "Pause Button",
            GroupName = SystemTabNames.Content, Order = 20)]
        public virtual string PauseButton { get; set; }
    }
}
using System.ComponentModel.DataAnnotations;
using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.DataAnnotations;
using Foundation.Cms.Settings;

namespace Foundation.Cms.Feature.Settings
{
    [SettingsContentType(DisplayName = "Site Structure Settings Page",
        GUID = "bf69f959-c91b-46cb-9829-2ecf9d11e13b",
        Description = "Site structure settings",
        SettingsName = "Page references")]
    public class ReferencePageSettings : SettingsBase
    {
        [Required]
        [AllowedTypes(typeof(PageData))]
        [Display(Name = "Article Parent Page", Description = "Select the root page where Article Pages live",
            GroupName = SystemTabNames.Content, Order = 10)]
        public virtual ContentReference ArticleListingPage { get; set; }
    }
}

Finally, we are going to add it to the Content View Model which all page controllers use it in my project to send a view model instead of the page directly. You can also add it to any Content View model you use for pages or blocks like the PageViewModel and BlockViewModel that are used in Alloy. Another option is to use the ContentViewModel class from the Episerver foundation project.

using EPiServer.Core;
using Foundation.Cms.Feature.Settings;

namespace Foundation.Cms.ViewModels.Interfaces
{
    public interface IContentViewModel<out TContent> where TContent : IContent
    {
        TContent CurrentContent { get; }

        LabelSettings LabelSettings { get; set; }

        ReferencePageSettings ReferencePageSettings { get; set; }
    }
}
using EPiServer.Core;
using EPiServer.ServiceLocation;
using Foundation.Cms.Feature.Settings;
using Foundation.Cms.Settings;
using Foundation.Cms.ViewModels.Interfaces;

namespace Foundation.Cms.ViewModels
{
    public class ContentViewModel<TContent> : IContentViewModel<TContent> where TContent : IContent
    {
        protected Injected<ISettingsService> _settingsService;

        public LabelSettings LabelSettings { get; set; }
        public ReferencePageSettings ReferencePageSettings { get; set; }

        public ContentViewModel() : this(default)
        {

        }

        public ContentViewModel(TContent currentContent)
        {
            CurrentContent = currentContent;
            LabelSettings = _settingsService.Service.GetSiteSettings<LabelSettings>();
            ReferencePageSettings = _settingsService.Service.GetSiteSettings<ReferencePageSettings>();
        }

        public TContent CurrentContent { get; set; }
    }

    public static class ContentViewModel
    {
        public static ContentViewModel<T> Create<T>(T content) where T : IContent => new ContentViewModel<T>(content);
    }
}

Having implemented the content view model that way, allow us to get the labels using a simple syntax in the view as shown below.

Foundation.Cms.ViewModels.ContentViewModel<ArticleDetailPage>

@Model.LabelSettings.PlayButton

Compile the code and check everything is working as expected.

To make all this work, we need to create the corresponding settings in the Cms. However, sometimes the site settings tab located in the assets pane will not appear. In that case, what you can do is press the profile icon at the top right corner, press my settings, and then click in the reset views button.

Now you can go to the site settings tab and then to the folder of the site you want to create a setting, then click the hamburger icon, move to the new option and click in new setting option.

When you click the new setting option, you will be able to create any of the settings base items that inherit from the settings base class. In this scenario you can choose between label settings and site structure settings. You need one of each one per site in order to avoid errors.

Finally, fill the required fields for you settings base item.

That is it. Now, you can remove the settings that are in your home page or settings page and move them to use this new approach. If you have any question let me know. I hope it will help someone and as always keep learning !!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: