Monday, January 20, 2014

Change order of newly created publishing page or publishing site in navigation programmatically in Sharepoint

Most probably you already know about interesting behavior of Sharepoint navigation (since it exists from Sharepoint 2007): when you try to work with navigation nodes programmatically by accessing PublishingWeb.Navigation.GlobalNavigationNodes (or CurrentNavigationNodes), this collection will be empty until you will go to Site settings > Navigation and click Ok button. After this collection is filled and you may start really working with it. There is also number of workarounds for this already which allow to prefill navigation nodes and thus work with them using object model during provisioning (starting from Gary Lapointe’s gl-setnavigationnodes stsadm extension or PowerShell script from Waldek Mastykarz. If you will search you will find couple more solution). These solutions may be combined by one criteria: they solve problem for provisioning, but what about maintenance?

Will try to illustrate the problem: suppose that we provisioned site collection with number of sub sites and pages on the root site, so navigation (for this article it doesn’t matter is it current or global navigation) looks like this after provisioning:


Blue color means that nodes are provided dynamically by PortalSiteMapProvider, but not from PublishingWeb.Navigation.GlobalNavigationNodes collection. If we will use workarounds for prefilling navigation or if we will go to Site settings > Navigation and will click Ok, then navigation will look like this:


Green color means that navigation nodes are retrieved from PublishingWeb.Navigation.GlobalNavigationNodes collection, i.e. not constructed dynamically. After that we create new publishing web or new publishing page e.g. via feature. Interesting that after this navigation again uses dynamic node for this newly created sub site/page:


I.e. navigation is constructed both from PublishingWeb.Navigation.GlobalNavigationNodes collection and dynamically from PortalSiteMapProvider. It introduces problem e.g. if we need to change the order of the corresponding navigation node (using SPNavigationNode.Move method) we won’t be able to do it because there won’t be such node in it. Solution is the following: at first we need to mark corresponding publishing page or web as excluded from navigation:

   1: var page = pweb.GetPublishingPages().FirstOrDefault(
   2:     p => string.Compare(p.Name, pageName, true) == 0);
   3: if (page != null)
   4: {
   5:     page.IncludeInGlobalNavigation = false;
   6: }

Here are methods which we can use depending on the scenario:

After this PortalSiteMapProvider won’t show this page in navigation:


After that create new navigation node for the page or web programmatically and move it to the correct place:

   1: PublishingWeb pweb = ...;
   2: var globalNavigation = pweb.Navigation.GlobalNavigationNodes;
   4: var node = SPNavigationSiteMapNode.CreateSPNavigationNode(title, url,
   5:     NodeTypes.AuthoredLinkPlain, globalNavigation);
   6: var dt = DateTime.Now;
   7: node.Properties["CreatedDate"] = dt;
   8: node.Properties["LastModifiedDate"] = dt;
   9: node.Properties["Description"] = "";
  10: node.Properties["Target"] = "";
  11: node.Update();
  13: var nodeSite = globalNavigation.Cast<SPNavigationNode>().
  14:     FirstOrDefault(n => n.Title == "Test");
  15: if (nodeSite != null)
  16: {
  17:     node.Move(globalNavigation, nodeSite);
  18: }

In this example we moved new node for our page after node which corresponds to page/site with title “Test”. After this navigation looks like this:


I.e. we have navigation node for the new page in the right place in navigation, while dynamic node is hidden. Hope that this trick will help you in the working with Sharepoint navigation.

No comments:

Post a Comment