Try our conversational search powered by Generative AI!

Loading...
Area: Optimizely CMS
Applies to versions: 10.0-11.20
Other versions:
ARCHIVED This content is retired and no longer maintained. See the version selector for other versions of this topic.

Extending the navigation

Recommended reading 

You can extend the navigation to let editors access Episerver CMS and other products from the global menu.

  • The [MenuItem] attribute adds an interface to the menu.
  • You can also configure and implement a custom menu provider.

Attributes and menu providers must reside in an assembly configured as a shell module.

In this topic

[MenuItem] attribute

Use MenuItem on ASP.NET MVC controllers. MenuItem adds links to the top menu (and requires the module to be registered; see Shell Modules). The required menuPath parameter is a logical path of the menu element in the menu. Use the Url parameter to add a linked URL to the interface.

The following example adds a menu item to the top menu bar with the text Start and the URL is inferred from the ASP.NET MVC route table:

public class DashboardController : Controller
{
  [MenuItem("/global/dashboard", Text = "Start")]
  public ActionResult Index()
  {
  }
}

When you have added menu items, you need to implement the new page to include Episerver's styling for shell and also render the menu so you can navigate back.

The key functions to render a menu are:

  • @Html.Raw(ClientResources.RenderResources("Navigation"))
  • @Html.Raw(Html.ShellInitializationScript()) 
  • @Html.Raw(Html.GlobalMenu()) 

In the following code example, the GlobalMenu line renders the HTML markup needed for the menu. Scripts and styles come from the RenderResources in the<head> tag.

@using EPiServer.Framework.Web.Resources
@using EPiServer.Shell.Navigation

<!DOCTYPE html>
<html>
  <head>
    <title>@ViewBag.Title</title>

    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />

    <!-- Shell -->
    @Html.Raw(ClientResources.RenderResources("ShellCore"))
    @Html.Raw(ClientResources.RenderResources("ShellWidgets"))

    <!-- LightTheme -->
    @Html.Raw(ClientResources.RenderResources( "ShellCoreLightTheme"))
 
    <!-- Navigation -->
    @Html.Raw(ClientResources.RenderResources("Navigation"))

    <!-- Dojo Dashboard -->
    @Html.Raw(ClientResources.RenderResources( "DojoDashboardCompatibility", new[] { ClientResourceType.Style }))
 
  </head>
  <body>
    @Html.Raw(Html.ShellInitializationScript())
    @Html.Raw(Html.GlobalMenu())
    <div>
      @RenderBody()
    </div>
  </body>
</html>

Localizing menu items with the MenuItem attribute

You can localize menu items defined with attributes with a static property of a resource class. ResourceType references a class with a static property. TextResourceKey is the name of the static property that returns the localized text.

Example:

[MenuItem("/global/dashboard", TextResourceKey = "Start", ResourceType = typeof(MenuResources))]

Organizing menu items

The menu path is used to organize menu items in a tree structure. All menu items in the top menu are in the /global bucket. The next segment is the name of menu section, for example, /global/cms. The last segment represents the actual user interface, for example, /global/cms/edit.

Creating a link in a menu

Some menu items have a URL. This creates a link in the menu. The page at the end of this URL should render a menu where the corresponding menu path is selected.

Permissions with the MenuItem attribute

You can restrict who sees a certain menu item by using the [Authorize] attribute. For example:

public class DashboardController : Controller
{
  [MenuItem("/global/dashboard")]
  [Authorize(Roles = "NoOne")]
  public ActionResult Index()
  {
  }
}

Using menu providers

The building blocks of the navigation are menu providers and menu items. A menu provider provides an enumeration of menu items which are organized in a tree according to their menu path. Episerver CMS contains a menu provider that looks at [MenuItem] attributes and provides them as menu items.

IMenuProvider

You can extend the standard menu by implementing a menu provider as an alternative to attributes. The menu provider returns menu items that are correctly localized. To use a menu provider, implement the IMenuProvider interface, decorate it with the [MenuProvider] attribute, and make it part of a registered shell module.

Adding menu items

