Model website navigation

Navigation is a necessary part of every website. Well-ordered navigation menus provide an overview of how the website’s content or its segments are structured. It also helps keep users engaged and leads them to explore more of the site.

We recommend modeling website navigation using reusable content items. Developers then prepare ways to render the navigation menu as required (e.g., using .NET view components).

The general process of creating website navigation consists of the following steps:

  1. Developers prepare a dedicated content type for individual Navigation items as well as for the Website navigation as a whole.
    • The Website navigation contains individual Navigation items and represents the navigation on the website.
  2. Editors create the Navigation items in the content hub. Each item links to a specific page in the site’s content tree, selected using the Page selector.
    • The selector populates its assigned field with the GUID of the selected page, which is used to retrieve the corresponding page and its URL.
  3. Editors create the Website navigation in the content hub and in it link individual navigation items created in the previous step.
    • The order of the linked navigation items represents the final state of the navigation menu on the live site.
  4. Developers implement a view component that takes all the linked Navigation items from the Website navigation and transforms them into the finalized menu component.

The following screenshot shows an example of a simple website navigation modeled in the content hub:

Navigation menu example

Model the navigation item content type

To model the content type for individual navigation items:

  1. Open the Content types application and select New content type.
  2. Fill in the following values:
    • Content type name: Navigation item
    • Namespace: MySite
    • Name: NavigationItem
    • Use for: Reusable content
  3. Select Save.

Define the fields used to hold page data:

  1. Select the Fields tab.
  2. Select New field and fill in the following values:
    • FieldName: NavigationItemName
    • Data type: Text
    • Field caption: Name
    • Form component: Text input
  3. Select New field and fill in the following values:
    • Field name: NavigationItemLink
    • Data type: Pages
    • Field caption: Link to
    • Tooltip text: Select a page from the content tree. Make sure that the page you have selected has a URL address.
    • Form component: Page selector
    • Maximum number of pages: 1
    • Tree path: empty (this will enable editors to select any page)
  4. Save your changes.
  5. Switch to the General tab.
    1. Select a relevant icon, for example: xp-arrow-right-top-square
    2. Save your changes.

The content type for individual navigation items is now successfully created. Editors can now create the navigation items in the content hub.

Adding a new navigation item in the content hub

Model the website navigation content type

To model the content type for website navigation:

  1. Open the Content types application and select New content type.
  2. Fill in the following values:
    • Content type name: Website navigation
    • Namespace: MySite
    • Name: WebsiteNavigation
    • Use for: Reusable content
  3. Select Save.

Define the field used to hold linked navigation items:

  1. Select the Fields tab.
  2. Select New field and fill in the following values:
    • FieldName: NavigationMenu
    • Data type: Content items
    • Field caption: Navigation menu
    • Form component: Content item selector
    • Allowed content type: Navigation item
    • Minimum number of selected items: 1
  3. Save your changes.
  4. Switch to the General tab.
    1. Select a relevant icon, for example: xp-menu
    2. Save your changes.

The content type for website navigation is now successfully created. Editors can now create the website navigation in the content hub.

Navigation menu example

Navigation menu hierarchy

To create complex, multi-level navigation menus, developers can define multiple content types representing individual sub-menus in the navigation that editors then combine to create a navigation menu hierarchy. For example, to model a Top Nav menu container > Nav menu column > Nav menu item hierarchy, the Website navigation content type will have a field for linking multiple Column navigation items which will link the individual Navigation items.

Editors can then organize the content items used for website navigation into folders in the content hub. This way they can make the menu hierarchy more visual and easily see in which channel application the navigation items are used.

Implement a view component that renders the menu

The next steps focus on creating a view component that renders all items linked in the Website navigation content item.

Before you begin, generate the code files for the Navigation item and Website navigation content types and make sure they are included in your project.

Create a view model

Create a dedicated model class for menu items and use it to pass the minimum required data to your views – typically at least a text caption and a URL for the navigation link.

