-
Custom rule condition to find Top-N Profile Key
September 9, 2019 Rodrigo Peplau 0
Here we are for another simple yet useful tip from the Smart Bookshelf Demo. Although we are now improving it with some Artificial Intelligence, the first version has Sitecore Rules-based Personalization in the hearth of the recommendation mechanism.
Our desired behavior is to light-up LED strips from the top 3 Book Genres, such as seen below:
The books you see on screen are shown according to the top 3 genres for the current visitor.
It automatically scrolls, showing one genre each time. Here is how the component looks like:
Our content tree is composed by Genre Pages, each of them with respective Profile Card assigned:
So when your visitor visits a Genre Page, he or she will get points for that respective Profile Card, enabling Sitecore to register and track what are the preferred genres. The same thing also happens when a Book Page is visited (achieved by using the technique explained in my last post).
At this point we are already able to see preferred genres for our contacts, by opening any known contact at the Experience Profile:
Rules Conditions
We will retrieve the top 3 genres by using Rules-based Personalization. What you see below is the personalization setting required to display the Poetry Genre if it’s “top 2″ for the current Visitor.
Custom Rule Condition: Matches Pattern Best X
Our custom condition is based on this OOTB condition:
/sitecore/system/Settings/Rules/Definitions/Elements/Visitor/Matches Pattern
However, it can only match match top 1, while our new condition accepts a number to test against.
Definition Item
- Path: /sitecore/system/Settings/Rules/Definitions/Elements/Visitor/Matches Pattern Best X
- Template: /sitecore/templates/System/Rules/Condition
- Text: where the current contact matches best [value,Text,,specific value] on profile key [ProfileKey,ProfileKey,,profile key]
- Type: Your.Namespace.Rules.Conditions.ContactPatternMatchBestCondition, Your.AssemblyName
- Make sure this points to your correct namespace
Source Code
Here is the source code to implement this condition. After setting up the Definition Item, as described at the previous topic, all you need to use it is to compile it.
using Sitecore.Abstractions; using Sitecore.Analytics; using Sitecore.Analytics.Tracking; using Sitecore.Data; using Sitecore.Framework.Conditions; using Sitecore.Rules; using Sitecore.Rules.Conditions; using System; using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using Sitecore.Diagnostics; namespace Your.Namespace.Rules.Conditions.ContactPatternMatchBestCondition { public class ContactPatternMatchBestCondition<T> : WhenCondition<T> where T : RuleContext { // ID for the item /sitecore/system/Settings/Content Testing/Personalization Suggestions/No pattern match private readonly ID _noPatternMatchItemId = ID.Parse("9E05C456-5CD0-405B-9D45-31DDD92AB8E4"); private string _profileKey; public ContactPatternMatchBestCondition() : this(DependencyResolver.Current.GetService<BaseLog>()) { } internal ContactPatternMatchBestCondition(BaseLog log) { Condition.Requires<BaseLog>(log, nameof(log)).IsNotNull<BaseLog>(); this.Log = log; } private string _value; public string Value { get => _value ?? string.Empty; set { Assert.ArgumentNotNull(value, nameof(value)); _value = value; } } public string ProfileKey { get => _profileKey; set => _profileKey = value ?? string.Empty; } internal BaseLog Log { get; } protected override bool Execute(T ruleContext) { Condition.Requires<T>(ruleContext, nameof(ruleContext)).IsNotNull<T>(); Condition.Ensures<ITracker>(Tracker.Current, string.Format("{0}.{1}", (object)"Tracker", (object)"Current")).IsNotNull<ITracker>(); Condition.Ensures<Session>(Tracker.Current.Session, string.Format("{0}.{1}.{2}", (object)"Tracker", (object)"Current", (object)"Session")).IsNotNull<Session>(); Condition.Ensures<Contact>(Tracker.Current.Session.Contact, string.Format("{0}.{1}.{2}.{3}", (object)"Tracker", (object)"Current", (object)"Session", (object)"Contact")).IsNotNull<Contact>(); if (string.IsNullOrEmpty(this.ProfileKey)) return false; IEnumerable<IBehaviorProfileContext> profiles = Tracker.Current.Session.Contact.BehaviorProfiles.Profiles; List<ID> idsList = this.GetIdsList(this.ProfileKey); if (!profiles.Any<IBehaviorProfileContext>() && idsList.Contains(this._noPatternMatchItemId)) return true; if (!idsList.Any()) return false; var profileKeyId = idsList.First(); int best; if (!int.TryParse(Value, out best)) return false; foreach (IBehaviorProfileContext profile in profiles) { var profileScores = GetProfileKeyValue(profile); if (profileScores.Count < best) return false; var index = best - 1; var specifiedBest = profileScores[index].Key; var specifiedValue = profileScores[index].Value; var isBest = specifiedBest == profileKeyId && specifiedValue>0; if (isBest) return true; } return false; } private List<KeyValuePair<ID,double>> GetProfileKeyValue(IBehaviorProfileContext profile) { if (profile == null) return new List<KeyValuePair<ID,double>>(); // ISSUE: explicit non-virtual call var ret = profile.Scores.ToList(); ret.Sort((pair1,pair2) => pair2.Value.CompareTo(pair1.Value)); return ret; } private List<ID> GetIdsList(string idList) { string[] strArray = idList.Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries); var idList1 = new List<ID>(); foreach (string str in strArray) { if (!string.IsNullOrEmpty(str)) { ID id = ID.Parse(str, ID.Null); if (!ID.IsNullOrEmpty(id)) idList1.Add(id); } } return idList1; } } }
Hope you enjoy it!
Programmatically "Visit" a page (and all xDB-related) Malformed querystring breaks Sitecore Experience Forms (Value cannot be null. Parameter name: key)
Proudly 9x Sitecore MVP
(2016-2024)
Localization
Recent Posts
Recent Comments
- navan on Meet MVPinny: the AI-Powered Sitecore Assistant
- Adriana on Content generation with Sitecore Connect and ChatGPT
- NAVAN on Automatic Sitecore NuGet upgrades with Powershell
- Hedipo S Menezes on Corey Peplau wrote this - WFFM conflict with Unity DI and a lesson on how Sitecore community is so amazing
- Rodrigo Peplau on ERROR [Content Testing]: Cannot find PhantomJS executable at ' (...) /data/tools/phantomjs/phantomjs.exe'. Aborting screenshot generation.
Archives
- June 2024
- April 2024
- February 2024
- December 2023
- November 2023
- August 2023
- July 2023
- January 2023
- February 2022
- December 2021
- November 2021
- March 2021
- July 2020
- February 2020
- September 2019
- July 2019
- April 2019
- March 2019
- December 2018
- February 2018
- January 2018
- November 2017
- September 2017
- August 2017
- July 2017
- March 2017
- February 2017
- November 2016
- September 2016
- August 2016
- July 2016
- April 2016
- November 2015
- September 2015
- July 2015
- April 2015
- March 2015
- February 2015
Categories
- Actions
- Active Directory
- Analytics
- Architecture
- Bug fixing
- CDP/Personalize
- ChatGPT
- Content Edition Experience
- Content Hub
- Continuous Integration
- Dev
- Development
- Environments
- Experience Editor
- Experience Forms
- Front-end
- Health Check builds
- Helix
- How To
- LDAP
- MVP
- MVP Summit
- MVPinny
- Phantom JS
- Powershell
- QA
- Richtext Editor
- Rules
- Security Provider
- SIF
- Sitecore 9
- Sitecore API
- Sitecore Community
- SItecore Connect
- Sitecore Modules
- Sitecore Rocks
- Sitecore Rule Processor
- Sitecore Symposium
- SPE
- SPEAK
- SUG
- Support Ticket
- TDS
- Team City
- Uncategorized
- Upgrades
- Visual Studio
- WFFM
- Workflow
- XConnect
- xDB
- XM Cloud