Last active
June 3, 2025 06:59
-
-
Save MartinMiles/baca6f87af475c8508a4c6374db78683 to your computer and use it in GitHub Desktop.
Sets Layout item for the page's presentation details (on a shared layout field) without modifying/resetting the rest of presentation/renderings
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| param( | |
| [string]$PageItemPath = "/sitecore/content/Zont/Habitat/Home/AAA", | |
| [string]$LayoutItemPath = "/sitecore/layout/Layouts/Foundation/JSS Experience Accelerator/Presentation/JSS Layout" | |
| ) | |
| # 1. Mount "master:" drive if missing | |
| if (-not (Get-PSDrive -Name master -ErrorAction SilentlyContinue)) { | |
| try { | |
| New-PSDrive -Name master -PSProvider Sitecore -Root "/" -Database "master" -ErrorAction Stop | Out-Null | |
| Write-Host "📁 Mounted master: drive." | |
| } | |
| catch { | |
| Write-Host "❌ Could not mount master: $_.Exception.Message" | |
| return | |
| } | |
| } | |
| # 2. Get master database | |
| $db = [Sitecore.Configuration.Factory]::GetDatabase("master") | |
| if ($null -eq $db) { | |
| Write-Host "❌ Unable to retrieve master database." | |
| return | |
| } | |
| # 3. Load the page item | |
| $pageItem = Get-Item -Path ("master:" + $PageItemPath) -ErrorAction SilentlyContinue | |
| if ($null -eq $pageItem) { | |
| Write-Host "❌ Page item not found at: master:$PageItemPath" | |
| return | |
| } | |
| # 4. Load the layout item | |
| $layoutItem = Get-Item -Path ("master:" + $LayoutItemPath) -ErrorAction SilentlyContinue | |
| if ($null -eq $layoutItem) { | |
| Write-Host "❌ Layout item not found at: master:$LayoutItemPath" | |
| return | |
| } | |
| # 5. Read existing __Renderings XML | |
| $existingXml = $pageItem.Fields[[Sitecore.FieldIDs]::LayoutField].Value | |
| # 6. Parse (or create) XmlDocument for <r>...</r> | |
| [xml]$xmlDoc = $null | |
| if ([string]::IsNullOrWhiteSpace($existingXml)) { | |
| # No current Shared Layout → new <r> root | |
| $xmlDoc = New-Object System.Xml.XmlDocument | |
| $root = $xmlDoc.CreateElement("r") | |
| # Add namespace declarations exactly as Sitecore expects | |
| $root.SetAttribute("xmlns:p", "p") | |
| $root.SetAttribute("xmlns:s", "s") | |
| $root.SetAttribute("p:p", "1") | |
| $xmlDoc.AppendChild($root) | Out-Null | |
| } | |
| else { | |
| try { | |
| $xmlDoc = New-Object System.Xml.XmlDocument | |
| $xmlDoc.LoadXml($existingXml) | |
| } | |
| catch { | |
| Write-Host "❌ Failed to parse existing __Renderings XML: $_.Exception.Message" | |
| return | |
| } | |
| } | |
| # 7. Grab namespace URIs from the root (<r>) element | |
| $root = $xmlDoc.DocumentElement | |
| # Typically these return "p" and "s" | |
| $nsP = $root.GetNamespaceOfPrefix("p") | |
| $nsS = $root.GetNamespaceOfPrefix("s") | |
| # 8. Find the single <d> under <r> | |
| # (This is the device node where your renderings live.) | |
| $dNode = $xmlDoc.SelectSingleNode("/r/d") | |
| if ($null -eq $dNode) { | |
| Write-Host "❌ No <d> device node found under <r> in Shared Layout. Cannot update layout." | |
| return | |
| } | |
| # 9. Compute the new layout GUID (uppercase, with braces) | |
| $layoutGuid = $layoutItem.ID.Guid.ToString("B").ToUpper() | |
| # 10. Set or overwrite the "s:l" attribute on <d> to point to our new layout | |
| # (This leaves all child <r>… elements intact.) | |
| $dNode.SetAttribute("l", $nsS, $layoutGuid) | |
| # 11. Also add "p:before"="*" so that Sitecore knows to insert this layout before existing renderings | |
| $dNode.SetAttribute("before", $nsP, "*") | |
| # 12. Ensure that <r> root still has the correct namespace declarations and p:p="1" | |
| # (If they were missing initially, we already added them in step 6.) | |
| # 13. Serialize back to a string | |
| $updatedXml = $root.OuterXml | |
| # 14. Write back into the __Renderings field (Shared Layout) | |
| try { | |
| $pageItem.Editing.BeginEdit() | |
| $pageItem.Fields[[Sitecore.FieldIDs]::LayoutField].Value = $updatedXml | |
| $pageItem.Editing.EndEdit() | |
| Write-Host "✅ Shared Layout updated successfully." | |
| Write-Host " Page: master:$PageItemPath (ID: $($pageItem.ID))" | |
| Write-Host " Layout: master:$LayoutItemPath (ID: $($layoutItem.ID))" | |
| } | |
| catch { | |
| if ($pageItem -and $pageItem.Editing.IsEditing) { | |
| $pageItem.Editing.CancelEdit() | |
| } | |
| Write-Host "❌ Error writing Shared Layout: $_.Exception.Message" | |
| throw | |
| } | |
| # 15. Verification: print out new __Renderings XML so you can confirm it kept your child <r> nodes | |
| Write-Host "`n🔍 New __Renderings content (Shared Layout):" | |
| Write-Host $updatedXml |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| You are a world-renowned Sitecore XM Cloud scripting expert. Generate a Sitecore PowerShell Extensions (SPE) script that does exactly the following, preserving every nuance: | |
| 1. **Parameter defaults** | |
| - At the top, include: | |
| ```powershell | |
| param( | |
| [string]$PageItemPath = "/sitecore/content/Zont/Habitat/Home/AAA", | |
| [string]$LayoutItemPath = "/sitecore/layout/Layouts/Foundation/JSS Experience Accelerator/Presentation/JSS Layout" | |
| ) | |
| ``` | |
| - These are the default paths to: | |
| - The page item whose Shared Layout must be updated. | |
| - The layout definition item to assign. | |
| 2. **Mount and database retrieval** | |
| - If the “master:” PSDrive is not already mounted, create it using: | |
| ```powershell | |
| New-PSDrive -Name master -PSProvider Sitecore -Root "/" -Database "master" -ErrorAction Stop | Out-Null | |
| ``` | |
| - Retrieve the master database with: | |
| ```powershell | |
| $db = [Sitecore.Configuration.Factory]::GetDatabase("master") | |
| ``` | |
| - If mounting or getting the database fails, write a clear `Write-Host` error and `return`. | |
| 3. **Item lookups** | |
| - Load the page item: | |
| ```powershell | |
| $pageItem = Get-Item -Path ("master:" + $PageItemPath) -ErrorAction SilentlyContinue | |
| ``` | |
| If `$pageItem` is `$null`, write an error and `return`. | |
| - Load the layout item: | |
| ```powershell | |
| $layoutItem = Get-Item -Path ("master:" + $LayoutItemPath) -ErrorAction SilentlyContinue | |
| ``` | |
| If `$layoutItem` is `$null`, write an error and `return`. | |
| 4. **Read existing Shared Layout XML** | |
| - Read the raw `__Renderings` field: | |
| ```powershell | |
| $existingXml = $pageItem.Fields[[Sitecore.FieldIDs]::LayoutField].Value | |
| ``` | |
| - Initialize an `XmlDocument`: | |
| - If `$existingXml` is empty or whitespace, create a new `<r>` root element with exactly these attributes: | |
| ```xml | |
| <r xmlns:p="p" xmlns:s="s" p:p="1"></r> | |
| ``` | |
| - Otherwise, load `$existingXml` into `XmlDocument`. If parsing fails, write an error and `return`. | |
| 5. **Preserve existing child `<r uid="…">…</r>` nodes inside `<d>`** | |
| - Under the root `<r>`, locate the single `<d>` element (device node). If none exists, write an error and `return`. | |
| - Do **not** recreate or remove any child `<r uid="…"><p:d/></r>` nodes—leave them untouched. | |
| - The `<d>` element’s `id` is the Default device GUID `{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}`. | |
| 6. **Update that `<d>` node** | |
| - Compute the uppercase GUID of the layout item: | |
| ```powershell | |
| $layoutGuid = $layoutItem.ID.Guid.ToString("B").ToUpper() | |
| ``` | |
| - Set or overwrite the `s:l` attribute on `<d>` (using the “s” namespace) to `$layoutGuid`. | |
| - Also set `p:before="*"` on `<d>` (using the “p” namespace). | |
| - Do **not** touch any other attributes or nested elements. | |
| 7. **Ensure namespace declarations remain** | |
| - If you created a brand-new `<r>` root, add attributes: | |
| ``` | |
| xmlns:p="p" xmlns:s="s" p:p="1" | |
| ``` | |
| - If loading existing XML, do not remove or alter any other attributes or child elements in `<r>`—only update `<d>`. | |
| 8. **Serialize and save** | |
| - Serialize **only** the `<r>…</r>` node’s `OuterXml` into a string. | |
| - Write that string back into the `__Renderings` field: | |
| ```powershell | |
| $pageItem.Editing.BeginEdit() | |
| $pageItem.Fields[[Sitecore.FieldIDs]::LayoutField].Value = $updatedXml | |
| $pageItem.Editing.EndEdit() | |
| ``` | |
| - If editing fails, cancel the edit and re-throw the exception. | |
| 9. **Confirm and report** | |
| - After saving, output via `Write-Host` a success message including both item paths and IDs. | |
| - Then print the new `__Renderings` XML so the user can verify it contains: | |
| - The `<r xmlns:p="p" xmlns:s="s" p:p="1">` root. | |
| - A single `<d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}" p:before="*" s:l="{YourLayoutGUID}">` element. | |
| - All original `<r uid="…"><p:d/></r>` child nodes preserved exactly. | |
| Your script must run without errors, respect any renderings already removed from standard values, update only the Shared Layout’s `<d>` node, and leave everything else unchanged. |
Author
MartinMiles
commented
Jun 3, 2025

Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment