SharePoint 2013 Managed Navigation: Pros, Cons, and Code

5 min readPublished May 02, 2013Updated May 02, 2022

This post originally appeared on the Perficient blog

I recently posted a script to export term sets in SharePoint (vetted in both 2010 & 2013). I was prompted to write that script, because the client I was working on had a very particular (and large!) managed navigation structure that I wanted to replicate across all environments to make testing code much simpler. This was my first experience using 2013’s managed navigation and I wanted to share my thoughts and see if anyone else has had similar/different experiences with it so far.

For those of you that don’t know, managed navigation is new in SharePoint 2013. It gives you the option to base the navigation on taxonomy rather than “physical” structure. It uses a dedicated term set for site navigation and the terms correspond to the friendly URL segment created.

For instance, http://site.com/example/of/managed/navigation would correspond to the following term hierarchy:

example (root term) –> of –> managed –> navigation

And the term ‘navigation’ would be mapped to the physical URL (the /Pages/page.aspx URL) of the specific page you want shown when a user navigates to that URL.

Managed navigation provides a lot of flexibility for how you want your site organized and optimizes your URLs for SEO. It makes it possible to move pages across “sites” or locations (if you think of a site in terms of what an end user sees rather than the SharePoint structure for site) without actually moving or touching the physical page.

In my experience, managed navigation is great in certain scenarios and in other instances may not be the best choice. I’ve briefly outlined the pros and cons that I’ve experienced personally.

Pros

  • User Experience: Managed navigation gives your site a consistent, easy URL schema for your end users. I don’t know about you, but not seeing http://site.com/Pages/AboutUs.aspx and seeing http://site.com/about-us instead just seems so much cleaner and more intuitive, especially as the logical organization gets deeper.
  • New customization opportunities: Who doesn’t love shiny new toys?? Because the navigation is now taxonomy driven, custom navigation controls are easier to code and maintain (in my opinion) and provide more flexibility. Navigation terms come with a lot of properties OOTB, but you can also define your own custom properties programmatically or through the UI to use in your custom controls.

Cons

  • Content authoring: In order to reap the full benefits of SEO optimized friendly URLs, you have to set the “Hide physical URL from search” property to true on every page otherwise search indexes the physical URL and you lose the benefits of the friendly URLs (especially if you have custom controls appearing on friendly URL pages which won’t appear on physical pages). However, this means that the physical pages are also hidden from search/within the document libraries. Even though this seems small, if you are a content author sifting through hundreds of pages in a library to edit a single page and can’t use the library’s search bar, this can become a huge pet peeve.
  • Limited to a single site collection: If you have multiple site collections composing your intranet/extranet/public website, you cannot share a single navigation term set among all of the site collections. For me, this is a major sore spot as its not possible to share global navigation across site collections, let alone the more granular levels of navigation. I don’t want to have to maintain multiple copies of a navigation term set manually so that whenever I click a ‘Home’ link across site collections, I go to the same page.

Code (.NET)

Below are some code samples just to get started using managed navigation programmatically.

I found myself having difficulty trying to figure out how to access the friendly URL for a term, because I couldn’t find the properties or methods I needed on the Term object. You must first get the NavigationTerm object for the Term, then you can get the friendly URL.

TermSetCollection navTermSets = session.DefaultSiteCollectionTermStore.GetTermSets(NavTermSetName, 1033);
   
//gets the collection of terms starting at the root term 'value'
var termCollection = from allTerms in navTermSets[0].Terms where allTerms.GetDefaultLabel(1033).ToLower() == "value" select allTerms;

if (termCollection != null && termCollection.Count() > 0)
{
  //gets the root term, 'value'
  Term term = termCollection.First();
  NavigationTerm navTerm = NavigationTerm.GetAsResolvedByWeb(term, web, "GlobalNavigationTaxonomyProvider");
  string friendlyUrl = navTerm.FriendlyUrlSegment.Value;
}

If you want to go the other direction, from the physical page to the friendly URL you would used the following code snippet.

//get the pages library
Guid pagesId = PublishingWeb.GetPagesListId(web);
SPList publishingPages = web.Lists[pagesId];

//get a reference to whichever page you want
SPListItem page = publishingPages.Item[0];

//a page can have multiple friendly URLs
IList<NavigationTerm> friendlyUrls = new List<NavigationTerm>();
friendlyUrls = TaxonomyNavigation.GetFriendlyUrlsForListItem(page, true);

To set the target URL programmatically, you have to set the Value property of the Navigation Term’s TargetUrl property. In this example, I’m using a hard coded physical URL, you would most likely get this value dynamically.

NavigationTerm navTerm = NavigationTerm.GetAsResolvedByWeb(term, web, "GlobalNavigationTaxonomyProvider");
navTerm.TargetUrl.Value = "~sitecollection/Pages/testpage.aspx";

Just for good measure, below is a code snippet for getting the Navigation Term and friendly URL and setting the TargetUrl property using Powershell if you prefer to go that route.

$taxonomySite = Get-SPSite -Identity $SiteUrl
$taxonomySession = Get-SPTaxonomySession -site $taxonomySite
$taxonomyTermStore =  $taxonomySession.TermStores | Select Name
$termStore = $taxonomySession.TermStores[$taxonomyTermStore.Name]

#make sure these 2 lines match your environment
$group = $termStore.Groups["Group name"]
$termSet = $group.TermSets["Term set name"]

foreach ($term in $termSet.GetAllTerms())
{
  $navTerm = [Microsoft.SharePoint.Publishing.Navigation.NavigationTerm]::GetAsResolvedByWeb($term, $taxonomySite.RootWeb, "GlobalNavigationTaxonomyProvider")

  #get friendly URL
  $friendlyUrl = $navTerm.FriendlyUrlSegment.Value


  #to set target URL
  $navTerm.TargetUrl.Value = "~sitecollection/Pages/testpage.aspx"
}

#to save all changes you made to term set
$termStore.CommitAll()

Again, if you want to go the other direction using Powershell, see below.

#Get the Publishing Web and pages within it
$pagesId = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPagesListId($web)
$publishingPages = $web.Lists[$pagesId]
$page = $publishingPages.Items[0]

$friendlyUrls = [Microsoft.SharePoint.Publishing.Navigation.TaxonomyNavigation]::GetFriendlyUrlsForListItem($page, $true)
 
if ($friendlyUrls.Count -ne $zero)
{
  $friendlyUrls | ForEach-Object{
  $friendlyUrl = $_.GetWebRelativeFriendlyUrl()

  #code here for what you want to do w/ the friendly URL
}
 
#if you want to access a navigation property like below
$field = $page.Fields["Hide physical URLs from search"]
$physUrlHidden = $page.GetFormattedValue($field.Title)]

Well-Rounded Dev

Liked this post? Subscribe to receive semi-regular thoughts by email.

    I won't send you spam. Unsubscribe at any time.