Exam Area: Content Area 1 – Product Knowledge (15%)
Source: https://academy.optimizely.com/student/path/3128969/activity/4970323
Published: Feb 16, 2026
- Performance anchor: The "100-item rule" prevents database latency and editorial lag.
- Architectural split: Container pages decouple logical data storage from the visual navigation tree.
- Multi-site logic:
SiteDefinition.Currentresolves current site context — avoid hard-coded IDs.- Inheritance control: Tree structure dictates both URL routing segments and security permissions.
The page tree reflects the visual navigation structure AND the logical data structure. Sophisticated implementations separate these:
Avoid more than 100 content items under a single node. Exceeding this causes:
GetChildrenDate-based: /News/2024/03/Article-Name/
Alphabetical: /Glossary/A/Architecture/
Category folders: /Products/Electronics/ /Products/Furniture/
// Resolve current site context — avoid hard-coded IDs
var currentSite = SiteDefinition.Current;
var startPageLink = currentSite.StartPage;
var rootPageLink = currentSite.RootPage;
var siteName = currentSite.Name;
SiteDefinition to a specific nodeContainer Page = page without associated rendering template → cannot be directly accessed via URL.
[ContentType(
DisplayName = "Container Page",
GUID = "aab97b20-1234-5678-abcd-000000000001",
Description = "Container for organizing pages")]
[AvailableContentTypes(
Availability = Availability.Specific,
Include = new[] { typeof(ArticlePage), typeof(ProductPage) }
)]
public class ContainerPage : PageData
{
// No properties — only structural/organizational
}
ContentReference.RootPage // Root of the page tree
ContentReference.StartPage // Start page of the site
ContentReference.GlobalBlockFolder // Global blocks folder
ContentReference.SiteBlockFolder // Site-specific blocks folder
ContentReference.WasteBasket // Trash / Waste Basket
URLs are generated hierarchically from the URLSegment property of each node:
/Services/Cloud/Hosting — inherits all parent segmentsPageName// Specific types only
[AvailableContentTypes(Availability = Availability.Specific, Include = new[] { typeof(ArticlePage) })]
public class NewsSectionPage : PageData { }
// Pure container — nothing can be created
[AvailableContentTypes(Availability = Availability.None)]
public class ReadOnlyContainerPage : PageData { }
var children = _contentRepository.GetChildren<PageData>(parentReference);
var descendants = _contentRepository.GetDescendents(parentReference);
var ancestors = _contentRepository.GetAncestors(contentReference);
The Page Tree is the hierarchical structure of all pages in the CMS.
Root
└── Start Page (/)
├── About Us (/about-us/)
│ ├── Team (/about-us/team/)
│ └── History (/about-us/history/)
├── Products (/products/)
│ ├── Product A (/products/product-a/)
│ └── Product B (/products/product-b/)
└── Contact (/contact/)
PagePeerOrderContentReference.RootPage // Root of the page tree
ContentReference.StartPage // Start page of the site
ContentReference.GlobalBlockFolder // Blocks folder
ContentReference.SiteBlockFolder // Site-specific blocks folder
ContentReference.WasteBasket // Trash
A Container Page is a page without a content template (does not render HTML), used only to organize the tree structure.
using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.DataAnnotations;
[ContentType(
DisplayName = "Container Page",
GUID = "aab97b20-1234-5678-abcd-000000000001",
Description = "Container for organizing pages")]
[AvailableContentTypes(
Availability = Availability.Specific,
Include = new[] { typeof(ArticlePage), typeof(ProductPage) }
)]
public class ContainerPage : PageData
{
// No specific properties
// Only uses built-in properties (Name, etc.)
}
Controls which types of content can be created within a page:
// Allow only ArticlePage and NewsPage to be created in this section
[AvailableContentTypes(
Availability = Availability.Specific,
Include = new[] { typeof(ArticlePage), typeof(NewsPage) }
)]
public class NewsSectionPage : PageData { }
// Allow nothing to be created (pure container)
[AvailableContentTypes(Availability = Availability.None)]
public class ReadOnlyContainerPage : PageData { }
// Allow everything
[AvailableContentTypes(Availability = Availability.All)]
public class FlexiblePage : PageData { }
Root
├── Start Page (StartPage) – home page
│ ├── Section Container (ContainerPage)
│ │ ├── Article 1 (ArticlePage)
│ │ └── Article 2 (ArticlePage)
│ └── Product Section (ContainerPage)
│ ├── Product 1 (ProductPage)
│ └── Product 2 (ProductPage)
└── Global Assets
├── Shared Blocks
└── Shared Media
// Get children of a page
var children = _contentRepository.GetChildren<PageData>(parentReference);
// Get all descendants
var descendants = _contentRepository.GetDescendents(parentReference);
// Get ancestors (breadcrumb)
var ancestors = _contentRepository.GetAncestors(contentReference);
// Get by ContentType
var articles = _contentRepository.GetChildren<ArticlePage>(sectionReference);
// SortOrder is set on the parent page
// In Admin: Properties → Settings → Sort subpages by
// In code
var startPage = _contentRepository.Get<StartPage>(ContentReference.StartPage);
// startPage.ChildOrderRule (EPiServer.Core.FilterSortOrder)
FilterSortOrder.None – No sortingFilterSortOrder.PublishedDescending – Newest firstFilterSortOrder.ChangedDescending – Most recently editedFilterSortOrder.Index – Manual order (drag & drop)FilterSortOrder.Alphabetical – A-ZContentReference.WasteBasketSiteDefinition.Current.StartPage used for? (Get the start page of the current site without hard-coding an ID)