Friday, March 20, 2015

implementing content targeting and when you would want to use them

There are many reasons why you may want to target content in SharePoint. Here I will explain 4 ways..

1. SPSecurityTrimmedControl

SharePoint 2007 introduced a wonderful web control called SPSecurityTrimmedControl that allows you to define sections of content based on user permission, authentication, and/or page mode. The type of content you can display conditionally may be plain text, raw HTML, or ASP.NET control. You can use it in masterpages, page layouts, or custom controls. Most of the time it’s a no-brainer to use it because it’s very flexible and easy to configure.
  • To show or hide content based on current user’s permission, you can use PermissionString:
    <SharePoint:SPSecurityTrimmedControl PermissionsString="EditListItems" runat="server"> 
        
    </SharePoint:SPSecurityTrimmedControl>
    SPBasePermissions lists all of the possible permission strings that you can configure. In addition, you can add the property PermissionMode, which allows you to define whether All permissions or Any permission that you’ve defined in the PermissionString is required to render content. Finally, if you wish to specify the context of when this is applied, you have the option via PermissionContext. This allows you to define the context of the permission trimming on the current folder, current list item, current list, current subsite, or on the entire site collection.
  • To show or hide content based on authentication, you can use AuthenticationRestrictions:
    <SharePoint:SPSecurityTrimmedControl runat="server" AuthenticationRestrictions="AuthenticatedUsersOnly">
        
    </SharePoint:SPSecurityTrimmedControl>
    The AuthenticationRestrictions property allows output to be accessible by AllAuthenticated or Anonymous users only.
  • To show or hide content based on current page’s mode, you can use the PageModes property. The modes are AllNormal, or Design.
Having mentioned all 3 possibilities with this control, the only time that you should use it is for defining sections visible based on PermissionString. Its capability to filter by authentication through AuthenticationRestrictions is limited to AllUsers or AuthenticatedUsersOnly and PageModes simply doesn’t work. To find out why, you can checkout this awesome explanation. Keep reading to find out alternative ways to target based on authentication and page mode.
Another word of caution with this control is on its performance. This control performs the check at the end of its life cycle in the Render method, which means pretty much every method of every child control gets executed. What this means is that you should use this sparingly and it is better used on raw HTML or plain text instead of complex controls.

2. LoginView

The next handsome devil is a ASP control called LoginView. Earlier I covered a way to implement content targeting based on authentication through SPSecurityTrimmedControl. However I also mentioned how this only works for AllUsers or AuthenticatedUsersOnly. How would you target content for anonymous users? This is where LoginView comes in. To target for anonymous users, you can leverage theAnonymousTemplate:
<asp:LoginView runat="server">
    <AnonymousTemplate>
        
        <SharePoint:Scriptlink runat="server" Name="~sitecollection/Style Library/js/anonymous.js" LoadAfterUI="true" OnDemand="false" Language="javascript" />
    </AnonymousTemplate>
</asp:LoginView>
Because this control uses templates, LoginView’s performance is better than SPSecurityTrimmedControl. Thus for conditionally displaying content based on authentication, this control will be a much better fit. Note that although in the example above I only showed the AnonymousTemplate, this control is also capable of creating LoggedInTemplate and RoleGroups. Quick note about RoleGroups: it is not equivalent of SharePoint Groups. To understand how this is managed, you can take a look here. Keep reading to find out how to properly implement audience targeted content based on SharePoint Groups.

3. EditModePanel

Earlier I mentioned that although SPSecurityTrimmedControl provides PageModes property, it does not work as designed. So what can you use to display content based on the mode of a SharePoint page? If you’re using publishing feature, then a very neat control to help you show or hide content based on page mode is EditModePanel. You can see it in action in out of the box SharePoint page layouts (e.g. ArticleLeft.aspx) where it registers CSS targeted for edit view:
<PublishingWebControls:editmodepanel runat="server" id="editmodestyles">
   
   <SharePointWebControls:CssRegistration name="<% $SPUrl:~sitecollection/Style Library/~language/Core Styles/zz2_editMode.css %>" runat="server"/>
</PublishingWebControls:editmodepanel>
This control comes in handy when you’re implementing a public website where the publishing experience for content authors and the user experience for anonymous visitors can be dramatically different. Here’s a MSDN blog article on how you can leverage this control to tweak page rendering for image fields through the use of PageDisplayMode. When this property is set to “Display”, the contained content will be rendered when the page is not in editing mode. When SharePoint 2010 was first introduced, this property stopped working as designed as the panel is only rendering for users that have edit permission to the page. After SP1, this issue has been resolved and it is currently working for SharePoint 2013. During the time that it wasn’t working, lots of people have came up with an approach to  mimic its 2007 behaviour by using AuthoringContainer. Here’s a blog post referencing that approach if you are interested.

4. Audience Target

Last but not least, I want to cover audience targeted content. SharePoint provides some out of the box configuration options via browser for Audience targeting, namely for web parts and navigation links. Below I will provide ways to automate deploying web parts and construct navigation with audience targeting configured. In addition I will walk over the option to use SharePoint web service GetGroupCollectionFromUserif you need something more heavy lifting that’s outside of the native audience features.

