Conditional markup
Sitecore gives a business user the ability to control certain aspects of how a rendering behaves through personalization rules. For example, when a specific condition is met the business user can specify:
- Which data source should be used.
- Which rendering is used.
- Whether the rendering should be displayed or hidden.
There are cases where more control is needed. For example, what if, when a rendering is hidden, you need to adjust the markup in order to avoid a broken layout? In this case, you need to be able to execute code when the personalization rule that is activated has an action assigned that hides the rendering.
This section describes how to define blocks of conditional logic where you can control the markup that is used when conditions are met. This can be used to configure conditional logic inside of rendering code.
#
Components#
Conditional blocksA "conditional block" represents a single personalization rule. There are three types of conditional blocks that can be assigned to a rendering:
- If block - This represents the first rule. Exactly one
if-block is supported. This block type is represented by
Uniform.Optimize.Emitters.IfBlock
. - Else-if blocks - This represents all of the remaining
rules that can be configured. Zero or many else-if blocks
are supported. This block type is represented by
Uniform.Optimize.Emitters.ElseIfBlock
. - Else block - This represents the default rule. Zero
or one else-blocks are supported. The default rule
identifies the default content that is displayed
when none of the personalization rules matches. This
block type is represented by
Uniform.Optimize.Emitters.ElseBlock
.
#
Root blocksA "root block" is a data structure that represents the set
of conditional blocks assigned to a rendering. The data
structure is represented by Uniform.Optimize.Emitters.RootItem
.
#
Conditional block helperIn Sitecore, personalization rules can be stored in multiple places. Regardless of where they are defined, personalization rules can be converted into the "root block" data structure.
"Root blocks" can be created from the following types:
- Rendering - The personalization rules assigned to a
Sitecore.Mvc.Presentation.Rendering
object. - Sitecore item - The personalization rules assigned to the item.
- Sitecore rule list - The rules in a
Sitecore.Rules.RuleList<Sitecore.Rules.ConditionalRenderings.ConditionalRenderingsRuleContext>
object.
The conversion of personalization rules into a "root block"
is handled by Uniform.Optimize.Emitters.ConditionalBlockHelper
.
#
Get markup delegateA developer is able to specify the markup to generate for each conditional block using a "get markup delegate". This delegate is a function that is called one time for each "conditional block" assigned to a "root block".
The signature of the delegate is:
string GetMarkupDelegate(IConditionalBlock block)
#
EmittersAn emitter is responsible for performing the following logic:
- Iterate the "conditional blocks" assigned to a "root block".
- Call the "get markup delegate" for each "conditional block".
- Wrap the output from the delegate with conditional logic that corresponds to the personalization rule represented by the "conditional block".
- Return a string that contains instructions and markup that can be executed by the personalization engine.
#
Examples#
Renderings (with personalization)This example demonstrates how to incorporate conditional logic within the code for a rendering with personalization rules assigned to it.
note
This example expects that an edge-side emitter is configured on your Sitecore instance.
note
In your Visual Studio project, add the a reference to each of the following assemblies:
Uniform.Optimize.Core
Uniform.Optimize.Personalization.Esi.Core
////Get the current rendering.var rendering = RenderingContext.Current.Rendering;////Get the root block that represents the personalization //rules assigned to the rendering.var rootBlock = ConditionalBlockHelper.GetRootBlock(rendering);////Create the delegate generates the markup for each//conditional block in the root block.var getMarkup = new GetMarkupDelegate(block =>{ // //Return a string based on the condition assigned //to the block. This string will be injected inside //a conditional block that reflects the condition //assigned to the block. return null;});////Create a buffer to hold the markup generated when//the emitter calls the markup delegate.var builder = new StringBuilder();using (var writer = new StringWriter(builder)){ // //Since the rendering is personalized, the emitter //will be injecting tags inside a block that is //expected to be a literal string value. The //enabler ensures the proper instructions are //added to the markup so the emitted tags are //executed. using (new EsiMarkupEscapeEnabler()) { // //Get the emitter. var emitter = EmitterHelper.GetEmitter(Sitecore.Context.Database); // //The emitter uses the delegate to generate //condition logic for the condition blocks //in the root block. emitter.Emit(rootBlock, getMarkup, writer); }}////Get the markup written to the buffer.var markup = builder.ToString();
#
Renderings (no personalization)This example demonstrates how to incorporate conditional logic within the code for a rendering without personalization rules assigned to it.
note
This example expects that a predefined personalization rule has been created and published on your Sitecore instance.
note
In your Visual Studio project, add the a reference to each of the following assemblies:
Uniform.Optimize.Core
////Get the item that represents the predefined rule.var itemId = "!!! ITEM ID !!!";var item = Sitecore.Context.Database.GetItem(itemId);////Get the root block that represents the personalization //rules assigned to the item.var rootBlock = ConditionalBlockHelper.GetRootBlock(item);////Create the delegate generates the markup for each//conditional block in the root block.var getMarkup = new GetMarkupDelegate(block =>{ // //Return a string based on the condition assigned //to the block. This string will be injected inside //a conditional block that reflects the condition //assigned to the block. return null;});////Create a buffer to hold the markup generated when//the emitter calls the markup delegate.var builder = new StringBuilder();using (var writer = new StringWriter(builder)){ // //Get the emitter. var emitter = EmitterHelper.GetEmitter(Sitecore.Context.Database); // //The emitter uses the delegate to generate //condition logic for the condition blocks //in the root block. emitter.Emit(rootBlock, getMarkup, writer);}////Get the markup written to the buffer.var markup = builder.ToString();
#
TroubleshootingThis section provides tips on how to troubleshoot when conditional logic is not rendered as expected.
#
Delegate is called only for the "else block"If your delegate is only being invoked with the "else block", this usually means the emitter is reporting itself to be inactive. The rules that determine whether an emitter is active or not depends which emitter is being used, but the following are things to check:
Sitecore page mode - Emitters are only active in selected Sitecore page modes. By default, only "normal" mode is supported. Supported page modes is controlled through the Uniform Optimize settings item in Sitecore.
Runtime mode is available - Emitters that support edge-side personalization often include logic to ensure they only generate conditional logic when they are run in an environment that supports the execution of edge-side logic.
For example, when Akamai runs edge-side logic, a specific HTTP request header is set. If this header is not available, the emitter assumes it is not running in Akamai, and therefore reports itself to be inactive.