Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / XHTML

SharePoint Custom Site Navigation

3.00/5 (2 votes)
12 May 2008BSD2 min read 1   393  
This articles provides an overview on how to do customized site navigation on MOSS publishing sites.

screen.png

Introduction

This articles provides an overview on how to do customized site navigation on MOSS publishing sites. If you are wondering whether that is configurable using the Site Settings page, read on.

Background

SharePoint 2007 comes with web content management features and its own custom SiteMapProvider. Out of the box, any sites and sub-sites created under a publishing site will have its URL nailed tp the top navigation menu. While this is desirable in a typical WCM environment and is certainly configurable from the built-in Site Settings functionality, when used in a non-WCM environment, it can be problematic.

Suppose you want a fixed top navigation menu that is not associated to your site topology, then the out of the box provider cannot be used.

You may ask why I would use the publishing site in the first place. Well, most of the SharePoint custom site definitions require you to use a definition that's based from the publishing one. In order to get user-swappable master pages and alternate CSS files, you have to start with the publishing site.

By default, the following section exists in the web.config file for a publishing site. As you can see, CurrentNavSiteMapProvider defines the provider used in a Publishing site.

XML
<siteMap defaultProvider="CurrentNavSiteMapProvider" enabled="true">
      <providers>
        <add name="SPNavigationProvider" type="Microsoft.SharePoint.Navigation.SPNavigationProvider, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="SPSiteMapProvider" type="Microsoft.SharePoint.Navigation.SPSiteMapProvider, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="SPContentMapProvider" type="Microsoft.SharePoint.Navigation.SPContentMapProvider, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="SPXmlContentMapProvider" siteMapFile="_app_bin/layouts.sitemap" type="Microsoft.SharePoint.Navigation.SPXmlContentMapProvider, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="AdministrationQuickLaunchProvider" description="QuickLaunch navigation provider for the central administration site" type="Microsoft.Office.Server.Web.AdministrationQuickLaunchProvider, Microsoft.Office.Server.UI, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="SharedServicesQuickLaunchProvider" description="QuickLaunch navigation provider for shared services administration sites" type="Microsoft.Office.Server.Web.SharedServicesQuickLaunchProvider, Microsoft.Office.Server.UI, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="GlobalNavSiteMapProvider" description="CMS provider for Global navigation" type="Microsoft.SharePoint.Publishing.Navigation.PortalSiteMapProvider, Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" NavigationType="Global" EncodeOutput="true" IncludePages="PerWeb" IncludeHeadings="true" IncludeAuthoredLinks="true" />
        <add name="CombinedNavSiteMapProvider" description="CMS provider for Combined navigation" type="Microsoft.SharePoint.Publishing.Navigation.PortalSiteMapProvider, Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" NavigationType="Combined" EncodeOutput="true" IncludePages="PerWeb" IncludeHeadings="true" IncludeAuthoredLinks="true" />
        <add name="CurrentNavSiteMapProvider" description="CMS provider for Current navigation" type="Microsoft.SharePoint.Publishing.Navigation.PortalSiteMapProvider, Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral,PublicKeyToken=71e9bce111e9429c" NavigationType="Current" EncodeOutput="true" IncludePages="PerWeb" IncludeHeadings="true" IncludeAuthoredLinks="true" />
        <add name="CurrentNavSiteMapProviderNoEncode" description="CMS provider for Current navigation, no encoding of output" type="Microsoft.SharePoint.Publishing.Navigation.PortalSiteMapProvider, Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" NavigationType="Current" EncodeOutput="false" IncludePages="PerWeb" IncludeHeadings="true" IncludeAuthoredLinks="true" />
        <add name="SiteDirectoryCategoryProvider" description="Site Directory category provider" type="Microsoft.SharePoint.Portal.WebControls.SiteDirectoryCategoryProvider, Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="MySiteMapProvider" description="MySite provider that returns areas and based on the current user context" type="Microsoft.SharePoint.Portal.MySiteMapProvider, Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="MySiteLeftNavProvider" description="MySite Left Nav provider that returns areas and based on the current user context" type="Microsoft.SharePoint.Portal.MySiteLeftNavProvider,  Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="UsagePagesSiteMapProvider" description="Provider for navigation in Portal Usage pages" type="Microsoft.SharePoint.Portal.Analytics.UsagePagesSiteMapProvider, Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="SPXmlAdminContentMapProvider" siteMapFile="_app_bin/admin.sitemap" type="Microsoft.SharePoint.Navigation.SPXmlContentMapProvider, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
      </providers>
 </siteMap>

Correspondingly, the actual control that spits out navigation control is placed in the master page as follows. This is the custom control that provides the ability to show/hide sub-sites and etc in the SharePoint Site Settings page.

XML
<publishingnavigation:portalsitemapdatasource id="SiteMapDataSourceRoot" runat="server" 
   sitemapprovider="CombinedNavSiteMapProvider" enableviewstate="true" 
   startfromcurrentnode="true" startingnodeoffset="0" showstartingnode="true">
</publishingnavigation:portalsitemapdatasource>

To override this behavior, you will need to do a few things.

  1. Create a new master page based on the BlackBand.master (or any master page in the directory under the PublishingLayouts feature).
  2. Replace the PublishingNavigation control declaration with a menu control.
  3. Create the code-behind file for the master page to load the custom navigation.
  4. Add the code-behind information to the master page directive and deploy the new master page to SharePoint plus the assemblies.
VB
Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
           MyBase.OnLoad(e)
           Dim menu As Menu = DirectCast(FindControl("Menu1"), Menu)

           Dim doc As XDocument = XDocument.Load(
               "C:\Inetpub\wwwroot\wss\VirtualDirectories\80\web.sitemap")
           Dim query = From c In doc.Element("menuitems").Elements("menuitem")

           Dim parentItem As MenuItem
           For Each element As XElement In query
               parentItem = New MenuItem()

               Dim subQuery = From c In element.Elements("menuitem")
               For Each node As XElement In subQuery
                   Dim item As New MenuItem()
                   With item
                       .Text = node.Attribute("text")
                       .NavigateUrl = node.Attribute("navigateurl")
                       .ToolTip = node.Attribute("tooltip")
                       .ImageUrl = "tool.png"
                   End With
                   parentItem.ChildItems.Add(item)

               Next

               With parentItem
                   .Text = element.Attribute("text")
                   .NavigateUrl = element.Attribute("navigateurl")
                   .ToolTip = element.Attribute("tooltip")
                   .ImageUrl = "heart.png"
               End With
               menu.Items.Add(parentItem)
           Next
End Sub

Essentially, the code-behind will load an XML file called web.sitemap (it can be any XML file you prefer) and iteratively add navigation nodes to the menu. This way, you can even add personalized nodes to the navigation as needed.

Points of Interest

Why using a Publishing Site?

Well, most of the SharePoint custom site definitions require you to use a definition that's based from the publishing one. In order to get user-swappable master pages and alternate CSS files, you have to start with the publishing site.

Why not XmlSiteMapProvider?

If you use that provider (out of the box from ASP.NET 2.0), you will not be able to modify the nodes in the navigation. The Items property of this object will have zero items for you to modify.

Why LINQ to XML?

Of course, using LINQ to XML is not needed. It merely simplifies hard-to-decipher nested loops or XPath that usually comes with XML document processing.

History

[May 14, 2008] Added a short FAQ section.

License

This article, along with any associated source code and files, is licensed under The BSD License