Set Rendering Parameters in Conditional Rendering

Sitecore has a set “Set Parameters” conditional rendering rule which sets the rendering parameters as the name implies. This rule has some limitations:

  1. It will remove all existing parameters
  2. User will have to know the querystring syntax to add the correct keys and values (e.g. parameter1=value1&parameter2=value2)

The second limitation can be resolved by educating the users to use correct syntax, but there is no option to resolve the first one. There are many legitimate scenarios where you would want to set some rendering parameters and either add some more based on a condition or overwrite the value for a particular parameter.

To support this scenario I created a custom conditional rendering rule to do this:

  1. If there is already a parameter and this is not specified in the conditional rendering rule, then leave it as is.
  2. If there is already a parameter, and the same is also set in the conditional rendering rule, then overwrite it with the value from conditional rendering rule.
  3. If the parameter is only in the conditional rendering rule, add it.

I used below code for my custom action:

using Sitecore.Diagnostics;
using Sitecore.Rules.Actions;
using Sitecore.Rules.ConditionalRenderings;
using System.Linq;

namespace Jeroen.Rules.ConditionalRendering
{
    public class MergeParameterAction<T> : RuleAction<T> where T : ConditionalRenderingsRuleContext
    {
        public string Name { get; set; }

        public string Value { get; set; }

        public override void Apply(T ruleContext)
        {
            Assert.ArgumentNotNull(ruleContext, "ruleContext");

            //grab the existing parameters
            var parameters = Sitecore.Web.WebUtil.ParseUrlParameters(ruleContext.Reference.Settings.Parameters);

            //parameter already there, overwrite
            if (parameters.AllKeys.Contains(Name))
            {
                parameters[Name] = Value;
            }
            //add new parameter
            else
            {
                parameters.Add(Name, Value);
            }

            //add updated parameters back
            ruleContext.Reference.Settings.Parameters =
                string.Join("&", parameters.AllKeys.SelectMany(
                    parameters.GetValues, (n, v) => string.Format("{0}={1}", n, v)));
        }
    }
}

Below screenshot shows how to add the action:

conditional-rendering-custom-action

Now the rule is available in Sitecore and ready to use. You can use the action multiple times in case you need to set multiple parameters as shown here. Now the additional parameters will be set and existing parameters will be kept, there is also no need for the user to remember the syntax, he can just click the name/value pair in the rule editor!

conditional-rendering-using-custom-action

Set any action in conditional rendering on item through personalize screen

The Sitecore UI supports setting any action in global conditional rendering rules, however this is not possible when you try to do this on an item through the personalize button in presentation details. In this case it only supports showing or hiding the component and setting the datasource. First screenshot below shows the editor when you go to the rules in the global conditional rendering (under “/sitecore/system/Marketing Control Panel/Personalization/Rules”). The second screenshot shows the editor when you make a change on the item. Notice that the rules option are limited here.

This is less of an issue if you are using WebForms as you can just make your rule a global rule. With MVC this can become more of a problem as MVC does not support global conditional rendering rules, in MVC you are still able to select a global rule however the rule will not do anything.

Solution

It turns out that this issue is only with the Sitecore UI and any action is supported it is just not possible to select it in the UI. Conditional rendering rules get stored in the Layout of an item in the Renderings and Final Renderings fields. Usually the easiest way to update the layout with the rule is to create the rule first as a Global Rendering rule and then grab the raw value of the rule. Below is an example with a sample rule that logs a message when it’s Sunday. See rule and associated XML below:

log-message-on-sunday

<ruleset>
  <rule uid="{EE27A156-B552-43C0-AFD2-616D9AAE2846}" name="Rule 1">
    <conditions>
      <condition id="{1F15625B-8BDC-4FD2-8F0C-6EE2B8EF0389}" uid="B96A756592C04746856F5F8F9784C3E1" day="{04CC0FD2-C5DE-4F7C-B263-B1C88BABA6CD}" />
    </conditions>
    <actions>
      <action id="{4D151B8B-BD5F-4479-A35F-EE740F6387E8}" uid="5AB9220AD9604A7FABBE48853926B82C" level="Info" text="It's Sunday!" />
    </actions>
  </rule>
</ruleset>

Now copy this XML and update the Renderings or Final Renderings field with it. Here is an example how to update the field with a sample item that has 1 rendering.

Initial:

<r xmlns:p="p" xmlns:s="s" p:p="1">
  <d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}">
    <r uid="{39EE95EC-3BA9-4D8A-AC3E-51DB3FBD353A}">
      
    </r>
  </d>
</r>

With conditional rendering rule added:

<r xmlns:p="p" xmlns:s="s" p:p="1">
  <d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}">
    <r uid="{39EE95EC-3BA9-4D8A-AC3E-51DB3FBD353A}">
      <rls>
        <ruleset>
          <rule uid="{EE27A156-B552-43C0-AFD2-616D9AAE2846}" name="Rule 1">
            <conditions>
              <condition id="{1F15625B-8BDC-4FD2-8F0C-6EE2B8EF0389}" uid="B96A756592C04746856F5F8F9784C3E1" day="{04CC0FD2-C5DE-4F7C-B263-B1C88BABA6CD}" />
            </conditions>
            <actions>
              <action id="{4D151B8B-BD5F-4479-A35F-EE740F6387E8}" uid="5AB9220AD9604A7FABBE48853926B82C" level="Info" text="It's Sunday!" />
            </actions>
          </rule>
        </ruleset>
      </rls>
    </r>
  </d>
</r>

Notice that the difference between the initial XML and the updated one is only an additional “rls” tag with the XML from the Global conditional rendering rule inside it. Now the rule will execute as expected!