A Closer Look at the AvailablePageTypes Attribute in EPiServer 7

March 2022 Update: This post was originally written for EPiServer version 7. In 2021, Episerver (now known as Optimizely) released version 12. Luckily, the information in this post has been relatively unchanged since it was written in 2013. Links to the documentation have been updated.

I was recently looking into how to fully use the [AvailablePageTypes] attribute in my page models, and after a bit of research and reading the sometimes confusing documentation, and the less confusing class documentation, I found it has some interesting and helpful features. Let's take a closer look at this attribute.

Update: If you are using EPiServer 7.5+, this attribute is now called AvailableContentTypes

Using the Attribute

As you could guess, this attribute is used to specify which page types can or cannot be created under an instance of a specific page type. This is an optional attribute, but it can drastically help organize the 'Create New Page' screen, while also preventing editors from creating pages in the wrong area. This attribute is not supported on block models.

Availability

The first parameter in the attribute is Availability. This parameter takes one value from the Availability enum found in the EPiServer.DataAbstraction.PageTypeAvailability namespace. There are four possible options:

  • All - This specifies that all page types will be available to be created under a page instance. This is the default value.
  • None - This specifies that no page types will be available to be created under a page instance. If this value is set, all other settings on the attribute are ignored.
  • Specific - This specifies that only the selected page types will be created under a page instance. This value makes more sense when configuring available page types in Admin Mode. (My guess is that when any of the other settings on the attribute is set, this value gets auto-selected.)
  • Undefined - You shouldn't use this, as it's not even an option in Admin Mode.

Include and Exclude

The two most common parameters for this attribute are Include and Exclude, both of which require an array of Types. One common example would be on a Start Page model:

[ContentType(GUID = "00000000-0000-0000-0000-000000000000")]
[AvailablePageTypes(
    Include = new Type[]{ typeof(StandardPage), typeof(ListPage) },
    Exclude = new Type[]{ typeof(StartPage), typeof(SettingsPage) }
)]
public class StartPage : PageData
{
}

In this page model, we are saying that we will allow any pages of type StandardPage and ListPage to be created, and we will not allow any pages of type StartPage or SettingsPage to be created.

Pretty simple and straightforward in my opinion.

IncludeOn and ExcludeOn

These parameters were a bit tricky to understand at first, primarily because the explanation in the documentation is a little confusing.

The documentation states:

IncludedOn differs from Include in the way that it is not excluding. That is. for types in IncludedOn that has all page types available no page types will be excluded. Include on the other hand will exclude all typed pages except the ones given in Include.

Excluded works so that if no types are set on Included then the result will be that all registered page types except the Excluded ones are available. If there are types registered in Included then all types in Included except the ones in Excluded are available. Below is an image that shows how Excluded and ExcludedOn are mapped to settings in admin mode.

This is how I see it:

You would use IncludeOn to specify that the current page type can be created under the specified page type(s). So for our example, we could use the IncludeOn parameter in the StandardPage to specify that it can be created under any page instance of the StartPage page type:

[ContentType(GUID = "00000000-0000-0000-0000-000000000000")]
[AvailablePageTypes(
    IncludeOn = new Type[]{ typeof(StartPage) }
)]
public class StandardPage : PageData
{
}

Similarly, you would use ExcludeOn to specify that the current page type can not be created under the specified page type(s). So for our example, we could the the ExcludeOn parameter in the SettingsPage to specify that it can not be created under any page instance of the StartPage page type:

[ContentType(GUID = "00000000-0000-0000-0000-000000000000")]
[AvailablePageTypes(
    ExcludeOn = new Type[]{ typeof(StartPage) }
)]
public class SettingsPage : PageData
{
}

So think of these parameters as a vice-versa of Include and Exclude. By using these parameters, you can keep the array of Types short and concise, while also reducing the need to go back and revise the Include or Exclude Type arrays of the other page model.

How the Attributes are Applied

With this attribute potentially spread across all of your page models, you might start finding yourself either conflicting or being redundant with your Include, IncludeOn, Exclude, and ExcludeOn parameters.

If that's the case, keep in mind how the attributes are applied:

  • Include implicitly excludes all page types not in the list
  • Exclude implicitly includes all page types not in the list
  • IncludeOn and ExcludeOn combine with the settings on the target page type
  • If there is a conflict, Exclude and ExcludeOn have priority over Include and IncludeOn.