Custom SXA Search Scope Query Token
Hello everyone, In this blog we will see how we can use a custom token in SXA search scope query. What is custom search scope query token and when it is useful.
So let's start with understanding what is SXA search scope query token. We all are aware like how search is an important and integral part of any website built using Sitecore. Specially when we are building a website using SXA then most of the time we use Search Result OOTB SXA component for any kind of listing. The Search Result OOTB component primary requirement is Search Scope query. We can build the scope query from Sitecore only where we can define things like Location, Templates etc.
Location: Used to help the Solr to get data from specific folder
Templates: Used to filter the Sitecore items created from specific templates
Many of the time, this suffice to build your search scope query to get the desired results. But we all know, there are times that we need something different from normal scope query to get our results. Let's take example to understand the same.
We are having a list of blog items inside our folder. The items are created from Blog templates. Now we want to list down the blogs in our website. If we are using SXA then, by using Location and template filter in our search scope query, we can get all the blogs items. Location will point to Blog folder and template will help to filter the blog items. Now, if we are having a multilist field as blog category or tags in blog item and we want to filter the blog list fetched from Solr query by this multilist field, the our normal above scope query will not worked.
So for such kind of scenario, Search Scope query tokens are helpful. We can create a required search scope query token. Search Scope query token are tokens that are replaces automatically by the Solr when a search query is fired. Basically this token is replaced by actual field of Solr with the required value.
Let's see, how we can create a search scope query token with a example below. In below example we will be _fullpath Solr field with actual value which will replace our query token.We are passing the item id as query string param on the page where we need to show the required item.
using Sitecore.ContentSearch.Utilities;
using Sitecore.XA.Foundation.Search.Attributes;
using Sitecore.XA.Foundation.Search.Pipelines.ResolveSearchQueryTokens;
using Sitecore.XA.Foundation.SitecoreExtensions.Extensions;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using System.Web;
namespace ShrikantTest.Foundation.SearchTokenResolver.Pipeline
{
public class FilterFullPathSXAToken : ResolveSearchQueryTokensProcessor
{
protected string Operation { get; private set; } = "must";
protected string TokenPart
{
get
{
return nameof(FilterFullPathSXAToken);
}
}
[SxaTokenKey]
protected override string TokenKey
{
get
{
return FormattableString.Invariant(FormattableStringFactory.Create("{0}|SxaTags", (object)this.TokenPart));
}
}
/// <summary>
/// process for persoanlized search token
/// </summary>
/// <param name="args"></param>
public override void Process(ResolveSearchQueryTokensEventArgs args)
{
try
{
if (args.ContextItem == null)
return;
for (int index = 0; index < args.Models.Count; ++index)
{
SearchStringModel model = args.Models[index];
if (model.Type.Is("sxa") && this.ContainsToken(model))
{
string taIndexfield = "_fullpath";
if (HttpContext.Current.Request.Url != null && HttpContext.Current.Request.UrlReferrer != null)
{
NameValueCollection queryCollectionReferrer = null;
if (!string.IsNullOrEmpty(HttpContext.Current.Request.UrlReferrer.Query) && HttpContext.Current.Request.UrlReferrer.Query.Contains("itemid"))
{
queryCollectionReferrer = HttpUtility.ParseQueryString(HttpContext.Current.Request.UrlReferrer.Query);
var queryitemid = queryCollectionReferrer.Get("itemid");
Sitecore.Data.Items.Item item = Sitecore.Context.Database.GetItem(queryitemid);
var itempath = item.Paths.FullPath;
if (!string.IsNullOrEmpty(itempath))
{
args.Models.Add(this.BuildModel(taIndexfield, itempath));
}
}
}
args.Models.Remove(model);
}
//Removing current model as its not valid
}
}
catch (Exception ex)
{
Sitecore.Diagnostics.Log.Error("FilterFullPathSXAToken.Process", ex, this);
}
}
/// <summary>
/// Building search string model
/// </summary>
/// <param name="replace"></param>
/// <param name="item"></param>
/// <returns></returns>
protected virtual SearchStringModel BuildModel(string indexfield, string itempath)
{
try
{
string value = $"{indexfield.ToLowerInvariant()}|{itempath}";
return new SearchStringModel("custom", value)
{
Operation = this.Operation
};
}
catch (Exception ex)
{
Sitecore.Diagnostics.Log.Error("FilterFullPathSXAToken.BuildModel", ex, this);
}
return null;
}
/// <summary>
/// checking token is SXA token
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
protected override bool ContainsToken(SearchStringModel model)
{
bool isMatch = false;
try
{
isMatch = Regex.Match(model.Value, FormattableString.Invariant(FormattableStringFactory.Create("{0}\\|[a-zA-Z ]*", (object)this.TokenPart))).Success;
}
catch (Exception ex)
{
Sitecore.Diagnostics.Log.Error("FilterFullPathSXAToken.ContainsToken", ex, this);
}
return isMatch;
}
}
}
If you go through the above code, you will see that, we are first getting the search string model having the token by calling ContainsToken() method, then we are building the Solr field with the actual value using BuildModel() method. This method adds a new string model to existig search string model which contains the Solr field with required value. This helps in filtering the required items while search query is called. The last step is to remove the old sxa token from search string model as we have replaced it with required Solr field and its value.
Now, its time to patch the Token query code in web.config
<?xml version="1.0"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<resolveSearchQueryTokens>
<processor type="ShrikantTest.Foundation.SearchTokenResolver.Pipeline.FilterFullPathSXAToken, ShrikantTest.Foundation.SearchTokenResolver" resolve="true"/>
</resolveSearchQueryTokens>
</pipelines>
</sitecore>
</configuration>
After all this is deployed to your solution, you will be able to see the sxa search scope token in Search query builder in sitecore.
The final scope query will look like below.
Hence your token FilterFullPathSXAToken|SxaTags will be replace by _fullpath:/sitecore/content/ShrikantTest/TestWebsite/Blog1. This value can be seen in your Solr dashboard too. Hope you might have enjoyed the article and we will see more Sitecore related blogs in future. Stay tuned.
Thanks for reading. Happy learning.
You can check my other blogs too if interested. Blog Website
Comments
Post a Comment