Template Hierarchies
Outline
- Templates are MVC renderers registered for content (controller + view, or another renderer).
- Hierarchy is how the runtime chooses among multiple templates, not the content tree.
- The usual decision points are context (full page vs. partial), type match, then tags/channels.
- Inheritance keeps content models and controllers reusable and consistent.
-
DisplayTemplates are the workhorse for block/property rendering (especially via
@Html.PropertyFor).
Overview
This lesson sits under Rendering Content Templates. It gives you a mental model for how Optimizely CMS 12 (ASP.NET Core) resolves which controller/view renders a content item, and the conventions that make the setup predictable for the next developer (including Future You).
Template selection hierarchy
You do not need to memorize an internal algorithm. Use this order to predict outcomes and debug quickly.
-
Start with the rendering context
Ask: are we rendering a full page request, or rendering content inside another view (for example, inside a ContentArea)? Context narrows candidate templates immediately.
-
Match by content type
Optimizely looks for templates that can render the content type being requested. If your models use inheritance, you can reuse patterns without duplication.
-
Refine with tags and TemplateDescriptor metadata
If more than one template can render the same type, tags let you steer which one wins in a given scenario (for example, full page vs. teaser, or different placements).
-
Fall back to general templates
If a specialized template is missing, the system can fall back to a more general template. Your goal is to make fallbacks intentional and consistent, not accidental.
If something renders unexpectedly, assume you have either (1) a different context than you think, or (2) multiple templates and the wrong one is winning due to tags or fallbacks.
▶Common rendering contexts you’ll actually see
-
Full page request
A URL routes to a page and the runtime renders it as a complete response.
-
Partial rendering
A page renders blocks inside a ContentArea or another container.
-
Display channel variation
Different templates may be chosen for different device/channel scenarios (when configured).
Content model inheritance conventions
A common approach is a base page type for shared fields (metadata, SEO, layout settings), then derived page types for specific page behavior.
Put shared page properties in one base type. Then keep specialized page types small and focused.
▶What to put in a base page type
-
Shared heading/title conventions
Make page naming and heading behavior consistent across the site.
-
SEO fields
Common meta title and meta description fields.
-
Layout settings
Theme flags, navigation options, and layout switches that should apply site-wide.
-
Shared ownership/classification fields
Fields like content owner, category, or classification used across many page types.
MVC conventions developers should follow
Optimizely CMS 12 builds on standard ASP.NET Core MVC. Treat templates like normal MVC: controllers return views, views use view models, and shared UI moves into partial views.
-
Page controller pattern
Use one page controller per page type when it improves clarity. Use a base controller when many page types share logic (for example, building common layout data).
-
Views should be easy to find
Follow standard MVC placement conventions so view discovery stays predictable. Avoid project-specific folders that force full-text search as the primary navigation strategy.
-
Use partial views for reusable UI
Navigation, cards/teasers, and small components should typically be partial views. This reduces duplication and keeps UI consistent across templates.
▶A simple folder convention (example)
-
/Controllersfor page controllers -
/Viewsfor page views -
/Views/Sharedfor shared layouts and partials -
/Views/Shared/DisplayTemplatesfor block/property templates
Use any convention your team prefers, but keep it consistent and documented.
DisplayTemplates conventions
When you render properties like ContentArea using @Html.PropertyFor(...), Optimizely commonly resolves block/property
rendering via DisplayTemplates.
Common convention for DisplayTemplates:
- Store block/property display templates under
~/Views/Shared/DisplayTemplates. - Name the template file after the type it renders (for example,
ContactBlock.cshtml).
- Is the block type rendered via a DisplayTemplate with the expected filename and location?
- Is a different template winning due to a tag or fallback?
- Is the block being rendered in a different context than you expected?
TemplateDescriptor and tags conventions
Use tags (and TemplateDescriptor metadata) only when you truly need multiple templates for the same content type. This is common for full page vs. teaser rendering, or a block that needs different layouts in different placements.
▶When tags are worth it
-
Teaser vs. full view
A compact card in a listing vs. the full page.
-
Placement-based rendering
Same block rendered differently in header vs. main content.
-
Channel-based rendering
A different template for specific channels, when configured.
▶A safe minimum approach
-
Start with one template per content type
Keep it simple until you have a clear scenario that requires a second option.
-
Add a second template only when the scenario has a name
For example: “Teaser” is a scenario. “Different” is not.
-
Keep tag names simple
Use consistent naming and document your tag set.
Developer checklist
Use this as your ABCD map to keep rendering predictable.
-
Align models and templates
Use inheritance for shared properties. Avoid copy/paste across page types.
-
Be consistent with MVC structure
Controllers and views should be easy to locate using standard MVC conventions.
-
Control partial rendering intentionally
Use
Views/Shared/DisplayTemplatesfor block/property templates. Add tags only when you truly need multiple rendering variants. -
Document your conventions
A short README in your solution beats tribal knowledge.
Quick practice (self-check)
▶ContentArea rendering debug
You render a ContentArea with @Html.PropertyFor(m => m.MainContentArea). A block layout looks wrong. Where do you look first?
- Check DisplayTemplates (filename and location).
- Check whether a tag-based template is winning unexpectedly.
- Confirm you are in the context you think you are (full vs. partial).
▶Shared metadata fields
Your ArticlePage and LandingPage share metadata fields. What should you refactor?
- Create (or expand) a base page type for shared properties.
- Consider a base controller if shared behavior is also duplicated.
Conclusion
Template hierarchies in CMS 12 are about predictable selection: understand context, keep type matching straightforward, use inheritance for reuse, rely on DisplayTemplates for block/property rendering, and introduce tags only when you have a clearly named scenario. If your structure is consistent, debugging becomes quick and boring, which is the best kind of debugging.
