Create an Item extension with Scriban in SXA 9.3.0

Empower your templates with custom Scriban item extensions in SXA 9.3.0

27/01/2020
Dominic Sinclair-Moore
FOUNDER
Dominic profile picture
incandescent bulb on black surface

SXA Scriban item extensions are used to make it easier to access fields, item properties and field properties. Personally, I've found the .url extension the most useful when implementing Scriban templates. Whilst there are a good number of out of the box extensions readily available, there are times where you may want to implement a custom extension, for example rendering an absolute URL instead of a relative URL (which is a limitation of the .url extension).

First of all, we need to install the Sitecore.XA.Foundation.Scriban NuGet package to the project we are enabling this functionality in. This package contains the GetScribanItemMembers pipeline which we need to hook into to register our extension with Scriban within Sitecore.

Now lets create a class called GetAbsoluteUrl and inherit the GetScribanItemMember from the Sitecore.XA.Foundation.Scriban package we've previously installed.

using Sitecore;
using Sitecore.XA.Foundation.Scriban.Pipelines.GetScribanItemMembers;

namespace Sitecore.Foundation.Variants.Pipelines.GetScribanItemMembers
{
    public class GetAbsoluteUrl : GetScribanItemMember
    {
    }
}

In our particular use case, we are creating an item extension to get an absolute URL so we also need to include the following NuGet packages:

Sitecore.Links
Sitecore.XA.Foundation.Multisite

Once these packages are installed we can add the following references below to our class and also implement the inherited abstract members from the GetScribanItemMember abstract class. In this case we are going to name our member (MemberName) "url_absolute".

using Sitecore;
using Sitecore.Links;
using Sitecore.Links.UrlBuilders;
using Sitecore.XA.Foundation.Multisite.Services;
using Sitecore.XA.Foundation.Scriban.Pipelines.GetScribanItemMembers;

namespace Sitecore.Foundation.Variants.Pipelines.GetScribanItemMembers
{
    public class GetAbsoluteUrl : GetScribanItemMember
    {
        protected override string MemberName
        {
            get
            {
                return "url_absolute";
            }
        }

        protected override void Resolve(GetScribanItemMembersPipelineArgs args)
        {
            // Logic goes here
        }
    }
}

At this point we are ready to implement our logic to render the absolute URL. We need the LinkProviderService to allow us to fetch the LinkProvider for the context site (where the Scriban template will be executed).

protected readonly ILinkProviderService LinkProviderService;

public GetAbsoluteUrl(ILinkProviderService linkProviderService)
{
    this.LinkProviderService = linkProviderService;
}

To implement the logic within the Resolve method we need to understand the different checks we need to make before we can get the item URL.

  1. If the GetScirbanItemMembersPipelineArgs mode is the same as MemberMode.Name then we need to add our member.
  2. If the GetScirbanItemMembersPipelineArgs item is null, we want to set our MemberValue to "#".
  3. If the GetScirbanItemMembersPipelineArgs mode is the same as MemberMode.Value then we need to add our logic to fetch the member value.

Simply put, we need two if statements first to validate the MemberMode and if the item is null. We can then add our logic to add our absolute URL value to the MemberValue.

protected override void Resolve(GetScribanItemMembersPipelineArgs args)
{
    if (args.Mode == MemberMode.Name)
    {
        args.Members.Add(this.MemberName);
        return;
    }
    if (args.Item == null)
    {
        args.MemberValue = "#";
        return;
    }
    // Absolute URL Logic here
}

Finally we can add our logic to the resolve method to fetch the link provider, set the item language and set the ItemUrlBuilderOptions to AlwaysIncludeServerUrl.

LinkProvider linkProvider = this.LinkProviderService.GetLinkProvider(Context.Site);
ItemUrlBuilderOptions itemUrlBuilderOptions = linkProvider.GetDefaultUrlBuilderOptions();
itemUrlBuilderOptions.Language = args.Item.Language;
itemUrlBuilderOptions.AlwaysIncludeServerUrl = true;
args.MemberValue = linkProvider.GetItemUrl(args.Item, itemUrlBuilderOptions);

The final result should look like this.

using Sitecore;
using Sitecore.Links;
using Sitecore.Links.UrlBuilders;
using Sitecore.XA.Foundation.Multisite.Services;
using Sitecore.XA.Foundation.Scriban.Pipelines.GetScribanItemMembers;

namespace Sitecore.Foundation.Variants.Pipelines.GetScribanItemMembers
{
    public class GetAbsoluteUrl : GetScribanItemMember
    {
        protected readonly ILinkProviderService LinkProviderService;

        public GetAbsoluteUrl(ILinkProviderService linkProviderService)
        {
            this.LinkProviderService = linkProviderService;
        }

        protected override string MemberName
        {
            get
            {
                return "url_absolute";
            }
        }

        protected override void Resolve(GetScribanItemMembersPipelineArgs args)
        {
            if (args.Mode == MemberMode.Name)
            {
                args.Members.Add(this.MemberName);
                return;
            }
            if (args.Item == null)
            {
                args.MemberValue = "#";
                return;
            }
            LinkProvider linkProvider = this.LinkProviderService.GetLinkProvider(Context.Site);
            ItemUrlBuilderOptions itemUrlBuilderOptions = linkProvider.GetDefaultUrlBuilderOptions();
            itemUrlBuilderOptions.Language = args.Item.Language;
            itemUrlBuilderOptions.AlwaysIncludeServerUrl = true;
            args.MemberValue = linkProvider.GetItemUrl(args.Item, itemUrlBuilderOptions);
        }
    }
}

At this point we have our new item extension ready to be included within the Sitecore pipeline for Scriban. To do this we need to create a patch file which adds a processor of our new type to the getScribanItemMembers node. We must include resolve="true" for our processor to enable Dependency Injection resolution. Our patch file looks as follows.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
    <sitecore>
        <pipelines>
          <getScribanItemMembers>
            <processor type="Sitecore.Foundation.Variants.Pipelines.GetScribanItemMembers.GetAbsoluteUrl, Sitecore.Foundation.Variants"
                       resolve="true" />
          </getScribanItemMembers>
        </pipelines>
    </sitecore>
</configuration>

There we have it, we now have our GetAbsoluteUrl processor within Sitecore and we can now take advantage of it within a Scriban template. To test it we can create a simple Scriban template with i_item.url and i_item.url_absolute to see the difference. As this is an item extension, we can apply this extension to any item types including i_datasource or i_home too.

{{ 
i_item.url
i_item.url_absolute
}}

Recent blog posts

Visual Studio screen for Azure functions with Franklin from GTA quoting "Ah nooo, here we go again"
The journey to the swagger page with Docker, Azure Functions and .NET 7.0
Read more
Durable function illustration with Azure function icon
Durable Functions and when to use them
Read more
silhouette of road signage during golden hour
How to migrate NVelocity Extensions to Scriban
Read more

At dotnet, we blend innovation, creativity, and technology to craft transformative digital solutions. From consultancy and engineering to data analytics, cloud hosting, and innovation, we offer a spectrum of services. Partner with us and embark on a journey of digital excellence.

What we do
  • Services
  • Work

© 2024 dotnet. All rights reserved.