Quick Links in Liferay using Audience Targeting

One of the common requirements across projects is showing the Quick links(Frequently visited links) to the user handy on home page so that when user logins, he can use these to navigate directly to desired page. In order to fulfill this requirement in portal using Liferay 7, we might need to use some Analytics tool and query it to get this kind of result or we need to implement custom solution. We can use Liferay Audience Targeting data to achieve this requirement and quickly implement the functionality without using any analytics tool or complex logic to preserve this information and retrieve. Below is the sample code that will return this information.

   public Map getLayoutFromFriendlyUrl(long userId, ThemeDisplay themeDisplay) {
     private static final int MAX_LINK_COUNT = 5;
     private static final String GROUP = “group”;
    long groupId = themeDisplay.getScopeGroupId();
    Map layoutMap = new LinkedHashMap<>();
    List mostClikedLinks = getMostClickedLinksByUser(userId);
    if (mostClikedLinks != null && mostClikedLinks.size() >= MAX_LINK_COUNT) {
      for (int i = 0; i < MAX_LINK_COUNT; i++) {
        Layout layout = null;
        Object[] link = mostClikedLinks.get(i);
      if(isPrivateLayout(link)) {
          layout = LayoutLocalServiceUtil.fetchLayoutByFriendlyURL(groupId, Boolean.TRUE,
              link[0].toString().substring(link[0].toString().lastIndexOf('/')));
        } else if (link[0].toString().contains(“web”)) {
          layout = LayoutLocalServiceUtil.fetchLayoutByFriendlyURL(groupId, Boolean.FALSE,
              link[0].toString().substring(link[0].toString().lastIndexOf('/')));
        }
        if (layout != null) {
          log.info("Layout Name: " + layout.getName());
          layoutMap.put(layout.getName(), link[0].toString());
        }
      }
      return layoutMap;
    } else {
      log.info("List returned by dynamic query is null or has <5 records");
      return layoutMap;
    }
  }
private boolean checkLayoutType(Object link, String type){
    return link[0].toString().contains(type);
}

/**
   * This method will fetch the list of most clicked links in last 30 days by a user
   * 
   * @param userId
   * @return
   */
  private List getMostClickedLinksByUser(long userId) {
    log.info("inside getMostClickedLinksByUser()");
    DynamicQuery query = AnalyticsEventLocalServiceUtil.dynamicQuery();
    ProjectionList projectionList = ProjectionFactoryUtil.projectionList();
    projectionList.add(ProjectionFactoryUtil.property("URL"))
        .add(ProjectionFactoryUtil.rowCount(), “clickCount”);
    Criterion criterion = null;
    criterion = RestrictionsFactoryUtil.eq(“userId”, userId);    
    criterion = RestrictionsFactoryUtil.and(criterion,
        RestrictionsFactoryUtil.ge(“createDate”,
            getDateBeforeDays(30)));
    projectionList
        .add(ProjectionFactoryUtil.groupProperty(“URL”))
        .add(ProjectionFactoryUtil.groupProperty(“userId”));
    query.setProjection(projectionList);
    query.addOrder(OrderFactoryUtil.desc(“clickCount”));
    query.add(criterion);    
    return AnalyticsEventLocalServiceUtil.dynamicQuery(query);    
  }
private Date getDateBeforeDays(int days) {
    Date date = new Date();
    Calendar calendar = new GregorianCalendar();
    calendar.setTime(date);
    calendar.add(Calendar.DATE, -days);
    return calendar.getTime();
  }

As shown in code, we query analytics table of Audience Targeting using “AnalyticsEventLocalServiceUtil” to get last visited page history. Also as shown in code, we can provide the time span to the query to get the data. We can write this function in Liferay custom service and call it from web content template or application display template(ADT) Sample template code to call the service and get the quick links is as shown below:


 <#assign qlinkService=serviceLocator.findService("com.liferay.myservice.service.QuickLinkService")>
<#assign linkMap = "">
<#if qlinkService?? >
<#attempt>
<#assign linkMap = qlinkService.getMostClickedLinksByUser(themeDisplay.getUserId(), themeDisplay)>
<#recover>
</#attempt>
<#if>
<#if linkMap?? && (linkMap?has_content) >
   <div class="lnv-card-wrapper">
       <#list linkMap?keys as linkKey>
	<div class="card="
                 <a href=="${linkMap[linkKey]} =" class=="internal=" target=="_self=" > ${linkKey}</a>
            </div>
     </#list>
</div>
</#if>

So when user has history of pages, then the most visited pages will be displayed to user to help him easy access to those pages.