Jeremy Davis
Jeremy Davis
Sitecore, C# and web development
Article printed from: https://blog.jermdavis.dev/posts/2015/editing-layout-details

Editing layout details

Published 20 July 2015
Updated 25 August 2016

I came across a Sitemap generation code), the idea interested me enough to do a bit more research into the topic, and try to work out the details.

So here's some notes on the hows and whys of using code to change layout details. (I'm working on Sitecore 6.6 here, but this information is relevant to many versions of Sitecore)

How are Layout Details stored

The information describing the presentation to use for an item is stored in the __Renderings field on each item. The field stores a blob of XML that describes presentation the settings. However, on the "page" item you don't necessarily see all of the data, as Sitecore uses what it calls "Layout Deltas" – the layout information on a page stores only the changes to the layout data on the Template Standard Values for the item.

You can view the layout details by enabling both the "Standard Fields" and "Raw Values" view of an item in Content Editor, and then looking at the Renderings field in the Layout region:

View Layout Details

Loading the Layout Details

To read meaningful data from the Renderings field, you have to take into account the Layout Delta behaviour. The XML in the Renderings field for a particular item is not necessarily all the data you need to process. Hence you need to make sure you use the correct Sitecore classes to read this data. To extract the full XML, you can use:

var page = Sitecore.Context.Database.GetItem("/sitecore/content/Home");
var field = page.Fields[Sitecore.FieldIDs.LayoutField];
string xml = LayoutField.GetFieldValue(field);

					

First we load a page, and then extract the Renderings field from it. The constant Sitecore.FieldIDs.LayoutField represents the name of the correct field. Finally the LayoutField class provides the GetFieldValue() method, which knows how to extract the data correctly.

If you look inside the code for this, GetFieldValue() uses another class called XmlDeltas to deal with the process of managing the deltas.

Once you have the XML, you have two choices about how to work with it. You could just manipulate the XML manually if you wanted. However the more supportable approach (which I'm interested here) is to use the API objects that Sitecore provides. And the class LayoutDefinitions manages this for us, and provides a method to parse the XML into objects:

var details = Sitecore.Layouts.LayoutDefinition.Parse(xml);

					

Modifying the Layout Details

To access and modify the data in your LayoutDefinition you need to navigate the structure of the object. It represents a similar model to that which you see in the Layout Details dialog:

Layout Details

So in the same way this bit of UI shows, you start traversing these objects by finding the appropriate Device. You can either iterate them:

foreach(DeviceDefinition device in details.Devices)
{
    // do something with device
}

					

or you can find a specific one by ID (The ID is the GUID of the Device item under /sitecore/layout/Devices):

var device = details.GetDevice("{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}");

					

Each of these devices then includes a series of Rendering Definitions - the things which need to be displayed when this device is being used. Again you can either iterate these, or extract specific ones. To iterate through the things that will be rendered, you can:

foreach(RenderingDefinition rendering in device.Renderings)
{
    // do something with a rendering
}

					

Each of these renderings have properties for things like the Datasource, the cache settings etc. They also have a unique ID for each individual rendering, as well as the ID of the Rendering / Sublayout that is being used for presentation. You can fetch specific renderings with:

RenderingDefinition r = device.GetRenderingByUniqueId("{43222D12-08C9-453B-AE96-D406EBB95126}");

					

(I don't believe these IDs are presented in the UI anywhere – so they make most sense in combination with iterating the collection)

Alternatively you can fetch by the UI component's ID. If you want to find exactly one rendering definition based on a specific control ID you can call:

RenderingDefinition r = device.GetRendering("{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}");

					

or if you expect to get back more than one rendering definition based on a specific component you could call:

foreach(RenderingDefinition r = device.GetRenderings("{43222D12-08C9-453B-AE96-D406EBB95126}"))
{
    // do something with a rendering
}

					

In all of these cases, you can then update the RenderingDefinition object's properties in the usual way. For example, if you wanted to set a data source:

RenderingDefinition r = device.GetRenderingByUniqueId("{43222D12-08C9-453B-AE96-D406EBB95126}");
r.Datasource = "/somewhere/thing/stuff";

					

You can also create new Rendering Definitions and add them to the Device object, or remove Rendering Definitions from the device using the device.AddRendering() and device.Renderings.Remove() methods.

Saving the Layout Details

After you've made your changes you need to save your data. As above, you need to ensure that you deal with the fact that you're saving a Layout Delta. And again this is done via the LayoutField class. For example:

string newXml = details.ToXml();
var field = page.Fields[Sitecore.FieldIDs.LayoutField];

using (new Sitecore.Data.Items.EditContext(page))
{
    LayoutField.SetFieldValue(field, newXml);
}

					

The Layout Details object knows how to serialise itself to XML via the ToXml() method, but we need to use the LayoutField.SetFieldValue() method to store this data to ensure that we save a delta rather than the whole layout definition.

[NB: After I wrote this, I realised that John West had already posted some of this detail on his blog. So if you're interested in his take on this, you may wish to read that post as well]

↑ Back to top