This tutorial takes you through the process of creating a custom trait

For this version of this tutorial - you should use a Magnolia Enterprise Pro bundle of the version 5.5.3 or higher. Since you are reading a page of Magnolia 5.6 documentation - we recommend using the latest version of the 5.6.x series, which is

Error rendering macro 'artifact-resource-macro'

com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and Java type class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and MIME media type application/octet-stream was not found

. You can use

Error rendering macro 'artifact-resource-macro'

com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and Java type class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and MIME media type application/octet-stream was not found

(the webapp) or

Error rendering macro 'artifact-resource-macro'

com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and Java type class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and MIME media type application/octet-stream was not found

as a base.

A trait is an attribute or property of a visitor or visit, such as age or gender, that you can use to personalize content. 

We create a trait that detects the visitor's operating system. Depending on the detected user agent, we serve the visitor a page with a personalized component. We create two component variants named "WINDOWS" and "OS-X" for a Text and image component.

The trait extracts the operating system from the User-Agent in the HTTP header:

  • Windows users are served a component with text that refers to the Windows system and a download link at ftp://mgnl.travel/maps-offline/windows.zip.
  • OS-X users are served a component with text that refers to the OS-X system and a download link at ftp://mgnl.travel/maps-offline/osx.zip.
  • If neither system is detected, Magnolia serves the "ORIGINAL" version of the component, containing generic text and a download link at ftp://mgnl.travel/maps-offline/other-systems.zip.



Create a module

A trait is deployed with a Magnolia module. Create a module first. Choose from these options depending on your skill level:

Option 1: Clone the project in Git

This option gives you a ready-made project that you can customize to your needs.

Choose this option if you know how to work with a Magnolia project and Git, and want to examine the code locally in your IDE. 

  1. Clone the documentation-trait-tutorial repository.

    git clone http://git.magnolia-cms.com/git/documentation/documentation-trait-tutorial.git

    After having cloned the repo, you can check out the tagged version for the tag named documentation-trait-tutorial-1.3:

    git checkout documentation-trait-tutorial-1.3
  2. Import the project into your IDE. Here's what the project looks like in IntelliJ IDEA:

  3. Build the project into a JAR and deploy it to your Magnolia instance. Or run the project in your IDE. To run it in an IDE, add the module as a dependency to your Magnolia bundle POM file (see Option 2).

Option 2: Add the project as a dependency to your bundle

Choose this option if you run Magnolia in your IDE, but don't plan to work on the code.

Add the project as a dependency in the POM files of your Magnolia bundle.

For Enterprise Edition bundles:

  1. In the dependencyManagement section of the EE-bundle parent POM file, add a dependency element with a version number:
     

    Error rendering macro 'artifact-maven-dependencies-snippet-macro'

    com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and Java type class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and MIME media type application/octet-stream was not found


  2. In the dependencies section of the enterprise-webapp POM file, add a dependency element without a version number:

    Error rendering macro 'artifact-maven-dependencies-snippet-macro'

    com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and Java type class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and MIME media type application/octet-stream was not found

     

    (info) If you use IMB WebSphere or Oracle WebLogic, add the dependency element in the appropriate POM file of your webapp of choice.

If you are using a custom bundle, add the dependency element with a version number in the POM file of your customized bundle.

Option 3: Download the module JAR

Choose this option if you are new to Magnolia and don't have a development environment (IDE). You can use the trait but won't be able to look at the code.

  1. Install the Magnolia Tomcat bundle.
  2. Download

    Error rendering macro 'artifact-resource-macro'

    com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and Java type class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and MIME media type application/octet-stream was not found

     from Nexus.
  3. Copy the JAR into <CATALINA_HOME>/webapps/<contextPath>/WEB-INF/lib folder. Typically this is <CATALINA_HOME>/webapps/magnoliaAuthor/WEB-INF/lib.
  4. Restart your Magnolia instance and run the Web update . This will install the documentation-trait-tutorial module.

Registering a trait

Any module can register a trait. Magnolia observes the  traits folder in your module configuration and adds new traits to a trait registry. Registered traits are then displayed to editors in the user interface. 

Here's the userAgent trait.

Node nameValue

 
modules


 
documentation-trait-tutorial


 
traits


 
userAgent


 
ruleField


 
valueField


 
converterClass

info.magnolia.documentation.examples.personalization.useragent.UserAgentParameterConverter

 
defaultPreviewTrait

true

 
traitClass

info.magnolia.documentation.examples.personalization.useragent.UserAgent

 
voterClass

info.magnolia.documentation.examples.personalization.useragent.UserAgentVoter

Properties:

<trait name>

required

Trait name. Choose a name that is easy for editors to understand such as countrydate or userAgent.

ruleField

required

Field used to define permitted values for the trait. See Rule field below.

valueField

required

Field used to enter a single value to test personalized content delivery. See Value field below.

converterClass

required

Converter class which must implement info.magnolia.personalization.preview.parameter.PreviewParameterConverter<Object>.

traitClass

required

Trait class. Doesn't have to explicitly implement any interface. Usually it is just a plain Java object which allows you to specify the trait and its characteristics.

voterClass

