an abstract image of a grid adhering to waves with various spotlights of teal and purple

Sitecore Rules Engine - Managing Top Level Navigation Inclusion

Eric Nordberg
Eric Nordberg

At Dreamcore North America, I was excited to see how Sitecore is applying the Rules Engine to introduce conditional logic.

Specifically, they demoed it in combination with DMS (digital marketing system – aka OMS v2) to handle personalization. This was ridiculously easy in the Sitecore 6.5 Page Editor. Also, it was used for mobile browser detection in the Mobile Device Detector shared source module.

The Rules Engine was released with Sitecore v6.1. But, we are just starting to see examples of it in action. I expect that we’ll see it used more and more as developers learn what it can do. 

Problem: Inclusion in Top Navigation

This is a common problem. The top level of the main site navigation should only contain the key landing/section/category pages. The site design displays these horizontally, leaving room for 5-6 pages.

Then, an author adds a new page at the root of the site, not realizing that the IncludeInTopNavigation is checked. Suddenly, this random new page is the main navigation, the design breaks, and everyone freaks out.

Potential Solutions

  1. Tell authors to be more careful. That sounds nice.
  2. Have the standard value of the IncludeInTopNavigation checkbox default to unchecked. This is the normal method for setting a default value like this. But, this is less than ideal if your page types are used at other levels of the site where you would want the box to be checked as a default.
  3. We could magically make the box be unchecked for all items when they are created at the root of the site. This is the solution we will outline below.  And, yes, the Rules Engine is just like magic. 

Solution Requirements

  1. When an item is created at the root of the site, the IncludeInTopNavigation checkbox field is unchecked.
  2. This checkbox can otherwise default to be checked for all other instances.

Solution Overview

  1. We’ll create a custom rule in the Rules Engine.
  2. This rule will be applied when items are added.
  3. The rule will activate in the condition that the added item is a page at the root level of the site.
  4. When the condition is true, the rule will trigger an action that will uncheck the IncludeInTopNavigation checkbox.

Solution Steps – At a High Level

  1. We need to create a Rules Engine Action that unchecks the checkbox.
  2. We need to create a Rules Engine Rule that uses Conditions to determine if the Action should be applied.
  3. We need to configure the site to apply the rule when items are added.

Create the Action class in Visual Studio

See the example code below.

1 using Sitecore.Rules;   
2 using Sitecore.Rules.Actions;   
3 using Sitecore.Data.Fields;   
5 namespace ExampleWebsite.Sitecore.SitecoreRules   
6 {   
7     publicclass ExcludeFromTopNavAction<t> : RuleAction<t> where T : RuleContext   
8     {   
9         privateconststring IncludeInTopNavigationFieldName = "Navigation-IncludeInTopNavigation";   
11         publicoverridevoid Apply(T ruleContext)   
12         {   
13             Assert.ArgumentNotNull(ruleContext, "ruleContext");   
14             var item = ruleContext.Item;   
15             if (item != null)   
16             {   
17                 var includeInTopNavigationField = (CheckboxField) item.Fields[IncludeInTopNavigationFieldName];   
18                 if (includeInTopNavigationField == null)   
19                     return;   
21                 item.Editing.BeginEdit();   
22                 includeInTopNavigationField.Checked = false;   
23                 item.Editing.EndEdit();   
24             }              
25         }   
27     }   
28 }   

I took the basic structure from an existing Sitecore Action using Redgate Reflector.  Then, you can see we are unchecking the checkbox field when it exists.

Create a Location for Rules in Sitecore

Sitecore Rules are managed under /sitecore/system/Settings/Rules.  Create a folder there for your website.  Under that new folder, create an Actions folder and an Item Added Rules folder.  These folders should all use the Folder template, which is the insert option provided by Sitecore for this part of the tree.

The Item Added Rules folder is a location for all custom rules we want to evaluate when items are added.  If we wanted to apply custom rules in other situations, we would create a folder for each event type (one possible example being: Item Deleted Rules).

The content tree structure we will achieve is below.


Create and Configure Your Rule Action Item

In the Actions folder, you will create your action. Use Insert from Template to create the action item, using the /sitecore/templates/System/Rules/Action template.

Configuring our custom Action is easy. The Text field will be used for the name of your action when referred to in Rules. The Type field will contain the namespace and assembly signature of our Action class.


Notes: Actions can be made more powerful by using Rule parameters in the Text field. For an example, see /sitecore/system/Settings/Rules/Content Editor Warnings/Actions/Set Content Editor Warning. This item has the following Text value: show content editor warning: [title,,,Title], [text,,,Text].

The Rules Engine Cookbook has some information on how to configure these parameters. But, it’s most likely that you will need to examine one of Sitecore’s existing actions using a tool like RedGate Reflector.

An alternative to Actions is to use Rule Scripts. These allow you to enter code directly into the Content Editor.  Scripts use the /sitecore/templates/System/Rules/Script template.  For a simple example, see /sitecore/system/Settings/Rules/Item Saved/Actions/Clear Rules Cache.

Create a Rule Template

Once your Action is configured, you will want to create a Rule item.  Here, you will want to be careful. You might be tempted to copy an existing Rule item that uses the /sitecore/templates/System/Rules/Rule template. But, if you do, you will not be able to apply your custom action with that rule. Instead, you will need to create your own Rule template.

In the Templates part of the tree, create a new template by copying and pasting from the /sitecore/templates/System/Rules/Rule template. The location of this template is not important. I would put it with your other site templates in a sub-folder.


