Improve sorting of subitems by Created Date


Description

Current implementation of CreatedComparer iterates through all item versions in all languages in order to find the lowest value in the Created field.

For sites that have many items with many versions, this algorithm may be not very optimal and cause delays when expanding items in the content tree.

One of the possible solutions to improve this behavior is:

One issue with this approach is that to make it work for items, which were created before applying it, you will need to fill their "__Item Created" field manually. 

This could be simply done by iterating over all items in content tree using Sitecore API and updating value of the field. You can use a sample "FillItemCreatedField.aspx" page from the step 3 below to update all content items with the lowest value of the Created field from available item versions.

Solution

Detailed description to implement this behavior is:

  1. Make a backup of your Master database.
  2. Create a shared field in the following template section, call it "__Item Created" and set field type to "DateTime".
    /sitecore/templates/System/Templates/Sections/Statistics
  3. This step is needed if you want to update the "__Item Created" field on existing items. Unzip the archive to the "\Website\layouts" folder of your solution, navigate to the appropriate url (http://website/layouts/FillItemCreatedField.aspx) and press the "Process" button.
  4. Create a handler class for the "item:created" event, which will fill the "__Item Created" field by current UTC time when an item is being created. Place resulted DLL assembly to the /Bin folder of your website:
    public class ItemEventHandler
        {
            public void OnItemCreated(object Sender, EventArgs args)
            {
                string fieldName = "__Item Created";
                ItemCreatedEventArgs createdArgs = Sitecore.Events.Event.ExtractParameter(args, 0) as ItemCreatedEventArgs;
                if (createdArgs == null)
                {
                    return;
                }
                Item item = createdArgs.Item;
                if (item != null && item.Fields[fieldName] != null)
                {
                    using (new EditContext(item, SecurityCheck.Disable))
                    {
                        item.Fields[fieldName].Value = Sitecore.DateUtil.ToIsoDate(DateTime.UtcNow);
                    }
                }
            }
        }
  5. Modify the "Web.config" file - add the created handler to the "item:created" event:
    <event name="item:created">
    <handler type="[namespace].ItemEventHandler, [assembly name]" method="OnItemCreated"/>
    </event>
  6. Create a comparer, which will use the added field. This step depends on Sitecore version you use, because starting from the Sitecore 6.5 Update-5 version -  the sorting logic was improved and a new base type for all comparers ExtractedKeysComparer was introduced. 

    For Sitecore 6.5 Update-5 and later
    public class ItemCreatedComparer : CreatedComparer 
    {
            protected override int DoCompare(Item item1, Item item2)
            {
                return this.GetItemCreationDate(item1).CompareTo(this.GetItemCreationDate(item2));
            }
            public override IKey ExtractKey(Item item)
            {
                Assert.ArgumentNotNull(item, "item");
                return new KeyObj { Item = item, Key = this.GetItemCreationDate(item), Sortorder = item.Appearance.Sortorder };
            }
            private DateTime GetItemCreationDate(Item item)
            {
                if (item.Fields["__Item Created"] == null)
                {
                    return DateTime.MinValue;
                }
                DateTime creationDate = Sitecore.DateUtil.ParseDateTime(item.Fields["__Item Created"].Value, DateTime.MinValue);
                return creationDate;
            }
        }  
    For earlier versions of Sitecore
    Use the same code as in the previous case, but exclude the ExtractKey method implementation. Compile it and copy the DLL assembly to the /Bin folder of your website.
  7. Create the "Item Created" item under the "/sitecore/system/Settings/Subitems Sorting/" item which uses the "/sitecore/templates/System/Child Sorting" template and set its "Type" field value to [namespace].ItemCreatedComparer,[assembly name]

More information on subitems sorting can be found in chapter 3.5 of the following article:
http://sdn.sitecore.net/Reference/Sitecore%206/Presentation%20Component%20API%20Cookbook.aspx

Note that the sort order has priority over the sorting rule. You can reset sort order by pressing the "Reset" button in the "Set Subitems sorting" window.