Develop a Collector Plugin

Overview

This guide describes how to implement a collector plugin that enables overriding collector data using the Alter Ego feature in Bloomreach Content.

Purpose

A collector plugin allows you to customize and override targeting data collected during channel preview in the Experience manager, specifically through the Alter Ego functionality.

Context

The Alter Ego feature lets CMS users impersonate a visitor with specific characteristics. In the Experience manager, the 'As viewed by' menu always includes the 'Alter Ego' option. When selected, the system collects targeting data and displays targeted content during channel preview. The 'Edit Alter Ego' button opens a window where you can override collected targeting data with custom values. For example, you can specify a particular location instead of using the location detected by the Relevance Module.

To support data overrides, you need to provide a collector plugin that can edit the JSON representation of targeting data. This plugin is similar to a characteristic plugin and supplies the UI components displayed in the 'Edit Alter Ego' window within the Channel Editor.

This page outlines the steps required to implement a collector plugin.

Configuration

Configure collector plugins in the repository at:

/hippo:configuration/hippo:frontend/cms/hippo-targeting

Each collector plugin is defined as a child node of type frontend:pluginconfig. Use the naming convention collector-<ID of your collector> for the node.

Each collector plugin node requires the following properties:

  • collector (String, required): The ID of the collector.
  • plugin.class (String, required): The fully qualified Java class name of the collector plugin.

You can add additional configuration properties to customize the plugin as needed.

Example: GroupsCollectorPlugin

The GroupsCollectorPlugin allows you to modify the groups to which a user belongs. The GroupsCollector returns group information as a comma-separated string. The plugin presents a checkbox group UI, allowing users to select one or more groups.

The plugin implementation consists of three files:

The following example is a simplified version of the GroupsCollectorPlugin from the Relevance Module.

Java Class

The Java class uses the @ExtClass annotation to associate the plugin with its JavaScript class.

GroupsCollectorPlugin.java:

