Monday, August 26, 2013

SharePoint 2013 Content Search Web Part (CSWP) in Variation Sites

The Content Search Web Part (CSWP) introduced in SharePoint 2013 displays search results in a way that we can change how search results appear on a page by using display templates. Each Content Search Web Part is associated with a search query and shows the results for that search query.

Even though there is a Query Builder option provided in the edit mode of the webpart, sometimes it is necessary to set the "QueryText" attribute of the Content Search Web Part Programmatically.

In a CSWP we can limit the search results to take from current site (This site) or from site collection (This site collection). But there is no way to specify another URL or relative URL without hardcoding the server name. In my case I wanted to read data from variation top sites as all of my language dependent SPLists were residing in <site_collection>/en and <site_collection>/fr level.


Therefore I had to extend OOB CSWP and create a custom CSWP for my use. My plan was to override the QueryText from the backend.


In order to override the QueryText attribute, I had to override the BeforeSerializeToClient event. So what I’m doing is;
  1. In the “Build Your Query” screen, in the Query Text field, add the path attribute and set my own value called “CurrentVariationLabel”, in addition to the other filters.
  2. Then in the “BeforeSerializeToClient” event, replace “CurrentVariationLabel” text with current variation label.
  3. I have written a private method called “GetCurrentVariationLabel” to get the current variation label.

protected override void OnLoad(EventArgs e)
{
   if (this.AppManager != null)
   {
     if (this.AppManager.QueryGroups.ContainsKey(this.QueryGroupName) &&
        this.AppManager.QueryGroups[this.QueryGroupName].DataProvider != null)
     {          this.AppManager.QueryGroups[this.QueryGroupName].DataProvider.BeforeSerializeToClient +=
      new BeforeSerializeToClientEventHandler(UpdateQueryText);
     }
   }
   base.OnLoad(e);
}

private void UpdateQueryText(object sender, BeforeSerializeToClientEventArgs e)
{
      DataProviderScriptWebPart dataProvider = sender as DataProviderScriptWebPart;
      dataProvider.QueryTemplate = dataProvider.QueryTemplate.Replace("CurrentVariationLabel", "\"" + GetCurrentVariationLabel() +"\"");
}

private static string GetCurrentVariationLabel()
{
   VariationLabel currentVL = null;

   if (SPContext.Current != null)
   {
      string currentUrl = SPContext.Current.Web.Url;
      ReadOnlyCollection<VariationLabel> variationLabels = null;
      if (Variations.Current != null)
      {
         variationLabels = Variations.Current.UserAccessibleLabels;
      }
      if (!String.IsNullOrEmpty(currentUrl) && variationLabels != null)
      {
         foreach (VariationLabel vl in variationLabels)
         {
            if (currentUrl.StartsWith(vl.TopWebUrl, StringComparison.CurrentCultureIgnoreCase))
            {
               currentVL = vl;
            }
         }
      }
    }

    if (currentVL != null)
    {
       return currentVL.TopWebUrl;
    }           
}

With the same approach, by changing GetCurrentVariationLabel() method, I can use my custom CSWP to limit results from any other sub-site as well.

1 comment:

Prasad Sampath Wickramasinghe said...

The CSWP returns content that is crawled. SharePoint search crawls only the major versions of content. If we need to display instant content or minor versions of content, CSWP is not an option. We can try Content Query Web Part (CQWP) instead.