3

Working on a client's site and they have thousands of items with layout. In the layout of every page we have two renderings - Top Navigation, then Pinned Navigation. We made an architectural mistake early on by putting Top Navigation before Pinned Navigation. We need Pinned to be before Top. Usually, this would be pretty easy to fix, but there's a bit of background here.

As explained in a recent question I posted, the navigation renderings are set on a base page template, and there are other templates with custom shared layouts that inherit from Base Page. The reason why this can't be fixed easily? For some reason when I change the Base Page template, changes do not automatically carry forward to other page templates that inherit from it... and resetting standard values isn't an option as we set a custom shared layout on those templates standard values (I'm pretty sure resetting would break all pages that use that template, if not immediately, the next time someone resets layout on the page level).

So, I thought maybe a PowerShell script would be the answer, but the only way I can think of (updating the __Renderings field manually) didn't work. I literally reordered the XML in the field using Raw values, saved, and the reorder did not happen (when I open Presentation Details again).

Then I found another way, through Sitecore Search, if I enter a query and click Search Operations -> Apply presentation, I could theoretically apply the reordering of these two renderings to all pages, but every time I do that I get an error (even if the results I am trying to apply presentation to are all of the same template type):

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Exception: Can't start with unequal nodes at Sitecore.Xml.Patch.XmlDiffHelper.DoCompare(IXmlElement original, IXmlElement modified, IElementIdentification identification, IComparisonContext context) at Sitecore.Xml.Patch.XmlDiffHelper.Compare(XmlDocument original, XmlDocument modified, IElementIdentification id, XmlPatchNamespaces ns)

So I've literally run out of options and am looking for some way to do this. I suppose not using renderings for header navigation components (and just having Html.Partials in the layout file) might have been a better option from the beginning, but I really don't know.

P.S.: Just as I was about to submit this question, one possibility hit me (although it's a workaround): using a different placeholder for one and updating the placeholder references in the layout cshtml. However, I feel like it would be nice to actually know a real solution to this. So, the questions I would like answered are:

  1. Why does updating the Base Page template not update other page templates inheriting from it automatically? (I am updating SHARED layout only. I NEVER update final layout)
  2. Why does updating the __Renderings field through Raw values and saving not have any impact on the ordering of the renderings when opening Presentation Details?
  3. Why am I getting an error trying to apply presentation to multiple page items of the same template type and what does the error mean (researched the main error message, nothing found).
  • Can you provide an example PowerShell script you use to change the order for renderings on a single page? This is perhaps the most efficient way to solve the issue. – Michael West Jan 4 '19 at 3:26
  • @MichaelWest No PS script. I literally just tried moving the <r> element corresponding to Top Nav after the <r> element for Pinned Nav in the __Renderings field, using raw values, and saved the item. I didn't want to write a PS script if it didn't work as simple as that. Is something more needed to make the change? – Paul Jan 4 '19 at 3:30
7

The following example uses Sitecore PowerShell Extensions to change the order of two renderings. The renderings are next to each other, and essentially swap positions.

Script

# Home Page
$item = Get-Item -Path "master:" -ID "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}"

# All renderings on the final layout
$renderings = Get-Rendering -Item $item -FinalLayout
# Show a table
$renderings | Select-Object -Expand ItemId | 
    ForEach-Object { Get-Item -Path "master:" -ID $_ } | Format-Table -Property Name

# Rendering I want to move
$scriptRendering = $renderings | Where-Object { $_.ItemId -eq "{37F58448-7460-4AD2-B0FB-67C85C2A49CB}" } | Select-Object -First 1
# Rendering in the desired position
$googleRendering = $renderings | Where-Object { $_.ItemId -eq "{927F51FD-6A7B-4B7E-B692-1B4A0989228F}" } | Select-Object -First 1

# Find the desired position
$index = [array]::IndexOf($renderings, $googleRendering)
Set-Rendering -Item $item -Instance $scriptRendering -Index $index -FinalLayout

$renderings = Get-Rendering -Item $item -FinalLayout
# Show a table
$renderings | Select-Object -Expand ItemId | 
    ForEach-Object { Get-Item -Path "master:" -ID $_ } | Format-Table -Property Name

Output

Notice that the Script Rendering and Google Rendering swap positions.

Name
----
LinkedIn Share Button
Google Plus One Button
ScriptRendering
Tweet Button

Name
----
LinkedIn Share Button
ScriptRendering
Google Plus One Button
Tweet Button
  • Works like a charm! I'll mark it as the accepted answer, but if anyone has any info on questions #1 or #3, feel free to add a separate answer. – Paul Jan 4 '19 at 7:09
4

With regards to point 2, the raw XML for the Renderings field contains some information about the placement of the rendering in relation to other renderings. That is why moving the elements around will not have the desired effect.

There will be an attribute in the rendering XML element that has a value like:

p:before="r[@uid='{0731F384-B47A-4BEB-82F0-91C83E8A7FF4}']"

which defines where the rendering appears relative to the one referenced by the p:before UID.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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