Earlier today I discovered that clones in Sitecore are not renamed when their source Items are renamed — I’m baffled over how I have not noticed this before since I’ve been using Sitecore clones for a while now
I’ve created some clones in my Sitecore instance to illustrate:
I then initiated the process for renaming the source item:
As you can see the clones were not renamed:
One might argue this is expected behavior for clones — only source Item field values are propagated to its clones when there are no data collisions (i.e. a source Item’s field value is pushed to the same field in its clone when that data has not changed directly on the clone — and the Item name should not be included in this process since it does not live in a field.
Sure, I see that point of view but one of the requirements of the project I am currently working on mandates that source Item name changes be pushed to the clones of that source Item.
So what did I do to solve this? I created an item:renamed event handler similar to the following (the one I built for my project is slightly different though the idea is the same):
using System; using System.Collections.Generic; using Sitecore.Data.Items; using Sitecore.Diagnostics; using Sitecore.Events; using Sitecore.Links; using Sitecore.SecurityModel; namespace Sitecore.Sandbox.Data.Clones { public class ItemEventHandler { protected void OnItemRenamed(object sender, EventArgs args) { Item item = GetItem(args); if (item == null) { return; } RenameClones(item); } protected virtual Item GetItem(EventArgs args) { if (args == null) { return null; } return Event.ExtractParameter(args, 0) as Item; } protected virtual void RenameClones(Item item) { Assert.ArgumentNotNull(item, "item"); using (new LinkDisabler()) { using (new SecurityDisabler()) { using (new StatisticDisabler()) { Rename(GetClones(item), item.Name); } } } } protected virtual IEnumerable<Item> GetClones(Item item) { Assert.ArgumentNotNull(item, "item"); IEnumerable<Item> clones = item.GetClones(); if (clones == null) { return new List<Item>(); } return clones; } protected virtual void Rename(IEnumerable<Item> items, string newName) { Assert.ArgumentNotNull(items, "items"); Assert.ArgumentNotNullOrEmpty(newName, "newName"); foreach (Item item in items) { Rename(item, newName); } } protected virtual void Rename(Item item, string newName) { Assert.ArgumentNotNull(item, "item"); Assert.ArgumentNotNullOrEmpty(newName, "newName"); if (!item.Access.CanRename()) { return; } item.Editing.BeginEdit(); item.Name = newName; item.Editing.EndEdit(); } } }
The handler above retrieves all clones for the Item being renamed, and renames them using the new name of the source Item — I borrowed some logic from the Execute method in Sitecore.Shell.Framework.Pipelines.RenameItem in Sitecore.Kernel.dll (this serves as a processor of the <uiRenameItem> pipeline).
If you would like to learn more about events and their handlers, I encourage you to check out John West‘s post about them, and also take a look at this page on the
Sitecore Developer Network (SDN).
I then registered the above event handler in Sitecore using the following configuration file:
<?xml version="1.0" encoding="utf-8" ?> <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <events> <event name="item:renamed"> <handler type="Sitecore.Sandbox.Data.Clones.ItemEventHandler, Sitecore.Sandbox" method="OnItemRenamed"/> </event> </events> </sitecore> </configuration>
Let’s take this for a spin.
I went back to my source item, renamed it back to ‘My Cool Item’, and then initiated another rename operation on it:
As you can see all clones were renamed:
If you have any thoughts/concerns on this approach, or ideas on other ways to accomplish this, please share in a comment.