You can, for example, build navigation using link collections, structure-based visual components like menus and breadcrumbs, or search-based navigation and filtering.
## Link Collections
A **Link Collection** is often used for things like related content or lists of links in the page footer. Since link collections are editorial content, this data needs to be stored in a user-defined property.
In this example, you add a property of the type `
LinkItemCollection` to a content type named _ArticlePage_ to enable editors to build a list of links that can be both internal or external. You could also use the type `
IList<ContentReference>` instead of `
LinkItemCollection` if you only reference internal content.
Add a page controller and then use `
Html.PropertyFor` to render the list of links in your page template. The default rendering for `
LinkItemCollection` will be an unordered list using _ul_, _li_ and \_a_tags.
### Custom Rendering of Link Collections
You can take full control of rendering when the built-in way does not work for you. As a simple example, you can replace `
PropertyFor` in the example above with your own logic, and iterate the collection yourself in the View.
Avoid adding custom rendering of properties directly into your page templates. When you do, make sure you use EditAttributes and FullRefreshPropertiesMetaData. We strongly recommend that you learn how to use **DisplayTemplates** and **UIHint** as described below instead. This will make it easier for editors to work with your templates, since it keeps the on-page editing experience working smoothly.
A better way to build custom rendering is to move it into a Display Template. Add a new partial template with the name **SeeAlso.cshtml** in your **DisplayTemplates** folder (_/Shared/DisplayTemplates/SeeAlso.cshtml)_, and move your custom rendering from your page template. Set the model to be the same type as the property type.
Then, restore your rendering in your page template to use `
PropertyFor` with an extra parameter that contains the name of the display template. On-page editing will work as expected and preview will be correct without forced page reloads.
Alternatively, add a `
UIHint` attribute to your property definition in your content model and specify the name of your display template for custom rendering.
Whenever you use `
Html.PropertyFor` to render this property in a template, it uses your custom rendering by default.
### Link Collections in Layout
If you want to use a Link Collection in, for example, your page footer, you can use a similar approach. The main difference is that you no longer want this data stored on each page; instead, you want to edit it once and see the page footer updated on all pages.
Common patterns to accomplish this to either add a user-defined property to the site's start page or to have a special content type just for site settings. You then load this content item and put it into your view model and use it from your layout.
## Structure-based navigation
There are many ways to build website navigations. A common method in CMS is to use the hierarchy of pages to construct lists and navigation. For the Alloy sample site, the **Top menu** is constructed from all the children of the start page. **Breadcrumbs **renders a list of all ancestors (parents) of a page in the hierarchy up to the start page. A **Hierarchical Menu** (or **Submenu**) mirrors a part of the page hierarchy. A **List of Pages** is often created by listing all children of a specific page or through a search. There are also data types that can be used to allow editors to construct arbitrary **collection of links**.
Menus can be built programmatically using collections of pages gathered through `
GetChildren(ContentReference)` and other methods of the `
IContentLoader` service. When you have retrieved an instance of a page, you have access to all values both user defined and build in.
### Display in navigation
All content that inherits from `
PageData` has a built-in boolean property named `
VisibleInMenu`. The intended use of this property is to enable an editor to hide pages from menus and breadcrumbs. There is no built-in logic for how this should work in your templates built; it is up to you as a developer to implement this functionality. There are a few examples below how this can be done.
## Create a page listing
To illustrate listings, we start by creating a simple list of pages that are children to the current page.
There are several ways of passing data to views. A **view model** is useful if you want to pass typed data beyond your content into your views. You can define a model type in the view, and then pass an instance of this type to the view from the action method.
We use a simple class in this example but in a real-world site, it is common to use base classes, interfaces, and generic types to make it easier to access the **view model** from your shared layout views. See [Content model and views](🔗).
Add the following code to your **page controller** to load all child pages below the current page and create a **view model**.
GetPage` and `
GetChildren` expect an ID parameter implemented by the `
ContentReference` class. You can find the current page ID in the property `
ContentLink`, and the property `
ParentLink` contains the ID of the parent page. The reason we have a class for the ID and not just a simple integer is to be able to load previosly published versions and drafts through the same methods.
You can filter the type of content you retrieved with `
GetChildren` by using a different class on the generic method. So, `
PageData` instead of `
ArticlePage` in the call above gives you a list of any type of page, and `
IContent` retrieves any type of content, including media, folders, and blocks.
Next step is to use the view model in your view to render the list of articles.
### Configure location of list
You can, of course, load other pages than the children of the current page. Here is an example that lets an editor pick the parent page for the list of pages by adding a property to our page type.
Then use this property as ID when you load the list of pages in your controller.
## Filtering content for access
Pages retrieved using calls to, for example, `
GetChildren` are not automatically filtered for access and availability.
As a developer you are always responsible to add funtionality for filtering content you have retrieved through Optimizely's API before you use it in a view. Forgetting this can cause broken links and you could also reveal sensitive information to unauthorized visitors of your site.
There are several utility classes to help you filter content. The first class you must learn how to use is `
FilterContentForVisitor`. It uses three other filters to remove unpublished pages (`
FilterPublished`), pages without templates (`
FilterTemplate`), and pages to which the current visitor does not have access (`
You will also see the static class `
FilterForVisitor` in many examples. This legacy class uses `
FilterContentForVisitor` but since it is static it makes unit testing harder to perform.
To learn more, see [Searching and filtering](🔗).
## Page listings in menu navigation
Top and left-navigation menus are common examples of site navigation components. To make the page list useful for navigation purposes, we must make it available from all pages on the site since navigation usually is rendered from shared layout templates.
One way to solve this is to let your controller prepare your view model with data needed by the shared layout, like meta data, menu items, breadcrumbs, and footer links. Another approach is to use helper methods directly in your shared views to retrieve what you need.
The following example shows an `
HtmlHelper` extension method named `
MenuList` that takes two parameters, first the ID of the parent page and the second is a html template. It gets all children of the parent page that should be visible for the visitor and renders the template. Selected is true if the Menu Item is in the path to the current page and that is often used to highlight where you are in the structure.
Use the `
MenuList` extension method in your page layout to render a top menu with the start page as first item followed by all children directly below the start page.
You can also use `
MenuList` to render hierarchical navigation by calling it recursively in your template.
To learn more, have a look at how the Alloy demo templates have been built.
A breadcrumb with the path to the current page can easily be created by using `
GetAnscestors` that returns a list of all parents from the specified page up to the root page.
Here is an example of a partial template that renders breadcrumbs. It applies several filters to get rid of unwanted items.
## Search-based navigation
You can also retrieve content through searching based on a set of criteria, or through query-based searches. You can use [Optimizely Search & Navigation](🔗) to add more powerful search features. Search & Navigation is automatically included if you are running the Optimizely Digital Experience Platform (DXP).