package com.onehippo.cms7.targeting.frontend.plugin.groups; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.query.Query; import com.onehippo.cms7.targeting.frontend.plugin.CollectorPlugin; import org.hippoecm.frontend.plugin.IPluginContext; import org.hippoecm.frontend.plugin.config.IPluginConfig; import org.hippoecm.frontend.session.UserSession; import org.json.JSONException; import org.json.JSONObject; import org.wicketstuff.js.ext.util.ExtClass; /** * Plugin for the groups collector. Available plugin properties: * <ul> * <li>groups: multi-value String property, each string specifies * a selectable group</li> * </ul> */ @ExtClass("Hippo.Targeting.GroupsCollectorPlugin") @SuppressWarnings("unused") public class GroupsCollectorPlugin extends CollectorPlugin { private List<Pattern> excludes; public GroupsCollectorPlugin(final IPluginContext context, final IPluginConfig config) { super(context, config); final String[] excludesConfig = config.getStringArray("excludes"); excludes = new ArrayList<Pattern>(); if (excludesConfig != null) { for (String exclude : excludesConfig) { excludes.add(Pattern.compile(exclude)); } } } @Override protected void onRenderProperties(final JSONObject properties) throws JSONException { super.onRenderProperties(properties); try { properties.put("groups", listGroups()); } catch (RepositoryException e) { throw new JSONException(e); } } private List<String> listGroups() throws RepositoryException { final Session session = UserSession.get().getJcrSession(); final StringBuilder statement = new StringBuilder(); statement.append("//element"); statement.append("(*, ").append("hipposys:group").append(")"); statement.append(" order by @jcr:name"); final Query q = session.getWorkspace().getQueryManager() .createQuery(statement.toString(), Query.XPATH); final List<String> groups = new ArrayList<String>(); final NodeIterator nodes = q.execute().getNodes(); while (nodes.hasNext()) { final String group = nodes.nextNode().getName(); if (!isExcluded(group)) { groups.add(group); } } return groups; } private boolean isExcluded(final String group) { if (group.equals("everybody")) { return true; } for (Pattern exclude : excludes) { if (exclude.matcher(group).matches()) { return true; } } return false; }

Properties File

The .properties file contains all internationalization (i18n) labels. The special key collector-description is displayed as the collector's description in the 'Edit Alter Ego' window.

GroupsCollectorPlugin.properties:

collector-description=is in the user group
groups-empty=No groups available
no-groups=<none>

All properties are automatically available in the JavaScript class via the resources variable. For example, the renderGroups method uses <none> when the group list is empty.

JavaScript Class

(function() { "use strict"; Ext.namespace('Hippo.Targeting'); Hippo.Targeting.GroupsCollectorPlugin = Ext.extend(Hippo.Targeting.CollectorPlugin, { constructor: function(config) { var editor; if (Ext.isEmpty(config.groups)) { editor = { message: config.resources['groups-empty'], xtype: 'Hippo.Targeting.TargetingDataMessage' }; } else { editor = { collector: config.collector, groups: config.groups, resources: config.resources, xtype: 'Hippo.Targeting.GroupsTargetingDataEditor' }; } Hippo.Targeting.GroupsCollectorPlugin.superclass.constructor .call(this, Ext.apply(config, { editor: editor, renderer: this.renderGroups })); }, renderGroups: function(value) { var groups = value ? value.groups: []; if (Ext.isEmpty(groups)) { return this.resources['no-groups']; } return groups.join(', '); } }); Hippo.Targeting.GroupsTargetingDataEditor = Ext.extend(Hippo.Targeting.TargetingDataCheckboxGroup, { constructor: function(config) { var checkboxes = []; Ext.each(config.groups, function(group) { checkboxes.push({ boxLabel: group, name: group }); }); Hippo.Targeting.GroupsTargetingDataEditor.superclass .constructor.call(this, Ext.apply(config, { columns: 2, items: checkboxes, vertical: true })); }, convertDataToCheckedArray: function(data) { var checkedArray = this.createBooleanArray(this.checkboxNames .length); if (!Ext.isEmpty(data.groups)) { Ext.each(data.groups, function(dataItem) { var index = this.checkboxNames.indexOf(dataItem); if (index >= 0) { checkedArray[index] = true; } }, this); } return checkedArray; }, convertCheckedBoxesToData: function(checkedBoxes) { var checkedIds = Ext.pluck(checkedBoxes, 'name'); return { collectorId: this.collector, groups: checkedIds }; } }); Ext.reg('Hippo.Targeting.GroupsTargetingDataEditor', Hippo.Targeting.GroupsTargetingDataEditor); }());

The JavaScript constructor defines both an editor and a renderer. The editor is the UI component used to edit targeting data. In this example, the editor is a checkbox group, but you can use any Ext.form.Field. The default editor is a text field. The renderer function converts the data string returned by the collector into a value displayed in the 'Edit Alter Ego' window. The groups renderer returns the string as-is, except when it is empty.

Java API

com.onehippo.cms7.targeting.frontend.plugin.CollectorPlugin

Base class for collector plugins.

Configuration properties:

  • collector (String, required): The ID of the collector.
  • plugin.class (String, required): The fully qualified Java class name of the collector plugin.

com.onehippo.cms7.targeting.frontend.plugin.dayofweek.DayOfWeekCollectorPlugin

Plugin for modifying the current day of the week.

com.onehippo.cms7.targeting.frontend.plugin.geo.GeoIPCollectorPlugin

Plugin for modifying the visitor's location.

Configuration properties:

  • locations (multiple String): List of location strings to display as selectable options in the editor. Each string uses the format city | country | latitude | longitude.

com.onehippo.cms7.targeting.frontend.plugin.groups.GroupsCollectorPlugin

Plugin for modifying the groups a visitor belongs to.

Configuration properties:

  • excludes (multiple String): List of regular expression patterns for group names to exclude from the selectable options in the editor.

com.onehippo.cms7.targeting.frontend.plugin.referrer.ReferrerCollectorPlugin

Plugin for modifying the referrer URL.

com.onehippo.cms7.targeting.frontend.plugin.returningvisitor.ReturningVisitorCollectorPlugin

Plugin for modifying whether the visitor is new or returning.

JavaScript API

Hippo.Targeting.CollectorPlugin

Base class for collector plugins. You can define a custom renderer and/or editor for targeting data.

Extends: Ext.util.Observable

Properties:

  • renderer (Mixed): Optional method that transforms the targeting data string into rendered data. See Ext.grid.Column.renderer for details.
  • editor (Ext.form.Field): Optional form field for editing the targeting data string.

Hippo.Targeting.TargetingDataCheckboxGroup

Checkbox group for editing targeting data. By default, the implementation iterates over a configurable property in the targeting data and assumes each element is the name of a checkbox in the group. All checked checkbox names are converted to an array and set in the targeting data. You can override the convertDataToCheckedArray and convertCheckedBoxesToData methods to customize this behavior.

Extends: Ext.form.CheckboxGroup

Properties:

  • targetingDataProperty (String): The property in the targeting data object to iterate over. Must be serialized as a JSON array.

Methods:

  • convertDataToCheckedArray(targetingData): Converts the targeting data to an array of booleans indicating which checkboxes should be checked.

    • Parameters:
      • targetingData (Object): The targeting data object serialized to JSON.
    • Returns:
      • An array of booleans. Each boolean indicates whether the corresponding checkbox should be checked.
  • convertCheckedBoxesToData(checkedBoxes): Converts an array of Ext.form.Checkbox objects to a targeting data object.

    • Parameters:
      • checkedBoxes (Array): Array of checked checkbox objects.
    • Returns:
      • A targeting data object.

Hippo.Targeting.TargetingDataMessage

Editor for targeting data that only displays a string. Use this to show a 'no options available' message instead of the standard editor.

Extends: Ext.form.DisplayField

Properties:

  • message (String): The message to display.

Hippo.Targeting.TargetingDataRadioGroup

Radio group for editing targeting data. By default, the implementation assumes the targeting data string is the inputValue of the radio button to select. You can override convertDataToInputValue and getValue to customize this behavior. Each radio button should have the same name property to ensure mutual exclusivity. Avoid using commas in radio button input values.

Extends: Ext.form.RadioGroup

Methods:

  • convertDataToInputValue(data): Converts the targeting data string to the inputValue of the radio button to select.

    • Parameters:
      • data (String): The data string from the collector.
    • Returns:
      • The input value of the radio button to select.
  • getValue(): Returns the targeting data string representing the selected radio button. The default implementation returns the inputValue of the selected radio button, or an empty string if none is selected.

Share Feedback
Page: /build/enterprise-plugins/targeting-relevance/develop-a-collector-plugin
Section: Build
Category *