Dynamic and nested placeholders in Sitecore

If you have worked with placeholders in Sitecore you will be familiar with a grid structure like the following:

As you probably know the challenge comes when you want to move Component 1 into the placeholder in Component 2. In most implementations this will result in all components in placeholder 1.1 and 1.2 being orphaned (i.e. not visible on the page).

This is another limitation of Sitecore that we have resolved in Keystone. By extending the Sitecore.Pipelines.Save.ConvertLayoutField processor we can detect this condition and re-process the XML of the layout details. To get you started here are the opening lines of code:

namespace Keystone.SBL.Pipelines
{
    class ConvertLayoutField
    {
        /// 
        /// Runs the processor to update the layout field.
        /// Extended to support nested placeholders.
        /// 
        /// The arguments.
        public void Process(SaveArgs args)
        {
            Assert.ArgumentNotNull((object)args, "args");
            Assert.IsNotNull((object)args.Items, "args.Items");
            foreach (SaveArgs.SaveItem saveItem in args.Items)
            {
                Sitecore.Data.Items.Item obj = Client.ContentDatabase.Items[saveItem.ID, saveItem.Language, saveItem.Version];
                if (obj != null)
                {
                    ArrayList changes = new ArrayList();
                    foreach (SaveArgs.SaveField saveField in saveItem.Fields)
                    {
                        Field field = obj.Fields[saveField.ID];
                        if (!field.IsBlobField && !(field.Type != "layout"))
                        {
                            string xml1 = field.Value;
                            string xml2 = saveField.Value;

The last two lines of code will give you the raw XML of the layout details before the save and what Sitecore is attempting to save. Depending on how you have implemented dynamic placeholders you will need to detect movement and deletion conditions and update the placeholder locations of children controls (or remove them).

Once you have your updated XML you can pass it back to Sitecore with something like:

saveField.Value = xmlDocument2.OuterXml;

If you want to see Keystone in action check out our demo videos.