Dan Matthews
Nov 20, 2013
  6791
(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);

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.

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 :)

Please login to comment.
Latest blogs
Opti ID overview

Opti ID allows you to log in once and switch between Optimizely products using Okta, Entra ID, or a local account. You can also manage all your use...

K Khan | Jul 26, 2024

Getting Started with Optimizely SaaS using Next.js Starter App - Extend a component - Part 3

This is the final part of our Optimizely SaaS CMS proof-of-concept (POC) blog series. In this post, we'll dive into extending a component within th...

Raghavendra Murthy | Jul 23, 2024 | Syndicated blog

Optimizely Graph – Faceting with Geta Categories

Overview As Optimizely Graph (and Content Cloud SaaS) makes its global debut, it is known that there are going to be some bugs and quirks. One of t...

Eric Markson | Jul 22, 2024 | Syndicated blog

Integration Bynder (DAM) with Optimizely

Bynder is a comprehensive digital asset management (DAM) platform that enables businesses to efficiently manage, store, organize, and share their...

Sanjay Kumar | Jul 22, 2024

Frontend Hosting for SaaS CMS Solutions

Introduction Now that CMS SaaS Core has gone into general availability, it is a good time to start discussing where to host the head. SaaS Core is...

Minesh Shah (Netcel) | Jul 20, 2024

Optimizely London Dev Meetup 11th July 2024

On 11th July 2024 in London Niteco and Netcel along with Optimizely ran the London Developer meetup. There was an great agenda of talks that we put...

Scott Reed | Jul 19, 2024