Solid, Liquid, Gas – Three states of Layout Details

I will take another break from the series about YouTube Video Picker Field (part 1, part 2) to talk some more about Layout Details. I briefly mentioned it when I blogged about cascading MVC renderings and now I want to dig in deeper.

Solid

The dehydrated state of Layout Details (a.k.a Presentation Details, a.k.a __Rendering) is XML.

    var solid = item.Fields[FieldIDs.LayoutField].Value ;

This is how Sitecore stores it int the __Rendering field of an item:

<r xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}" 
       l="{4CA7478E-6184-4890-9072-1156DB468A1B}"/>

    <d id="{EF7176AE-2502-401A-96C0-1E9918A982F7}" 
       l="{4CA7478E-6184-4890-9072-1156DB468A1B}"/>

    <d id="{5A6E7DC3-987F-4E74-AF78-AC0E544975F2}" 
       l="{4CA7478E-6184-4890-9072-1156DB468A1B}"/>
</r>

If your item’s data template doesn’t have standard values (and it probably should but that’s another blog post) the solid state of the item’s presentation will be a full layout. If you, however, define the skeleton presentation on the template’s standard values (or just create standard values item for that matter) your page item will have a delta:

<r p:p="1" xmlns:p="p" xmlns:s="s">
    <d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}">
        <r p:before="r[@uid='{5A60B548-962A-42F5-ADA9-EB1D098B4892}']" 
           s:ds="{703BAA83-8F36-4DC1-9FE4-84B9E58E5C42}" 
           s:id="{32E1B55D-1D01-42A1-8BAD-8663160922DF}" 
           s:ph="Content Main" 
           uid="{385CCCC4-46F3-44C4-B110-9FD7E6F8BEC5}"/>

        <r s:ds="{703BAA83-8F36-4DC1-9FE4-84B9E58E5C42}" 
           s:id="{32E1B55D-1D01-42A1-8BAD-8663160922DF}" 
           s:ph="/Content Main/Basic Test" 
           uid="{5A60B548-962A-42F5-ADA9-EB1D098B4892}"/>
    </d>
</r>

Look into LayoutField.GetFieldValue(), Sitecore.Data.Fields.XmlDeltas, and Sitecore.Xml.Patch.* to see how Sitecore does it internally. The important thing to note is that when you ask an item for item[FieldIds.LayoutDetails].Value you get a full representation – Sitecore will merge the delta in as needed. It will also separate out the delta to store in the item’s field on save so you don’t have to worry about it.

Your code will always operate on the full layout unless you make it work on the delta.

Liquid

The hydrated state of Layout Details is represented by the Sitecore.Layouts.LayoutDefinition class.

    var liquid = LayoutDefinition.Parse(solid);

    var solidified = liquid.ToXml();    

You will encounter LayoutDefinition instances a lot across Sitecore’s rendering pipelines. That said, MVC rendering pipelines prefer to work on the bare metal and pass around XElement representation of the solid state.

Gas

I find this state of layout details the most fascinating of all. When you edit content in the Page Editor you modify item’s field values. When you design your pages in Page Editor you modify presentation details:

{
  "r": {
    "@xmlns:xsd": "http://www.w3.org/2001/XMLSchema",
    "d": [
      {
        "@id": "{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}",
        "@l": "{4CA7478E-6184-4890-9072-1156DB468A1B}"
      },
      {
        "@id": "{EF7176AE-2502-401A-96C0-1E9918A982F7}",
        "@l": "{4CA7478E-6184-4890-9072-1156DB468A1B}"
      },
      {
        "@id": "{5A6E7DC3-987F-4E74-AF78-AC0E544975F2}",
        "@l": "{4CA7478E-6184-4890-9072-1156DB468A1B}"
      }
    ]
  }
}

It’s JSON. Try $sc('#scLayout').val() in the JS console when in Page Editor. Look closer. This JSON represents a full layout and is a direct result of:

    // using Newtonsoft.Json; 

    var doc = new XmlDocument(); 
    doc.LoadXml(solid);

    var gas =  JsonConvert.SerializeXmlNode(doc);

    var solidified = JsonConvert.DeserializeXmlNode(gas).OuterXml;  

When you assign renderings to placeholders or move them in or out, Sitecore keeps track of it in the #scLayout. The easiest way to observe it as it happens is to set a breakpoint on:

Sitecore.LayoutDefinition.setLayoutDefinition = function(layoutDefinition) {
  // ...
  if ($sc("#scLayout").val() != newValue) {
    $sc("#scLayout").val(newValue);
    Sitecore.PageModes.PageEditor.setModified(true);
  }
};

The modified gas form will be solidified and stored in the item’s __Rendering field when you save your changes.

    
// snippet that looks into what fields have changed on [item:saved]

var changes = Event.ExtractParameter(args, 1) as ItemChanges;

if (changes.FieldChanges.ContainsAnyOf(FieldIDs.LayoutField)) {
    FieldChange change = changes.FieldChanges[FieldIDs.LayoutField];

    string before = change.OriginalValue;
    string now = change.Value;

    // ...
}

Thoughts

I found it very convinient to grab the JSON state from the client side and either hydrate it or transform directly to solid XML for my test data. With dynamic placeholders, component based architectures, and variations of complex layouts you will likely find yourself writing extra handlers and processors to help Sitecore understand it. Unit testing that code is crucial and I hope you will find JSON representation of the layout details very accessible and handy.

Pavel Veller

Add a Comment

Your email address will not be published. Required fields are marked *

Or request call back