The other day I stumbled upon a thread in the Sitecore Developer Network (SDN) forums that briefly touched upon replacing proxies with clones, and I wondered whether anyone had built any sort of tool that creates clones for items being proxied — basically a tool that would automate creating clones from proxies — and removes the proxies once the clones are in place.
Since I am not aware of such a tool — not to mention that I’m hooked on programming and just love coding — I decided to create one.
The following command is my attempt at such a tool:
using System; using System.Linq; using Sitecore.Configuration; using Sitecore.Data.Items; using Sitecore.Data.Proxies; using Sitecore.Diagnostics; using Sitecore.Shell.Framework.Commands; namespace Sitecore.Sandbox.Commands { public class TransformProxyToClones : Command { public override void Execute(CommandContext context) { Assert.ArgumentNotNull(context, "context"); TransformProxyItemToClones(GetContextItem(context)); } private static void TransformProxyItemToClones(Item item) { Assert.ArgumentNotNull(item, "item"); if(!CanTransform(item)) { return; } string proxyType = GetProxyType(item); Item source = GetItem(GetSourceItemFieldValue(item)); Item target = GetItem(GetTargetItemFieldValue(item)); if (AreEqualIgnoreCase(proxyType, "Entire sub-tree")) { DeleteItem(item); CloneEntireSubtree(source, target); } else if (AreEqualIgnoreCase(proxyType, "Root item only")) { DeleteItem(item); CloneRootOnly(source, target); } } private static void CloneEntireSubtree(Item source, Item destination) { Clone(source, destination, true); } private static void CloneRootOnly(Item root, Item destination) { Clone(root, destination, false); } private static Item Clone(Item cloneSource, Item cloneDestination, bool deep) { Assert.ArgumentNotNull(cloneSource, "cloneSource"); Assert.ArgumentNotNull(cloneDestination, "cloneDestination"); return cloneSource.CloneTo(cloneDestination, deep); } private static void DeleteItem(Item item) { Assert.ArgumentNotNull(item, "item"); if (Settings.RecycleBinActive) { item.Recycle(); } else { item.Delete(); } } public override CommandState QueryState(CommandContext context) { Assert.ArgumentNotNull(context, "context"); if (CanTransform(GetContextItem(context))) { return CommandState.Enabled; } return CommandState.Hidden; } private static Item GetContextItem(CommandContext context) { Assert.ArgumentNotNull(context, "context"); return context.Items.FirstOrDefault(); } private static bool CanTransform(Item item) { Assert.ArgumentNotNull(item, "item"); return IsProxy(item) && IsSourceDatabaseFieldEmpty(item) && !string.IsNullOrWhiteSpace(GetProxyType(item)) && !string.IsNullOrWhiteSpace(GetSourceItemFieldValue(item)) && !string.IsNullOrWhiteSpace(GetTargetItemFieldValue(item)); } private static bool IsProxy(Item item) { Assert.ArgumentNotNull(item, "item"); return ProxyManager.IsProxy(item); } private static string GetProxyType(Item item) { Assert.ArgumentNotNull(item, "item"); return item["Proxy type"]; } private static bool IsSourceDatabaseFieldEmpty(Item item) { Assert.ArgumentNotNull(item, "item"); return string.IsNullOrWhiteSpace(item["Source database"]); } private static string GetSourceItemFieldValue(Item item) { Assert.ArgumentNotNull(item, "item"); return item["Source item"]; } private static string GetTargetItemFieldValue(Item item) { Assert.ArgumentNotNull(item, "item"); return item["Target item"]; } private static Item GetItem(string path) { Assert.ArgumentNotNullOrEmpty(path, "path"); return Context.ContentDatabase.GetItem(path); } private static bool AreEqualIgnoreCase(string one, string two) { return string.Equals(one, two, StringComparison.CurrentCultureIgnoreCase); } } }
The above command is only visible for proxy items having both source and target items set, and the proxy is for the context content database.
When the command is invoked, the source item — conjoined with its descendants if its sub-tree is also being proxied — is cloned to the target item, after the proxy definition item is deleted.
I registered the above command in Sitecore using an include configuration file:
<?xml version="1.0" encoding="utf-8" ?> <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <commands> <command name="item:transformproxytoclones" type="Sitecore.Sandbox.Commands.TransformProxyToClones, Sitecore.Sandbox"/> </commands> </sitecore> </configuration>
I also wired this up in the core database for the item context menu (I’ve omitted a screenshot on how this is done; If you would like to see how this is done, please see part 1 and part 2 of my post showing how to add to the item context menu).
Let’s take this for a drive.
I created a bunch of items for testing:
I then created a proxy for these test items:
I then right-clicked on our test proxy item to launch its context menu, and then clicked on the “Transform Proxy To Clones” menu option:
The proxy item was removed, and we now have clones:
If you can think of any other ideas around proxies or clones, or know of other tools that create clones from proxies, please leave a comment.
Great article. I know it is a bit old, and most Sitecore instances have probably already replaced all their proxies, but… has anybody done this with a Powershell script instead?