Scriban templates are incredibly easy to use and out-of-the-box are quite powerful on their own. What happens when we are presented with a problem that requires access to field details that are not accessible? We build an extension.
In our case, we needed to build a component, such as a banner, that showed one image for desktop and another for mobile. You can already produce a responsive image in a Scriban template, but showing two images and determining which to show based upon screen size. For example:
<picture>
<source srcset="image-2.png" media="(min-width: 800px)">
<img src="image-1.png" alt="" />
</picture>
In the above setup, we are showing image-1.png
by default. When the screen size is larger than 800px wide, we substitute image-2.png
.
It's all fine and dandy but to do this in a Scriban template we need to know the image url. If you've built a custom rendering and can control the model passed in, i.e. the o_model
then you could build this functionality in.
What if you don't have that? What if we wanted something simpler that can be re-used across multiple Scriban templates. Let's build an image extension for Scriban templates.
For the configuration file, we need to add the extension to the pipeline.
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
<sitecore>
<pipelines>
<generateScribanContext>
<processor type="ABCCompany.Foundation.Extensions.Pipelines.ImageExtensions, ABCCompany.Foundation.Extensions" resolve="true" />
</generateScribanContext>
</pipelines>
</sitecore>
</configuration>
Now for the purposes of this example, we've kept things pretty simple. You could obviously extend this even further if desired. Ultimately we're just trying to connect the ImageField
attributes with our Scriban model.
using Sitecore.Data.Fields;
using System;
namespace ABCCompany.Foundation.Extensions.Models
{
public class ImageInfo
{
public string src { get; set; }
public string alt { get; set; }
public string classname { get; set; }
public ImageInfo() { }
public ImageInfo(ImageField item)
{
try
{
src = Sitecore.Resources.Media.MediaManager.GetMediaUrl(item.MediaItem);
}
catch (Exception e)
{
src = null;
}
alt = item.Alt;
classname = item.Class;
}
}
}
With the model setup, all that's left to do is to create the extension that recognizes the scriban function we're setting up and applies the model to it such we can get the information we need.
using Scriban.Runtime;
using Sitecore.Data.Fields;
using Sitecore.Data.Items;
using Sitecore.XA.Foundation.Abstractions;
using Sitecore.XA.Foundation.Scriban.Pipelines.GenerateScribanContext;
using System;
using ABCCompany.Foundation.Extensions.Models;
namespace ABCCompany.Foundation.Extensions.Pipelines
{
public class ImageExtensions : IGenerateScribanContextProcessor
{
protected readonly IPageMode PageMode;
private readonly IContext context;
private delegate ImageInfo ImageInfoDelegate(Item item, object imageFieldName);
public ImageExtensions(IPageMode pageMode, IContext context)
{
PageMode = pageMode;
this.context = context;
}
// Setup the sc_image_info scriban function
public void Process(GenerateScribanContextPipelineArgs args)
{
var imageInfo = new ImageInfoDelegate(GetImageInfo);
args.GlobalScriptObject.Import("sc_image_info", (Delegate)imageInfo);
}
// Gather the information from the ImageField and apply it to the Model we want returned.
public ImageInfo GetImageInfo(Item item, object field)
{
if (item == null
|| String.IsNullOrWhiteSpace((string)field)
|| item.Fields[(string)field] == null
)
{
return null;
}
ImageField imgField = (ImageField)item.Fields[(string)field];
if (imgField == null)
{
return null;
}
return new ImageInfo(imgField);
}
}
}
Returning null, while not always ideal, is ok in this case as we can easily detect it within the scriban script.
Now with the extension in place, if we want to utilize it within a Rendering Varianty we can simply call it as follows:
{{- image = (sc_image_info i_item 'Image') -}}
When we want to access the attributes we can do so as shown below.
<img src="{{image.src }}" alt="{{image.alt}}" class="{{image.class}}"/>
This gives us a lot of options when we want to setup not only responsive image design but also for things like improving accessibility. Now obviously in this example I've only extracted a small portion of what you can retrieve from the ImageField
so expanding upon it should be a no brainer. Have fun!
Sign up to our bi-weekly newsletter for a bite-sized curation of valuable insight from the Sitecore community.