Skip to content
  • Home
  • SharePoint Solutions
  • Sports
  • OffBeat
  • About
  • Contact

Share A Solution

Written by AlearnerMay 28, 2016September 20, 2017

Automatically add Friendly URLs In SharePoint

Managed metadata navigation is a new feature that has been part of SharePoint 2013. The basic purpose of managed metadata navigation is to provide Friendly URL for your sites and pages in SharePoint.  I have found SharePoint publishing site as a great tool for Content Management through out my work with different organization. There are caveats that comes along but in average i found it helpful for public anonymous sites who needs constant content update.

One bottleneck  of the SharePoint public site was the URL that comes by default with Publishing sites. Most of the client who are not familiar with the SharePoint structure didn’t liked the  extra term  that comes with SharePoint. Most of the SharePoint Internet site URL has “/pages” embedded in their URL. “/pages” will have some meaning and someone familiar with SharePoint can relate to it. But for normal public it is an extra word to type to get to a particular page in the web. IF we browse around most of the web sites don’t have a extra word which doesn’t mean anything.

There are ways to handle a friendly URL for SharePoint site like in this blog FriendlyURL. Since Microsoft introduced managed metadata navigation, it has somehow been a tool that can serve the purpose of adding Friendly URL for sites and pages and sub-sites in a publishing site.  But one thing i found little hassle and confusing with Managed metadata  navigation is it is manual for sub sites and pages under sub-sites.  Till date there is a bug in managed metadata navigation which is more described in this blog  ManagedMetadataNavigation Bug.

So in this article i am going to explain about the solutions that i have written for one of my projects which will automate the managed metadata navigation process, that overcomes all these problems and users doesn’t have to do things manually.

This code has been tested and used successfully in my pas work. It will be great if you guys have some ideas to improve the code or the process, it will be a pleasure to adopt that.

Here is the whole process

  1. Add an Empty project to Visual Studio 2013

1

2. Make sure you make this solution as Farm Solution

2

3.Make sure following Dlls are added to your project

  • Microsoft.SharePoint.Taxonomy
  • Microsoft.SharePoint.Publishing

4.Now add new item to the project and  pick the Event receivers template

3

5. In the list of Events pick the Web Event and Check Web Deleting and Web Provisioning.

4

6. Repeat the same process for Adding another Event Receiver and this time pick List Item Event Receivers and make sure u pick Pages Library from the event source item.

5

7. Once we have our Event receivers code files are ready now we can write the actual code that make things happen.

Find the Event receivers code file for pages 6

Comment out the existing code inside the ItemDeleting and ItemChecking code block.

Following is the function that will be referenced in both ItemDeleting and ItemChecking code block. Put this code inside the event receiver for pages.

This function is the main function that handles the adding and deleting for page items.


