Security Trimming on Site Navigation Using Managed Metadata

by Uma Narayanan
Security Trimming on Site Navigation Using Managed Metadata

SharePoint can help, through structured navigation, provide users with a new, metadata-driven experience.


In earlier versions of SharePoint, the only possible way of navigation was by using structured navigation. With structured navigation, there were certain features out of the box, like setting an audience. This helped display links on the left based on user's permissions. In SharePoint 2013, a new way of navigation is introduced; it is managed metadata (term store) driven. Users can use the term store to create the navigation. Currently, the term store navigation doesn't have an audience feature.

In this article, we will use term store and JavaScript to implement security trimming.


To begin with, the term store needs to be set up. In the central administration, under "Application Management," click "Manage services on server". Ensure "Managed Metadata Web Service" is in the list of services is started. In addition to this, go to "Application Management" and click "Manage service applications". Create a new "Managed metadata service" application if it's not created already. After the basic setup is done, we will create a set of terms that we will use in navigation.

In the site collection, use the gear icon to go to the "Site Settings" page. On the "Site Settings" page, under "Site Administration", click the "Term Store management" link as shown in Figure 1:

Figure 1: Showing the Site Administration information

In "Term Store Management", we will create a group name, "Navigation". Under that, we will create a term set named 'JS Frameworks'. In this term set, we will create multiple terms, as shown in Figure 2:

Figure 2: Creating the Framework terms

Click the term 'Angular'. This will bring up the details section in the right-hand section. In the right-hand section, click the "Custom properties" tab, as shown in Figure 3:

Figure 3: Finding the Custom properties tab

In the custom properties section, under "Shared Properties", we add two properties, "Permission" and "Url", and their values. The "Permission" key will have the group names as values. In addition, we are using a "Url" to store the link.

Note: Currently, in this example, only one group is validated. This also can be extended to support multiple groups.

Figure 4: Viewing the Shared Properties tab

Click the "Add" button to add new properties. Until this point, all the configurations at the SharePoint site is completed.

Go to the 'Site Assets' library and upload the jQuery file. Now, we will look at the custom code.

Create a new HTML page named 'Navigation.html' and add the following HTML code snippet:

<script src="../SiteAssets/jquery-1.8.2.min.js"></script>
<div class="RCLeftNav" id="rcLeftNav">


This is a placeholder where the navigation will be displayed.

Add a <Script> section in the HTML and insert the following code:


   RegisterSod('tax.js', _spPageContextInfo.siteAbsoluteUrl +
   RegisterSodDep("tax.js", "sp.js");

Because we are reading the term store data, we need to ensure the SP.Taxonomy.js file is loaded.

The next step is to load the data. To do that, we write a function that will read the data from the term store and form the collection:

 1. var LoadNavigation = function () {
 2.    return $.Deferred(function (def) {
 3.       getTerms();
 4.       function getTerms() {
 5.          var context = SP.ClientContext.get_current();
 6.          var terms =
                  getByName("Navigation", 1033).get_termSets().
                  getByName('JS Frameworks', 1033).get_terms();
 7.          var web = context.get_web();
 8.          var currentUser = web.get_currentUser();
 9.          groupCollection = currentUser.get_groups();
10.          context.load(terms);
11.          context.load(currentUser);
12.          context.load(groupCollection, 'Include(Title,Id)');
13.          context.executeQueryAsync(function () {
14.          var termArray = [];
15.          var termEnum = terms.getEnumerator();
16.          while (termEnum.moveNext()) {
17.             var oTerm = termEnum.get_current();
18.             var urlObj = oTerm.get_customProperties("Url");
19.             var urlVal = "";
20.             urlVal = urlObj.Url;
21.             var permissionObj = oTerm.get_customProperties("Permission");
22.             var permissionVal = "";
23.             permissionVal = permissionObj.Permission;
24.             var groupEnumerator = groupCollection.getEnumerator();
25.             while (groupEnumerator.moveNext()) {
26.                var oGroup = groupEnumerator.get_current();
27.                var groupName = oGroup.get_title();
28.                if (groupName == permissionVal) {
29.                   termArray.push({ termname: oTerm.get_name(), termUrl: urlVal });
30.                }
31.             }
32.          }
33.          def.resolve(termArray);
34.       }, function (s, a) {
35.          def.reject(a.get_message());
36.        });   //end of execute query async
37.      }   //end of function getTopics
38.    });   //end of deferred
39. }   //end of Load Topics

Let's understand the code. Line 6 retrieves the terms in the group named "Navigation" and a termset named "JS Frameworks". Lines 8 and 9 get the groups the current user belongs to. This will be used to determine which links are visible for the user. At this point, the terms and groups are not retrieved; we need to load them and call the context method executeQueryAsync to populate the data, as depicted in Lines 10 and 13, respectively.

At Line 14, we declare an array named 'termArray'. Using the termEnum enumerator, we loop through all the terms. Line 18 gets the custom property "Url" and Line 20 retrieves the value stored in the 'Url' property. Similarly, Lines 21 and 23 retrieve the group name by using 'permission' value.

At Lines 25-28, we loop through the groups the user belongs to and compare the result with the group that was mentioned in the term property named "permission". Lines 28-29 verify if the user belongs to the group; if yes, the term is added to the collection named 'termArray'.

Until now, we have written the method to populate the term array. The following code binds the data to the UI.

 1. SP.SOD.executeFunc("tax.js", null, function () {
 2.    var topics = LoadNavigation();
 3.    $.when(topics)
 4.    .done(function (terms) {
 5.       var divHtml = "<ul>";
 6.       for (i = 0; i < terms.length; i++) {
 7.          divHtml += "<li>";
 8.          divHtml += "<a href='" + terms[i].termUrl + "'>" +
 9.          terms[i].termname + "</a></li>";
10.       }
11.       divHtml += "</ul>";
12.       $("#rcLeftNav").html(divHtml);
13.    })
14.    .fail(function (errMsg) {
15.    })
16. });

Line 4 retrieves the populated term array after the 'LoadNavigation' method is executed successfully. If it fails, Line 14 is executed. Lines 6-10 loop through the terms and create HTML elements. Line 12 binds the formed HTML with the div element Id declared in the HTML.

This example helps us achieve navigation based on group permissions.


In this example, we saw how we can use custom properties in 'terms' to control the navigation display on the UI. We can extend the same to add images against terms to display on the UI. In this example, we used JQuery to create the navigation.



Originally published on .
This article was originally published on Wednesday Oct 22nd 2014
Mobile Site | Full Site