Web Part Target Audiences Property

SharePoint web parts have a native web part property called Target Audiences that allows you to use a people picker to assign audience filters. Through the use of people picker, you can choose to add Global Audiences, Distribution/Security Groups, or SharePoint Groups. Once this property is configured, this web part will only be visible to people who are a member of the configured list. Most of the times configuring the web part manually through browser is just fine but what if you need to deploy a lot of web parts targeting a specific group and you need to test it repetitively? This would require deploying web parts through features or code.
The Target Audiences web part property is actually stored in AuthorizationFilter. When you export V2 web parts, the property is stored in IsIncludedFilter which has been marked as obsolete (internally this property just references the AuthorizationFilter property). Web parts that are not V2 will not export AuthorizationFilter, which makes the deployment process that much more difficult especially when there’re virtually no documentation on how this property can be constructed on MSDN. Below is an extraction of sample code from a blog article and summary on how you can construct with the correct format for this property:
// The global audience is stored as a GUID and is the only type of item that can be stored without any delimiter information if no other items exist.  Multiple items are separated with a comma.
string[] globalAudienceGuid = new string[] {"e4687e64-c9d8-4860-bbc3-ec036bf9915d"};
// The distribution list is stored as an LDAP string.  Multiple items are separated with a new line character ("\n").
string[] dlDistinguishedNames = new string[] {"cn=group1,cn=users,dc=spdev,dc=com", "cn=group2,cn=users,dc=spdev,dc=com"};
// The SharePoint groups are stored as a named value (i.e., "Members", "Owners", etc.) and multiple items are separated with a comma.
string[] sharePointGroupNames = new string[] {"Demo Members", "Demo Owners"};
// Each item is delimited with two semi-colons: ";;" but you can avoid hard coding by using the GetAudienceIDsAsText method of the AudienceManager class. Note that this same format is used for the Audience field of a publishing page.
string targetAudienceProperty = AudienceManager.GetAudienceIDsAsText(globalAudienceIDs, dlDistinguishedNames, sharePointGroupNames);
Now that you know how to populate this field, you can use the web part definitions in features or programmatically update them by code.

SharePoint Navigation Audience Field

Out of the box top and left navigation in SharePoint allow you to add Global Audiences, Distribution/Security Groups, or SharePoint Groups to the Audience field through browser configuration, which works similarly to the web parts. The manually configured link will only appear to users who are a member of the groups configured.
Creating the navigation structure programmatically can be achieved by calling SPNavigationSiteMapNode.CreateSPNavigationNode followed by SPNavigationSiteMapNode.UpdateSPNavigationNode. Since navigation only needs to be setup once, a preferred method is accomplishing this by using PowerShell. The following code snippet will help get you started:
$node = [Microsoft.SharePoint.Publishing.Navigation.SPNavigationSiteMapNode]::CreateSPNavigationNode($name, $url, $nodeType, $collection)
$updatedNode = [Microsoft.SharePoint.Publishing.Navigation.SPNavigationSiteMapNode]::UpdateSPNavigationNode($node, $null, $name, $node.Url, $description, $target, $audience, $false)
If you already have the top navigation created and you simply want to update its Audience programmatically, you can follow code sample found here.

Audience Targeting in Masterpage and Page Layouts

Besides web parts and navigation, you may want to display raw HTML conditionally based on SharePoint Groups. The best approach that I found is to leverage the web service GetGroupCollectionFromUser. You can leverage this web service to create a reusable web control to wrap around raw HTML in your masterpage and page layouts. Alternatively, a more lightweight solution is to use SPServices jQuery library which abstracts SharePoint’s web services. Since it is based on jQuery, it  requires no server side deployment. Follow code snippet below for a way to target content for users in certain SharePoint Groups:
// Make sure SP Services is loaded
function insureSPServices(callbackFunction) {
    if ($().SPServices == null) {
        jQuery.getScript("/style library/js/jquery.SPServices.min.js", callbackFunction);
    } else {
        callbackFunction.call(null, "Already Loaded");
    }
}
function isGroupMember(groupName, callback) {
    $().SPServices({
        operation: "GetGroupCollectionFromUser",
        userLoginName: $().SPServices.SPGetCurrentUser(),
        async: true,
        completefunc: function (xData, Status) {
            callback($(xData.responseXML).find("Group[Name='" + groupName + "']").length == 1);
        }
    });
};
function InitializePage(data, textStatus) {
    isGroupMember("myGroupName", function (result) {
        if (result) {
            // Code for when current user is in the group
        }
    });
}
$(document).ready(function () {
    insureSPServices(InitializePage);
});
In a nutshell, there are many out of the box ways to configure targeted content for your SharePoint site. Even when you’re out of luck with native ways, there are other methods that you can use. However, never forget that the primary reason to implement any of them should be for better user experience for your site visitors. It’s never a good idea to implement something custom just because you can. Always stick to out of the box features as much as possible.

No comments:

Post a Comment