I have written a PowerShell script that replaces sublayouts with renderings across all pages in a Sitecore site. Everything is working well except for the order of the renderings. The order always follows the order of the sublayouts in the page layout not the actual order seen in Experience Editor.

Does anyone know how I can get the order of the sublayouts and then apply that to the new renderings?

I read that the rendering 'index' can be used to get and set the order but when I run this script on a page the index always returns as null for all renderings:

$device = Get-LayoutDevice -Default
$database = "master" #master|web
$path = "$($database):/sitecore/content/home"
$item = Get-Item -Path $path

$finalRenderings = @(Get-Rendering -Item $item -FinalLayout -Device $defaultDevice)

foreach($rendering in $finalRenderings) {
    Write-Host "Rendering Placeholder: " $rendering.Placeholder
    Write-Host "Rendering Index: " $rendering.Index

    $renderingItem = Get-Item $rendering.ItemID
    Write-Host "Rendering Name: " $renderingItem.DisplayName
}

Exploring the commands Get-Rendering and Set-Rendering I found out this:

  • The index of the renderings in the raw xml matches the ordered when calling Get-Rendering. Perhaps the "index" information you need is in the ordering of the $finalRenderings variable.
  • The Set-Rendering command has a parameter to insert at a specific index.

I would recommend you try these two things:

  1. View the result of the Final Layout xml and field make note of the order of the uid and p:after= tags.
  2. Compare the order of #1 with the output of Get-Rendering.

Does the order of p:after= tags reflect the order you expect in the Experience Editor?

Example: List the renderings and compare with the raw xml. The uid order is the same.

$device = Get-LayoutDevice -Default
$item = Get-Item -Path "master:" -ID "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}"

$finalRenderings = @(Get-Rendering -Item $item -FinalLayout -Device $defaultDevice)

foreach($rendering in $finalRenderings) {
    Write-Host "Rendering UniqueId: " $rendering.UniqueId
}

$finalLayoutField = $item.Fields[[Sitecore.FieldIDs]::FinalLayoutField]
[Sitecore.Data.Fields.LayoutField]::GetFieldValue($finalLayoutField)
Rendering UniqueId:  {43222D12-08C9-453B-AE96-D406EBB95126}
Rendering UniqueId:  {CF044AD9-0332-407A-ABDE-587214A2C808}
Rendering UniqueId:  {B343725A-3A93-446E-A9C8-3A2CBD3DB489}
<?xml version="1.0" encoding="UTF-8"?>
<r xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}" l="{14030E9F-CE92-49C6-AD87-7D49B50E42EA}">
      <r ds="" id="{885B8314-7D8C-4CBB-8000-01421EA8F406}" par="" ph="main" uid="{43222D12-08C9-453B-AE96-D406EBB95126}" />
      <r ds="" id="{CE4ADCFB-7990-4980-83FB-A00C1E3673DB}" par="" ph="/main/centercolumn" uid="{CF044AD9-0332-407A-ABDE-587214A2C808}" />
      <r ds="" id="{493B3A83-0FA7-4484-8FC9-4680991CF743}" par="" ph="/main/centercolumn/content" uid="{B343725A-3A93-446E-A9C8-3A2CBD3DB489}" />
   </d>
   <d id="{46D2F427-4CE5-4E1F-BA10-EF3636F43534}" l="{14030E9F-CE92-49C6-AD87-7D49B50E42EA}">
      <r ds="" id="{493B3A83-0FA7-4484-8FC9-4680991CF743}" par="" ph="content" uid="{A08C9132-DBD1-474F-A2C A-6CA26A4AA650}" />
   </d>
</r>

Index isn't a property of the rendering definition object returned by Get-Rendering , even though you can use -Index as a parameter in Add-Rendering .

Using

$(Get-Rendering -Item $item -FinalLayout -Device $defaultDevice)[0] | Get-Member 

lists these:

TypeName: Sitecore.Layouts.RenderingDefinition

Name                MemberType     Definition
----                ----------     ----------
Equals              Method         bool Equals(System.Object obj)
GetHashCode         Method         int GetHashCode()
GetType             Method         type GetType()
LoadXml             Method         Sitecore.Xml.Serialization.XmlSerializable LoadXml(string xml), Sitecore.Xml.Serialization.XmlSerializable LoadXml(string xml, string xsltFilename)
SaveAsXml           Method         void SaveAsXml(string filename)
ToString            Method         string ToString()
ToXml               Method         string ToXml(), string ToXml(string xsltFilename)
Cachable            Property       string Cachable {get;set;}
ClearOnIndexUpdate  Property       string ClearOnIndexUpdate {get;set;}
Conditions          Property       string Conditions {get;set;}
Datasource          Property       string Datasource {get;set;}
DynamicProperties   Property       System.Xml.XmlAttribute[] DynamicProperties {get;set;}
ItemID              Property       string ItemID {get;set;}
MultiVariateTest    Property       string MultiVariateTest {get;set;}
Parameters          Property       string Parameters {get;set;}
PersonalizationTest Property       string PersonalizationTest {get;set;}
Placeholder         Property       string Placeholder {get;set;}
Rules               Property       System.Xml.Linq.XElement Rules {get;set;}
UniqueId            Property       string UniqueId {get;set;}
VaryByData          Property       string VaryByData {get;set;}
VaryByDevice        Property       string VaryByDevice {get;set;}
VaryByLogin         Property       string VaryByLogin {get;set;}
VaryByParameters    Property       string VaryByParameters {get;set;}
VaryByQueryString   Property       string VaryByQueryString {get;set;}
VaryByUser          Property       string VaryByUser {get;set;}
OwnerItemId         ScriptProperty System.Object OwnerItemId {get='{{20C2E00A-D359-420A-8E05-919CEE9EC686}}';}
OwnerItemPath       ScriptProperty System.Object OwnerItemPath {get="master:\content\Path\To\Your\Owner\Item";}

So you will need to run through the renderings returned with Get-Rendering and count them, until you reach the rendering before where you want to insert.

Incidentally, reading the renderings into an array in your script is unecessary:

$finalRenderings = @(Get-Rendering -Item $item -FinalLayout -Device $defaultDevice)

Powershell always returns a single object or a collection. You can replace this with:

$finalRenderings = Get-Rendering -Item $item -FinalLayout -Device $defaultDevice

You can also pipe that directly into a ForEach-Object and use the current object shorthand $_

$finalRenderings | ForEach-Object {
Write-Host "Rendering UniqueId: " $_.UniqueId
}

So if you know the ItemID of the rendering you want to insert after:

$i=0
$matchID = "ID To Match"
$finalRenderings | ForEach-Object {
    $i++
    if($_.ItemID -eq $matchID) {
        $MyIndex = i
        Break
    }
 }

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.