required

Voter class which must extend AbstractBoolVoter<TraitCollector>. See Voters.

defaultPreviewTrait

optional, default is false

Adds the trait to the Preview app. Set this property to true for traits that editors preview content with routinely. It makes the Preview app faster to use. If a trait is used rarely, leave the property out.

traitStorageClass

optional, default is info.magnolia.personalization.trait.storage.StorageAwareTraitCollector$RequestScopedTraitStorage

If the trait is expected to remain the same for all requests in the current session, you can set the value to info.magnolia.personalization.trait.storage.StorageAwareTraitCollector$SessionScopedTraitStorage , which will avoid resolving the trait in each request. The trait will be resolved once for the current session. The value is implemented for example for the country trait in the default installation of Magnolia.

Rule field

A rule field defines values for the trait when you choose an audience. For example, you need two rule fields to define a date range: one for start date and another for end date. Magnolia uses the input entered into the rule field(s) to construct a voter. The voter then decides whether the visitor or visit matches the rule or not. When the rule is met, personalized content is delivered.

The rule field is displayed to users in the Choose audience dialog:

Choose a field definition class that lets the user specify the permitted values. In some cases, a simple text field is enough (country). In others, for example where you need the user to select a value (new visitor, registered visitor, logged-in visitor), a select field is appropriate. For more complex fields, use a composite field. See List of fields for more.

userAgent rule field:

Node nameValue

 
userAgent


 
ruleField


 
class

info.magnolia.ui.form.field.definition.TextFieldDefinition

 
transformerClass

info.magnolia.personalization.ui.SimpleTraitValueTransformer

 
type

String

Properties:

ruleField

required

Rule field node

class

required

Field definition class . The field must be known to the system. If you introduce a new field and only want it available in your module, configure it in the  /modules/<module name>/fieldTypes node. See Custom fields.

transformerClass

required

Transformer class which must implement info.magnolia.personalization.ui.SimpleTraitValueTransformer .

type

required/optional

Field type. In this case it is a bean property of the superclass ( TextFieldDefinition ) of the definition class. The type is not needed in every case.

Value field

A value field is for previewing variants. The field is displayed to users in the Preview app when viewing the page as a visitor:

When you enter a value that matches the rule, for example "Macintosh" in the image above, the voter tests the value against the rule and Magnolia displays the content variant associated with the value.

userAgent value field:

Node nameValue

 
userAgent


 
valueField


 
class

info.magnolia.ui.form.field.definition.TextFieldDefinition

 
type

String

Properties:

valueField

required

Value field node.

class

required

Field definition class . See Rule field (above) and Custom fields if you need to create a new field.

type

required/optional

Field type. In this case it is a bean property of the superclass (  TextFieldDefinition  ) of the definition class. The type is not needed in every case.

Registering a trait detector filter

Once you have registered the trait, provide a TraitDetectorFilter and register it in the filter chain to make sure the appropriate variant is served.

UserAgentDetectorFilter registration in the filter chain.

Node nameValue

 
server


 
filters


 
context


 
contentType


 
userAgent


 
class

info.magnolia.documentation.examples.personalization.useragent.UserAgentDetectorFilter

 
<more filters>


Properties:

filters

required

Filters node

<filter name>

required

Filter name. Name the filter after your trait. Ideally name the node to match the trait registration node. In our example the filter name is userAgent. The system doesn't require that both nodes have the same name, but it makes it easier to identify the purpose of the filter.

class

required

Class that implements AbstractTraitDetectorFilter<Object>

Position of the filter in the chain

Make sure the filter is in the right position in the chain. Filters are executed in the order they are registered in the chain, from top to bottom. You want to position the filter right after the contentType filter.

When installing a module, you can define the position with ModuleVersionHandler#getExtraInstallTasks.

info.magnolia.documentation.examples.personalization.setup.PersonalizationExamplesModuleVersionHandler
public class PersonalizationExamplesModuleVersionHandler extends DefaultModuleVersionHandler {
    @Override
    protected List<Task> getExtraInstallTasks(InstallContext installContext) {
        List<Task> tasks = new ArrayList<Task>();
        tasks.add(new FilterOrderingTask("userAgent", new String[]{"contentType"}));
        return tasks;
    }
}

In the example above the configuration tree is simplified. Other filters may also want to be right after contentType. In a production environment it may look like this: 

Creating component variants

Now you can create component variants and choose an audience using the new trait.

The documentation-trait-tutorial module installs an example page named maps-download that contains two custom variants of the Text and image component:

Windows variant

OS-X variant

Original

(warning) It is not possible to specify an audience for the original. The original acts as fallback (default) content when no variants match the visitor.

Testing the result

You can test the personalized variants using a browser plugin or on different computers running Windows and OS-X. User agent switcher add-ons that allow you to spoof and mimic various user agents are available for FirefoxChrome/Chromium, and Opera.

You should now be able to see different renderings of the page containing the personalized variants of the Text and image component depending on the user agent. 

Windows user agent

OS-X user agent

Other user agents

#trackbackRdf ($trackbackUtils.getContentIdentifier($page) $page.title $trackbackUtils.getPingUrl($page))