Rendering a General Link
in Sitecore MVC is pretty simple using the FieldRenderer
:
1 | <div> |
It uses the attributes of the General Link
field to create an <a>
tag as a text link. But what if you want to use something more complex, like an image as the link or an entire promo card?
In MVC that is still pretty simple:
1 | <div> |
or
1 | <div> |
Its tricky with Scriban
But with SXA and Scriban rendering variants, it becomes a little more tricky to do that. With Scriban we have the sc_link
object along with the standard field renderer. So there are a few ways to render a standard text link:
1 |
|
Using the sc_link
object we can even add an image to the link:
1 | <div class="field-promolink"> |
But that does limit what a content editor can do with a General Link
field. It only uses the url attribute of the field and ignores things like the target, css class names, title text for ADA compliance etc… It also doesn’t allow for things like anchor links or email links etc…
What we really need is a BeginField
and EndField
options for Scriban. Fortunately, this is Sitecore and as with most things in Sitecore, we can add that!
Adding the Processor
For the processor, we need to add 2 new functions to scriban, sc_beginfield
and sc_endfield
. sc_endfield
is going to be very simple, no parameters will be passed to it. But sc_beginfield
will need to have the same setup as the sc_field
function that is out of the box. So let’s start by looking at that processor and creating the customisation there. To add a customization we have to implement IGenerateScribanContextProcessor
, but also we want to derive our class from FieldRendererBase
:
1 | public class BeginEndFieldProcessor : FieldRendererBase, IGenerateScribanContextProcessor |
So lets break that down. First we are creating 2 functions for the implementation of the 2 scriban functions and we are registering them with the args.GlobalScriptObject
.
The BeginRenderImpl
implementation is mostly a copy of the AddFieldRendererFunction.RenderFieldImpl
that adds the sc_field
function to Scriban. This uses the item, field and parameters array to create a new FieldRenderer
object:
1 | RenderFieldResult fieldRenderer = CreateFieldRenderer(item, fieldName, parametersCollection).RenderField(); |
In the original, it just returns the .Result()
of that, which contains the entire rendered out content. But we only want to return the .FirstPart
in this call. But we also need to store the .LastPart
so that when we call sc_endfield
, it renders the correct closing tags for the field we are rendering.
To do this I added and IScribanRenderingCache
that is registered with the container as a Scoped
object. This internally contains a stack that we can push the results of .LastPart
onto, now when we call sc_endfield
, that will pop the stack and get the corresponding closing tag. Using a stack means we can also nest sc_beginfield
if we needed to, the call to sc_endfield
will always provide the correct closing tag.
Using the Functions in a Scriban Template
So how do we use these? Lets say we just want a simple Image Field rendered as the contents of an <a>
tag:
1 | {{ sc_beginrender i_item 'Link' [['text', ' ']]}} |
will render as:
1 | <a href="/url/set/in/field" title="Alt text from general link attributes"> |
What about something more complex?
1 | {{ sc_beginrender i_item 'Link' [['class', 'font-uppercase font-bold'], ['text', ' ']]}} |
will render as:
1 | <a href="/url/set/in/field" class="font-uppercase font-bold" title="Alt text from general link attributes"> |
Notice that we can still pass in all the attributes to the sc_beginrender
that you can with sc_field
. You may also notice that we have passed in ['text', ' ']
as an attribute. This tells the FieldRenderer
to ignore the value set in the Description
attribute of the general link. It replaces it with a space. If we leave that out, the first example would render as:
1 | <a href="/url/set/in/field" title="Alt text from general link attributes">Link Description |
This doesn’t just work with link fields either, it works with anything that can be rendered through the FieldRenderer
, the actual outcome will depend on the field type used, YMMV.
tl/dr;
Get the code here: https://github.com/GuitarRich/sxa-modules
Enjoy
- Richard Seal
References: