Dan Matthews
Nov 20, 2013
visibility 8068
star star star star star
(0 votes)

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

Comments

Al Higgs
Al Higgs Nov 21, 2013 03:45 PM

Nice article Dan!

Al Higgs
Al Higgs Nov 21, 2013 03:46 PM

Very useful to know Dan

thomassvensen
thomassvensen Jan 17, 2014 01:16 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
Dan Matthews Feb 11, 2014 08:27 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!

Oct 15, 2016 07:29 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
Dan Matthews Nov 10, 2016 01:22 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 :)

error Please login to comment.
Latest blogs
Composition Over Inheritance: Why Your Content Contract Is Not a Base Class

Inside the structural conformance pattern in SaaS CMS — from server-side inheritance to pipeline governance. A contract in Optimizely SaaS CMS is...

Vipin Banka | Sep 19, 2026

Optimizely Opti ID Integration: Why the API Key Was Missing from the DXP Management Portal

While working on an Optimizely CMS 12 Opti ID integration recently, we ran into an issue that initially appeared to be related to SSO authenticatio...

Madhu | Sep 18, 2026 |

Extending a Contract: What You Can Override

Contracts share fields across content types — but not every field setting can be overridden. Push the same contract onto several components, and CM...

Chirag Khanna | Sep 18, 2026 |

Building a Blazor Server UI Inside the Optimizely CMS 13 Admin Shell

What I learned shipping a Blazor Server UI inside Optimizely CMS 13 — Razor components in a NuGet package, the Blazor hub next to MapContent(),...

Stanisław Szołkowski | Sep 17, 2026 |