Loading...
Area: Optimizely CMS
Applies to versions: 12 and higher
Other versions:
ARCHIVED This content is retired and no longer maintained. See the version selector for other versions of this topic.

Developing custom visitor group criteria

Recommended reading 
Note: This documentation is for the preview version of the upcoming release of CMS 12/Commerce 14/Search & Navigation 14. Features included here might not be complete, and might be changed before becoming available in the public release. This documentation is provided for evaluation purposes only.

Visitor group criteria are the building blocks of a visitor group. Optimizely comes with a number of predefined visitor group criteria but you can develop your own as well.

In this topic

How it works

Each criterion defines a condition which is evaluated to determine if a visitor is part of a group. If a sufficient number of visitor group criteria are fulfilled, the visitor is considered a member of that group. The following example shows a Query string criterion that is fulfilled if the query string search has the value visitorgroups:

QueryStringCriteria.png

From a development standpoint, a visitor group criterion is a combination of (at least) two classes:

  • model class, which stores and persists user input from the user interface.
  • criterion class, which evaluates the context and the data stored in the model to determine if the criteria are fulfilled.

Prerequisites

Make sure that your project references and the following assemblies contain the classes you need to create criteria and models.

Creating a model class

The model class stores and persists user input from the user interface and provides the criterion class with access to the settings. The model class must implement ICriterionModel, since instances of the model class will be persisted to the Dynamic Data Store, IDynamicData. The best way to implement those interfaces is to inherit from CriterionModelBase, which contains standard implementations.

The only method you must override is CriterionModelBase.Copy. If you are working with simple value type properties, it is sufficient to let you override call base.ShallowCopy. If your model has reference type properties and you want to make sure that each instance of the model has its own copy of the referenced objects, you need to extend the Copy override with more logic.

public class YourModelClass : CriterionModelBase
  {
    public override ICriterionModel Copy() { return base.ShallowCopy(); }
  }

Add public properties to your class that correspond to the settings you want available in the user interface, where inputs are created for the public properties. Depending on the type of the property, a suitable element is used when editing the criterion.

public string MyString { get; set; }
public int MyInt { get; set; }

Using the CriterionPropertyEditor property attribute

You can use the attribute to control parts of rendering of the property. PreText and AfterText are used to display strings before and after the element. For example “Ordered within“ [element] “days”. AdditionalPropsJson can be used to send additional configuration to the element like setting the type or add inline styling. You also have the ability to set a translation for the label, whether to ignore the property or not, the default value and ordering of the property.

[CriterionPropertyEditor(
PreTextTranslationKey="/path/to/xml", 
AfterTextTranslationKey = "/path/to/xml",
LabelTranslationKey=”/path/to/xml”,
Order=1
DefaultValue=”0”
AdditionalPropsJson="{ \"type\" : \"time\" }")]
  public string MyString { get; set; }

If you want the input for a value to be a drop-down list with predefined options, set SelectionFactoryType on the CriterionPropertyEditor attribute. The SelectionFactoryType is a type that implements ISelectionFactory. The ISelectionFactory has a GetSelectListItems method that is responsible for supplying options for the drop-down list.

You can use an EnumSelectionFactory included in the CMS to present the options of an Enum in a drop-down list. When you use EnumSelectionFactory, provide translations of the Enum values and place the translated values in your own XML file in the /lang directory. See Enumeration Localization in Localizing the visitor group criterion.
[CriterionPropertyEditor(SelectionFactoryType = typeof(EnumSelectionFactory))]
public SomeEnum MyEnumSelector { get; set; }

Validating the server side

You can add input validation to your properties by using the attribute classes in System.ComponentModel.DataAnnotations. The following validation rules are supported:

  • [Required] 
  • [Range(double Minimum, double maximum)] 
  • [StringLength(int maximumLength)]  
  • [RegularExpression(string pattern)] 
[Required]
[StringLength(10)]
  public string MyString { get; set; }

If you want to add custom server side validation, you can implement the interface IValidateCriterionModel on your model. The IValidateCriterionModel supplies a Validate method that is called when you save a visitor group containing the criterion.

public class YourModelClass : CriterionModelBase, IValidateCriterionModel
  {
    public string MyString { get; set; }
    public CriterionValidationResult Validate(VisitorGroup currentGroup)
      {  
         if (MyString.Length > 5)
           {
             return new CriterionValidationResult(false, "MyString is too long!", "MyString");
           }
         return new CriterionValidationResult(true);
      }
   ...
   }

Creating a criterion class

After you have a model class, create the criterion class to evaluate the context and the data stored in the model, to determine if the criteria is fulfilled or not. The connection between the criterion and model classes is created via CriterionBase – the base class that you must use for the criterion class – which is a generic class that accepts ICriterionModel parameters. You must override the CriterionBase.IsMatch method, which is the central method for a criterion; it is called when evaluating if a user is a member of a visitor group.

Decorate the criterion class with VisitorGroupCriterion attribute, which identifies your class as a criterion and makes it available for use. VisitorGroupCriterion has the following settings:

  • Category. The name of group in the criteria picker user interface where this criterion is located. Criteria with the same Category value are grouped together.
  • Description. A text describing how the criterion works.
  • DisplayName. A short name that identifies the criterion in menus and visitor groups.
  • LanguagePath. The path in the XML language files where the strings associated with this criterion is located. See Localizing the visitor group criterion.
  • ScriptUrl. A URL referring to a JavaScript file that you load when this criterion is edited.
[VisitorGroupCriterion(
  Category = "My Criteria Category",
  Description = "How the criterion works",
  DisplayName = "Short Name",
  LanguagePath="/xml/path/to/translations/",
  ScriptUrl="javascript-that-should-be-loaded-for-the-UI.js")]
    public class YourCriterionClass: CriterionBase<YourModelClass>
      {
        public override bool IsMatch(IPrincipal principal, HttpContextBase httpContext)
          {
            // Your evaluation code here.
            // The model class instance is available via the Model property.
          }
      }

Subscribing to events

You can subscribe to specific events by overriding the Subscribe method, which gathers information about events that occur prior to the call to the IsMatch method. For example, the built-in Visited Page criterion needs to keep track of all pages that are visited in the current session. You can subscribe to the following events:

  • EndRequest
  • StartRequest
  • StartSession
  • VisitedPage

If you override the Subscribe method and attach event handlers, make sure that you also override the Unsubscribe method and detach the event handlers.

public override void Subscribe(ICriterionEvents criterionEvents)
  {
    criterionEvents.StartRequest += criterionEvents_StartRequest;
  }
public override void Unsubscribe(ICriterionEvents criterionEvents)
  { 
    criterionEvents.StartRequest -= criterionEvents_StartRequest;
  }
void criterionEvents_StartRequest(object sender, CriterionEventArgs e)
  {
    // Handle the event
  }
Do you find this information helpful? Please log in to provide feedback.

Last updated: Jul 02, 2021

Recommended reading