You can add menu sections and sub-menu items such as menu sections, drop-downs, URLs and pop-up menu items. Each menu item defines a path which determines its location in the menu hierarchy. For example, a URL menu item with path /global/cms/myMenu is placed in the CMS section of the menu (which has the path /global/cms).

Types:

  • URL Menu Item are links; a click navigates to specified URL.
  • Popup Menu Item are links opened in a popup window (javascript window.open).
  • Section Menu Item are top menu sections which open an underlying menu.
  • Drop-Down Menu Item are drop-down style menu items designed for the utility menu area (right).

Example:

/// <summary>
/// Provides menu items for the CMS product.
/// </summary>
[MenuProvider]
public class CmsMenuProvider : IMenuProvider
{
    /// <summary>
    /// Provides the CMS menu section and the CMS settings section.
    /// </summary>
    /// <returns>
    /// A list of <see cref="MenuItem"/>s that the provider exposes.
    /// </returns>
    public IEnumerable<MenuItem> GetMenuItems()
    {
        // Create the top menu section
        var section = new SectionMenuItem("CMS", // Title
            "/global/cms"); // Logical path
      
        // Visible to CMS editors
        section.IsAvailable = (request) => 
            PrincipalInfo.HasEditAccess;

        // Create the edit menu item below the top section
        var cmsEdit = new UrlMenuItem("Edit", // Title
            "/global/cms/edit", // Logical path
            "/path/to/edit/default.aspx"); // URL
    
        // Visible to CMS editors
        cmsEdit.IsAvailable = (request) => 
            PrincipalInfo.HasEditAccess;
            
        return new MenuItem[] { section, cmsEdit };
    }
}

Localizing menu items with a menu provider

A menu provider returns localized menu items.

Permissions with the menu provider

The menu provider can defer permission filtering to the menu item by setting the IsAvailable delegate to a method that checks access for the user provided with the RequestContext parameter.

Flow of menu items

Menu items flow from the providers into a hierarchical model, which is rendered into HTML.

Configuring web.config

To extend the menu you can, for example, configure web.config as follows:

<episerver.shell>
  <navigation>
    <add text="Intranet" menuPath="/global/intra" 
      url="http://intra" sortIndex="100" />
    <add text="My section" menuPath="/global/my" 
      menuItemType="Section" sortIndex="300" />
    <add text="Edit" menuPath="/global/my/edit" 
      url="/my/edit.aspx" sortIndex="100" />
    <add text="Admin" menuPath="/global/my/admin" 
      url="/my/admin.aspx" sortIndex="200" />
  </navigation>
</episerver.shell>

Examples

