Editing layout details

I came across a Stack Overflow question recently, from someone who was interested in programatically changing settings in the Layout Details of Sitecore pages. While I knew a bit of the answer at the time (that I’d worked out while prototyping 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]


One thought on “Editing layout details

  1. And if you’re on Sitecore 8, the new Final Renderings field works the same way: it’s a versioned layout delta to the layout delta in the shared layout field, which is itself a layout delta to the standard values.

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