Integrate Sitecore Dictionary into SXA Rendering Variants

Sitecore Experience Accelerator can help you the speed up the production of website on so many levels like different work run in parallel, use of reusable renderings. It is impressive how quickly you can build even a simple site using existing OTTB Rendering Variants. The ease of creating those variants is breathtaking. It is easy to connect your component to Sitecore items fields. In multi-language implementations, the integration with Sitecore dictionary is missing IMHO. You can use Text Rendering Field and then use a different value for each language, but this translation scope limits to this Rendering Variant. What if, for the brand consistency, we want to use the Dictionary for translation and leverage SXA ease of creating new variants without any code change.

The solution – new Rendering Variant Field – Dictionary Text.

It behaves exactly like Text Rendering Field except the string value comes from Sitecore Dictionary.

How to achieve this ? Few simple steps:

Create a parser

 using Sitecore.Data;
 using Sitecore.XA.Foundation.SitecoreExtensions.Extensions;
 using Sitecore.XA.Foundation.Variants.Abstractions.Pipelines.ParseVariantFields;
  
 namespace Project.Foundation.DictionaryText.pipelines.parseVariantFields
 {
     public class ParseDictionaryText : ParseVariantFieldProcessor
     {
         public override ID SupportedTemplateId => new ID("{CA998620-F034-4EC1-BBCA-66863E4624DE}");
  
         public override void TranslateField(ParseVariantFieldArgs args)
         {
             var variantFieldArgs = args;
             var variantText = new Models.DictionaryText(args.VariantItem);
             variantText.ItemName = args.VariantItem.Name;
             variantText.Text = args.VariantItem[Sitecore.XA.Foundation.RenderingVariants.Templates.VariantText.Fields.Text];
             variantText.DictionaryKey = args.VariantItem[Templates.VariantText.Fields.DictionaryKey];
             variantText.Tag = args.VariantItem.Fields[Sitecore.XA.Foundation.RenderingVariants.Templates.VariantText.Fields.Tag].GetEnumValue();
             variantText.IsLink = args.VariantItem[Sitecore.XA.Foundation.RenderingVariants.Templates.VariantText.Fields.IsLink] == "1";
             variantText.LinkField = args.VariantRootItem[Sitecore.XA.Foundation.Variants.Abstractions.Templates.IVariantDefinition.Fields.LinkField];
             variantText.CssClass = args.VariantItem[Sitecore.XA.Foundation.RenderingVariants.Templates.VariantText.Fields.CssClass];
             variantFieldArgs.TranslatedField = variantText;
         }
     }
 } 

Create Rendering

 public class RenderDictionaryText : RenderRenderingVariantFieldProcessor
     {
         public override Type SupportedType => typeof(Models.DictionaryText);
  
         public override RendererMode RendererMode => RendererMode.Html;
  
         public override void RenderField(RenderVariantFieldArgs args)
         {
             if (!(args.VariantField is Models.DictionaryText variantField))
             {
                 return;
             }
  
             var dictionaryRepository = ServiceLocator.ServiceProvider.GetService<IDictionaryRepository>();
             var control = (Control)new LiteralControl(dictionaryRepository.GetValue(variantField.DictionaryKey));
             if (variantField.IsLink)
             {
                 control = InsertHyperLink(control, args.Item, variantField.LinkAttributes, variantField.LinkField, false, args.HrefOverrideFunc);
             }
  
             if (!string.IsNullOrWhiteSpace(variantField.Tag))
             {
                 var tag = new HtmlGenericControl(variantField.Tag);
                 AddClass(tag, variantField.CssClass);
                 AddWrapperDataAttributes(variantField, args, tag);
                 MoveControl(control, tag);
                 control = tag;
             }
  
             args.ResultControl = control;
             args.Result = RenderControl(args.ResultControl);
         }
     }
 } 

CREATE MODEL and REGISTER with DI

 using Sitecore.XA.Foundation.RenderingVariants.Fields;
 using Sitecore.Data.Items;
  
 namespace Project.Foundation.DictionaryText.Models
 {
     public class DictionaryText : VariantText
     {
         public DictionaryText(Item variantItem) : base(variantItem)
         {
         }
  
         public static new string DisplayName => "Dictionary Text";
  
         public string DictionaryKey { get; set; }
     }
 } 

CREATE Rendering view

 @using Sitecore.XA.Foundation.MarkupDecorator.Extensions
 @using Sitecore.XA.Foundation.RenderingVariants.Extensions
 @using Sitecore.XA.Foundation.SitecoreExtensions.Extensions
  
 @model Project.Foundation.DictionaryText.Models.DictionaryTextModel
  
 @if (Model.DataSourceItem != null || Html.Sxa().IsEdit)
 {
     <div @Html.Sxa().Component(Model.Rendering.RenderingCssClass ?? "promo", Model.Attributes)>
         <div class="component-content">
             @if (Model.DataSourceItem == null)
             {
                 @Model.MessageIsEmpty
             }
             else
             {
                 foreach (var variantField in Model.VariantFields)
                 {
                     @Html.RenderingVariants().RenderVariant(variantField, Model.Item, Model.RenderingWebEditingParams, Model)
                 }
             }
         </div>
     </div>
 } 

register PIPELINES

Add A Rule to make a new rendering variant field AVAILABLE for new rendering variants

Resolve Context Language based on Geolocation

