HomeDev GuideRecipesAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

Add and configure menu items

Describes how to add and set up menu items.

MenuItem attribute

The [MenuItem] attribute provides the simplest way to add a link to the global menu from an MVC controller. The module must be registered as a shell module.

The menuPath parameter (required) defines the logical path of the menu element. The Url parameter (optional) specifies the linked URL. By default, the URL resolves to the registered shell route: /EPiServer/{ShellModule}/{controller}/{action} for protected modules and /modules/{ShellModule}/{controller}/{action} for public modules.

The following example adds a menu item with the text Start to the top menu bar. The URL is inferred from the registered route for the shell module:

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

After adding menu items, implement the page to include CMS styling for Shell and render the menu for navigation.

The primary function to render the menu is @Html.CreatePlatformNavigationMenu().

Only call Html.ShellInitializationScript() when the page shows content beyond the navigation menu. The navigation menu itself does not need the script.

Wrap content under the menu in an element decorated with Html.ApplyPlatformNavigation().

📘

Note

The Platform Navigation font sizing uses REM and expects the root element to have size 16px (browser default). Some style frameworks, such as Bootstrap 3, override the root font size while others, like Bootstrap 4, do not.

For CMS versions 11.21 and higher, use CreatePlatformNavigationMenu() and ApplyPlatformNavigation().

📘

Note

You no longer need @Html.Raw(ClientResources.RenderResources("Navigation")) nor @Html.Raw(Html.ShellInitializationScript()).

@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 -->
    @ClientResources.RenderResources("ShellCore")
    
    <!-- LightTheme -->
    @ClientResources.RenderResources("ShellCoreLightTheme")
  </head>
  <body>
    @Html.CreatePlatformNavigationMenu()
    <div @Html.ApplyPlatformNavigation()>
        @RenderBody()
    </div>
  </body>
</html>

Localize menu items with the MenuItem attribute

Localize menu items to display translated text based on the editor's language preference. Specify TextResourceKey to resolve the key against LocalizationService. Alternatively, set ResourceType to a class with a static property named after the TextResourceKey value that returns the localized text.

The following example uses a resource type for localization:

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

Organize menu items

The menu path organizes menu items in a tree structure. Items in the top menu reside in the /global bucket. The next segment is the menu section name, for example, /global/cms. The last segment represents the actual interface, for example, /global/cms/edit.

Permissions with the MenuItem attribute

Control which users see specific menu items by combining the shell module's default security policy with custom authorization rules. Configure the default policy through authorizationPolicy in module.config. CMS evaluates the menu item's availability through that policy. Apply the AuthorizeAttribute to specify additional authorization that complements the module policy. When both exist, CMS evaluates both policies for the request.

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

Add menu item examples

The following examples demonstrate common patterns for adding menu items to the global navigation.

Global menu button

Add a top-level button that links to an external URL.

namespace Alloy.Business {
  public class EpiServerWorldGlobalMenuItem: Controller {
    [MenuItem(MenuPaths.Global + "/globalLink",
      SortIndex = SortIndex.First - 10,
      Text = "Optimizely world",
      Url = "https://world.episerver.com/cms/")]
    public ActionResult Index(string viewName) {
      return View();
    }
  }
}

Extend the CMS menu section

Add an item to the existing CMS section using a menu provider.

namespace Alloy.Business {
  [MenuProvider]
  public class CmsMenuProvider: IMenuProvider {
    private readonly ModuleTable _modules;

    public CmsMenuProvider(ModuleTable modules) {
      _modules = modules;
    }

    public IEnumerable<MenuItem> GetMenuItems() {
      var menuItems = new List<MenuItem>();
      menuItems.Add(new UrlMenuItem("Another link to Admin",
        MenuPaths.Global + "/cms" + "/cmsMenuItem",
        Path.Combine(_modules.FindModule("EPiServer.CMS.UI.Admin").ResourceBasePath, "default")) {
        SortIndex = SortIndex.First + 25,
          AuthorizationPolicy = CmsPolicyNames.CmsAdmin
      });

      return menuItems;
    }
  }
}

Add a second-level menu

The following example adds a second-level menu to the existing admin menu.

public class ExtendedAdminController : Controller {
  [MenuItem("/global/cms/admin/extension", Text = "Admin Extension", SortIndex = 60)]
  public IActionResult Index() {
    return View();
  }
}

Global menu section

Create a custom section in the global menu with child items. Avoid using the main navigation for external links. For external links, use the User Settings menu instead (see the following example).

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("Optimizely Forum", MainMenuPath) {
        SortIndex = SortIndex.Last + 10
      });

      menuItems.Add(new UrlMenuItem("CMS", MainMenuPath + "/item1",
        "https://world.episerver.com/forum/developer-forum/-Optimizely-75-CMS/") {
        SortIndex = 1,
      });

      menuItems.Add(new UrlMenuItem("Commerce", MainMenuPath + "/item2",
        "https://world.episerver.com/forum/developer-forum/Optimizely-Commerce/") {
        SortIndex = 2,
      });

      menuItems.Add(new UrlMenuItem("Forms", MainMenuPath + "/item3",
        "https://world.episerver.com/forum/developer-forum/episerver-forms/") {
        SortIndex = 3,
      });

      return menuItems;
    }
  }
}

Use MenuProvider to extend the User Settings menu

Add a link to the User Settings drop-down list using a 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;
    }
  }
}

Extend the User Settings menu using controller action

Add a link to the User Settings menu using a controller action instead of a menu provider.

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 Optimizely",
      Url = "https://www.episerver.com/about/company/overview/")]
    public ActionResult Index(string viewName) {
      return View();
    }
  }
}

Drop-down menu with items

Create a drop-down list menu aligned to the right side of the navigation bar.

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("Optimizely 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;
    }
  }
}