(888) 685-3101 ext. 2

Liferay’s Audience Targeting application raises the engagement experience of your portal to a whole new level. This app allows you to segment your audience, target specific content to different user segments, and create campaigns to target content to user segments. It also allows you to track user actions and generate reports that provide insight into the effectiveness of your campaigns.

As an example, in an intranet scenario for a global multinational company, you might use audience targeting to segment users by location and target content based on these location-based segments. This enables your users to only see content relevant to them and reduces the noise.

In this post I will walk you through a tutorial on how to show/hide navigation pages based on user segments. The notion is that we will defer to Liferay’s Role Based Access Control (RBAC) to filter the navigation based on the security set-up, and then we will apply another layer of filtering to filter out any pages that are not relevant to the currently logged-in user because of the user segments that he/she is not a member of.

Liferay Audience Targeting

The 3 cases I need to consider when displaying a page are –

  • Show pages that have no user segments associated to them
  • Display pages that may have categories assigned to them, but don’t have anything to do with user segments
  • Display pages that have user segments selected that match the current user.

SeviceLocator needs to be available to make this work. Edit your portal-ext.properies file with the following properties

velocity.engine.restricted.classes=
velocity.engine.restricted.variables=

To keep the code clean I like to define the main variables I’ll be using for the theme in the init_custom.vm file.
init_custom.vm

## -------- Audience Targeting Section -------- ##
#set ($userSegmentLocalService = $serviceLocator.findService("content-targeting-api","com.liferay.content.targeting.service.UserSegmentLocalService"))
#set ($assetCategoryLocalService = $serviceLocator.findService("com.liferay.portlet.asset.service.AssetCategoryLocalService"))
#set ($userSegmentIds = $request.getAttribute("userSegmentIds"))

userSegmentIds returns all userSegmentIds that match the current user using the site.
userSegmentLocalService will be used to get more information about a particular userSegment.
assetCategoryLocalService is used to get the assetCategories for each page. Note that assetCategoryId is different than userSegmentId. Each userSegment has an assetCategoryId associated with it. So these are some of the parts that we will compare next.

navigation.vm

<nav id="navigation" class="$nav_css_class">
<ul>
<ul>#foreach ($nav_item in $nav_items) #set ($nav_item_attr_has_popup="") #set ($nav_item_attr_selected="") #set ($nav_item_css_class = "") #if ($nav_item.isSelected()) #set ($nav_item_attr_selected="aria-selected='true'") #set ($nav_item_css_class = "selected") #end #if ($nav_item.hasChildren()) #set ($nav_item_attr_has_popup="aria-haspopup='true'") #end ## -------- START Audience Targeting Section -------- ## #set ($hasUserSegment = false) #set ($ignoreCategory = false) #set ($navItemCategoryIds = $assetCategoryLocalService.getCategoryIds("com.liferay.portal.model.Layout", $nav_item.getLayout().getPlid())) #foreach ($id in $userSegmentIds) #set ($userSegmentId = $userSegmentLocalService.getUserSegment($id).getAssetCategoryId()) #foreach ($catId in $navItemCategoryIds) #if ($userSegmentId == $catId) #set ($hasUserSegment = true) #break #else #if ($userSegmentLocalService.fetchUserSegmentByAssetCategoryId($catId)) #set ($hasUserSegment = false) #break #else #set ($ignoreCategory = true) #break #end #end #end #end ## -------- END Audience Targeting Section -------- ## #if ($navItemCategoryIds.size() == 0 || $hasUserSegment || $ignoreCategory)
	<li id="layout_$nav_item.getLayoutId()" class="$nav_item_css_class">$nav_item.icon() $nav_item.getName() #if ($nav_item.hasChildren())
<ul class="child-menu">
<ul class="child-menu">#foreach ($nav_child in $nav_item.getChildren()) #set ($nav_child_attr_selected="") #set ($nav_child_css_class = "false") #if ($nav_child.isSelected()) #set ($nav_child_attr_selected="aria-selected='true'") #set ($nav_child_css_class = "selected") #end
	<li id="layout_$nav_child.getLayoutId()" class="$nav_child_css_class">$nav_child.getName()</li>
</ul>
</ul>
#end

#end</li>
</ul>
</ul>
#end #end
</nav>

Above is the complete code for navigation.vm – I’m going to explain each part.

#set ($navItemCategoryIds = $assetCategoryLocalService.getCategoryIds("com.liferay.portal.model.Layout", $nav_item.getLayout().getPlid()))

Since the code I added, is inside of the foreach loop for $nav_item it iterates over each navigation item. The above code gets the assetCategoryIds associated with each page.

The first foreach loop iterates over each userSegmentId. Then gets the assetCategoryId associated with each userSegmentId. The second foreach loop iterates over each assetCategoryId for the $nav_item. I used two variables as flags: ($hasUserSegment, $ignoreCategory)

#foreach ($id in $userSegmentIds)
	#set ($userSegmentId = $userSegmentLocalService.getUserSegment($id).getAssetCategoryId())
        #foreach ($catId in $navItemCategoryIds)
           #if ($userSegmentId == $catId)
		#set ($hasUserSegment = true)
		#break
	   #else
	      #if ($userSegmentLocalService.fetchUserSegmentByAssetCategoryId($catId))
		#set ($hasUserSegment = false)
		#break
	      #else
		 #set ($ignoreCategory = true)
		 #break
	      #end
            #end
         #end
#end

The section where the navigation link is displayed. I wrap it within an if statement that checks for pages that have no userSegments or Categories, Pages that matches the current user’s usersegment’s assetCategoryId, and finally display pages that don’t have any userSegments but may have other categories assigned to the page.

#if ($navItemCategoryIds.size() == 0 || $hasUserSegment || $ignoreCategory)
<ul>
	<li id="layout_$nav_item.getLayoutId()" class="$nav_item_css_class">
$nav_item.icon() $nav_item.getName() $nav_item_caret

...
#end</li>
</ul>

Hope you enjoyed this post. Leave comments below if you have any questions.

Share This