How to Create Custom Item Bucket Rules in Sitecore CMS

April 21, 2015

Blog | Development | How to Create Custom Item Bucket Rules in Sitecore CMS
How to Create Custom Item Bucket Rules in Sitecore CMS

Welcome back to our series on learning how to use and develop for Sitecore CMS. Today’s post is the follow-up to “How to Configure Item Bucket Paths in Sitecore CMS.”

Custom item bucket rules can be used to extend Sitecore’s bucket selection and path capabilities. By default, Sitecore can only select items based off of:

  • bucket item ID
  • bucket item name
  • bucket item template
  • new item template

Where paths are concerned, by default, Sitecore can create paths based off of:

  • item creation date
  • item ID
  • item Name

Today, we’re going to look at how to create custom item bucket rules. This includes creating the Sitecore items necessary to customize rule conditions and actions, as well as a code example for generating paths based off of a custom date field.

Note:
This tutorial will make use of the item bucket created in “How to Create Item Buckets in Sitecore CMS”.

Creating the Items

Bucketing rules in Sitecore are built from two item types: Conditions, and Actions. Item selection is managed by “Condition” items, while path generation is managed by “Action” items. Both item types can be found in /sitecore/system/Settings/Rules/Definitions/Elements/Bucketing.

In this example I will walk through creating a custom action. The same steps can be used to create custom conditions.

Select the Bucketing item, and create a new “Action” child item. Name the new item “Resolve Custom Date Field Based Path”.

Update the Text field to: create the folder structure based on the [fieldid,Tree,root=/sitecore/Templates,custom date] field of the new bucketable item in [format,Format,yyyy/MM/dd/HH/mm,this] format.

The text in the square brackets is used to control the links in the actions and conditions. The parts that make up the links are:

  1. fieldid – the property that will be used to store the data in the relevant class
  2. Tree – the interface action that will occur when the link is clicked
  3. root=/sitecore/Templates – parameters to pass to the interface action. In this example, the root item of the selection is specified.
  4. custom date – the text that will be shown in the link.

Update the “Type” field to point to the class that will be used for the action. My class will be named CreateDateFieldBasedPath in the GeekHive.Framework.Sitecore.Buckets.Rules namespace within a DLL named GeekHive.Framework.dll, so my type field will be GeekHive.Framework.Sitecore.Buckets.Rules.CreateDateFieldBasedPath,GeekHive.Framework.

Save the changes.

Writing the Code

Custom actions must extend the Sitecore.Rules.Actions.RuleAction generic abstract class, while custom conditions must extend the Sitecore.Rules.Conditions.WhenCondition generic abstract class.

Create a class called CreateDateFieldBasedPath that extends RuleAction:

public class CreateDateFieldBasedPath : RuleAction where T : BucketingRuleContext
{
    //...
}

Properties are needed to support the fieldid and format fields that were specified from the action item’s “Text” field.

public ID FieldID { get; set; }
public string Format { get; set; }

The Apply abstract method must be implemented.

public override void Apply(T ruleContext)
{
    //...
}

The Apply method takes a BucketingRuleContext which has a number of accessors that can be used to configure the final path. As the Apply method has no return value, the ruleContext.ResolvedPath parameter is how the final bucket path is returned.

For this example, the goal is to have the path based off of the DateTime value in the selected field, using the format provided.

Get the Date

Getting the date is a little tricky. When items are being created, the Apply method may be called before the item actually exists in the database. For this reason, the date should be initialized using the item creation date, and overridden with the value from the field when available.

var date = ruleContext.CreationDate;

Before the field can be accessed, the item needs to be read from the database:

var item = ruleContext.Database.GetItem(ruleContext.NewItemId);

As stated before, it’s possible that the item won’t be in the database, so a null check is in order:

if (item != null)
{
    //...

The field then needs to be read from the database

var field = (DateField) item.Fields[FieldID];

It’s possible that the wrong field item was selected, so another null check is in order:

if (field != null)
{
    //...

Now that the field is acquired, the date value can be assigned. All together, the item access is:

var item = ruleContext.Database.GetItem(ruleContext.NewItemId);
if (item != null)
{
    var field = (DateField) item.Fields[FieldID];
    if (field != null)
    {
        date = field.DateTime;
    }
}

Get the Format

Getting the format is straightforward compared to getting the date.

var format = Format;

Sitecore even has a convenient static property to access the default bucket folder path from configuration.

if (string.IsNullOrEmpty(format))
    format = BucketConfigurationSettings.BucketFolderPath;

Assign the ResolvedPath

ruleContext.ResolvedPath is a simple string that will be split on / characters to create the path used for the item in the bucket.

ruleContext.ResolvedPath = date.ToString(format, Context.Culture);

All Together Now

The complete code for this example is:

using Sitecore;
using Sitecore.Buckets.Rules.Bucketing;
using Sitecore.Buckets.Util;
using Sitecore.Data;
using Sitecore.Data.Fields;
using Sitecore.Rules.Actions;

namespace GeekHive.Framework.Sitecore.Buckets.Rules
{
    public class CreateDateFieldBasedPath : RuleAction where T : BucketingRuleContext
    {
        public ID FieldID { get; set; }
        public string Format { get; set; }

        public override void Apply(T ruleContext)
        {
            var date = ruleContext.CreationDate;

            var item = ruleContext.Database.GetItem(ruleContext.NewItemId);
            if (item != null)
            {
                var field = (DateField) item.Fields[FieldID];
                if (field != null)
                {
                    date = field.DateTime;
                }
            }

            var format = Format;
            if (string.IsNullOrEmpty(format))
                format = BucketConfigurationSettings.BucketFolderPath;

            ruleContext.ResolvedPath = date.ToString(format, Context.Culture);
        }
    }
}

Tim Leverett

Senior Developer
Tags
  • Sitecore
Sitecore Survival Guide Volume 1

If you found this post helpful, there are plenty more where it came from! You'll find the first 10 here.

Download the first 10 posts in our Sitecore how-to series by Developer Tim Leverett!

Updating the Rule

Move the DLL into the bin directory of the Sitecore installation.

Select the /sitecore/system/Settings/Buckets/Item Buckets Settings item and click the "Edit Rule" button above the "Rules for Resolving the Bucket Folder Path" field.

Delete the "create the folder structure..." action that was created in “How to Configure Item Bucket Paths in Sitecore CMS” by clicking the "Delete" button shown when hovering the action.

Add the new "create the folder structure based on the custom date field..." action that we just created.

Click on the "custom date" link and use it to select User Defined/Article/Article Data/Date. Click OK in the modal.

Click on the "this" link and update the format to yyyy/MM/dd. Click OK in the prompt.

Because the Date field belongs to the Article template type, it's worth adding a condition that the new bucketable item is based on the article template.

Click OK in the "Rule Set Editor" modal and save the changes to the "Item Buckets Settings" item.

Select the /sitecore/content/Example/Home/Articles item and use the Sync button in the Buckets button group on the Configure tab of the ribbon to update the paths for all items. Be sure to update the Date fields on articles before syncing.

Additional Notes

Item bucket paths based off of fields that change regularly may not be a good design decision because the path to the item would need to be updated every time the field changed. This could negatively impact SEO and possibly produce link-rot if pages that once existed were no longer available at the same location.

Additionally be aware that the entire bucket would need to be synced every time any item in the bucket needed to be synced. This could negatively impact site performance.


If you see any bugs in the code (other than Buzz!) or have any questions or comments, feel free to drop us a line or message me directly.

Recent Work

Check out what else we've been working on