LibrarySites.Banner

Dynamic Bucket Item Paths in the Sitecore ASP.NET CMS | John West | Sitecore Blog

This blog post describes an approach to managing paths to items semi dynamically in the Sitecore ASP.NET web Content Management System (CMS) and Experience Platform (XP). In this context, dynamic means using logic to control item paths when CMS users edit content, which is more dynamic than controlling item paths when users create items or move them, especially into a bucket.

In previous blog posts, I mentioned that:

  • The logic that Sitecore uses to determine the paths to items in buckets applies only when creating items in or moving items into a bucket. When creating an item, the user has not had a chance to alter data that the system could use to determine the optimal path to an item.
  • If the data used to determine the path to an item in a bucket changes, Sitecore does not move the item accordingly.
  • Many solutions need to control paths to items that are not in buckets.

Therefore, some implementations could benefit from a solution that intercepts item updates to:

  • Re-apply pathing rules to items in buckets (or not, if we don’t want URLs of bucketed items to change).
  • Apply general pathing rules for items not in buckets.

We have at least three options for intercepting item updates:

  • The saveUi pipeline. In this case we should not need to interact with the user and we may want our logic to fire from API calls rather than only user operations such as saveUi, so other techniques seem more appropriate.
  • item:saving or item:saved event handlers: These would probably work.
  • OnItemSaved rule: While it may seem overcomplicated at first, in addition to allowing re-use of existing conditions, the rules engine making our logic more flexible, visible, and easily configurable. It should not be difficult to rewrite this rules engine prototype as an event handler.

When I first looked at this problem six months ago, I published a prototype for a condition to determine whether an item is in a bucket. We can use this with an action that applies bucketing path rules. That could look something like this:

namespace DocumentImporter.Rules.ItemPath.Actions
{
  using Sitecore.Buckets.Managers;
  using Sitecore.Data.Items;
  using Sitecore.Diagnostics;
  using Sitecore.Rules.Actions;
 
  public class ApplyBucketRules<T> : RuleAction<T>
    where T : Sitecore.Rules.RuleContext
  {
    //TODO: separate action to apply rules defined in item
 
    public override void Apply(T ruleContext)
    {
      Assert.ArgumentNotNull(ruleContext, "ruleContext");
      Assert.ArgumentNotNull(ruleContext.Item, "ruleContext.Item");
      Item likeABucket = ruleContext.Item.Parent;
 
      while (likeABucket != null && !BucketManager.IsBucket(likeABucket))
      {
        likeABucket = likeABucket.Parent;
      }
 
      if (likeABucket == null)
      {
        likeABucket = likeABucket.Parent;
 
        while (likeABucket != null && likeABucket.TemplateID.ToString()
          != Sitecore.Buckets.Util.Constants.BucketFolder)
        {
          likeABucket = likeABucket.Parent;
        }
 
        if (likeABucket == null)
        {
          Log.Error(
            this + " : Apply invoked for " + ruleContext.Item.Paths.FullPath + " not in bucket",
            this);
          return;
        }
      }
 
      BucketManager.MoveItemIntoBucket(ruleContext.Item, likeABucket);
    }
  }
}

For this I created the /sitecore/system/Settings/Rules/Definitions/Elements/Item Path/Apply Bucket Rules item from the System/Rules/Action template, set Text to apply bucket path rules, and set Type to Sitecore.Sharedsource.Rules.ItemPath.Actions.ApplyBucketRules,Sitecore.Sharedsource. Then I created the /sitecore/system/Settings/Rules/Item Saved/Rules/Apply Path Rules rule definition item from the System/Rules/Rule data template and bound the condition to the action.

Resources