SXA Variant Token Resolver for Breadcrumb

Hello everyone, I am back with another blog. This time we will discuss something about SXA variant token and how it is useful while creating rendering variants in SXA. We will also discuss a scenario where Variant Token helped us to achieve the required functionality.

Let's start without delaying. We were asked to implement a search functionality in SXA. If user search for any keyword, then user must be redirected to search result page where he will be shown all the matched result. So whoever has worked on SXA will be thinking that its simple to implement the required ask using SXA OOTB functionality. 

Steps we will be following to achieve the same is:

1. Use the Search Box OOTB component.

2. Configure the required search scope query in Search Box Component

3. Give the Signature and configure the required Search Result Page where the user should be redirected, when someone search for something.

4. On the Search Result Page where we are showing the user all matched results, we will add Search Result Component which OOTB SXA component. 

5. Then we will configure the Search Result Component required configuration. Signature which will be similar to what we have specified in Search Box component. Scope Query, Page Size and others. The Scope query will be same as what specified in Search box.

6. One more configuration we will be using the Rendering Variant Selection created from Search Result Component in SXA

7. After all configuration is set up, we can verify the functionality.

Now comes our main point of discussion. There was an extra ask to us that whatever Search Result list is coming, for each entry in list we need to show the required breadcrumb for the same.

After doing little bit of search in google for the solution part, we understood that we cannot directly include SXA OOTB Breadcrumb component in rendering variant. The major reason for this was, Search Result component is executed using API approach. There is API call which is triggered to backend system to get the desired result. So whatever result is returning, we can use those data only.

So here comes SXA Variant Token for the rescue. SXA variant token gives us a way to introduce our custom backend logic to execute the same. So we can return anything like html also which will be replacing the token in rendering variant.

Let's see the Code for the same which was implement. 

This code can modified according to one's requirement.

       
using Sitecore.Data.Items;
using Sitecore.Sites;
using Sitecore.XA.Foundation.Variants.Abstractions.Pipelines.ResolveVariantTokens;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;

namespace ShrikantTest.Feature.Search.Pipeline
{
    public class ResolveBreadcrumb : ResolveVariantTokensProcessor
    {
        public override string Token => "$breadcrumb";
        private const string BREADCRUMB_SEPARATOR = "<span class=\"breadcrumb-chevron\">></span>";
        private const string parentlist = "<ol>{0}</ol>";
        private const string childlist = "<li class=\"bread-crumb\"><a href = {0}>{1}</a><span>></span></li>";

        public override void ResolveToken(ResolveVariantTokensArgs args)
        {
            if (args.ResultControl != null)
            {
                args.ResultControl.Controls.Add(new LiteralControl
                {
                    Text = GetBreadcrumbPath(args.ContextItem, Sitecore.Context.Site)
                });
            }
            else
            {
                args.Result = GetBreadcrumbPath(args.ContextItem, Sitecore.Context.Site);
            }
        }

        private string GetBreadcrumbPath(Item contextItem, SiteContext site)
        {
            StringBuilder breadcrumbString = new StringBuilder();
            var ancestors = GetBreadcrumbs(contextItem, site);
            var finalchildlist = string.Empty;
           
            foreach(var data in ancestors)
            {
                finalchildlist = finalchildlist + string.Format(childlist, data.PageUrl, data.PageTitle);
            }
            
            return string.Format(parentlist, finalchildlist);
        }

        private ICollection<Breadcrumbdata> GetBreadcrumbs(Item current, SiteContext site)
        {
            List<Breadcrumbdata> breadcrumbs = new List<Breadcrumbdata>();

            while (current != null)
            {
                if(DoesItemHasLayout(current))
                {
                    Breadcrumbdata br = new Breadcrumbdata();
                    var breadcrumbValue = current.DisplayName;
                    if (current.Fields["NavigationTitle"] != null && !string.IsNullOrEmpty(current.Fields["NavigationTitle"].Value))
                    {
                        br.PageTitle = current.Fields["NavigationTitle"].Value;
                        br.PageUrl = Sitecore.Links.LinkManager.GetItemUrl(current);
                    }

                    // could add additional logic to opt in/out of 
                    // the breadcrumb based on a template/field
                    breadcrumbs.Add(br);
                    if (breadcrumbs.Count == 2)
                    {
                        break;
                    }
                    if (current.TemplateID.ToString().ToUpper().Equals("{FBB36B3F-6D4E-4846-803E-CB90934C9257}"))
                    {
                        break;
                    }
                }
               current = current.Parent;
            }

            breadcrumbs.Reverse();

            return breadcrumbs;
        }

        private static bool DoesItemHasLayout(Item itemId)
        {
            if (itemId != null)
            {
                LayoutItem layoutItem = itemId.Visualization.GetLayout(Sitecore.Context.Device);
                if (layoutItem != null)
                {
                    return true;
                }
            }
            return false;
        }

    }

    public class Breadcrumbdata
    {
        public string PageTitle { get; set; }
        public string PageUrl { get; set; }
    }
}

	   
 

The $breadcrumb is the token value which will added in Rendering variant.Now we need to add this token resolver as patch file. You can refer the below config for the same.

       
<?xml version="1.0"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
	<sitecore>
		<pipelines>
			<resolveVariantTokens>
				<processor type="ShrikantTest.Feature.Search.Pipeline.ResolveBreadcrumb, ShrikantTest.Feature.Search" resolve="true"  />
			</resolveVariantTokens>
		</pipelines>
	</sitecore>
</configuration>
	   
 

Thanks for reading. Happy learning and will come back with someother interesting blogs.

Comments

Popular posts from this blog

Sitecore XM Cloud Form Integration with Azure Function as Webhook

Automate RSS Feed to Sitecore XM Cloud: Logic App, Next.js API & Authoring API Integration

Create and Fetch Content From Sitecore Content Hub One using GraphQL and React