Then, in the template builder, update the Source of the Rule field to be your Rules folder.


Create the Your Rule Item

In your Item Added Rules folder, use Insert from Template to insert a rule from this new template.

Enter a Name for your Rule and edit the Rule field. See below for the completed rule.


The Rule editing interface is very intuitive.  If you configured your template correctly, you should see your Rule Action as an option.

For this Rule, I went with the out-of-box Rule conditions.  Sitecore has a very robust set of conditions to choose from.

Most of the conditions here are fairly obvious.  Items where the level is equal to 3 are directly under the site Home node in the content tree.  For page items, these would be at the site root, where we want to uncheck our IncludeInTopNavigation checkbox.


Create a Handler to Apply Your Rules

Create a handler class in Visual Studio.  See example code below.


1 using System; 12:41 PM 7/14/201112:41 PM 7/14/2011  
2 using Sitecore.Data.Items;   
3 using Sitecore.Diagnostics;   
4 using Sitecore.Events;   
5 using Sitecore.Rules;   
6 using Sitecore.SecurityModel;   
9 namespace ExampleWebsite.Sitecore.SitecoreRules   
10 {   
11     publicclass ItemEventHander   
12     {   
13         protectedvoid OnItemAdded(object sender, EventArgs args)   
15         {   
16             Assert.ArgumentNotNull(sender, "sender");   
17             Assert.ArgumentNotNull(args, "args");   
18             var item = Event.ExtractParameter(args, 0) as Item;   
20             if (item != null)   
21             {   
22                 RunItemAddedRules(item);   
23             }   
24         }    
26         privatestaticvoid RunItemAddedRules(Item item)   
27         {   
28             RunRules(item, "/sitecore/system/Settings/Rules/ExampleWebsite/Item Added Rules”); 
29         }  
31         private static void RunRules(Item item, string path) 
32         { 
33             Item item2; 
34             Assert.ArgumentNotNull(path, "path"); 
35             using (new SecurityDisabler()) 
36             { 
37                 item2 = item.Database.GetItem(path); 
38                 if (item2 == null) 
39                 { 
40                     return; 
41                 } 
42             } 
43             var context2 = new RuleContext 
44             { 
45                 Item = item 
46             }; 
47             var ruleContext = context2; 
48             var rules = RuleFactory.GetRules<RuleContext>(item2, "Rule");   
49             if (rules != null)   
50             {   
51                 rules.Run(ruleContext);   
52             }   
53         }   
54     }   
55 }  

I took this structure from an existing Sitecore handler using RedGate Reflector.  The only unique thing about it is the path to our Rules location in the content tree: "/sitecore/system/Settings/Rules/ExampleWebsite/Item Added Rules”.

Update the Web.Config to Call the Handler Class

Next, we will update the Sitecore Item Added Event in the web.config to call this handler.  See the example configuration below.

1 < sitecore database = "SqlServer">  
2     < sc.variable name = "dataFolder" value="C:\inetpub\wwwroot\ExampleWebsite\Data" />  
3     < sc.variable name = "mediaFolder" value="/upload" />  
4     < sc.variable name = "tempFolder" value="/temp" />  
5     < prototypes >  
7       < sc.include file = "/App_Config/Prototypes.config" />  
9     </ prototypes >  
11     <!-- EVENT MAPS  
13       events.timingLevel =  
14         none   - No timing information is logged for any of the events (no matter what their local settings are)  
15         low    - Start/end timing is logged for events with handlers. Local settings override.  
16         medium - Start/end timing is logged for all events. Local settings override.  
17         high   - Start/end timing is logged for all events. Also, start/end for each handler is logged. Local settings override.  
18         custom - Only local settings apply. Events without settings are not logged.  
20       event.timingLevel =  
21        none    - No timing information is logged for the event.  
22        low     - The combined time of all handlers is logged for the event. If no handlers are specified, nothing is logged.  
23        medium  - The combined time of all handlers is logged for the event. Even if it does not have any handlers.  
24        high    - The combined and individual time of all handlers is logged for the event.  
25     -->  
27     < events timingLevel = "custom">  
28       < event name = "data:updated" />  
29       < event name = "item:added">  
30         < handler type = "ExampleWebsite.Sitecore.SitecoreRules.ItemEventHander, ExampleWebsite.Sitecore" method="OnItemAdded" />  
31         < handler type = "Sitecore.Data.Fields.ItemEventHandler, Sitecore.Kernel" method="OnItemAdded" />  
32       </ event >  


It’s that easy. Actually, the steps are a little putsy, but once configured, the Rules Engine can be very powerful. I am definitely looking forward to using it more in future projects.

Related Resources

  1. Rules Engine Cookbook: This documentation currently does not do the best job of providing required details.  But, it does provide a decent overview of the key concepts.
  2. RedGate Reflector: Sometimes the best approach is to see what Sitecore does.  Reflector is a great tool to decompile and review Sitecore’s assemblies.
  3. Mobile Device Detector – Shared Source Module: This module uses Rules Engine conditions to evaluate User Agents and Actions to change to a mobile device.  It is an excellent example of the Rules Engine in action.

Let's Get Started

We'd love to hear from you. We probably have a lot in common. I mean, you like chatting about data-binding, UX patterns, and javascript functions, right?


Cookies help us improve your website experience. By using our website, you agree to our use of cookies and our privacy policy.