• About this blog
  • About me
  • Contact
Sitecore XperiencesThe things I've seen as a Sitecore Professional
  • About this blog
  • About me
  • Contact
Menu
  • About this blog
  • About me
  • Contact
  • 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:

    Face Detection picture

    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:

    Recommended Books

    Our content tree is composed by Genre Pages, each of them with respective Profile Card assigned:

    Mapping Genres and Profile Cards

    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:

    Experience Profile shows preferred Genres

     

    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

     

    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!

    Categories: Analytics, Rules, xDB

    Programmatically "Visit" a page (and all xDB-related) Malformed querystring breaks Sitecore Experience Forms (Value cannot be null. Parameter name: key)

    Leave a Reply Cancel reply

    Your email address will not be published. Required fields are marked *

      Am Not Spammer

    You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Proudly 8x Sitecore MVP (2016-2023) MVP 2016-2023

Localization

Recent Posts

  • Content generation with Sitecore Connect and ChatGPT
  • XM Cloud Starter Kit with Content Hub Integration
  • Meet the (Brand new) Advanced Powershell Packaging Features
  • Rodrigo Peplau wins his 8th Sitecore MVP Award
  • Glossary: Sitecore CDP vs Sitecore XP

Recent Comments

  • 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.
  • Fred on ERROR [Content Testing]: Cannot find PhantomJS executable at ' (...) /data/tools/phantomjs/phantomjs.exe'. Aborting screenshot generation.
  • Rodrigo Peplau on Language specific MediaProvider breaking icons at Media Library

Archives

  • 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
  • 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

Meta

  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org

Recent Posts

  • Content generation with Sitecore Connect and ChatGPT
  • XM Cloud Starter Kit with Content Hub Integration
  • Meet the (Brand new) Advanced Powershell Packaging Features
  • Rodrigo Peplau wins his 8th Sitecore MVP Award
  • Glossary: Sitecore CDP vs Sitecore XP
  • ReplaceHTML doesn’t work in Web Experiences with Sitecore Personalize
  • Sitecore Personalize: Difference between “Experiences” and “Experiments”
  • Automatic Sitecore NuGet upgrades with Powershell
  • Sitecore 10.1 Form Send E-mail VS Community Send E-mail
  • (Bug-free) Custom Form IDs in Sitecore Forms

Tag Cloud

    Architecture Automation Continuous Integration Debugging Development Environments Hackathon How To PhantomJS Powershell Server Roles TDS Team City Team Development for Sitecore XConnect

Pages

  • About this blog
  • About me
  • Contact

Search

Copyright © 2015 Rodrigo Peplau Theme created by PWT. Powered by WordPress.org