Rules in the Page Editor

This is a different way of disabling buttons on fields in Sitecore’s Page Editor, based on field values and the actual field, as was described in this post. This time I will be using the Sitecore Rules engine rather than removing items from a list.

The inspiration from this blog post came from @KevinObee, who put in this answer to the same question:

In short the answer he gave is: Use the Rules Engine as described here (a blog post by Adam Conn).

This sounded like a very interesting (not to mention powerful and elegant) solution, so here goes.

As Kevin gave a link to Sitecore’s blog, this was my starting point. I roughly followed Step 1 and Step 2 – but made my own Step 3. The only thing I didn’t follow is Step 2.4. I didn’t create the Command field.

I did this because I didn’t want to execute this rule for only my own command – the StackOverflow question specified it’s an existing (i.e. Sitecore out-of-the-box) command. This was my first issue – how do I get to the CommandStates of all buttons?

It turns out one can use the getQueryState pipeline. Found this out through this excellent post by @MikeReynolds. Thanks for that 😉

For my solution I created an include file:

<?xml version="1.0"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <getQueryState>
        <processor type="TestApplication.HidePageEditorButtonsUsingRules.RunRules, TestApplication" />
      </getQueryState>
    </pipelines>
  </sitecore>
</configuration>

My RunRules class:

public class RunRules
{
  public void Process(GetQueryStateArgs args)
  {
    Assert.ArgumentNotNull(args, "args");
    args.CommandState = QueryState(args.CommandContext);
  }

  public CommandState QueryState(CommandContext context)
  {
    Assert.ArgumentNotNull(context, "args");
    var ruleContext = new CommandRuleContext();
    ruleContext.Item = context.Items[0];
    var ruleItems = context.Items[0].Database.SelectItems("/sitecore/system/Settings/Rules/Command Rules/Rules/*");

    foreach (var ruleItem in ruleItems)
    {
      var rules = RuleFactory.ParseRules<CommandRuleContext>(ruleItem.Database, ruleItem["Rules"]);
      if (rules != null && rules.Count > 0)
      {
        rules.Run(ruleContext);
      }
    }

    return ruleContext.CommandState;
  }
}

So now I can put in a rule like:

initialrule

So far so good. The only problem is that the question also specified that there might be multiple fields on the page, some of which would have the buttons, some wouldn’t.

First of all, I created a new Condition to be able to facilitate this requirement:

newcondition

This is my SpecificField class:

public class SpecificField<T> : StringOperatorCondition<T> where T : CommandRuleContext
{
  public string Value { get; set; }
  protected override bool Execute(T ruleContext)
  {
    Assert.ArgumentNotNull(ruleContext, "ruleContext");
    var item = ruleContext.Item;
    if (item == null)
    {
      return false;
    }

    string fieldName = ruleContext.FieldName;
    if (string.IsNullOrEmpty(fieldName))
    {
      return false;
    }

    return base.Compare(fieldName.ToUpperInvariant(), Value.ToUpperInvariant());
  }
}

Now I can change my Rule field to add this condition:

updatedrule

I’ll need to change some other things as well in our previous code.

The Process method in the RunRules class now looks like this:

public void Process(GetQueryStateArgs args)
{
  Assert.ArgumentNotNull(args, "args");

  if (args.CommandContext.Parameters["field"] != null)
  {
    args.CommandState = QueryState(args.CommandContext);
  }
}

The updated lines of code are highlighted.

In the QueryState method of the RunRules class, I add the field to the commandContext like this:

public CommandState QueryState(CommandContext context)
{
  Assert.ArgumentNotNull(context, "args");
  var ruleContext = new CommandRuleContext();
  ruleContext.Item = context.Items[0];
  ruleContext.FieldName = context.Parameters["field"];
  var ruleItems = context.Items[0].Database.SelectItems("/sitecore/system/Settings/Rules/Command Rules/Rules/*");

  foreach (var ruleItem in ruleItems)
  {
    var rules = RuleFactory.ParseRules<CommandRuleContext>(ruleItem.Database, ruleItem["Rules"]);
    if (rules != null && rules.Count > 0)
    {
      rules.Run(ruleContext);
    }
  }

  return ruleContext.CommandState;
}

The added line is highlighted.

After building this and running it, the result for the title field is:

titlefield

And the subtitle field:

subtitlefield

Of course, all commands are now removed. This could be customized relatively easy by adding a new Condition to the Rule field, which would check the Command – very similar to the SpecificField class above.

Also, you might notice the Personalize button still displays. I’m not entirely sure why, but I’m thinking it’s a timing issue – it might be because the GetRenderingTestVariations gets added after the getQueryState pipeline runs. I haven’t really looked into this. If anyone can shed a light on this, please let me know in the comments.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s