Surendra Sharma

Surendra Sharma

Search This Blog

Tuesday, August 28, 2018

Sitecore Event: Move item to datewise folder automatically based on date field


You may have items such as news, publication, blog, events etc. that contain date field.

Its great to show these items according to datewise so that each item should place in "YYYY > MMM > dd" path. This type of content structure is good to locate the item quickly.

Whenever content editor creates such item with specified date and save the item, our job is to fire an event to move that item in the respective date folder. If date folder is not exist then it should be created automatically and move the item into that.

In below image there are two year folders - 2017 and 2018. I am adding new item "Test News Article 111" and selected its date as "12-Feb-2016". When I click on save button, my event automatically created folders 2016, February and 12 and moved the item under that.

Moving news item to datewise folder automatically
Moving news item to datewise folder automatically


Implementation Details

Create 3 template items in Sitecore for Year, Month and Date at path “/sitecore/templates/Project/Common/Content Types” as below

Name – Year Folder
Template - /sitecore/templates/System/Templates/Template
Icon - Business/32x32/calendar.png

Name – Month Folder
Template - /sitecore/templates/System/Templates/Template
Icon - Business/32x32/calendar_31.png

Name – Day Folder
Template - /sitecore/templates/System/Templates/Template
Icon - Business/32x32/calendar_7.png

Create constant to specify different news items details as
 
namespace Sitecore.Foundation.SitecoreExtensions
{
    using Sitecore.Data;

    public struct Constants
    {
        public struct DateWiseStructure
        {
            public static readonly ID NewsArticleTemplateID = new ID("{B69277AD-E917-4B9F-9136-A12E0A3E462F}");
            public static readonly ID NewsArticleParentID = new ID("{FBF578DE-0640-43CF-91C1-492ECD093BC4}");
            public static readonly string NewsDateFieldName = "NewsDate";
            public static readonly ID YearFolderItemTemplateID = new ID("{B64C595D-FE20-44B1-96CC-38F292730437}");
            public static readonly ID MonthFolderItemTemplateID = new ID("{F1183F76-17AC-4DF3-877C-85726A16EECA}");
            public static readonly ID DayFolderItemTemplateID = new ID("{A443C72F-8A0B-4816-BCEF-D537905A7331}");
        }
    }
}

To implement such functionality, we need to write below code for Save event

using Sitecore.Collections;
using Sitecore.Data;
using Sitecore.Data.Fields;
using Sitecore.Data.Items;
using Sitecore.Data.Managers;
using Sitecore.Globalization;
using Sitecore.SecurityModel;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Sitecore.Foundation.SitecoreExtensions.Extensions
{
    /// <summary>
    /// Save Event to create folder struture datewise in Sitecore content tree
    /// </summary>
    public class ItemSaveEventHandler
    {

        /// <summary>
        /// Check language version is exist for the item
        /// </summary>
        /// <param name="item"></param>
        /// <param name="contextLanguage"></param>
        /// <param name="database"></param>
        /// <returns></returns>
        public bool HasGivenLanguageVersion(Item item, Language contextLanguage, Database database)
        {
            try
            {
                if (item != null && item.Languages != null && contextLanguage != null)
                {
                    Item languageSpecificItem = database.GetItem(item.ID, contextLanguage);
                    if (languageSpecificItem != null && languageSpecificItem.Versions.Count > 0)
                    {
                        return true;
                    }
                }
            }
            catch (Exception ex)
            {
                Sitecore.Diagnostics.Log.Error("Error while checking language version of item " + item.ID + " Error is " + ex, typeof(BasicUtil));
            }

            return false;
        }

        /// <summary>
        /// Save Event method to create folder struture datewise in Sitecore content tree
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public void OnItemSaved(object sender, EventArgs args)
        {
            if (args == null || Sitecore.Context.Site.Name.ToLower().Equals("publisher")) return;

            Item itemToOrganize = Sitecore.Events.Event.ExtractParameter(args, 0) as Item;

            if(itemToOrganize == null || itemToOrganize.Name.ToLower().Equals("__standard values") || !itemToOrganize.TemplateID.Equals(Constants.DateWiseStructure.NewsArticleTemplateID))
            {
                return;
            }

            Item parentOfTypeAutosave = null;
            Database master = Sitecore.Configuration.Factory.GetDatabase("master");

            parentOfTypeAutosave = SitecoreUtil.GetItem(Constants.DateWiseStructure.NewsArticleParentID, master);

            if (parentOfTypeAutosave == null || BasicUtil.IsOfTypeFolder(itemToOrganize)) return;

            string dateFld = string.Empty;

            ID dayFolderTemplateID;
            if (itemToOrganize.TemplateID.Equals(Constants.DateWiseStructure.NewsArticleTemplateID))
            {
                dateFld = Constants.DateWiseStructure.NewsDateFieldName;
                dayFolderTemplateID = Constants.DateWiseStructure.DayFolderItemTemplateID; //Day Folder Template ID
            }
            else
            {
                return;
            }

            Item _currentYearItem = null;
            Item _currentMonthItem = null;
            Item _currentDayItem = null;
            bool _yearFolderExist = false;
            bool _monthFolderExist = false;
            bool _dayFolderExist = false;
            DateTime date = ((DateField)itemToOrganize.Fields[dateFld]).DateTime.Date;

            LanguageCollection languages = LanguageManager.GetLanguages(master);
            Item langItem = null;
            DateTime langDate = DateTime.MinValue;
            if (date == DateTime.MinValue)
            {
                foreach (Language language in languages)
                {
                    if (HasGivenLanguageVersion(itemToOrganize, language, master))
                    {
                        langItem = master.GetItem(itemToOrganize.ID, language);
                        langDate = ((DateField)langItem.Fields[dateFld]).DateTime.Date;

                        if (langDate != DateTime.MinValue && date < langDate)
                        {
                            date = langDate;
                        }
                    }
                }
            }

            List<Item> yearItems =
                parentOfTypeAutosave.Children.Where(
                    x => x.TemplateID.Equals(Constants.DateWiseStructure.YearFolderItemTemplateID) && x.Name.Equals(date.ToString("yyyy"))).ToList();

            if (yearItems.Any())
            {
                _yearFolderExist = true;
                _currentYearItem = yearItems.First();
                List<Item> monthItems = _currentYearItem.Children.Where(x => x.TemplateID.Equals(Constants.DateWiseStructure.MonthFolderItemTemplateID) &&
                    x.Name.ToLower().Equals(date.ToString("MMMM").ToLower())).ToList();

                if (monthItems.Any())
                {
                    _monthFolderExist = true;
                    _currentMonthItem = monthItems.First();

                    List<Item> dayItems = _currentMonthItem.Children.Where(x => x.TemplateID.Equals(dayFolderTemplateID) && x.Name.Equals(date.ToString("%d"))).ToList();

                    if (dayItems.Any())
                    {
                        _dayFolderExist = true;
                        _currentDayItem = dayItems.First();
                    }
                    else
                    {
                        _dayFolderExist = false;
                    }
                }
                else
                {
                    _monthFolderExist = false;
                }
            }
            else
            {
                _yearFolderExist = false;
            }

            if (!_yearFolderExist)
            {
                using (new SecurityDisabler())
                {
                    TemplateID yearTemplateId = new TemplateID(Constants.DateWiseStructure.YearFolderItemTemplateID);
                    _currentYearItem = parentOfTypeAutosave.Add(date.ToString("yyyy"), yearTemplateId);
                }
            }
            if (!_monthFolderExist)
            {
                using (new SecurityDisabler())
                {
                    TemplateID monthTemplateId = new TemplateID(Constants.DateWiseStructure.MonthFolderItemTemplateID);
                    _currentMonthItem = _currentYearItem.Add(date.ToString("MMMM"), monthTemplateId);
                }
            }
            if (!_dayFolderExist)
            {
                using (new SecurityDisabler())
                {
                    TemplateID dayTemplateId = new TemplateID(dayFolderTemplateID);
                    _currentDayItem = _currentMonthItem.Add(date.ToString("%d"), dayTemplateId);
                }
            }
            if (itemToOrganize.Parent.Name.Equals(_currentDayItem.Name)
                && itemToOrganize.Parent.Parent.Name.Equals(_currentMonthItem.Name)
                && itemToOrganize.Parent.Parent.Parent.Name.Equals(_currentYearItem.Name)) return;

            using (new SecurityDisabler())
            {
                itemToOrganize.MoveTo(_currentDayItem);
            }
        }
    }
}

Create custom config file to register this event as

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
    <sitecore>
        <events>
            <event name="item:saved">
                <handler type="Sitecore.Foundation.SitecoreExtensions.Extensions.ItemSaveEventHandler,Sitecore.Foundation.SitecoreExtensions" method="OnItemSaved"/>
            </event>
        </events>
       
    </sitecore>
</configuration>

That’s it.

Now whenever you are creating any such news item, it will move to correct date folder.

Note :- If you have not specified any value in date fields then that item will move to 0001 > 01 > 01 folder.

I hope you enjoy this Sitecore article. Stay tuned for more Sitecore related articles.

Till that happy Sitecoring :)

Please leave your comments or share this article if it’s useful for you.