Menu view model


public class NavigationItemViewModel
{
    // Defines the properties of the NavigationItem view model
    public string MenuItemText { get; set; }
    public string MenuItemRelativeUrl { get; set; }
}

Create a view component

Next, create a view component that collects all linked items from the Website navigation and transforms them into links to actual pages in the system.

When loading data for the navigation menu:

  • Use the content item query API to retrieve the Website navigation with linked content items representing individual menu items. For more information about the retrieval of reusable data, see Retrieve content items.
  • Retrieve navigation items as strongly typed objects using the generated classes – NavigationItem.
  • Use the IWebPageUrlRetriever.Retrieve method to retrieve URLs from the GUIDs of the linked pages. For more information about URL retrieval, see Get page URLs.
  • Cache all retrieved data for improved performance.
Menu view component


using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;

using Kentico.Content.Web.Mvc.Routing;
using CMS.Websites;
using CMS.ContentEngine;
using CMS.Websites.Routing;

using MySite.Models;

public class NavigationMenuViewComponent : ViewComponent
{
    private readonly IContentQueryExecutor executor;
    private readonly IWebPageUrlRetriever urlRetriever;
    private readonly IWebsiteChannelContext channelContext;
    private readonly IPreferredLanguageRetriever preferredLanguageRetriever;

    public NavigationMenuViewComponent(
        IContentQueryExecutor contentQueryExecutor,
        IWebPageUrlRetriever pageUrlRetriever,
        IWebsiteChannelContext websiteChannelContext,
        IPreferredLanguageRetriever preferredLanguageRetriever)
    {
        // Initializes instances of required services using dependency injection
        this.executor = contentQueryExecutor;
        this.urlRetriever = pageUrlRetriever;
        this.channelContext = websiteChannelContext;
        this.preferredLanguageRetriever = preferredLanguageRetriever;
    }

    public async Task<IViewComponentResult> InvokeAsync()
    {
        // Gets all linked 'Navigation items' from the 'Website navigation'
        var query = new ContentItemQueryBuilder()
            .ForContentType(
                    contentTypeName: WebsiteNavigation.CONTENT_TYPE_NAME, 
                    configureQuery: config => config
                        .WithLinkedItems(1))
            .InLanguage(preferredLanguageRetriever.Get());

        // Materializes the query
        IEnumerable<WebsiteNavigation> websiteNavigation = await executor.GetMappedResult<WebsiteNavigation>(query);

        List<NavigationItem> navigationItems = websiteNavigation.FirstOrDefault().NavigationMenu.ToList();

        var menuItemGuids = navigationItems
            .Select(ni => ni.NavigationContentItemLink.First().WebPageGuid)
            .ToList()
            .AsReadOnly();

        // Retrieves URLs of linked pages
        IDictionary<Guid, WebPageUrl> urls = await urlRetriever.Retrieve(
            webPageItemGuids: menuItemGuids
            websiteChannelName: channelContext.WebsiteChannelName,
            languageName: preferredLanguageRetriever.Get(),
            forPreview: channelContext.IsPreview);

        // Creates a list of view models from retrieved data
        IEnumerable<NavigationItemViewModel> menuItems = navigationItems
            .Select(ni => new NavigationItemViewModel {
                MenuItemRelativeUrl = urls[ni.NavigationItemLink.First().WebPageGuid].RelativePath,
                MenuItemText = ni.NavigationItemName
                });

        return View("~/Components/ViewComponents/NavigationMenu/Default.cshtml", menuItems);
    }
}

Create a view to display the navigation menu

In the component’s view, render the collection of view models:

Menu view


@model IEnumerable<MySite.Models.NavigationItemViewModel>

<ul class="nav-menu">
    @foreach (var navigationItem in Model)
    {
        <li>
            <a href="@navigationItem.MenuItemRelativeUrl">@navigationItem.MenuItemText</a>
        </li>
    }
</ul>

Invoke the view component within your site’s pages or layout as required.