Sitecore 8: Changing Renderings Programmatically

I am sure that most of you working with Sitecore were at some point in the situation of upgrading a solution. This is not an easy task, especially if the upgrade does not work by simply going through the upgrade steps from a version to the next one. In my case, I am in the process of upgrading a Sitecore 7.0 solution to Sitecore 8.2, and because of the legacy code that we cannot use anymore,  my team and I decided that we will start from scratch with a clean Sitecore 8.2 solution, we will migrate the data using scripts, and we will completely rebuild the presentation layer. The data migration, though not a subject of this post, is done by adding the old master db in the new solution, thus allowing us to programmatically transfer items from the old master to the new master. Our approach did not pose many problems, but I did have to investigate a bit how to reuse components.

In the old solution, there are many components that contain a lot of content, which we don’t want to lose. Migrating the datasource items is not difficult, but we need to redo the relations between them and the components that have to appear on the pages. The old renderings are gone, but we will have new ones in the new solution. To be more specific, if in the old solution, on a page oldPageItem, there is a component with the rendering oldRendering, assigned to a placeholder oldPh and it has the datasource item oldDsItem, then in the new solution, on the page newPageItem with the same ID as oldPageItem, we will have the new rendering newRendering, assigned to the new placeholder newPh, but with the datasource item newDsItem with the same ID as oldDsItem. In other words, we are keeping the content, but completely changing the presentation layer. To do this automatically, I wrote the following piece of code:

/* get the page in the new master db */
var newPageItem = newMasterDb.GetItem(oldPageItem.ID);
if (newPageItem == null)
{
    return;
}

/* get the rendering list of the old page item */
var renderingsList = 
    oldPageItem.Visualization.GetRenderings(Context.Device, true);
if (renderingsList == null)
{
    return;
}

/* get the layout definition and the current device definition 
   from the new page item; we are working on the final layout */
LayoutField layoutField = 
    new LayoutField(newPageItem.Fields[FieldIDs.FinalLayoutField]);
LayoutDefinition layoutDefinition = 
    LayoutDefinition.Parse(layoutField.Value);
DeviceDefinition deviceDefinition = 
    layoutDefinition.GetDevice(Context.Device.ID.ToString());

/* go through all the old renderings and identify the one used on 
   the component that needs to be added on the new page item */
foreach (var rendering in renderingsList)
{
    /* we can identify the rendering by name 
       (we could also do it by ID) */
    if (rendering.RenderingItem.Name.Equals("oldRendering"))
    {
        /* get the datasource ID from the rendering */
        var datasourceId = rendering.Settings.DataSource;
        if (datasourceId != null)
        {
            var oldPlaceholder = rendering.Placeholder;
            var newPlaceholder = string.Empty;
            var newRenderingId = string.Empty;

            /* the same component could be rendered in more 
               than one placeholder, so check the name of 
               the old placeholder;
               if it is a nested placeholder in the main 
               placeholder, we need to include it in the check */
            if (oldPlaceholder.Equals("/oldMainPh/oldPh"))
            {
                /* assign the name of the new placeholder;                    
                   if it is a nested placeholder in the 
                   main placeholder, we need to include it */
                newPlaceholder = "/newMainPh/newPh";
                
                /* assign the GUID of the new rendering; 
                   this has to exist in the new solution */
                newRenderingId = "<newRenderingID>";
            }

            if (string.IsNullOrEmpty(newPlaceholder) || 
                string.IsNullOrEmpty(newRenderingId))
            {
                continue;
            }

            /* create the new rendering definition and add 
               it to the current device definition */
            RenderingDefinition newRenderingDefinition = 
                new RenderingDefinition();
            newRenderingDefinition.ItemID = newRenderingId;
            newRenderingDefinition.Placeholder = newPlaceholder;
            newRenderingDefinition.Datasource = datasourceId;
            
            deviceDefinition.AddRendering(newRenderingDefinition);
        }                             
    }
}

/* update the presentation layer of the new page item 
   with the layout definition obtained above */
using (new SecurityDisabler())
{
    newPageItem.Editing.BeginEdit();
    layoutField.Value = layoutDefinition.ToXml();
    newPageItem.Editing.EndEdit();
}

The above code assumes we are working on a given page item, but we can iterate through all the page items where we need to make these changes. We also assumed that the migrated content items to the new solution keep the same IDs as in the old solution.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s