Got a requirement to display a value passed with a URL parameter on a page (URL decoded of course). I want to achieve the goal as quick as possible, with the minimum steps, ideally. So, here we go..
1. Just use existing VariantField (located at /sitecore/templates/Foundation/Experience Accelerator/Rendering Variants/VariantField
). When copying, ensure you keep new variant field template outside of Experience Accelerator folder (to avoid it being lost on future SXA upgrade), ideally somewhere within a folder with serialization configured.
2. Remove unwanted fields from a new template. I left only a few I felt necessary, but you may end up having even less. Another thing I've done at this step was adding a user-friendly label to the field, to avoid editors' confusion with a misleading naming:
3. Then you need to create a model. As the simplest, I inherited from VariantField
public class VariantQueryString : VariantField
{
public VariantQueryString(Item variantItem) : base(variantItem)
{
}
}
With a parser, I only process those fields I will be using - what I kept from the previous step:
public class ParseQueryStringField : ParseField
{
public override ID SupportedTemplateId => Constants.RenderingVariants.Templates.QueryString;
public override void TranslateField(ParseVariantFieldArgs args)
{
ParseVariantFieldArgs variantFieldArgs = args;
variantFieldArgs.TranslatedField = new VariantQueryString(args.VariantItem)
{
// this property is reused under different purpose rather than named - it stores URL parameter name
FieldName = args.VariantItem[Constants.RenderingVariants.Fields.QueryField.FieldName],
Tag = args.VariantItem.Fields[Constants.RenderingVariants.Fields.QueryField.Tag].GetEnumValue(),
CssClass = args.VariantItem[Constants.RenderingVariants.Fields.QueryField.CssClass],
Prefix = args.VariantItem[Constants.RenderingVariants.Fields.QueryField.Prefix],
Suffix = args.VariantItem[Constants.RenderingVariants.Fields.QueryField.Suffix],
RenderIfEmpty = args.VariantItem[Constants.RenderingVariants.Fields.QueryField.RenderIfEmpty] == "1"
};
}
}
Also reference IDs of these fields within Constants
class:
public static class Constants
{
public static class RenderingVariants
{
public static class Fields
{
public static class QueryField
{
public static ID Tag { get; } = new ID("{F556DEDD-5D6B-4FFF-A904-E4C65AB0E698}");
public static ID CssClass { get; } = new ID("{B3B6B300-1704-493B-999C-AD21CCE58FEF}");
public static ID FieldName { get; } = new ID("{9D3717EF-CD09-4D98-8C4A-914299503626}");
public static ID Prefix { get; } = new ID("{5844C4AA-5E48-4721-8E30-91646E430C83}");
public static ID Suffix { get; } = new ID("{0EFAF48E-E0DD-4408-80D3-4C001101E834}");
public static ID RenderIfEmpty { get; } = new ID("{E14C3930-FE6C-48AC-99D8-C6867B489066}");
}
}
}
}
4. Finally, implementing RenderQueryStringField
class. Nothing complex - just getting a value from the query string, wrapping it with a selected tag/styles and rendering it into the page. Also, there's a fallback scenario for Experience Editor when a given parameter is missing from URL but component needs to be visible.
public class RenderQueryStringField : RenderVariantField
{
public override Type SupportedType => typeof(VariantQueryString);
public override RendererMode RendererMode => RendererMode.Html;
public override void RenderField(RenderVariantFieldArgs args)
{
var variantField = args.VariantField as VariantQueryString;
if (variantField != null)
{
args.ResultControl = RenderQueryStringValue(variantField, args);
args.Result = RenderControl(args.ResultControl);
}
}
protected virtual Control RenderQueryStringValue(VariantField variantField, RenderVariantFieldArgs args)
{
var queryString = HttpContext.Current.Request.QueryString;
if (!string.IsNullOrEmpty(variantField.FieldName) && !string.IsNullOrWhiteSpace(variantField.Tag))
{
if (queryString.HasKeys() && queryString[variantField.FieldName] != null)
{
var tag = new HtmlGenericControl(variantField.Tag);
AddClass(tag, (variantField.CssClass + " " + GetFieldCssClass(variantField.FieldName)).Trim());
tag.InnerText = queryString[variantField.FieldName];
return tag;
}
if (args.IsControlEditable && PageMode.IsExperienceEditorEditing)
{
return GetVariantFieldNameLiteral(variantField.FieldName);
}
}
return new LiteralControl();
}
protected virtual HtmlGenericControl GetVariantFieldNameLiteral(string parameterName)
{
var missingField = new HtmlGenericControl("span");
missingField.Attributes.Add("class", "missing-field-hint");
missingField.InnerText = $"[{parameterName}] URL paramenter";
return missingField;
}
}
5. I am adding new field variant into existing Foundation project, but if you haven't got one - you might create it. Do not forget to include config patches. something like below:
?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<parseVariantFields>
<processor type="Platform.Foundation.Variants.Pipelines.VariantFields.QueryString.ParseQueryStringField, Platform.Foundation.Variants" resolve="true" patch:before="processor[@type='Sitecore.XA.Foundation.RenderingVariants.Pipelines.ParseVariantFields.ParseField, Sitecore.XA.Foundation.RenderingVariants']" />
</parseVariantFields>
<renderVariantField>
<processor type="Platform.Foundation.Variants.Pipelines.VariantFields.QueryString.RenderQueryStringField, Platform.Foundation.Variants" resolve="true" patch:before="processor[@type='Sitecore.XA.Foundation.RenderingVariants.Pipelines.RenderVariantField.RenderVariantField, Sitecore.XA.Foundation.RenderingVariants']" />
</renderVariantField>
</pipelines>
</sitecore>
</configuration>
6. You might consider adding a new variant field into Insert options. Once done, add it as you normally do with variant fields:
Result. That is how it works when passing a URL parameter with a value:
When a parameter is missing from URL, this is how it looks like in Experience Editor, at least making component selectable:
Hope you find this post helpful!