Triggering a Sitecore 8 Outcome with a Rule Action
This post is a quick follow-on from my previous post Thoughts on Sitecore Outcomes.
As I stated in my previous post, there is currently no way for marketers to trigger an Outcome in Sitecore the same way as you would a Goal. There are no actions in the Rules Engine or an interface to assign an Outcome result to a page.
As I had some code, I thought I’d write a Rules action to do this. It was also a good refresher in setting up rules and actions in Sitecore.
Setting up the Rule
First things first, I changed the template for the Outcome definition item to add a new Rules field. With this in place marketers could add conditions on each Outcome and set the Outcome to be the current Outcome item.
With this in place, marketers have access to all the new conditions in the rules engine and have the flexibility to trigger the Outcome whenever they want.
The code
I then created the code for the Rule Action. The action takes the current Outcome item and a monetary value as parameters and creates the object on the current contact.
public class SetOutcomeRuleAction<T> : RuleAction<T> where T : RuleContext
{
public decimal MonetaryValue { get; set; }
public override void Apply(T ruleContext)
{
Assert.ArgumentNotNull(ruleContext, "ruleContext");
SetOutcome(ruleContext.Item);
}
private void SetOutcome(Item definitonItem)
{
if (Tracker.Current == null)
return;
ID id = ID.NewID;
ID interactionId = ID.Parse(Tracker.Current.Interaction.InteractionId);
ID contactId = ID.Parse(Tracker.Current.Contact.ContactId);
var definitionItem = definitonItem;
if(Tracker.Current.HasOutcome(definitionItem.ID))
return;
var outcome = new ContactOutcome(id,definitionItem.ID,contactId)
{
DateTime = DateTime.UtcNow.Date,
MonetaryValue = MonetaryValue,
InteractionId = interactionId
};
var manager = Factory.CreateObject("outcome/outcomeManager", true) as OutcomeManager;
if (manager != null)
manager.Save(outcome);
}
}
Running the Rules
I needed a way for these rules to be checked at runtime while a user is browsing the site. I used a simple pipeline processer for this that kicks in after the Sitecore.Analytics.Pipelines.InitializeTracker.RunRules processor.
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.Pipelines.HttpRequest;
using Sitecore.Rules;
using System;
using System.Collections.Generic;
using System.Linq;
using Sitecore;
using Sitecore.Analytics.Pipelines.InitializeTracker;
namespace CoreBlimey.OutcomeRules.Pipelines
{
public class RunOutcomeRules : InitializeTrackerProcessor
{
public string OutcomeRootItemId { get; set; }
public string OutcomeDefinitionId { get; set; }
private const string RulesField = "Rules";
public override void Process(InitializeTrackerArgs args)
{
if (Context.Database == null
|| Context.Item == null
|| Context.PageMode.IsPageEditorEditing
|| String.Compare(Context.Database.Name, "core", StringComparison.OrdinalIgnoreCase) == 0)
{
return;
}
if(Context.Item.Paths.IsContentItem)
ProcessOutcomeRules();
}
private void ProcessOutcomeRules()
{
var outcomes = GetOutcomeItems();
foreach(var outcome in outcomes)
{
RunRule(outcome);
}
}
private IEnumerable<Item> GetOutcomeItems()
{
Item outcomeRootItem = Sitecore.Context.Database.GetItem(ID.Parse(OutcomeRootItemId));
if(outcomeRootItem != null)
return outcomeRootItem.Axes.GetDescendants().Where(c => c.TemplateID.Equals(ID.Parse(OutcomeDefinitionId)) && !string.IsNullOrEmpty(c[RulesField])).ToList();
return new List<Item>();
}
public bool RunRule(Item outcomeItem)
{
if (outcomeItem == null)
return false;
string ruleXml = outcomeItem[RulesField];
if (String.IsNullOrEmpty(ruleXml))
return false;
RuleList<RuleContext> rules = new RuleList<RuleContext> { Name = outcomeItem.Paths.Path };
RuleList<RuleContext> parsed = RuleFactory.ParseRules<RuleContext>(
Context.Database,
ruleXml);
rules.AddRange(parsed.Rules);
if (rules.Count < 1)
return false;
RuleContext ruleContext = new RuleContext { Item = outcomeItem };
rules.Run(ruleContext);
return ruleContext.IsAborted;
}
}
}
Pulling the Trigger
When a user meets the conditions specified in the rules the Outcome will be recorded on the contact’s activity tab
All the code discussed here can be found on GitHub:
https://github.com/ianjohngraham/CoreBlimey.Utils/tree/master/CoreBlimey.OutcomeRules
Thanks for checking out this post. Until next time!