2

I've seen examples such as here on how to create a custom Scriban function.

How would I go about implementing one which supports the Content Search API like that shown here?

Example: Function called sc_searchitems calls the Content Search API.

<h3 class="field-promotitle">{{ sc_field i_item 'PromoTitle' }}</h3>
{{ sc_field i_item 'PromoText' }}
{{ 
   queryid = "{1A5CDCC5-EBB7-49B9-8C56-7E7F74BE0C26}"
   fieldname = "Title"
}}
<ul class="items">
  {{ for i_searchitem in ( sc_searchitems i_page queryid o: "Title,Ascending" p: 50 ) }}
  <li>{{ i_searchitem.Fields[fieldname] }}</li>
  {{ end }}
</ul>

1 Answer 1

3

I was able to accomplish this in a few steps in SXA 9.3. This approach implements the ISearchService included with SXA. We're basically extracting code that is used by the SearchController.

Step 1 : Implement the custom search function. Add this to your IGenerateScribanContextProcessor.

private delegate IEnumerable<Item> SearchItemsDelegate(Item item, string s, string q = null, string o = null, int p = 10, int e = -1, string g = null, double r = -1);
protected ISearchService SearchService { get; } = ServiceLocator.ServiceProvider.GetService<ISearchService>();
protected ISortingService SortingService { get; } = ServiceLocator.ServiceProvider.GetService<ISortingService>();

public IEnumerable<Item> SearchItemsImpl(Item item, string s, string q = null, string o = null, int p = 10, int e = -1, string g = null, double r = -1)
{
    var siteInfo = SiteResolver.GetSiteInfo(item);
    var scopesIDs = s?.Split(',', '|').Where(ID.IsID).Select(ID.Parse);

    Coordinate center = null;
    if (!string.IsNullOrEmpty(g))
    {
        center = g?.Replace("|", ",");
    }

    var query = this.SearchService.GetQuery(new SearchQueryModel
    {
        Coordinates = center,
        ItemID = item?.ID,
        Query = q,
        ScopesIDs = scopesIDs
    }, out var indexName);

    var sortings = o?.Split('|').TrimAndRemoveEmpty();
    query = this.SortingService.Order(query, sortings, center, siteInfo.Name);
    if (e > 0)
    {
        query = query.Skip(e);
    }
    if (p > 0)
    {
        query = query.Take(p);
    }

    return query.Select(i => i.Uri).ToList()
        .Select(u => Factory.GetDatabase(u.DatabaseName)
            .GetItem(u.ItemID, u.Language, u.Version));
}

Step 2 : Add the function to the global script object.

args.GlobalScriptObject.Import("sc_searchitems", new SearchItemsDelegate(SearchItemsImpl));

Step 3 : Add a scriban rendering variant.

{{ 
   queryid = "{BBC62A76-2207-465B-BA0D-073BE71FD90C}"
   fieldname = "Title"
}}
<ul class="items">
  {{ for i_searchitem in ( sc_searchitems i_page queryid o: "Title,Ascending" p: 50 ) }}
  <li>{{ i_searchitem.Fields[fieldname] }}</li>
  {{ end }}
</ul>

Note: This version may have some missing features. If you improve upon feel free to share with me and I'll update this answer.

Update: You may have noticed that at the end of the code where the items are pulled from the search engine that Uri is selected. In my experience I've found that the SXA search can be made significantly faster by selected just the Uri from the search engine and then getting items based on that property. A feature request would be for SXA to do the same by default.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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