private void AddDeleteNavigation(SPWeb currentweb, SPWeb parentweb, SPWeb current_rootweb, Boolean Delete, SPListItem item)
        {
            try
            {

                IList urlpartslists = currentweb.ServerRelativeUrl.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                ///variable declaration
                string parentwebrelative_url = parentweb.ServerRelativeUrl.ToString();
                string pagetitle = item.DisplayName;
                string currentweb_url = urlpartslists[urlpartslists.Count - 1].ToString();
                string currenweb_relativeurl = currentweb.ServerRelativeUrl.ToString().Replace(current_rootweb.ServerRelativeUrl.ToString(), "");

                ///taxonomy declartion
                ///

                TaxonomySession taxSession = new TaxonomySession(currentweb.Site);
                TermStore TermStore = taxSession.TermStores[0]; //Provide your term store name

                Group termgroup = TermStore.Groups["Site Navigation"]; // Provide your Site Navigatoin Name

                TermSet currenterm = termgroup.TermSets[urlpartslists[0].ToString()];
                NavigationTermSet navTermSet = NavigationTermSet.GetAsResolvedByWeb(currenterm, current_rootweb, StandardNavigationProviderNames.GlobalNavigationTaxonomyProvider);

                if (currentweb.IsRootWeb)
                {

                    if (Delete && curr_web_term_exists != null)
                    {
                        curr_web_term_exists.Delete();

                    }
                    else
                        if (!Delete && curr_web_term_exists == null)
                        {

                            curr_web_term_exists = navTermSet.CreateTerm(pagetitle, NavigationLinkType.FriendlyUrl);
                            curr_web_term_exists.FriendlyUrlSegment.Value = pagetitle;
                            curr_web_term_exists.TargetUrl.Value = "~sitecollection" + "/" + item.File.Url.ToString();

                        }
                    TermStore.CommitAll();

                }

                else if ((!currentweb.IsRootWeb) && (currentweb.ParentWeb.IsRootWeb))
                {

                    try
                    {
                        NavigationTerm curr_web_term_exists = navTermSet.Terms.Where(t => t.Title.ToString() == urlpartslists[1].ToString().Replace("_", "")).FirstOrDefault();
                        NavigationTerm curr_page_term_exists = curr_web_term_exists.Terms.Where(t => t.Title.ToString() == pagetitle).FirstOrDefault();
                        if (Delete && curr_page_term_exists != null)
                        {

                            curr_page_term_exists.Delete();

                        }
                        else if (curr_page_term_exists == null && !Delete)
                        {

                            curr_page_term_exists = curr_web_term_exists.CreateTerm(pagetitle, NavigationLinkType.FriendlyUrl);
                            curr_page_term_exists.FriendlyUrlSegment.Value = pagetitle;
                            curr_page_term_exists.TargetUrl.Value = "~sitecollection" + "/" + currenweb_relativeurl + "/" + item.File.Url.ToString();

                        }

                        TermStore.CommitAll();

                    }
                    catch (Exception ex)
                    {
                        SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("ManagedMetadata Navigation", TraceSeverity.Unexpected, EventSeverity.Information), TraceSeverity.Unexpected,ex.Message);

                    }

                }

                else
                    if (!currentweb.ParentWeb.IsRootWeb && !currentweb.IsRootWeb)
                    {
                        try
                        {

                            NavigationTerm first_term = navTermSet.Terms.Where(t => t.Title.ToString() == urlpartslists[1].ToString().Replace("_", "")).FirstOrDefault();
                            NavigationTerm parent_term = null;

                            if ((first_term.Title.ToString() == urlpartslists[2].ToString().Replace("_", "")) && urlpartslists.Count == 3)
                            {
                                NavigationTerm pageterm = first_term.Terms.Where(t => t.Title.ToString() == pagetitle).FirstOrDefault();
                                if (Delete != true && pageterm == null)
                                {

                                    NavigationTerm newterm = first_term.CreateTerm(pagetitle, NavigationLinkType.FriendlyUrl);
                                    newterm.FriendlyUrlSegment.Value = pagetitle;
                                    newterm.TargetUrl.Value = "~sitecollection" + "/" + currenweb_relativeurl + "/" + item.File.Url;
                                }
                                else
                                    if (Delete)
                                    {

                                        NavigationTerm delteterm = first_term.Terms.Where(t => t.Title.ToString() == pagetitle).FirstOrDefault();
                                        delteterm.Delete();

                                    }

                            }
                            else
                            {
                                for (int i = urlpartslists.Count - 1; i > 0; i--)
                                {
                                    parent_term = first_term.Terms.Where(t => t.Title.ToString() == (urlpartslists[i].ToString().Replace("_", ""))).FirstOrDefault();
                                    if (parent_term != null && i == urlpartslists.Count - 1)
                                    {

                                        if (Delete && curr_page_term_exists != null)
                                        {

                                            curr_page_term_exists.Delete();

                                        }
                                        else
                                            if (!Delete && curr_page_term_exists == null)
                                            {

                                                NavigationTerm newterm = parent_term.CreateTerm(pagetitle, NavigationLinkType.FriendlyUrl);
                                                newterm.FriendlyUrlSegment.Value = pagetitle;
                                                newterm.TargetUrl.Value = "~sitecollection" + "/" + currenweb_relativeurl + "/" + item.File.Url;
                                            }
                                        break;
                                    }
                                    else if (parent_term != null)
                                    {
                                        first_term = parent_term;
                                        parent_term = null;
                                        i = urlpartslists.Count;

                                    }
                                }
                            }
                            TermStore.CommitAll();

                        }
                        catch (Exception ex)
                        {
                            SPDiagnosticsService.Local.WriteTrace(0,
 new SPDiagnosticsCategory("ManagedMetadata Navigation", TraceSeverity.Unexpected, EventSeverity.Information), TraceSeverity.Unexpected,ex.Message);

                        }

                    }
                -
            }
            catch (Exception ex)
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("ManagedMetadata Navigation", TraceSeverity.Unexpected, EventSeverity.Information), TraceSeverity.Unexpected, ex.Message);
            }
        }

Now Add following code in ItemDeleting of the page item receiver

try { 
    string fileurl = properties.ListItem.File.Url;
    //Check if the current page is not welcome page and not a system page. 
    //When a web is created then it adds few pages which will trigger these events.
    //so to avoid them we filter out at here. 
   if (fileurl != properties.ListItem.Web.RootFolder.WelcomePage && !fileurl.Contains("_catalogs"))
     { 
          SPWeb web = properties.List.ParentWeb;
          SPListItem item = properties.ListItem;
          SPWeb current_parentweb = web.ParentWeb;
          SPWeb current_rootweb = web.Site.RootWeb;
          AddDeleteNavigation(web, current_parentweb, current_rootweb, true, item);
     } 
   }
  catch (Exception ex)
    { SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("ManageMetadata Navigation", TraceSeverity.Unexpected, EventSeverity.Information), TraceSeverity.Unexpected, ex.Message);
  }

