Extend the CMS navigation
Describes how to extend the navigation for Optimizely Content Management System (CMS).
CMS version 11.21 and higher.
The following section shows how to extend the navigation for Optimizely Content Management System (CMS) version 11.21 and higher.
You can extend the navigation to let editors access CMS and other products from the global menu.
- The
[MenuItem]
attribute adds an interface to the menu. See Add and configure menu items. - You can also configure and implement a custom menu provider; see Use menu providers.
Attributes and menu providers must reside in an assembly configured as a shell module.
CMS introduced a global navigation menu in version 11.21 of CMS UI that differs slightly from how it worked before. If you upgrade the global navigation menu, see Upgrade navigation.
Optimizely Content Management System (CMS) version 10 to 11.20.
The following sections show how to extend the navigation for Optimizely Content Management System (CMS) version 10 to 11.20.
You can extend the navigation to let editors access 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.
[MenuItem] attribute
Use MenuItem on ASP.NET MVC controllers. MenuItem
adds links to the top menu (and requires the module to be registered; see Configure 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 ASP.NET MVC route table infers the URL:
public class DashboardController: Controller {
[MenuItem("/global/dashboard", Text = "Start")]
public ActionResult Index() {}
}
When you add menu items, implement the page to include CMS's shell styling and 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>
Localize 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))]
Organize menu items
The menu path organizes menu items in a tree structure. Menu items in the top menu are in the /global
bucket. The next segment is the name of the menu section, for example, /global/cms
. The last segment represents the actual user interface, for example, /global/cms/edit
.
Create a link in a menu
Some menu items have a URL that 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() {}
}
Use menu providers
The building blocks of the navigation are menu providers and menu items. A menu provider enumerates menu items organized in a tree according to their menu path. 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 attribute alternative. 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.
Add menu items
You can add menu sections and sub-menu items such as menu sections, drop-downs, URLs, and popup menu items. Each menu item defines a path, determining 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 a specified URL.
- Popup Menu Item are links opened in a window (JavaScript
window.open
). - Section Menu Item are top menu sections that 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
};
}
}
Localize 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 rendered into HTML.
Configure navigation in 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
Global 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();
}
}
}
Extend 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;
}
}
}
Global menu section
Note
While the example below works, you should not use the main navigation for external links.
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;
}
}
}
Extend 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 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();
}
}
}
Extend the User Settings menu using the 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;
}
}
}
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;
}
}
}
Updated 2 months ago