Sitecore Bucket Structure – Item Field Value Based

Bucketing structure in Sitecore is a rule based where the default structure is derived from this setting

In this blog post I am going to share how we can create a bucket structure based on a field value of the item being created into a bucket as in consider News Articles or Products which has a field “Release Date” / “Posted Date”. It is good to create bucket structure based on these dates as compared to the created date of the item. Why? Content Authors can easily navigate through the bucket as they will have in hand information about when a new articles or product was released rather than remembering the created date of the Sitecore item.

So let’s buckle up seat belt and get hands on to see who we can achieve it,

Create a RuleAction class NewsReleaseDate that inherits from Sitecore.Buckets.Rules.Bucketing.RuleAction

public class NewsReleaseDateBasedPath : RuleAction

where T : BucketingRuleContext

{

#region ...Properties

public string Format { get; set; }

#endregion

#region ...Public Methods

public const string CST = "Central Standard Time";

public override void Apply(T ruleContext)

{

string format = this.Format;

if (string.IsNullOrEmpty(format))

{

//Take the format for creating bucket structure from a custom setting defined in a configuratoin file

format = Sitecore.Configuration.Settings.GetSetting("BucketConfiguration.NewsReleaseDatePathFormat", "yyyy/MM/dd");

}

DateTime releaseDate = ConvertToCst(DateTime.UtcNow);

//master database is referenced as command runs under Core DB context

var item = Sitecore.Data.Database.GetDatabase("master").GetItem(ruleContext.NewItemId);

//if item is null bucket structure will be creadetd in default format

//So pass the yyyy/MM/dd format

if (item == null)

{

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

return;

}

//AutoGenerated Model class for new article base

NewsArticleBaseItem newsItem = new NewsArticleBaseItem(item);

if (newsItem == null) return;

//Read the release date field value

if (newsItem.ReleaseDate!=null && !String.IsNullOrEmpty(newsItem.ReleaseDate.ToString()))

{

releaseDate = ConvertToCst(newsItem.ReleaseDate.DateTime.ToUniversalTime());

}

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

}

public DateTime ConvertToCst(DateTime utcDate)

{

return TimeZoneInfo.ConvertTimeFromUtc(utcDate, TimeZoneInfo.FindSystemTimeZoneById(CST));

}

#endregion

}

Now make few tweaks to Sitecore,
1) Create Element Folder at path /sitecore/system/Settings/Rules/Definitions/Elements/

NewsReleaseDateBucketing-1

2) Create a new action and update the type field to refer to the code class created earlier.

NewsReleaseDateBucketing-2

3) On Item Buckets Setting at path /sitecore/system/Settings/Buckets/Item Buckets Settings
Add the rule and action for your template

NewsReleaseDateBucketing-3

Click on the Edit Rule to add new rule and action for News Release Date

NewsReleaseDateBucketing-4

You will see Bucketing News Elements folder now available

NewsReleaseDateBucketing-5

Save the Item bucket settings item and we are all set to create a news article which will get stored initially with the created date as you have still not changed the valued of the release date of the new news article. Once the release date field is updated the news article will move to the bucket structure based on the value provided in the release date field.

That’s all for now I have to share keep Sitecoring and keep sharing because “Sharing is Caring”

Sitecore KeepAlive config patching

The heartbeat of Sitecore is it’s keepalive.aspx which keeps Sitecore alive and working continuously. There is a good KB article provided by sitecore “Automatic site recycling after the site has been idle for a period” to understand what a KeepAlive.aspx is all about. Another good read is “Keeping Sitecore alive”.

During an implementation in a scaled environment where we had separate CM, Publishing and Aggregation cum Processing server or multiple CD servers, we need to make sure all the environments are up and running all the time. Adding the url of keepalive.aspx on a server which hits itself does not works all the times as the website might be down due to apppool recycle or the machine itself got restarted and there has been no first request yet made to sitecore. The KeepAlive agent can run only if sitecore is up and a first request has already been made after the appPool recycle.

So one of the option is to make sitecore keealive agent hit url of other servers in the vicinity.

Here’s an example for CD servers hitting each other,


<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">

<sitecore>

<scheduling>

<agent patch:before="*[@type='Sitecore.Tasks.TaskDatabaseAgent']" name="CD01" type="Sitecore.Tasks.UrlAgent" method="Run" interval="00:15:00">

<param desc="url">http://CD1hostname/sitecore/service/keepalive.aspx</param>

<LogActivity>true</LogActivity>

</agent>

<agent patch:after="*[@name='CD01']" type="Sitecore.Tasks.UrlAgent" name="CD02" method="Run" interval="00:15:00">

<param desc="url">http://CD2hostname/sitecore/service/keepalive.aspx</param>

<LogActivity>true</LogActivity>

</agent>

</scheduling>

</sitecore>

</configuration>

Example of CM, Publishing Instance and Aggregation / Processing Server hitting each other,


<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">

<sitecore>

<scheduling>

<agent patch:before="*[@type='Sitecore.Tasks.TaskDatabaseAgent']" name="CM01" type="Sitecore.Tasks.UrlAgent" method="Run" interval="00:15:00">

<param desc="url">http://CM01hostname/sitecore/service/keepalive.aspx</param>

<LogActivity>true</LogActivity>

</agent>

<agent patch:after="*[@name='CM01']" type="Sitecore.Tasks.UrlAgent" name="CD02" method="Run" interval="00:15:00">

<param desc="url">http://CM02hostname/sitecore/service/keepalive.aspx</param>

<LogActivity>true</LogActivity>

</agent>

<agent patch:after="*[@name='CM02']" type="Sitecore.Tasks.UrlAgent" name="PI01" method="Run" interval="00:15:00">

<param desc="url">http://PI01hostname/sitecore/service/keepalive.aspx</param>

<LogActivity>true</LogActivity>

</agent>

<agent patch:after="*[@name='PI01']" type="Sitecore.Tasks.UrlAgent" name="AG01" method="Run" interval="00:15:00">

<param desc="url">http://AG01hostname/sitecore/service/keepalive.aspx</param>

<LogActivity>true</LogActivity>

</agent>

</scheduling>

</sitecore>

</configuration>

 

Let’s validate what we see at /sitecore/admin/showconfig.aspx

KeepAlive-1

You might be wondering why do I need to add “name” attribute to all the agent nodes and use patch:after / patch:before. Her’s the reason why, if we use the below patching sitecore only picks the last node and ignores patching of all the other agent.


<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">

<sitecore>

<scheduling>

<!-- The time format is "HH:MM:SS" -->

<agent type="Sitecore.Tasks.UrlAgent" method="Run" interval="00:05:00">

<!-- Replace [WEBSITE] with the appropriate domain -->

<param desc="url">http://CD01hostname/sitecore/service/keepalive.aspx</param>

<LogActivity>true</LogActivity>

</agent>

<agent type="Sitecore.Tasks.UrlAgent" method="Run" interval="00:05:00">

<!-- Replace [WEBSITE] with the appropriate domain -->

<param desc="url">http://CD02hostname/sitecore/service/keepalive.aspx</param>

<LogActivity>true</LogActivity>

</agent>

</scheduling>

</sitecore>

</configuration>

The resultant config patching if seen using /sitecore/admin/showconfig.aspx would reveal that it only picked the last node of the agent.
KeepAlive-2