Add following code in the ItemCheckingIn code block

try
            {
                string fileurl = properties.ListItem.File.Url;
                if (fileurl != properties.ListItem.Web.RootFolder.WelcomePage && !fileurl.Contains("_catalogs"))
                {                   

                    SPWeb web = properties.List.ParentWeb;
                    string listurl = properties.ListItem[SPBuiltInFieldId.EncodedAbsUrl].ToString();
                    SPListItem item = web.GetListItem(listurl);
                    SPWeb current_parentweb = web.ParentWeb;
                    SPWeb current_rootweb = web.Site.RootWeb;
                    AddDeleteNavigation(web, current_parentweb, current_rootweb, false, item);                   

                }

            }
            catch (Exception ex)
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("ManagedMetadata", TraceSeverity.Unexpected, EventSeverity.Information), TraceSeverity.Unexpected, ex.Message);
            }

Compile the solution. We have the page item events receiver done now let’s do the Web event-receiver code file.

6.Open the eventreceiver.cs file for the web Event-receiver. 7
There is not much different in the logic of the Site. Most of the logic you will find is just being reused. I guess we can still use only page item event receiver including the welcome page in the event receiver. I hope someone will make a use of that. For now let me write the code for Site Event receiver.

Here is the main function that does the delete and adding of the navigation for Web.

At the top paragraph of this article i was talking about an issues with managed metadta navigation. to fix or workaround with that i added an underscore at the end of my subsite URL so that we can get away with that bug. the following code looks for an underscore and replaces it for the friendly URL.

private void WebAddDeleteNavigation(SPWeb currentweb, SPWeb parentweb, SPWeb current_rootweb, Boolean Delete)
        {
            try
            {
                IList urlpartslists = currentweb.ServerRelativeUrl.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);

                string currentweb_url = urlpartslists[urlpartslists.Count - 1].ToString();
                string correctedweb_url = currentweb_url.Replace("_", "");
                string currenweb_relativeurl = currentweb.ServerRelativeUrl.ToString().Replace(current_rootweb.ServerRelativeUrl.ToString(), "");

                TaxonomySession taxSession = new TaxonomySession(currentweb.Site);
                TermStore TermStore = taxSession.TermStores[0];

                Group termgroup = TermStore.Groups["Site Navigation"];

                String termsetcount = Convert.ToString(termgroup.TermSets.Count);

                TermSet currenterm = termgroup.TermSets[0];
                NavigationTermSet navTermSet = NavigationTermSet.GetAsResolvedByWeb(currenterm, current_rootweb, StandardNavigationProviderNames.GlobalNavigationTaxonomyProvider);

                if ((!currentweb.IsRootWeb) && (currentweb.ParentWeb.IsRootWeb))
                {

                    try
                    {

                        if (termgroup != null)
                        {
                            NavigationTerm curr_web_term_exists = navTermSet.Terms.Where(t => t.Title.ToString() == correctedweb_url).FirstOrDefault();

                            if (Delete && curr_web_term_exists != null)
                            {

                                curr_web_term_exists.Delete();

                            }
                            else
                                if (!Delete)
                                {

                                    curr_web_term_exists = navTermSet.CreateTerm(correctedweb_url, NavigationLinkType.FriendlyUrl);
                                    curr_web_term_exists.FriendlyUrlSegment.Value = correctedweb_url;
                                    curr_web_term_exists.TargetUrl.Value = "~sitecollection" + "/" + currenweb_relativeurl + "/Pages/default.aspx";

                                }

                        }
                        TermStore.CommitAll();

                    }
                    catch (Exception ex)
                    {
                        SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Manage Metadata", TraceSeverity.Unexpected, EventSeverity.Information), TraceSeverity.Unexpected,ex.Message);
                    }

                }

                else
                    if (!currentweb.ParentWeb.IsRootWeb && !currentweb.IsRootWeb)
                    {
                        try
                        {

                            NavigationTerm first_term = navTermSet.Terms.Where(t => t.Title.ToString() == urlpartslists[1].ToString().Replace("_", "")).FirstOrDefault();
                            NavigationTerm parent_term = null;

                            if ((first_term.Title.ToString() == urlpartslists[1].ToString().Replace("_", "")) && urlpartslists.Count == 3)
                            {
                                if (Delete != true)
                                {

                                    NavigationTerm newterm = first_term.CreateTerm(correctedweb_url, NavigationLinkType.FriendlyUrl);
                                    newterm.FriendlyUrlSegment.Value = correctedweb_url;
                                    newterm.TargetUrl.Value = "~sitecollection" + "/" + currenweb_relativeurl + "/Pages/default.aspx";
                                }
                                else
                                    if (Delete)
                                    {

                                        NavigationTerm delteterm = first_term.Terms.Where(t => t.Title.ToString() == correctedweb_url).FirstOrDefault();
                                        delteterm.Delete();

                                    }

                            }
                            else
                            {
                                for (int i = urlpartslists.Count - 1; i > 0; i--)
                                {
                                    parent_term = first_term.Terms.Where(t => t.Title.ToString() == urlpartslists[i].ToString().Replace("_", "")).FirstOrDefault();
                                    if (parent_term != null && i == urlpartslists.Count - 2)
                                    {
                                        if (Delete)
                                        {
                                            NavigationTerm curr_site_term_exists = parent_term.Terms.Where(t => t.Title.ToString() == correctedweb_url).FirstOrDefault();

                                            if (curr_site_term_exists != null)
                                            {
                                                curr_site_term_exists.Delete();

                                            }

                                        }
                                        else
                                        {

                                            NavigationTerm newterm = parent_term.CreateTerm(correctedweb_url, NavigationLinkType.FriendlyUrl);
                                            newterm.FriendlyUrlSegment.Value = correctedweb_url;
                                            newterm.TargetUrl.Value = "~sitecollection" + "/" + currenweb_relativeurl + "/Pages/default.aspx";
                                        }
                                        break;
                                    }
                                    else if (parent_term != null)
                                    {
                                        first_term = parent_term;
                                        parent_term = null;
                                        i = urlpartslists.Count - 1;

                                    }
                                }
                            }
                            TermStore.CommitAll();

                        }
                        catch (Exception ex)
                        {
                            SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Manage Metadata", TraceSeverity.Unexpected, EventSeverity.Information), TraceSeverity.Unexpected, ex.Message);
                        }

                    }

            }
            catch (Exception ex)
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Manage Metadata", TraceSeverity.Unexpected, EventSeverity.Information), TraceSeverity.Unexpected,  ex.Message);
            }

        }

