Introduction
Every SharePoint version comes with OOB navigation feature, which is quite useful. You can quickly create a site navigation, provide some audience and there you go, your site navigation is set.
Suppose you have some very strange business requirement, where the OOB navigation does not serve the purpose and you are being asked to customize it for the sake of Business requirement, now that would be a challenge for some people.
In one of my projects, there was a very complex requirement. We had to manipulate the Top and Left navigation based on some kind of impersonation. For example, When User A logs in, this user will have the ability to impersonate into another user account. The whole Top and Left navigation would behave as if the actual user has logged in who has been impersonated by user A.
User A logs in and the following screen appears from where they can click on account and can impersonate as if that account is logging in to the portal.
After impersonation, the custom code kicks in and loads the navigation like following. Both are different on the basis of which account was clicked from Gridview
above. And also, the sub items under each menu will be different based on which one is clicked.
We tried achieving this through manipulating the OOB navigation through Audiences and Groups but that did not achieve the desired result and many bugs were reported. Normal User OOB navigation would work fine, but the impersonated one was not.
The only possible solution to this complex business requirement was to write the whole Top and Left navigation from start and code it based on the business requirement.
So here we go!
Sharepoint Content Types and List
First step towards building up custom site navigation is to have a Navigation data source. We have different options for this. I went with a SharePoint Custom List. The reason I chose a Custom List is simple. Our business requirement was to have a Parent Navigation and sub items underneath it with one Level.
Content Type
Create the following content types:
SharePoint LIST
Create a Sharepoint list based on the above content type and add the data.
Top navigation is represented by Folder Content Type.
Children are created using Item Content Type.
Example of an item created:
Using the Code
The whole idea of creating this article is to create a simple project which would demonstrate how to create a SharePoint custom navigation based on the Custom List above. I would not delve down about the details of how I achieved the end result of our business require, but I will show how to create the custom navigation and then once you know the basics, you can manipulate the code to achieve the desired result.
- The first step is to create an Interface to represent the navigation nodes. The same interface will be used to represent Top and Left navigation items.
public interface INavigationItem
{
#region PROPERTIES
string Title { get; set; }
string Url { get; set; }
string Audience { get; set; }
int Order { get; set; }
int Id { get; set; }
bool IsOpenInNewWindow { get; set; }
#endregion
#region METHODS
Dictionary<INavigationItem, int>
GetParentNavItems(SPList _TopNavList, SPFolder _Folder);
INavigationItem GetParentNavItem(string sParentNavTitle);
Dictionary<INavigationItem, int> GetChildNavItems
(SPList _TopNavList, SPFolder _Folder, int iParentFolderID);
Dictionary<INavigationItem, int>
GetChildNavItems(SPList _TopNavList, SPFolder _Folder);
SiteMapNodeCollection PopluateNavigationItems
(SPList _TopNavList, SPFolder _StartingFolder, PortalSiteMapNode psmNode);
#endregion
}
- A SharePoint Solution will be created to code the Navigation solution. Sharepoint
PortalSiteMapProvider
is the class to use represent the nodes. This class inherits the Sitemapnode
class. The difference between a SiteMapNode
and a PortalSiteMapNode
, is that the PortalSiteMapNode
uses MOSS security trimming. This is a good thing. Use it. However, there isn’t a PortalSiteMapNodeCollection
class in Sharepoint. You still use a SiteMapNodeCollection
to add and delete nodes.
public class TopNavigationProvider : PortalSiteMapProvider
{
}
public class LeftNavigationProvider : PortalSiteMapProvider
{
}
This class has GetChildNodes
method of PortalSiteMapnode
class is the method to create nodes. This method has various override signatures and can be used as per requirement. I am using the following method, node object shall be boxed to PortalSiteMapNode
to get the Sharepoint node.
private SiteMapNodeCollection GetChildNodes(SiteMapNode node)
{
PortalSiteMapNode pNode = node as PortalSiteMapNode;
}
- Then another class is being used to set up the whole navigation (both TOP and Left) which will be inherited from our Interface to set up Top and Left navigation. These classes will be used inside provider classes
GetChildNodes
method to create navigation.
public class TopNavigationItem : INavigationItem
{
}
public class LeftNavigationItem : INavigationItem
{
}
- The next step is to set up the Web.config. Add the following keys to sitemap section in the Web.config. Here,
TopNavigationProvider
is the name of the class which has the logic for Top navigation.
<siteMap defaultProvider="CurrentNavigation" enabled="true">
<providers>
<add name="TopNavigationProvider" type="XYZ.Navigation.TopNavigationProvider,
XYZ.Navigation, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=a1a91a3" NavigationType="Global" />
<add name="LeftNavigationProvider" type="XYZ.Navigation.LeftNavigationProvider,
XYZ.Navigation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a1a91a32d"
NavigationType="Global" />
- The next step is to set up the Master page. Inside site master page, there are two sections which represent the Top navigation and Left navigation providers. We will override out of the box providers will use our custom providers. It is never wise to play with Master pages directly. So please make all the changes using the SharePoint Designer. Edit the master page which your site is using and replace the following section to use our custom providers. replace the
<asp:ContentPlaceHolder id="PlaceHolderTopNavBar" runat="server">
in master page with the following for Top Navigation Bar. Use the exact SiteMapProvider
name for Top Navigation from your web.config entries.
<asp:ContentPlaceHolder id="PlaceHolderTopNavBar" runat="server">
<h2 class="ms-hidden">
<SharePoint:EncodedLiteral runat="server"
text="<%$Resources:wss,topnav_pagetitle%>"
EncodeMethod="HtmlEncode"/></h2>
<asp:ContentPlaceHolder id="PlaceHolderHorizontalNav"
runat="server">
<SharePoint:AspMenu
ID="TopNavigationMenuV4"
Runat="server"
EnableViewState="true"
DataSourceID="topSiteMap"
AccessKey="<%$Resources:wss,navigation_accesskey%>"
UseSimpleRendering="true"
UseSeparateCss="false"
Orientation="Horizontal"
StaticDisplayLevels="1"
MaximumDynamicDisplayLevels="3"
SkipLinkText=""
CssClass="s4-tn"/>
<asp:SiteMapDataSource
SiteMapProvider="TopNavigationProvider"
StartFromCurrentNode="true"
StartingNodeOffset="0"
ShowStartingNode="false"
EnableViewState="true"
id="topSiteMap"
runat="server"
/>
</asp:ContentPlaceHolder>
</asp:ContentPlaceHolder>
- Replace the
<asp:ContentPlaceHolder id="PlaceHolderLeftNavBar" runat="server">
in master page with the following for left Navigation Bar. Use the exact SiteMapProvider
name for Left Navigation from your web.config entry.
<asp:ContentPlaceHolder id="PlaceHolderLeftNavBar" runat="server">
<SharePoint:AspMenu
ID="CurrentNav"
EncodeTitle="false"
runat="server"
EnableViewState="false"
DataSourceID="ContentSiteMap"
UseSeparateCSS="false"
UseSimpleRendering="true"
Orientation="Vertical"
StaticDisplayLevels="2"
MaximumDynamicDisplayLevels="0"
CssClass="s4-ql"
SkipLinkText="<%$Resources:cms,masterpages_skiplinktext%>"/>
<asp:SiteMapDataSource
SiteMapProvider="LeftNavigationProvider"
ShowStartingNode="False"
id="ContentSiteMap"
runat="server"
/>
</asp:ContentPlaceHolder>
- Upload the master page and deploy the WSP and you should have custom navigation being driven from SharePoint list.
Conclusion
So, we saw how we can override the OOB navigation using some of the above steps. Attached is the code which you can download and create a basic solution to set up the custom navigation. I hope this helps.