Below you can find few examples of adding menu items.

  1. GGlobal menu button

    using System.Web.Mvc;
    using EPiServer.Shell.Navigation;
    
    namespace Alloy.Business
    {
        public class EpiServerWorldGlobalMenuItem : Controller
        {
            [MenuItem(MenuPaths.Global + "/globalLink", SortIndex = SortIndex.First - 10, Text = "Episerver world",
                Url = "https://world.episerver.com/cms/")]
            public ActionResult Index(string viewName)
            {
                return View();
            }
        }
    }
  2. Extending the CMS menu section


    using System.Collections.Generic;
    using EPiServer;
    using EPiServer.Security;
    using EPiServer.Shell.Navigation;
    
    namespace Alloy.Business
    {
        [MenuProvider]
        public class CmsMenuProvider : IMenuProvider
        {
            public IEnumerable<MenuItem> GetMenuItems()
            {
                var menuItems = new List<MenuItem>();
                menuItems.Add(new UrlMenuItem("Another link to Admin",
                    MenuPaths.Global + "/cms" + "/cmsMenuItem",
                    UriSupport.ResolveUrlFromUIAsRelativeOrAbsolute("Admin/Default.aspx"))
                {
                    SortIndex = SortIndex.First + 25,
                    IsAvailable = (request) => PrincipalInfo.HasAdminAccess
                });
    
                return menuItems;
            }
        }
    }
  3. New global menu section

    Please note that while the example below works, it is not recommended to use the main navigation for external links. A better example for external links could be example 6 below.

    using System.Collections.Generic;
    using EPiServer.Security;
    using EPiServer.Shell.Navigation;
    
    namespace Alloy.Business
    {
        [MenuProvider]
        public class GlbalSectionMenuProvider : IMenuProvider
        {
            const string MainMenuPath = MenuPaths.Global + "/customSection";
    
            public IEnumerable<MenuItem> GetMenuItems()
            {
                var menuItems = new List<MenuItem>();
    
                menuItems.Add(new SectionMenuItem("Episerver Forum", MainMenuPath)
                {
                    SortIndex = SortIndex.Last + 10,
                    IsAvailable = (request) => PrincipalInfo.HasEditAccess
                });
    
                menuItems.Add(new UrlMenuItem("CMS", MainMenuPath + "/item1",
                    "https://world.episerver.com/forum/developer-forum/-Episerver-75-CMS/")
                {
                    SortIndex = 1,
                });
    
                menuItems.Add(new UrlMenuItem("Commerce", MainMenuPath + "/item2",
                    "https://world.episerver.com/forum/developer-forum/Episerver-Commerce/")
                {
                    SortIndex = 2,
                });
    
                menuItems.Add(new UrlMenuItem("Forms", MainMenuPath + "/item3",
                    "https://world.episerver.com/forum/developer-forum/episerver-forms/")
                {
                    SortIndex = 3,
                });
    
                return menuItems;
            }
        }
    }
  4. Extending the User Settings menu using controller action


    using System.Web.Mvc;
    using EPiServer.Shell.Navigation;
    
    namespace Alloy.Business
    {
        /// <summary>
        ///  Menu item under User Settings menu (menu added using using controller action)
        /// </summary>
        /// <returns></returns>
        public class EpiServerWorldMenuItem : Controller
        {
            [MenuItem(MenuPaths.UserSettings, SortIndex = SortIndex.First - 10, Text = "About Episerver",
                Url = "https://www.episerver.com/about/company/overview/")]
            public ActionResult Index(string viewName)
            {
                return View();
            }
        }
    }
  5. Extending the User Settings menu using menu provider


    using System.Collections.Generic;
    using EPiServer.Shell.Navigation;
    
    namespace Alloy.Business
    {
        [MenuProvider]
        public class UserSettingsMenuProvider : IMenuProvider
        {
            public IEnumerable<MenuItem> GetMenuItems()
            {
                var menuItems = new List<MenuItem>();
                var item = new UrlMenuItem("Documentation", MenuPaths.User + "/episerver2",
                    "https://world.episerver.com/documentation/")
                {
                    SortIndex = SortIndex.Last + 10
                };
                menuItems.Add(item);
                return menuItems;
            }
        }
    }
  6. New drop-down menu with items


    using System.Collections.Generic;
    using EPiServer.Shell.Navigation;
    
    namespace Alloy.Business
    {
        [MenuProvider]
        public class DropdownMenuProvider : IMenuProvider
        {
            const string DropdownMenuPath = MenuPaths.Global + "/customDropdownMenu";
    
            public IEnumerable<MenuItem> GetMenuItems()
            {
                var menuItems = new List<MenuItem>();
    
                var userMenu = new DropDownMenuItem("Episerver blogs", DropdownMenuPath)
                {
                    SortIndex = SortIndex.Last - 20,
                    Alignment = MenuItemAlignment.Right
                };
                menuItems.Add(userMenu);
    
                menuItems.Add(new UrlMenuItem("CMS", DropdownMenuPath + "/item1",
                    "https://world.episerver.com/blogs/?type=cmsblog&page=1")
                {
                    SortIndex = 1,
                });
    
                menuItems.Add(new UrlMenuItem("Commerce", DropdownMenuPath + "/item2",
                    "https://world.episerver.com/blogs/?type=commerceblog&page=1")
                {
                    SortIndex = 2,
                });
    
                menuItems.Add(new UrlMenuItem("Find", DropdownMenuPath + "/item3",
                    "https://world.episerver.com/blogs/?type=findblog&page=1")
                {
                    SortIndex = 3,
                });
    
                return menuItems;
            }
        }
    }

Related topics

Do you find this information helpful? Please log in to provide feedback.

Last updated: Sep 06, 2019

Recommended reading