Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save MartinMiles/d8dc3ac2c54e5b62836ee00e583d943a to your computer and use it in GitHub Desktop.
Save MartinMiles/d8dc3ac2c54e5b62836ee00e583d943a to your computer and use it in GitHub Desktop.
Used to help mapping rederings to the placeholders
param(
[string]$itemPath = "/sitecore/content/Zont/Habitat/Home/AAA"
)
Set-Location -Path $PSScriptRoot
$config = Get-Content -Raw -Path ./config.LOCAL.json | ConvertFrom-Json
# Write-Output "ConnectionUri: $($config.connectionUri)"
# Write-Output "Username : $($config.username)"
# Write-Output "SPE Remoting Secret : $($config.SPE_REMOTING_SECRET)"
# Write-Output "Get item fields of '$itemPath'..."
Import-Module -Name SPE
$session = New-ScriptSession -ConnectionUri $config.connectionUri -Username $config.username -SharedSecret $config.SPE_REMOTING_SECRET
Invoke-RemoteScript -Session $session -ScriptBlock {
# -----------------------------------------------
# Script: Export-PageLayoutHierarchyAsJson-Final-Minified.ps1
# Purpose: Produce nested JSON for “/sitecore/content/Zont/Habitat/Home/AAA”,
# with "uid" first, then "placeholders", and output minified JSON.
# -----------------------------------------------
# 1. MOUNT MASTER: PSDrive IF NOT ALREADY PRESENT
if (-not (Get-PSDrive -Name master -ErrorAction SilentlyContinue)) {
New-PSDrive -Name master -PSProvider Sitecore -Root "/" -Database "master" -ErrorAction Stop | Out-Null
}
# 2. GET MASTER DB & PAGE ITEM
$database = [Sitecore.Configuration.Factory]::GetDatabase("master")
if (-not $database) { return }
$pageItem = $database.GetItem($Using:itemPath)
if (-not $pageItem) { return }
# 3. IDENTIFY “DEFAULT” DEVICE (or fallback)
$allDevices = $database.Resources.Devices.GetAll()
if (-not $allDevices) { return }
$deviceItem = $allDevices | Where-Object { $_.Name -eq "Default" }
if (-not $deviceItem) { $deviceItem = $allDevices[0] }
# 4. GET ALL RENDERING REFERENCES (incl. inherited standard-values)
$renderingRefs = $pageItem.Visualization.GetRenderings($deviceItem, $true)
if (-not $renderingRefs) {
$emptyTree = @{
UID = $pageItem.ID.ToGuid().ToString("D")
placeholders = @()
}
($emptyTree | ConvertTo-Json -Depth 5) -replace "\s+", ""
return
}
# 5. COLLECT UNIQUE PLACEHOLDER PATHS (no leading slash)
$allPlaceholderPaths = $renderingRefs |
Where-Object { $_.Placeholder } |
ForEach-Object { $_.Placeholder.TrimStart("/") } |
Sort-Object -Unique
# 6. HELPER: Build placeholder object
function Build-PlaceholderObject {
param(
[string]$placeholderPath,
[Sitecore.Layouts.RenderingReference[]]$allRefs
)
$refsHere = $allRefs | Where-Object { $_.Placeholder.TrimStart("/") -ieq $placeholderPath }
$renderingNodes = @()
foreach ($ref in $refsHere) {
$renderingNodes += Build-RenderingObject -ref $ref -allPaths $allPlaceholderPaths -allRefs $allRefs
}
return @{
placeholder = $placeholderPath
renderings = $renderingNodes
}
}
# 7. HELPER: Build rendering object (uid first, then placeholders)
function Build-RenderingObject {
param(
[Sitecore.Layouts.RenderingReference]$ref,
[string[]]$allPaths,
[Sitecore.Layouts.RenderingReference[]]$allRefs
)
$renderingNode = [ordered]@{ uid = $ref.UniqueId.ToString() }
$ph = $ref.Placeholder.TrimStart("/")
$childKeys = @()
foreach ($candidate in $allPaths) {
if ($candidate -like "$ph/*") {
$relative = $candidate.Substring($ph.Length + 1)
$segment = $relative.Split("/")[0]
$childKey = "$ph/$segment"
if (-not ($childKeys -contains $childKey)) { $childKeys += $childKey }
}
}
if ($childKeys.Count -gt 0) {
$childPlaceholderObjects = @()
foreach ($child in $childKeys) {
$childPlaceholderObjects += Build-PlaceholderObject -placeholderPath $child -allRefs $allRefs
}
$renderingNode["placeholders"] = $childPlaceholderObjects
} else {
$renderingNode["placeholders"] = @()
}
return $renderingNode
}
# 8. TOP-LEVEL PLACEHOLDER KEYS (no "/")
$topLevelKeys = $allPlaceholderPaths | Where-Object { $_ -notlike "*/?*" }
# 9. BUILD TREE
$placeholderArray = @()
foreach ($top in $topLevelKeys) {
$placeholderArray += Build-PlaceholderObject -placeholderPath $top -allRefs $renderingRefs
}
# 10. WRAP WITH ROOT UID
$result = [ordered]@{
UID = $pageItem.ID.ToGuid().ToString("D")
placeholders = $placeholderArray
}
# 11. OUTPUT MINIFIED JSON
($result | ConvertTo-Json -Depth 10) -replace "\s+", ""
}
Stop-ScriptSession -Session $session
# -----------------------------------------------
# Script: Export-PageLayoutHierarchyAsJson-Final-Minified.ps1
# Purpose: Produce nested JSON for “/sitecore/content/Zont/Habitat/Home/AAA”,
# with "uid" first, then "placeholders", and output minified JSON.
# -----------------------------------------------
param(
[string]$PageItemPath = "/sitecore/content/Zont/Habitat/Home/AAA"
)
# 1. MOUNT MASTER: PSDrive IF NOT ALREADY PRESENT
if (-not (Get-PSDrive -Name master -ErrorAction SilentlyContinue)) {
New-PSDrive -Name master -PSProvider Sitecore -Root "/" -Database "master" -ErrorAction Stop | Out-Null
}
# 2. GET MASTER DB & PAGE ITEM
$database = [Sitecore.Configuration.Factory]::GetDatabase("master")
if (-not $database) { return }
$pageItem = $database.GetItem($PageItemPath)
if (-not $pageItem) { return }
# 3. IDENTIFY “DEFAULT” DEVICE (or fallback)
$allDevices = $database.Resources.Devices.GetAll()
if (-not $allDevices) { return }
$deviceItem = $allDevices | Where-Object { $_.Name -eq "Default" }
if (-not $deviceItem) { $deviceItem = $allDevices[0] }
# 4. GET ALL RENDERING REFERENCES (incl. inherited standard-values)
$renderingRefs = $pageItem.Visualization.GetRenderings($deviceItem, $true)
if (-not $renderingRefs) {
$emptyTree = @{
UID = $pageItem.ID.ToGuid().ToString("D")
placeholders = @()
}
($emptyTree | ConvertTo-Json -Depth 5) -replace "\s+", ""
return
}
# 5. COLLECT UNIQUE PLACEHOLDER PATHS (no leading slash)
$allPlaceholderPaths = $renderingRefs |
Where-Object { $_.Placeholder } |
ForEach-Object { $_.Placeholder.TrimStart("/") } |
Sort-Object -Unique
# 6. HELPER: Build placeholder object
function Build-PlaceholderObject {
param(
[string]$placeholderPath,
[Sitecore.Layouts.RenderingReference[]]$allRefs
)
$refsHere = $allRefs | Where-Object { $_.Placeholder.TrimStart("/") -ieq $placeholderPath }
$renderingNodes = @()
foreach ($ref in $refsHere) {
$renderingNodes += Build-RenderingObject -ref $ref -allPaths $allPlaceholderPaths -allRefs $allRefs
}
return @{
placeholder = $placeholderPath
renderings = $renderingNodes
}
}
# 7. HELPER: Build rendering object (uid first, then placeholders)
function Build-RenderingObject {
param(
[Sitecore.Layouts.RenderingReference]$ref,
[string[]]$allPaths,
[Sitecore.Layouts.RenderingReference[]]$allRefs
)
$renderingNode = [ordered]@{ uid = $ref.UniqueId.ToString() }
$ph = $ref.Placeholder.TrimStart("/")
$childKeys = @()
foreach ($candidate in $allPaths) {
if ($candidate -like "$ph/*") {
$relative = $candidate.Substring($ph.Length + 1)
$segment = $relative.Split("/")[0]
$childKey = "$ph/$segment"
if (-not ($childKeys -contains $childKey)) { $childKeys += $childKey }
}
}
if ($childKeys.Count -gt 0) {
$childPlaceholderObjects = @()
foreach ($child in $childKeys) {
$childPlaceholderObjects += Build-PlaceholderObject -placeholderPath $child -allRefs $allRefs
}
$renderingNode["placeholders"] = $childPlaceholderObjects
} else {
$renderingNode["placeholders"] = @()
}
return $renderingNode
}
# 8. TOP-LEVEL PLACEHOLDER KEYS (no "/")
$topLevelKeys = $allPlaceholderPaths | Where-Object { $_ -notlike "*/?*" }
# 9. BUILD TREE
$placeholderArray = @()
foreach ($top in $topLevelKeys) {
$placeholderArray += Build-PlaceholderObject -placeholderPath $top -allRefs $renderingRefs
}
# 10. WRAP WITH ROOT UID
$result = [ordered]@{
UID = $pageItem.ID.ToGuid().ToString("D")
placeholders = $placeholderArray
}
# 11. OUTPUT MINIFIED JSON
($result | ConvertTo-Json -Depth 10) -replace "\s+", ""
Write a SPE (Sitecore PowerShell Extensions) script that does the following, exactly as described:
1. Mount the “master” PSDrive if it doesn’t already exist.
2. Load the master database and retrieve the item at `/sitecore/content/Zont/Habitat/Home/AAA`. If the database or item can’t be found, exit quietly.
3. Identify the “Default” device under `/sitecore/layout/Devices`. If no device named “Default” exists, fall back to the first device in the list.
4. Call `GetRenderings($deviceItem, $true)` on the page item’s `Visualization` property so that you get all `RenderingReference` objects—including any inherited from standard values.
5. Build a nested JSON structure with this exact format:
{
"UID": "<page-item-guid-without-braces>",
"placeholders": [
{
"placeholder": "<full-placeholder-path>",
"renderings": [
{
"uid": "{<rendering-uid>}",
"placeholders": [
{
"placeholder": "<child-placeholder-path>",
"renderings": [
{ "uid": "{<child-rendering-uid>}" },
]
},
]
},
]
},
]
}
- Top‐level key `"UID"` must be the page item’s GUID (no braces, standard “D” format).
- Under `"placeholders"`, list each unique placeholder path (no leading slash) that appears in any `RenderingReference.Placeholder`. For example, `"headless-main"`, `"footer"`, etc.
- For each placeholder object:
- Create a `"renderings"` array containing one object per rendering whose `Placeholder` equals exactly that path.
- Each rendering object must list `"uid"` first (the rendering’s GUID, with braces) and then `"placeholders"`.
- Determine child placeholders by finding any placeholder path that begins with `"<this-placeholder>/"`, stripping off the parent prefix, taking the next segment, and reconstructing the full child path. Recursively build placeholder objects under each rendering object in the same format.
- Ensure that even if a rendering has no children, it still has a `"placeholders": []` key after its `"uid"`.
6. Output the final JSON as a single minified string (no spaces, tabs, or line breaks) by piping the result of `ConvertTo-Json -Depth 10` into a regex replacement that removes all `\s+`.
7. Use ordered hashtables (`[ordered]@{ ... }`) whenever you need to guarantee that `"uid"` appears before `"placeholders"` in each rendering object, and that `"UID"` appears before `"placeholders"` at the root.
8. If there are no renderings at all (e.g. `GetRenderings()` returned zero), output a JSON object with `"UID"` set to the page item’s GUID and `"placeholders": []`, also minified.
The final script should be copy-and-paste–ready in Sitecore PowerShell ISE.
@MartinMiles
Copy link
Author

image
image

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