Sitecore Language resolver didn’t change much since I am working with Sitecore. I remember John West blog post explaining the order of resolution.

  1. The sc_lang query string parameter.
  2. The language prefix in the path in the requested URL.
  3. The language cookie associated with the context site.
  4. The default language associated with the context logical site.
  5. The DefaultLanguage setting specified in web.config.

But what if I would like to change it ?

  1. The sc_lang query string parameter.
  2. The language prefix in the path in the requested URL.
  3. The language cookie associated with the context site.
  4. The language corresponding to visitor IP – using Geolocation service 
  5. The default language associated with the context logical site.
  6. The DefaultLanguage setting specified in web.config.

Continue reading

Sitecore compliance with GDPR- Part III

In  my previous blogs about General Data Protection Regulation (EU GDPR) –  Sitecore compliance with GDPR- Part III – I wrote about compliance at large. Then in Sitecore compliance with GDPR- Part II  a closer look how should be done in Sitecore. This time, I would like to go a little bit deeper – prevent Sitecore from tracking visitor action in session.

Continue reading

xDB Cloud service REST API explained

How to use REST API reference for the xDB Cloud service is described well here. But for someone it will use it for the first time may not be that obvious. Here is a description “for dummies”.

First we have to obtain valid authentication token to make a call to xDB Cloud API. it must to be included as a HTTP header in all requests. Here are a description of this call.  I use Fiddler as a tool.

Continue reading

How to track from where visitor downloaded a PDF file

For the Website owner it is important to know how the data is accessed in order to understand the flow. This information will be used in Website personalization process to optimize.  For the content page we can use Path Analyzer.  For media assets it is a different story.  In our case a visitor cans download from landing page, case study detail page and search results page. He has to find a way how to track in xDB all PDF downloads regardless from where the visitor access it.

Continue reading

Sitecore 8.2 Rendering Issues

We experienced issues with shared layout on few of our pages. Presentation assembling seemed not following Presentation Detail Information Flow.

Based on Sitecore documentation this is a flow

rendering

 

  • SharedLayout option uses __Rendering field
  • FinalLayout option uses __Final Rendering field
  • Going from right to left, if a field has a layout delta, it goes to the field to its left to gather more presentation information.

After the investigation we noticed that on Save Button click in Experience Editor, the full share layout is saved and not the delta in __rendering fields. ( in case when a page is inheriting renderings from standards values).

Sitecore provided us with a patch. You can request one – the reference number is 144214

Is your xDB Cloud Consumption plan right for you ?

When I join my current project first thing I did as architect is an audit.  Make sure that architecture is optimized for current traffic and all best practices has been followed.  The client website use Sitecore xDB Cloud with xDB Plus subscription. It allows you up to 250 000 contacts at anytime and up to 2 500 000 interactions per month.

Contacts

How it’s measured: Total identified contact stored at any time.

Interactions

How it’s measured: Net new interaction created in a given period of time.

I check our current consumption to find out that we can switch to xDB base subscription and pay 30% of what are paying right now.

In some cases you better pay overage price before switch to the next subscription plan.

2017-10-24 11_42_15-xDB - Sales Enablement - March 2015 V2.pptx [Protected View] - PowerPoint

In case you want to generate your own reports or load data directly from mongo, you can access to your xDB database using and mongo viewer application.
Open your connectionstrings.config file and find the “analytics” connection string:
mongodb://{user-name}:{password}@{host1}:{port1},{host2}:{port2}/{guid}-Analytics?ssl=true;replicaSet={hostX}
You have replicaset on XdbCloud so use the host1 and port1 to connect.
Set up values in the following way:

con 2

con 2

But the best approche is to use  sitecore xDB Cloud API

https://gateway-xdb-scs.cloud.sitecore.net/api/xdb/Consumption/licenseId/deploymentId/year/month

where

  • licenseId – your Sitecore license ID
  • deploymentId – the unique identification of the deployment
  • year – the consumption year
  • month – the consumption month

Important

To ensure that your customers only access their own xDB sets, you must use a valid authentication token whenever you make a call to the xDB Cloud API. You can generate these tokens by using a valid Sitecore license file to call the SSO Encode Sitecore License endpoint. You must include the generated token as a HTTP header in all other requests called X-ScS-Nexus-Auth.

Visit this page -> xDB Cloud Consumption

Create dynamic menu with page sections

Since Sitecore Habitat has been released I was looking for a Helix based solution which can be use for Greenfield project. Once again – Habitat is only an example of project implementing Helix architecture.  I looked at Helixbase and I tried to  implement one of bootstrap free template sites to evaluate it as a candidate.

agency

I thought it would be nice to add automatically to the menu new section item each time that editor is adding a new one and create an anchor to that section.

 

@model RenderingModel
@{
 var currentItem = Sitecore.Context.Item;
 RenderingReference[] myRenderings = currentItem.Visualization.GetRenderings(Sitecore.Context.Device, true);
 var layoutField = new LayoutField(currentItem);
 LayoutDefinition layoutDef = LayoutDefinition.Parse(layoutField.Value);
 DeviceDefinition deviceDef = layoutDef.GetDevice(Sitecore.Context.Device.ID.ToString());
 string sectionId = string.Empty;

}
<!-- Collect the nav links, forms, and other content for toggling -->

<!-- /.navbar-collapse -->