LibrarySites.Banner

Programmatically Update Layout Details with the Sitecore ASP.NET CMS

The How to programmatically change settings listed under the presentation tab (eg, Layout Details) thread on the Sitecore Developer Network (SDNforums prompted me to write this blog post about updating layout details using the Sitecore ASP.NET CMS.

Layout details specify the layouts, sublayouts and renderings to use for various types of device archetypes that access a web site built with Sitecore. For more information about layout details, layouts, sublayouts, renderings and devices, see the Presentation Component Reference on SDN.

Sitecore manages layout details as an XML value in the __Renderings field (*NOT* the legacy __Renderers field) in the Layout section defined by the standard template (Sitecore.FieldIDs.LayoutField). For more information about the standard template, see the Data Definition Reference on SDN.

Because layout details reference layouts, sublayouts, and renderings by GUID, you might be able to perform your update with a simple search and replace:

Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase("master"); 
Sitecore.Data.Items.Item item = master.GetItem("/sitecore/content/home"); 
  
if (item.Fields[Sitecore.FieldIDs.LayoutField].ContainsStandardValue 
  && item.Template.StandardValues != null) 
{ 
  item = item.Template.StandardValues; 
} 
  
string xml = item[Sitecore.FieldIDs.LayoutField]; 
const string replaceThis = "{828ADAAC-D040-484C-8634-CA9CDF51C510}"; 
const string withThat = "{DC7AD9D7-62E6-4F5C-B0EF-91103622B4B0}"; 
  
if (xml.Contains(replaceThis)) 
{ 
  using (new Sitecore.Data.Items.EditContext(item)) 
  { 
    item[Sitecore.FieldIDs.LayoutField] = xml.Replace(replaceThis, withThat); 
  } 
}

Otherwise, you can use the the Sitecore.Layouts.LayoutDefinition class and the classes that it exposes (thanks again to @techphoria414 for the original code in the SDN forum thread Data Source as GUID vs Path):

Sitecore.Layouts.LayoutDefinition layout = 
  Sitecore.Layouts.LayoutDefinition.Parse(item[Sitecore.FieldIDs.LayoutField]); 
bool updated = false; 
  
for (int i = 0; i < layout.Devices.Count; i++) 
{ 
  Sitecore.Layouts.DeviceDefinition device = 
    layout.Devices[i] as Sitecore.Layouts.DeviceDefinition; 
  
  if (device != null && device.Layout == replaceThis) 
  { 
    device.Layout = withThat; 
    updated = true; 
  } 
  
  for (int j = 0; j < device.Renderings.Count; j++) 
  { 
    Sitecore.Layouts.RenderingDefinition rendering =  
      device.Renderings[j] as Sitecore.Layouts.RenderingDefinition; 
  
    if (rendering != null && rendering.ItemID == replaceThis) 
    { 
      rendering.ItemID = withThat; 
      updated = true; 
    } 
  } 
} 
  
if (updated) 
{ 
  using (new Sitecore.Data.Items.EditContext(item)) 
  { 
    item[Sitecore.FieldIDs.LayoutField] = layout.ToXml(); 
  } 
}

As Nick notes in the first forum thread referenced, and as I failed to do in my speculative response on that thread, be sure to save the XML back to the item.

Note that this code runs in the security context of the context user and does not include any error control. Also note that updating standard values is specifically complicated by layout standard values, clones, and layout deltas. At the very least, you might want to refer to update item.Template.StandardValues rather than items under /sitecore/content. For more information about standard values, see the Data Definition Reference on SDN. For more information about clones, see my blog post Sitecore CMS 6.4 Cloning. For more information about layout deltas, see the Presentation Component Reference on SDN and Adam Conn's blog post Layout Deltas What Ifs.