Deep Dive Sitecore Personalization
Hello Everyone. This is my first blog with respect to Sitecore and I am really excited about it.
This blog is all about Sitecore Personalization. We all have already worked on Sitecore Personalization either using Rule based personalization or Behavior based personalization. Rule base personalization basically include some specific condition when met, we personalize the experience of the users. Similarly behavior based personalization include what's the behavior of the user on our website and accordingly we show or recommend something based upon user past interactions. Rule base personalization can be showing Banner data different based on users country. Behavior based personalization can be based on user interest on our website and showing them similar interest articles. We can use Profiling feature or lead score to achieve the same.
We all know that to make the personalization feature working on website, we have to add rule at renderings on Presentation details of the page item. When the page will load and during the execution of our rendering some action will happen based on the rule set and if the conditions are met, we will get different personalize result for the user. But have we ever wondered, how this actually happens in the backend. If not then please read the article and you will know the magic.
There is engine called Rule engine in Sitecore. This engine is nothing but a piece of code which execute to give the personalize result. It take all the conditions or rules define on rendering and execute it to give either true or false value. If the condition matches, then the rule engine for the rule will return true and accordingly whatever action is defined against it, we get the result accordingly. If not match then it will go till all the rules to satisfy the condition. If nothing satisfy then we will get the default action.
So lets see the code now.
public Item GetPersonalizationDataSourceItem(RenderingReference reference,
RenderingReference[] refernces) {
bool flag = false;
bool conditionsatisfied = false;
RuleDetail rd = new RuleDetail();
Item dataitem = null;
if (reference != null && reference.Settings.Rules != null &&
reference.Settings.Rules.Count > 0) {
foreach(var rule in reference.Settings.Rules.Rules) {
if (!conditionsatisfied) {
Log.Info($"CustomRule - {DateTime.Now.Date.ToString()}", this);
var ruleContext = new Sitecore.Rules.ConditionalRenderings
.ConditionalRenderingsRuleContext(refernces.ToList(), reference);
Log.Info($"CustomRuleContext - {DateTime.Now.Date.ToString()}", this);
flag = EvaluateRules(ruleContext, rule);
if (flag) {
var dataAction = rule.Actions[0];
var setDataSourceAction = dataAction as Sitecore.Rules.ConditionalRenderings.
SetDataSourceAction<Sitecore.Rules.ConditionalRenderings.
ConditionalRenderingsRuleContext> ;
if (setDataSourceAction != null) {
Item dataSourceItem = GetDataSourceItem(setDataSourceAction.DataSource,
reference.Database);
if (dataSourceItem != null) {
rd.actionid = dataSourceItem;
rd.rulename = rule.Name;
}
}
conditionsatisfied = true;
break;
}
}
}
}
dataitem = rd.actionid;
return dataitem;
}
public bool EvaluateRules(ConditionalRenderingsRuleContext ruleContext,
Rule<ConditionalRenderingsRuleContext> rule) {
Log.Info($"CustomRuleConditionEvaluate - {DateTime.Now.Date.ToString()}", this);
bool result = false;
RuleStack stack = new RuleStack();
rule.Condition.Evaluate(ruleContext, stack);
if (ruleContext.IsAborted || (stack.Count == 0) || !((bool) stack.Pop())) {
result = false;
} else {
result = true;
}
return result;
}
So if you see the above code, we are basically taking two parameter in above method. First one is the rendering component which have all rules on it and another is the list of all the rendering components on that item. Then we are iterating the component to check the rule count on that component. If any rule is there, the we are taking all the rules for evaluation and as soon as the rule is satisfying we are breaking the loop and getting the appropriate action associated with it. We need to take care of some important points here.
1. We need to create a reference of ruleContext class which will be useful for rule evaluation.
2. We need to then call the Evaluate function which is basically evaluating your rule. This method is your backend logic used by Sitecore to check your rule and return true and false. We can consider this method as heart of Sitecore Rule engine.
3. Once Evaluation is done, appropriate action is called.
Below is the whole sample code provided which can be leverage according to one's requirement
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.Layouts;
using Sitecore.Rules;
using Sitecore.Rules.ConditionalRenderings;
using Sitecore.Diagnostics;
namespace SitecorePractice.Foundation.SitecoreExtensions.Helpers {
public class GetPersonalizedDataItems {
public Item GetPersonalizationDataSourceItems(Item i) {
Item list = null;
RenderingReference[] refernces = GetRenderingReferences(i);
list = GetPersonalizationDataSourceItem(refernces[0], refernces);
return list;
}
public Item GetPersonalizationDataSourceItem(RenderingReference reference
, RenderingReference[] refernces) {
bool flag = false;
bool conditionsatisfied = false;
RuleDetail rd = new RuleDetail();
Item dataitem = null;
if (reference != null && reference.Settings.Rules != null
&& reference.Settings.Rules.Count > 0) {
foreach(var rule in reference.Settings.Rules.Rules) {
if (!conditionsatisfied) {
Log.Info($"CustomRule - {DateTime.Now.Date.ToString()}", this);
var ruleContext = new Sitecore.Rules.ConditionalRenderings.
ConditionalRenderingsRuleContext(refernces.ToList(), reference);
Log.Info($"CustomRuleContext - {DateTime.Now.Date.ToString()}", this);
flag = EvaluateRules(ruleContext, rule);
if (flag) {
var dataAction = rule.Actions[0];
var setDataSourceAction = dataAction as Sitecore.Rules.ConditionalRenderings
.SetDataSourceAction < Sitecore.Rules.ConditionalRenderings.ConditionalRenderingsRuleContext > ;
if (setDataSourceAction != null) {
Item dataSourceItem = GetDataSourceItem(setDataSourceAction.DataSource
, reference.Database);
if (dataSourceItem != null) {
rd.actionid = dataSourceItem;
rd.rulename = rule.Name;
}
}
conditionsatisfied = true;
break;
}
}
}
}
dataitem = rd.actionid;
return dataitem;
}
public bool EvaluateRules(ConditionalRenderingsRuleContext ruleContext
, Rule < ConditionalRenderingsRuleContext > rule) {
Log.Info($"CustomRuleConditionEvaluate - {DateTime.Now.Date.ToString()}", this);
bool result = false;
RuleStack stack = new RuleStack();
rule.Condition.Evaluate(ruleContext, stack);
if (ruleContext.IsAborted || (stack.Count == 0) || !((bool) stack.Pop())) {
result = false;
} else {
result = true;
}
return result;
}
public RenderingReference[] GetRenderingReferences(Item i) {
if (i == null) {
return new RenderingReference[0];
}
return i.Visualization.GetRenderings(Sitecore.Context.Device, false);
}
private static Item GetDataSourceItem(string id, Database db) {
Guid itemId;
return Guid.TryParse(id, out itemId) ?
db.GetItem(new ID(itemId)) :
db.GetItem(id);
}
}
public class RuleDetail {
public string rulename {
get;
set;
}
public Item actionid {
get;
set;
}
}
}
Thanks for reading and hope this will help. Will be back with some more blogs so stay tuned.
Comments
Post a Comment