Views: 5297
Number of votes: 0
Average rating:

Restricting available page types for Root page

Now that we have strongly typed page types in EPiServer 7, we wonder how we ever lived without it. Actually… we just used the superb Page Type Builder, but that’s not the point. We now want to do everything in code rather than in the Admin mode, and we nearly can. However, there are a couple of little things that we can’t quite do yet, and restricting the available page types for the Root page is one of them. Typically, you will only ever be creating ‘start pages’ under the Root page, and you’ll probably have a specific type for the start page. If we do a ‘New page’ under the Root though, we get all of our page types listed! That’s a bit messy. So what are our options? Well, the Root page is in Admin mode; it’s called ‘Welcome page in Edit Mode’ and it’s type is ‘SysRoot’. We could restrict available page types there. But that’s going back to the dark ages. You can’t commit that to source control like other code and have it picked up by everyone else. A much nicer way would be to use the AvailablePageTypes attribute. No luck there though – the SysRoot has no code definition that I can find (according to Admin mode it doesn’t come from code) and so you can’t use it with the strongly-typed AvailablePageTypes attribute. Possibly you could create a definition for the SysRoot in code, but that’s a pretty scary thing to do and I personally wouldn’t want to go there – I used to do it in Page Type Builder but I wouldn’t want to in EPiServer 7.

So what do we do? I was asked that by a student in a training course recently, and so I had to comeup with an answer. Actually, it’s pretty easy. We use an Initialization Module and the API to do what Admin mode is doing, but automatically and in code. The code to achieve this is shown below. Note that in this example the start page type is ‘StartPage’.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using EPiServer.Framework;
using EPiServer.ServiceLocation;
using EPiServer.DataAbstraction;
using EPiServerZA.Models.Pages;
 
namespace EPiServerZA.Business
{
    [InitializableModule]
    [ModuleDependency(typeof(EPiServer.Data.DataInitialization))]
    public class RestrictRootPages : IInitializableModule
    {
        public void Initialize(EPiServer.Framework.Initialization.InitializationEngine context)
        {
            var sysRoot = ServiceLocator.Current.GetInstance<IContentTypeRepository>().Load("SysRoot") as PageType;
            var startPage = ServiceLocator.Current.GetInstance<IContentTypeRepository>().Load(typeof(StartPage));
 
            var setting = new EPiServer.DataAbstraction.PageTypeAvailability.AvailableSetting();
 
            setting.Availability = EPiServer.DataAbstraction.PageTypeAvailability.Availability.Specific;
            setting.AllowedPageTypeNames.Add(startPage.Name);
 
            ServiceLocator.Current.GetInstance<EPiServer.DataAbstraction.PageTypeAvailability.IAvailableSettingsRepository>().RegisterSetting(sysRoot, setting);
        }
 
        public void Preload(string[] parameters)
        {
           
        }
 
        public void Uninitialize(EPiServer.Framework.Initialization.InitializationEngine context)
        {
           
        }
    }
}

The code simply grabs the SysRoot and StartPage types from the content type repository then makes the StartPage the only available page type on the SysRoot. There is a dependency on DataInitialization so that the repositories should be ready to use when this runs. Any clarifications or easier ways to achieve this are welcome Smile

Nov 20, 2013

Al Higgs
(By Al Higgs, 11/21/2013 4:45:50 PM)

Nice article Dan!

Al Higgs
(By Al Higgs, 11/21/2013 4:46:03 PM)

Very useful to know Dan

thomassvensen
(By thomassvensen, 1/17/2014 2:16:08 PM)

Very useful, Dan, thank you!

We are using 7.5.409, and I found they've changed things slightly. My coded ended up looking like this:

var locator = ServiceLocator.Current;
var contentTypeRepository = locator.GetInstance();
var sysRoot = contentTypeRepository.Load("SysRoot") as PageType;
var startPage = contentTypeRepository.Load(typeof(StartPage));
var setting = new AvailableSetting {Availability = Availability.Specific};
setting.AllowedContentTypeNames.Add(startPage.Name);
var availabilityRepository = locator.GetInstance();
availabilityRepository.RegisterSetting(sysRoot, setting);

dan.matthews
(By dan.matthews, 2/11/2014 9:27:13 AM)

Thanks for the update Thomas, yes it makes sense that it is slightly different in 7.5 as they have abstracted some additional things around content!

eric.herlitz
(By eric.herlitz, 10/15/2016 9:29:44 PM)

The code will only work if there actually is a startpage created. A null protect on the startpage variable and the code is usable once again!

var locator = ServiceLocator.Current;
var contentTypeRepository = locator.GetInstance();
var sysRoot = contentTypeRepository.Load("SysRoot") as PageType;
var startPage = contentTypeRepository.Load(typeof(StartpagePage));
if (startPage != null)
{
    var setting = new AvailableSetting { Availability = Availability.Specific };
    setting.AllowedContentTypeNames.Add(startPage.Name);
    var availabilityRepository = locator.GetInstance();
    availabilityRepository.RegisterSetting(sysRoot, setting);
}

Thanks for sharing.

dan.matthews
(By dan.matthews, 11/10/2016 2:22:39 PM)

Thanks for feedback Eric... I presume you mean start page TYPE created, which you might not have on first time load as it's possible I guess that the start page type hasn't synced into your content type repository BEFORE this loads. Maybe you could change your module dependency to a later one (like EPiServer.Web.InitializationModule) which would probably ensure that you have your StartpagePage type (in your example) already synced into the content type repository before this code runs. Otherwise, this will only pick up and run on your second load :)

Please login to comment.