1

I have being working on Sitecore 93 SXA, and I'm creating a sxa search query token by extending pipeline ResolveSearchQueryTokensProcessor referring this blog to get the date field of item and compare it with current date, and filter out the SearchStringModel meeting the criteria. here is my code:

protected string TokenPart { get; } = "ExcludeItemWithPreviousDateInDateField";

[SxaTokenKey]
protected override string TokenKey => FormattableString.Invariant(FormattableStringFactory.Create("{0}|FieldName", (object)this.TokenPart));

public override void Process(ResolveSearchQueryTokensEventArgs args)
{
    if (args.ContextItem == null || args.ContextItem.ID.IsNull)
        return;
    for (var index = 0; index < args.Models.Count; ++index)
    {
        var model = args.Models[index];
        
        if (model.Type.Equals("sxa", StringComparison.OrdinalIgnoreCase) && ContainsToken(model))
        {
            string fieldName = model.Value.Replace(TokenPart, string.Empty).TrimStart('|');
            var dateField = args.ContextItem.Fields[fieldName];
            if (dateField != null)
            {
                args.Models.Insert(index, this.BuildModel(fieldName, dateField.Value));
            }
            args.Models.Remove(model);         
        }
    }
}

private bool isPastEvent(string fieldValue)
{
    var endOfToday = DateTimeProvider.GetUtcNow().Date.AddHours(23).AddMinutes(59).AddSeconds(59);
    var fieldTime = DateUtil.ParseDateTime(fieldValue, DateTime.MaxValue).Date.AddHours(23).AddMinutes(59).AddSeconds(59);    

    if (endOfToday > fieldTime)
        return true;

    return false; 
}

private SearchStringModel BuildModel(string fieldName, string fieldValue)
{
    if(isPastEvent(fieldValue))
        return new SearchStringModel("custom", FormattableString.Invariant(FormattableStringFactory.Create("{0}|{1}", (object)fieldName.ToLowerInvariant(), (object)fieldValue)))
        {
            Operation = "must"
        };

    return null;
} 
   protected override bool ContainsToken(SearchStringModel m)
    {
        return Regex.Match(m.Value, FormattableString.Invariant(FormattableStringFactory.Create("{0}\\|[a-zA-Z ]*", (object)this.TokenPart))).Success;
    }

here is my patch file:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" >
  <sitecore>
    <pipelines>
      <resolveSearchQueryTokens>
         <processor type="Sitecore.PartnerHub.Feature.SXAExtension.ExcludeItemWithPreviousDate, Sitecore.PartnerHub.Feature.SXAExtension" resolve="true" patch:before = "*[1]"/>
      </resolveSearchQueryTokens>
    </pipelines>
  </sitecore>
</configuration>

Now when I am including the patch and dlls in the local instance, something like this in response body:

{"TotalTime":69,"CountTime":0,"QueryTime":17,"Signature":"onlyevents","Index":"sitecore_sxa_master_index","Count":5, "Result" :[jsoncontent]}

The log I found in the Search log for token is:

7844 17:22:59 INFO Solr Query - ?q=__solr_norm_field_name_s:(_url)&start=0&rows=1&fq=_template:(455a3e98a6274b408035e683a0331ac7)&fq=_indexname:(sitecore_master_index)&wt=xml 9860 17:23:00 INFO Solr Query - ?q=((((_template:(d6c0b976d5a74ec598ad8c770cbc751f) AND _template:(ExcludeItemWithPreviousDateInDateField|EventDate)) AND _path:(11111111111111111111111111111111)) AND _datasource:(sitecore)) AND _latestversion:(1))&start=0&rows=20&fl=*,score&fq=_indexname:(sitecore_master_index)&wt=xml

In Solr log:

2020-11-23 13:33:57.631 INFO (qtp952562199-206) [
x:syedaABB93_master_index] o.a.s.c.S.Request [syedaABB93_master_index] webapp=/solr path=/select params={q=((((_template:(d6c0b976d5a74ec598ad8c770cbc751f)+AND+_template:(ExcludeItemWithPreviousDateInDateField|EventDate))+AND+_path:(11111111111111111111111111111111))+AND+_datasource:(sitecore))+AND+_latestversion:(1))&fl=*,score&start=0&fq=_indexname:(sitecore_master_index)&rows=20&wt=xml&wt=xml&version=2.2} hits=0 status=0 QTime=0

Update: I have updated the logs and changed the code, by putting date check in build model. But the code is searching the field value for search model in the current page, which is independent of the search result. My search scope is having template id and sxa token only.

I am trying first time to extend sxa search token, so please guide me if I'm doing anything wrong...

Thanks in advance.

7
  • Can you try debugging to check what happens in the Process function? Just to make sure the code is only handling your token and not all.
    – Gatogordo
    Nov 20 '20 at 16:13
  • args.Models.Remove(model) must be called for each model containing your token as you do replace that with the correct model for the search - you have a date check around it that doesn't belong there
    – Gatogordo
    Nov 20 '20 at 16:15
  • @gatogordo, okay got your point, but I want to filter the items in serach result which are true to that date check. Where should I do that check?
    – Tabbuu
    Nov 21 '20 at 14:32
  • 1
    You have to create your filter in the BuildModel - not in the Process. Your code must transform a model from Sitecore to a model that the search engines can use.
    – Gatogordo
    Nov 21 '20 at 16:16
  • @Gatogordo , I can now see the token in the suggestion box, and as per your suggestion I have added the date check in build model, but upon debugging, it seems like the model is checking upon the current item for field name where the search result is being added, but the page is independent of that field. How Can I make my search filter independent of the context item , and make it run for the particular template , am I doing something wrong ? My build query: +template:d6c0b976-d5a7-4ec5-98ad-8c770cbc751f;sxa:ExcludeItemWithPreviousDateInDateField|FieldName
    – Tabbuu
    Nov 24 '20 at 7:41
1

I think your not getting how this token is being executed. You are doing to check for a past event within the code (in your isPastEvent method) which is wrong as you are still converting the model from the input into something useable for the search api. At that moment you can (and are) working with the context item - which is not what you want. You want this logic to be executed on your results, but to achieve that you must adapt the model creation as such. It is the query that must filter on the dates, not your code.

So delete your isPastEvent code - you don't need it.

And change the BuildModel into something like this:

private SearchStringModel BuildModel(string fieldName)
{
    return new SearchStringModel("custom", FormattableString.Invariant(FormattableStringFactory.Create("{0}|{1}", (object)fieldName.ToLowerInvariant(), "[0001-01-01T00:00:00Z TO 2020-11-24T23:59:59Z]")))
        {
            Operation = "must"
        };
} 

I'm not sure about the exact syntax for creating a model with a date-field search though. Should be something like this but that might be not 100% accurate. And of course, you need to use the dates you want - I've put some dates in there as an example.

5
  • I cannot hard code date value in the build model, as I want to remove the item whose date has less value than the current date.
    – Tabbuu
    Nov 25 '20 at 10:51
  • You don't need to hardcode the current date - Datetime.Today will do?
    – Gatogordo
    Nov 25 '20 at 10:58
  • As per my understanding we need to pass only those models that meet the date criteria,? am i thinking it in wrong way? and If we provide the date range in model, how would it filter?
    – Tabbuu
    Nov 25 '20 at 11:11
  • No, you only have 1 model that you work with. Your model is your query, not the results. If you set in the model (query) that the date must be between today and a day way ahead in the future you should only get those results.
    – Gatogordo
    Nov 25 '20 at 11:14
  • This worked for me, but only for the pages having that particular field. Thanks for your explanation @gatogordo
    – Tabbuu
    Nov 26 '20 at 8:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.