Once you have this function added in the site navigation event receiver code file. now lets update the the event receiver methods.

In the Web Deleting method put this code

try
            {
                SPWeb web = properties.Web;                

                if (web.Webs.Count == 0)
                {
                    SPWeb current_parentweb = web.ParentWeb;
                    SPWeb current_rootweb = web.Site.RootWeb;
                    AddDeleteNavigation(web, current_parentweb, current_rootweb, true);

                }

            }
            catch (Exception ex)
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Managed Metadata Navigation", TraceSeverity.Unexpected, EventSeverity.Information), TraceSeverity.Unexpected, "web deleting " + ex.Message);

            }


In the WebProvisioned method add following code

try            {

                SPWeb web = properties.Web;
                web.Navigation.UseShared = true;
                SPWeb current_parentweb = web.ParentWeb;
                SPWeb current_rootweb = web.Site.RootWeb;
                AddDeleteNavigation(web, current_parentweb, current_rootweb, false);

            }
            catch (Exception ex)
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Managed Metadata", TraceSeverity.Unexpected, EventSeverity.Information), TraceSeverity.Unexpected, "web provisioning " + ex.Message);
            }

Compile the solutions and Deploy to your Web Application.

Few things to be noted before activating the feature
1. Make sure your terms store name is correct int he service application and in the code
2. Site collection is publishing site template
3. Change navigation to managed metadata navigation
4. Users who will be adding new pages and new site need enough permission at least contribute in the term store and term set in the managed metadata service application.

 

Here is the codeplex link to this solutions Enable Auto SharePoint Friendly URL

Like this:

Like Loading...
Posted in SharePoint Solutions.Tagged ManagedMetadata, ManagedMetadata Navigation, SharePoint, SharePoint InternetSite, SharePoint PublishingSite, SharePointNavigation.

Leave a Reply Cancel reply

Fill in your details below or click an icon to log in:

Gravatar
WordPress.com Logo

You are commenting using your WordPress.com account. ( Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. ( Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. ( Log Out /  Change )

Cancel

Connecting to %s

Post navigation

Next Post Site Breadcrumb for SharePoint 2013
Create a website or blog at WordPress.com
  • Follow Following
    • Share A Solution
    • Already have a WordPress.com account? Log in now.
    • Share A Solution
    • Customize
    • Follow Following
    • Sign up
    • Log in
    • Copy shortlink
    • Report this content
    • View post in Reader
    • Manage subscriptions
    • Collapse this bar
 

Loading Comments...
 

    %d bloggers like this: