codeflood logo

Post item:saved Event Handler Execution

Sitecore allows classes to subscribe to particular events so arbitrary code may run when certain "things" happen. Possibly one of the most often subscribed events is the item:saved event which fires when an item is, you guessed it, saved. Whether through the UI or the API the event will always fire. This is very handy for changing or cleaning up an item once the author has signaled that they're happy with it (by hitting the save button). Just a side note, don't do your validation here, use item or field validators instead.

Something that is often done using the item:saved event is to move the item to an appropriate structure. Some may say this is good for SEO, but we do it in Sitecore as a performance measure. Sitecore performance (particularly in the content editor) can degrade if too many items exist under a common parent item. There are various guidelines floating about for the maximum number of child items that should be allowed under a common parent but I generally say try to keep it to less than 100 and definitely less than 200 (less is better).

When we talk about "structuring" an item we generally mean placing it into an item hierarchy of several levels. Each level in the hierarchy is related to some aspect of the item. If the item represents a person then the hierarchy levels may represent letters in their name (the person "John Smith" goes in /person/s/john smith). If the item is date based the levels may represent elements of the date (an event goes in a year folder, then a month folder such as /event/2013/November/my-event).

Let's say we have a news item with a field called News Date which contains the date the news is being reported on. I prefer a separate date for this kind of item rather than inferring the news date from the updated or created fields as news can be authored ahead of time (press release) or may need to have minor updates made that shouldn't affect the "date" of the item (fix a spelling mistake). Now we want to structure the news in a hierarchy based on the News Date field. Though this is good for performance we now have a single piece of data replicated in two places; once in the field and once in the structure. We need to ensure these two instances of the same data are kept in sync. And believe me, don't trust your authors to ensure they keep the news in the right location.

The easiest way to ensure the date field and structure are kept in sync is by using the News Mover module from the Sitecore Marketplace. This module will move the item to a folder structure based on the date selected in the configured field by hooking into the item:saved event. Awesome! We've got a way to ensure no news item is created in a flat structure...but what if we didn't anticipate the volume of items beforehand and now we have 700 news items directly under the news root item before the News Mover module was put in place? Adding event handlers after the fact doesn't retrospectively execute the handlers for any items.

Unstructured news items

(OK, not quite 700 items in my example screenshot but you get the idea.)

We need a way to execute the item:saved event for all those items without manually going through and hitting that save button 700 items. We can do that with Revolver! To process a number of items at once I can use one of the find, query or search commands. For this case I'll use the find command as it uses content tree traversal so I can be sure all my items will be processed. Next I need a way to save the item. This can be done by updating a field value. But I don't really want to change anything on the item, I just want to invoke the save event. For setting a field value in Revolver I can use the sf command which also allows me to use the previous field value in the new field value through the token $prev$.

Let's put it all together. First I need to navigate down to my news root item. Let's assume this lives at /sitecore/content/my-site/news.

cd /sitecore/content/my-site/news

Now to execute the find command on all the children of that item.

find (sf -nv __updated ($prev$))

I've specified no parameters to find so it will process all children. If I wanted all descendants I would need to add the -r parameter. The parameter passed to find (enclosed in brackets) is the command to execute against each matched item; the sf command. This command will set the value of the __updated field to the current (previous) value. Incidentally this actually has no affect as Sitecore will update the field value immediately after we update the field value to show when it was last updated. The -nv parameter causes Revolver to not create a new version before updating the field value. By setting the field value the item:saved event is raised and News Mover can restructure the news items.

Structured news items

Comments

John West

Alistair, do you do anything to ensure the year and month folders get published before the news item in this case?

Alistair Deneys

Good question John, you bring up a vital consideration.
This blog post was just about the data structures and item creation processes. I've not mentioned anything about publishing here. If you are following this advice, to structure you're news items in folders for performance and usability, then you'll need to ensure the folders containing the news items are published before the news item itself. This wouldn't be an issue if you're using incremental site publishes, but it would be an issue if the author was just doing an item publish on the news item.
I've seen solutions in the past which added publish pipeline processors which did these checks and added the ancestor items to the publish process if required.

[…] item to a proper place on save (like Alistair describes in his article – but in […]

Leave a comment

All fields are required.