Blog post Technical, Tridion

How to update all XO promotions after a Blueprint change in SDL Web 8.5 and earlier versions

Whenever Content Editors are working with XO (Experience Optimization) module, they define XO promotions (rules) which specify:

  • which content is visible,
  • for which types of users,
  • for which market,
  • and under which conditions.

In this case, the market refers to the Publication(s) for which this Promotion is active. This step provides the option to define a promotion for multiple Publications by selecting one in lower levels of the Blueprint with the checked option “Include child Publications”:

Selecting ‘Include child Publications’ option when defining publication scope.

This means that the Promotion will be active for all Child Publications — which is expected. But we have a problem whenever we change the BluePrint structure by adding new child Publication. In this case, XO Promotions are not updated automatically, so the Content Editors must open each and every one of them and do, “Save and close.” During this action, the XO module will perform the update under the hood, but this can be tedious and time-consuming for the editors — especially when there are hundreds of Promotions.

Notification showing that BluePrint structure has changed and that the Promotions should be updated.

Fixing this issue is different between Tridion Sites 9 and previous versions because SDL changed the XO engine from Fredhopper to Elasticsearch. This fix focuses on pre-9 versions (2013, 8, 8.1, and 8.5). For version 9 (with Elasticsearch engine), this fix doesn’t apply and will have to be modified.

The following steps explain how to partially automate this process and introduce a somewhat easier update procedure.

Step 1: Update the business.xml file

Open the business.xml file found at: /<fredhopper home>/data/instances/<indexer instance>/config/ within your Fredhopper instance.

Locate the “SmartTarget Meta Promotion” Promotion within the file. It’s created and managed internally by the XO module and can’t be updated by the UI. But we can see what’s in it, and use it in the tool.

<campaign:line> node contains the HTML-encoded values of all the promotions:

<campaign:line>
  &lt;!--&lt;PromotionsMetaData&gt;&lt;MetaData&gt;&lt;IsExperiment&gt;false&lt;/IsExperiment&gt;&lt;Id&gt;d78933d1-6250-436e-b439-e21039537259&lt;/Id&gt;&lt;IncludeChildPublications&gt;true&lt;/IncludeChildPublications&gt;&lt;Name&gt;IE User&lt;/Name&gt;&lt;Regions&gt;&lt;Region&gt;Sidebar&lt;/Region&gt;&lt;Region&gt;Inset 1&lt;/Region&gt;&lt;Region&gt;Footer&lt;/Region&gt;&lt;/Regions&gt;&lt;ScopePublication&gt;tcm:0-2-1&lt;/ScopePublication&gt;&lt;/MetaData&gt;&lt;PublicationTargetId&gt;CdEnvironment1&lt;/PublicationTargetId&gt;&lt;/PromotionsMetaData&gt;--&gt;
</campaign:line>

When you decode this data you’ll see it contains information about the promotions:

<PromotionsMetaData>
	<MetaData>
		<IsExperiment>false</IsExperiment>
		<Id>d78933d1-6250-436e-b439-e21039537259</Id>
		<IncludeChildPublications>true</IncludeChildPublications>
		<Name>IE User</Name>
		<Regions>
			<Region>Sidebar</Region>
			<Region>Inset 1</Region>
			<Region>Footer</Region>
		</Regions>
		<ScopePublication>tcm:0-2-1</ScopePublication>
	</MetaData>
	<PublicationTargetId>CdEnvironment1</PublicationTargetId>
</PromotionsMetaData>

<ScopePublication> and <IncludeChildPublications> provide the info of the selected Publication and determine whether it is enabled in Child Publications.

For each Promotion, if <IncludeChildPublications> is set to true, then the tool needs to identify all of the Child Publications. You can do this with a Core Service tool. Compare all the Publications you can retrieve using Core Service to the ones specified in the business.xml file.

Add a new <trigger:trigger> node for each of the missing Publications in each of the corresponding Promotions.

<trigger:trigger>
  <trigger:element trigger="SmartTarget Publication">
    <trigger:condition operation="equals" invert="false">
      <trigger:operand>tcm:0-7-1</trigger:operand>
    </trigger:condition>
  </trigger:element>
</trigger:trigger>

Where <trigger:operand> node value is the TcmId of the publication.

Step 2: Update trigger-types.xml

Open the trigger-types.xml file at: /<fredhopper home>/data/instances/<indexer instance>/config/ location in your Fredhopper instance.

Add all of the missing (and newly created Publications) to the st_publication trigger:

<trigger-type basetype="text" url-param="st_publication" name="SmartTarget Publication">
    <list-of-values multiselect="true">
      <value>tcm:0-1-1</value>
      <value>tcm:0-2-1</value>
      <value>tcm:0-3-1</value>
    </list-of-values>
  </trigger-type>

This trigger contains a unique list of all the publications used in XO promotions, so update it with the list provided by the tool.

Step 3: Restart Fredhopper

Restart the Indexer instance with following command (if you have Fredhopper hosted on Linux):

#./bin/instance indexer stop
#./bin/instance indexer start

There are similar existing commands when Fredhopper is hosted on Windows.

A restart of the instance will make the Indexer pick up the latest changes in business.xml and trigger-types.xml files.

Push the changes to all query instances with the fresh-index-to-live command:

#./bin/fresh-index-to-live indexer

This command will push the changes from Indexer to all query instances, including the same (business.xml and trigger-types) files.

Step 4: Restart the XO Management Service

Just restart the SDL XO Management Service. After the restart, all changes in XO UI should be updated and without the “Changed BluePrint Hierarchy” notification.

Aftermath: Hope in the future

This article has explained how you can, in a semi-automatic fashion, develop a tool that will analyze your XO promotions and update them when new publications have been created. Creating a tool is more of a Band-Aid for the problem; in the long-run, a solution should be integrated into the product itself. If the BluePrint changes are already integrated into Tridion, the case should be the same for the Experience Optimization module.

In that regard, I have created an idea on community.sdl.com site, so feel free to upvote it if you see believe that this is something SDL should implement in future releases.

If you have any questions about the development of the tool or, in general, feel free to contact us.

Contact us to discuss your project.
We're ready to work with you.
Let's talk