HomeDev GuideAPI Reference
Dev GuideAPI ReferenceUser GuideLegal TermsGitHubNuGetDev CommunitySubmit a ticketLog In

Page types and templates

Explains the concept of pages, page types and templates, and how these are associated in Optimizely Content Management System (CMS). It also describes how to create a simple page type with rendering.



The examples here are based on MVC.

Optimizely Content Management System (CMS) relates pages, page types, and page templates in the following ways:

  • page type defines a set of properties, for example, page name and publish date.
  • page is an instance of the .NET class defining the page type. When you create a page in edit view, values are assigned to the properties and stored in the database.
  • The controller and view fetch the stored property values and render the output.
  • template can be associated with the page type to render the output in a certain context.

In the following, you will find examples of how to work with page types and associated controllers, views, and templates for rendering the content.



Standard routing is not registered by default for MVC, but if it is used, renaming of a controller or action will affect the URL/route to the action.

Page types

In Optimizely Content Management System (CMS), you usually define page types in code as classes based on a model inheriting from EPiServer.Core.PageData. A PageData object is the programmatic representation of a page containing the properties defined in your .NET class. The value of currentPage is automatically set to the PageData object that the client requests. During initialization, CMS scans the bin folder for .NET classes inheriting PageData and creates a page type for each of the classes found. CMS creates a corresponding property on the page type for public properties on the class.

Create a page type

Using the Visual Studio integration, you create a page type by adding the Page type item to the Pages subfolder under Models in your project. See Get started with Content Cloud (CMS 11).

The abstract SitePageData base class inherits from EPiServer.Core.PageData. This base class has an SEO property for pages inheriting from the class.

Example: A simple article page type with a MainBody editor area of the property type XhtmlString, inheriting from the SitePageData base class.

using System;
using System.ComponentModel.DataAnnotations;
using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.DataAnnotations;
using EPiServer.SpecializedProperties;

namespace MyEpiserverSite.Models.Pages {
    [ContentType(DisplayName = "ArticlePage", GUID = "b8fe8485-587d-4880-b485-a52430ea55de", Description = "Basic page type for creating articles.")]
    public class ArticlePage: SitePageData {
        Name = "Main body",
        Description = "The main body editor area lets you insert text and images into a page.",
        GroupName = SystemTabNames.Content,
        Order = 10)]
      public virtual XhtmlString MainBody {


  Example: ** The SitePage base class, with the SEO property.

namespace MyEpiserverSite.Models.Pages {
  public abstract class SitePageData: EPiServer.Core.PageData {
    [Display(GroupName = "SEO", Order = 200, Name = "Search keywords")]
    public virtual String MetaKeywords {

CMS automatically generates a unique GUID for the page type when creating a page type using the Visual Studio extension. Also, note that page types implicitly contain a set of built-in properties available for pages, regardless of the instance. See PageData.Property for built-in properties. 

Because CMS has not created the rendering, you cannot edit pages based on this page type from the On-Page edit view; only from the All Properties edit view.



Why are the properties declared as virtual here? What happens in the background is that a proxy class is created for the page type, and data is loaded from the database to a property carrier (Property), receiving the data. Through Castle (Inversion of Control tool), the properties in the proxy page type will be set, and this only works if properties are declared as virtual. If the properties are not declared virtual, you need to implement get/set so that these will read/write data to the underlying property collection instead.

Page controllers and views

Models, controllers, and views in MVC clearly separate data, business logic, and presentation. The controller contains the business logic, handles URL requests, and selects the view, a visual data model presentation. In MVC, the controller is the registered class that supports specific page types, and you can regard it as the template. The template defines which content types it can render in a specific context.

Create a controller and a view

Using the Optimizely Visual Studio extension, you create a controller by adding a CMS item of type Page Controller (MVC) to the Controllers folder in your project. Your controller should inherit from EPiServer.Web.Mvc.PageController<T>, where T is your page type. If it chooses the renderer for the page type, it calls this controller for the page type. 

To add the corresponding view for the controller, create a subfolder under Views and add a CMS item of type Page View (MVC). Or, click inside the controller to add the view. Ensure you follow the standard naming conventions in MVC for your model, controllers, and views.

PageControllerBase class reuses logic for multiple pages, which holds the logic for a logout action, and inherits from PageController. You can also add a view model to more than just page objects to the views.

Use HTML helpers in MVC to render properties, such as Html.PropertyFor, which renders property values based on their property type.

Example: The controller for displaying the Article page type, inheriting from PageControllerBase.

using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using EPiServer;
using EPiServer.Core;
using EPiServer.Framework.DataAnnotations;
using EPiServer.Web.Mvc;
using MyEpiserverSite.Models.Pages;
using System.Web.Security;

namespace MyEpiserverSite.Controllers {
  [TemplateDescriptor(Default = true)]

  public class ArticlePageController: PageControllerBase<ArticlePage> {
    public ActionResult Index(ArticlePage currentPage) {
      // Implementation of action view the page. 
      return View(currentPage);

Example: The page controller base, inheriting from PageController, and with SitePageData as generic type.

namespace MyEpiserverSite.Controllers {
  public abstract class PageControllerBase<T>: PageController<T> where T: SitePageData {
    // Providing a logout action for the page.
    public ActionResult Logout() {
      return RedirectToAction("Index");

Example: The corresponding rendering view displays the Article page.

@using EPiServer.Core
@using EPiServer.Web.Mvc.Html

@model MyEpiserverSite.Models.Pages.ArticlePage 
<h1>@Html.DisplayFor(m => m.Heading)</h1>

  <h3>@Html.PropertyFor(m => m.Introduction)</h3>

  <div >
  @Html.PropertyFor(m => m.MainBody) 

With the added rendering using Html.PropertyFor, the property is now also editable in the On-Page editing view.

Use HTML Helpers

You can also use other specific CMS HTML helpers as an alternative to Html.PropertyFor. There are helpers for rendering links, content areas, translations, and navigation. You call these HTML helpers through Html.DisplayFor, but you can also use them directly.

Use templates

Templates define how you render content. The template (controller) selected to render a content instance depends on the context. Use the TemplateDescriptor attribute to add metadata and define default templates, and Tags to define which template to use. Based on this information and any defined display channels and display options settings, the TemplateResolver decides which template to use in a specific context.

Template registration and routing

Page types and controllers created from code using the CMS Visual Studio integration are strongly typed and inherit from CMS base classes to ensure that the templates used are automatically registered as supported for the specified page type. See Rendering for information.