Last active
June 15, 2025 08:41
-
-
Save MartinMiles/d927b7a3556b9f645417cb8aa6720e7b to your computer and use it in GitHub Desktop.
Processes all the rendering for a page and rebinds a top level component from one to another (say, from `page-layout` to `headless-main`) including those nested
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
# ----------------------------------------------------------- | |
# Inline Script for Sitecore PowerShell ISE: | |
# Replace Multiple Placeholders for Renderings | |
# Target Item: Default is /sitecore/content/Zont/Habitat/Home/AAA | |
# DB: master | |
# - Processes Standard Values, Shared Layout, and Final Layout. | |
# - Replaces three placeholder pairs: | |
# $OldPlaceholder1 → $NewPlaceholder1 | |
# $OldPlaceholder2 → $NewPlaceholder2 | |
# $OldPlaceholder3 → $NewPlaceholder3 | |
# - Logs every change to the console. | |
# ----------------------------------------------------------- | |
param( | |
[string] $PageItemPath = "/sitecore/content/Zont/Habitat/Home/AAA", | |
[string] $OldPlaceholder1 = "page-layout", | |
[string] $NewPlaceholder1 = "headless-main", | |
[string] $OldPlaceholder2 = "header-top", | |
[string] $NewPlaceholder2 = "headless-header", | |
[string] $OldPlaceholder3 = "footer", | |
[string] $NewPlaceholder3 = "headless-footer" | |
) | |
# 1) Ensure master: PSDrive is mounted | |
if (-not (Get-PSDrive -Name master -ErrorAction SilentlyContinue)) { | |
New-PSDrive -Name master -PSProvider Sitecore -Root "/" -Database "master" -ErrorAction Stop | Out-Null | |
} | |
# 2) Get the master database and the page item | |
$db = [Sitecore.Configuration.Factory]::GetDatabase("master") | |
$item = $db.GetItem($PageItemPath) | |
if ($null -eq $item) { | |
Write-Error "Item not found at path: $PageItemPath" | |
return | |
} | |
# 3) Prepare an ArrayList for logging | |
$script:logEntries = New-Object System.Collections.ArrayList | |
# 4) Function to replace placeholders in a raw layout XML | |
function Replace-PlaceholdersInLayout { | |
param( | |
[string] $layoutXml, | |
[string] $contextItemID, | |
[string] $contextName, | |
[string] $languageName | |
) | |
$layoutDef = [Sitecore.Layouts.LayoutDefinition]::Parse($layoutXml) | |
$changed = $false | |
# Build mapping array from parameters | |
$mappings = @( | |
@{ Old = $OldPlaceholder1; New = $NewPlaceholder1 }, | |
@{ Old = $OldPlaceholder2; New = $NewPlaceholder2 }, | |
@{ Old = $OldPlaceholder3; New = $NewPlaceholder3 } | |
) | |
foreach ($devDef in $layoutDef.Devices) { | |
$deviceName = $devDef.Name | |
foreach ($rendDef in $devDef.Renderings) { | |
$oldPlaceholder = $rendDef.Placeholder | |
if ([string]::IsNullOrEmpty($oldPlaceholder)) { continue } | |
$newPlaceholder = $null | |
foreach ($mapping in $mappings) { | |
$old = $mapping.Old | |
$new = $mapping.New | |
if ($oldPlaceholder -eq $old) { | |
$newPlaceholder = $new | |
break | |
} | |
$prefix = "/$old/" | |
if ($oldPlaceholder.StartsWith($prefix)) { | |
$suffix = $oldPlaceholder.Substring($prefix.Length) | |
$newPlaceholder = "/$new/" + $suffix | |
break | |
} | |
} | |
if ($null -ne $newPlaceholder -and $newPlaceholder -ne $oldPlaceholder) { | |
$rendDef.Placeholder = $newPlaceholder | |
$changed = $true | |
$entry = [PSCustomObject]@{ | |
ItemID = $contextItemID | |
Context = $contextName | |
Language = $languageName | |
Device = $deviceName | |
RenderingID = $rendDef.RenderingID | |
OldPlaceholder = $oldPlaceholder | |
NewPlaceholder = $newPlaceholder | |
} | |
$null = $script:logEntries.Add($entry) | |
} | |
} | |
} | |
if ($changed) { | |
return $layoutDef.ToXml() | |
} else { | |
return $null | |
} | |
} | |
# 5) Update Standard Values of the template | |
$templateItem = $db.GetItem($item.TemplateID.ToString()) | |
if ($null -eq $templateItem) { | |
Write-Error "Unable to find template item for ID: $($item.TemplateID)" | |
return | |
} | |
$stdValuesItem = $templateItem.Children | Where-Object { $_.Name -eq "__Standard Values" } | |
if ($null -eq $stdValuesItem) { | |
Write-Error "No __Standard Values found under template: $($templateItem.Paths.FullPath)" | |
} else { | |
# Shared Layout (__Renderings) | |
$stdSharedField = $stdValuesItem.Fields["__Renderings"] | |
if ($stdSharedField -and -not [string]::IsNullOrWhiteSpace($stdSharedField.Value)) { | |
$newXml = Replace-PlaceholdersInLayout ` | |
-layoutXml $stdSharedField.Value ` | |
-contextItemID $stdValuesItem.ID.ToString() ` | |
-contextName "Standard Values Shared Layout" ` | |
-languageName "" | |
if ($newXml) { | |
$stdValuesItem.Editing.BeginEdit() | |
try { | |
$stdSharedField.Value = $newXml | |
Write-Host "✅ Standard Values (Shared Layout) updated on template: $($templateItem.Name)" | |
} finally { | |
$stdValuesItem.Editing.EndEdit() | |
} | |
} else { | |
Write-Host "ℹ️ No changes needed in Standard Values Shared Layout." | |
} | |
} else { | |
Write-Host "ℹ️ Standard Values Shared Layout is empty or missing. Skipping." | |
} | |
# Final Layout (__Final Renderings) | |
$stdFinalField = $stdValuesItem.Fields["__Final Renderings"] | |
if ($stdFinalField -and -not [string]::IsNullOrWhiteSpace($stdFinalField.Value)) { | |
$newXml = Replace-PlaceholdersInLayout ` | |
-layoutXml $stdFinalField.Value ` | |
-contextItemID $stdValuesItem.ID.ToString() ` | |
-contextName "Standard Values Final Layout" ` | |
-languageName "" | |
if ($newXml) { | |
$stdValuesItem.Editing.BeginEdit() | |
try { | |
$stdFinalField.Value = $newXml | |
Write-Host "✅ Standard Values (Final Layout) updated on template: $($templateItem.Name)" | |
} finally { | |
$stdValuesItem.Editing.EndEdit() | |
} | |
} else { | |
Write-Host "ℹ️ No changes needed in Standard Values Final Layout." | |
} | |
} else { | |
Write-Host "ℹ️ Standard Values Final Layout is empty or missing. Skipping." | |
} | |
} | |
# 6) Iterate through all languages of the page item | |
foreach ($lang in $item.Languages) { | |
$langName = $lang.Name | |
$versionedItem = $db.GetItem($PageItemPath, $lang) | |
if ($null -eq $versionedItem) { | |
Write-Host "⚠️ Item does not exist in language: $langName. Skipping." | |
continue | |
} | |
# Shared Layout (__Renderings) | |
$sharedField = $versionedItem.Fields["__Renderings"] | |
if ($sharedField -and -not [string]::IsNullOrWhiteSpace($sharedField.Value)) { | |
$newXml = Replace-PlaceholdersInLayout ` | |
-layoutXml $sharedField.Value ` | |
-contextItemID $versionedItem.ID.ToString() ` | |
-contextName "Shared Layout" ` | |
-languageName $langName | |
if ($newXml) { | |
$versionedItem.Editing.BeginEdit() | |
try { | |
$sharedField.Value = $newXml | |
Write-Host "✅ [$langName] Shared Layout updated on: $($versionedItem.Paths.FullPath)" | |
} finally { | |
$versionedItem.Editing.EndEdit() | |
} | |
} else { | |
Write-Host "ℹ️ [$langName] No changes needed in Shared Layout." | |
} | |
} else { | |
Write-Host "ℹ️ [$langName] Shared Layout is empty or missing. Skipping." | |
} | |
# Final Layout (__Final Renderings) | |
$finalField = $versionedItem.Fields["__Final Renderings"] | |
if ($finalField -and -not [string]::IsNullOrWhiteSpace($finalField.Value)) { | |
$newXml = Replace-PlaceholdersInLayout ` | |
-layoutXml $finalField.Value ` | |
-contextItemID $versionedItem.ID.ToString() ` | |
-contextName "Final Layout" ` | |
-languageName $langName | |
if ($newXml) { | |
$versionedItem.Editing.BeginEdit() | |
try { | |
$finalField.Value = $newXml | |
Write-Host "✅ [$langName] Final Layout updated on: $($versionedItem.Paths.FullPath)" | |
} finally { | |
$versionedItem.Editing.EndEdit() | |
} | |
} else { | |
Write-Host "ℹ️ [$langName] No changes needed in Final Layout." | |
} | |
} else { | |
Write-Host "ℹ️ [$langName] Final Layout is empty or missing. Skipping." | |
} | |
} | |
# 7) Output a brief table of every placeholder change | |
if ($logEntries.Count -gt 0) { | |
Write-Host "`n========== Placeholder Replacement Log ==========`n" | |
$logEntries | | |
Sort-Object Context, Language, Device | | |
Format-Table ` | |
@{Label="Item ID"; Expression={$_.ItemID}}, ` | |
@{Label="Context"; Expression={$_.Context}}, ` | |
@{Label="Language"; Expression={$_.Language}}, ` | |
@{Label="Device"; Expression={$_.Device}}, ` | |
@{Label="Rendering ID"; Expression={$_.RenderingID}}, ` | |
@{Label="Old Placeholder";Expression={$_.OldPlaceholder}}, ` | |
@{Label="New Placeholder";Expression={$_.NewPlaceholder}} ` | |
-AutoSize | |
Write-Host "`nTotal changes: $($logEntries.Count)`n" | |
} else { | |
Write-Host "`n✅ No placeholders matching the specified parameters were found. No changes made." | |
} |
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 PowerShell Extensions scripting expert. Write a single SPE script ready to paste directly into Sitecore PowerShell ISE (no saving to file) against the master database that does exactly the following: | |
1. **Parametrize everything at the top**: | |
- Accept these parameters (all strings): | |
- `$PageItemPath` (default: `"/sitecore/content/Zont/Habitat/Home/AAA"`) | |
- `$OldPlaceholder1` (default: `"page-layout"`) | |
- `$NewPlaceholder1` (default: `"headless-main"`) | |
- `$OldPlaceholder2` (default: `"header-top"`) | |
- `$NewPlaceholder2` (default: `"headless-header"`) | |
- `$OldPlaceholder3` (default: `"footer"`) | |
- `$NewPlaceholder3` (default: `"headless-footer"`) | |
2. **Mount the master drive if necessary**: | |
- If no `master:` PSDrive exists, create it with: | |
``` | |
New-PSDrive -Name master -PSProvider Sitecore -Root "/" -Database "master" -ErrorAction Stop | Out-Null | |
``` | |
3. **Get the master database and the target page item**: | |
- Use `[Sitecore.Configuration.Factory]::GetDatabase("master")` to get the master database. | |
- Load the item at `$PageItemPath`. If it doesn’t exist, write an error and stop. | |
4. **Prepare logging**: | |
- Create an `ArrayList` called `$logEntries` (as `$script:logEntries = New-Object System.Collections.ArrayList`) to store PSCustomObjects for every placeholder change. Do not use `+=` on a PSObject. | |
5. **Define a helper function `Replace-PlaceholdersInLayout`** that takes: | |
- `$layoutXml` (string) | |
- `$contextItemID` (string) | |
- `$contextName` (string) | |
- `$languageName` (string) | |
Inside the function: | |
- Parse `$layoutXml` using `[Sitecore.Layouts.LayoutDefinition]::Parse($layoutXml)` into a `$layoutDef`. | |
- Initialize `$changed = $false`. | |
- Build an array `$mappings = @( | |
@{ Old = $OldPlaceholder1; New = $NewPlaceholder1 }, | |
@{ Old = $OldPlaceholder2; New = $NewPlaceholder2 }, | |
@{ Old = $OldPlaceholder3; New = $NewPlaceholder3 } | |
)`. | |
- Loop through `$layoutDef.Devices` and then through `$devDef.Renderings`. For each rendering: | |
- Read `$oldPlaceholder = $rendDef.Placeholder`. If null or empty, `continue`. | |
- Initialize `$newPlaceholder = $null`. | |
- For each mapping in `$mappings`: | |
1. If `$oldPlaceholder -eq $mapping.Old`, set `$newPlaceholder = $mapping.New` and `break`. | |
2. Else if `$oldPlaceholder.StartsWith("/$($mapping.Old)/")`, set `$suffix = $oldPlaceholder.Substring(("/" + $mapping.Old + "/").Length)` and `$newPlaceholder = "/" + $mapping.New + "/" + $suffix`, then `break`. | |
- If `$newPlaceholder` is not null and not equal to `$oldPlaceholder`: | |
- Assign `$rendDef.Placeholder = $newPlaceholder`. | |
- Set `$changed = $true`. | |
- Create a PSCustomObject entry with properties: | |
- `ItemID = $contextItemID` | |
- `Context = $contextName` | |
- `Language = $languageName` | |
- `Device = $deviceName` | |
- `RenderingID = $rendDef.RenderingID` | |
- `OldPlaceholder = $oldPlaceholder` | |
- `NewPlaceholder = $newPlaceholder` | |
- Add it to `$script:logEntries` via `$null = $script:logEntries.Add($entry)`. | |
- After looping, if `$changed`, return `$layoutDef.ToXml()`, else return `$null`. | |
6. **Update the template’s __Standard Values item**: | |
- Get `$templateItem = $db.GetItem($item.TemplateID.ToString())`. If null, write an error and stop. | |
- Find its child named `__Standard Values`: | |
``` | |
$stdValuesItem = $templateItem.Children | Where-Object { $_.Name -eq "__Standard Values" } | |
``` | |
If null, write an error and stop. | |
- Process `$stdValuesItem.Fields["__Renderings"]` (Shared Layout) if it exists and is not empty: | |
- Call `Replace-PlaceholdersInLayout` with: | |
- `-layoutXml $stdSharedField.Value` | |
- `-contextItemID $stdValuesItem.ID.ToString()` | |
- `-contextName "Standard Values Shared Layout"` | |
- `-languageName ""` | |
- If the function returns non-null `$newXml`, do: | |
``` | |
$stdValuesItem.Editing.BeginEdit() | |
try { | |
$stdSharedField.Value = $newXml | |
Write-Host "✅ Standard Values (Shared Layout) updated on template: $($templateItem.Name)" | |
} finally { | |
$stdValuesItem.Editing.EndEdit() | |
} | |
``` | |
- Otherwise, `Write-Host "ℹ️ No changes needed in Standard Values Shared Layout."` | |
- Process `$stdValuesItem.Fields["__Final Renderings"]` (Final Layout) in the same manner, with `contextName "Standard Values Final Layout"`. | |
7. **Iterate through all languages of the page item**: | |
- For each `$lang` in `$item.Languages`: | |
- Set `$langName = $lang.Name`. | |
- Get `$versionedItem = $db.GetItem($PageItemPath, $lang)`. If null, `Write-Host "⚠️ Item does not exist in language: $langName. Skipping."` and `continue`. | |
- Process `$versionedItem.Fields["__Renderings"]` (Shared Layout): | |
- If present and non-empty, call `Replace-PlaceholdersInLayout` with: | |
- `-layoutXml $sharedField.Value` | |
- `-contextItemID $versionedItem.ID.ToString()` | |
- `-contextName "Shared Layout"` | |
- `-languageName $langName` | |
- If returns non-null, begin editing, set `Value = $newXml`, end editing, and `Write-Host "✅ [$langName] Shared Layout updated on: $($versionedItem.Paths.FullPath)"`. Else `Write-Host "ℹ️ [$langName] No changes needed in Shared Layout."` | |
- If missing or empty, `Write-Host "ℹ️ [$langName] Shared Layout is empty or missing. Skipping."` | |
- Process `$versionedItem.Fields["__Final Renderings"]` (Final Layout) identically with `contextName "Final Layout"`. | |
8. **After all language versions**, output a brief table of every placeholder change: | |
- If `$logEntries.Count -gt 0`: | |
``` | |
Write-Host "`n========== Placeholder Replacement Log ==========`n" | |
$logEntries | | |
Sort-Object Context, Language, Device | | |
Format-Table ` | |
@{Label="Item ID"; Expression={$_.ItemID}}, ` | |
@{Label="Context"; Expression={$_.Context}}, ` | |
@{Label="Language"; Expression={$_.Language}}, ` | |
@{Label="Device"; Expression={$_.Device}}, ` | |
@{Label="Rendering ID"; Expression={$_.RenderingID}}, ` | |
@{Label="Old Placeholder";Expression={$_.OldPlaceholder}}, ` | |
@{Label="New Placeholder";Expression={$_.NewPlaceholder}} ` | |
-AutoSize | |
Write-Host "`nTotal changes: $($logEntries.Count)`n" | |
``` | |
- Else, `Write-Host "`n✅ No placeholders matching the specified parameters were found. No changes made."` | |
9. **Everything must run inline in Sitecore PowerShell ISE**, so you can paste the entire block into ISE and click Run without saving to a separate file. Ensure that the three placeholder‐pair parameters (`OldPlaceholder1`, `NewPlaceholder1`, etc.) allow replacing: | |
- `"page-layout"` → `"headless-main"` | |
- `"header-top"` → `"headless-header"` | |
- `"footer"` → `"headless-footer"` | |
by default, but can be overridden when running inline. | |
Provide the complete script exactly as described, following Sitecore PowerShell best practices and using BeginEdit()/EndEdit() properly. |
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
# ----------------------------------------------------------- | |
# Inline Script for Sitecore PowerShell ISE: | |
# Replace Multiple Placeholders for Renderings | |
# Target Item: Default is /sitecore/content/Zont/Habitat/Home/AAA | |
# DB: master | |
# - Processes Standard Values, Shared Layout, and Final Layout. | |
# - Replaces three placeholder pairs: | |
# $OldPlaceholder1 → $NewPlaceholder1 | |
# $OldPlaceholder2 → $NewPlaceholder2 | |
# $OldPlaceholder3 → $NewPlaceholder3 | |
# - Removes leading slash for any top-level placeholder (single segment). | |
# - Logs every change to the console. | |
# ----------------------------------------------------------- | |
param( | |
[string] $PageItemPath = "/sitecore/content/Zont/Habitat/Home/target", | |
[string] $OldPlaceholder1 = "page-layout", | |
[string] $NewPlaceholder1 = "headless-main", | |
[string] $OldPlaceholder2 = "header-top", | |
[string] $NewPlaceholder2 = "headless-header", | |
[string] $OldPlaceholder3 = "footer", | |
[string] $NewPlaceholder3 = "headless-footer" | |
) | |
# 1) Ensure master: PSDrive is mounted | |
if (-not (Get-PSDrive -Name master -ErrorAction SilentlyContinue)) { | |
New-PSDrive -Name master -PSProvider Sitecore -Root "/" -Database "master" -ErrorAction Stop | Out-Null | |
} | |
# 2) Get the master database and the page item | |
$db = [Sitecore.Configuration.Factory]::GetDatabase("master") | |
$item = $db.GetItem($PageItemPath) | |
if ($null -eq $item) { | |
Write-Error "Item not found at path: $PageItemPath" | |
return | |
} | |
# 3) Prepare an ArrayList for logging | |
$script:logEntries = New-Object System.Collections.ArrayList | |
# 4) Function to replace placeholders in a raw layout XML | |
function Replace-PlaceholdersInLayout { | |
param( | |
[string] $layoutXml, | |
[string] $contextItemID, | |
[string] $contextName, | |
[string] $languageName | |
) | |
$layoutDef = [Sitecore.Layouts.LayoutDefinition]::Parse($layoutXml) | |
$changed = $false | |
# Build mapping array from parameters | |
$mappings = @( | |
@{ Old = $OldPlaceholder1; New = $NewPlaceholder1 }, | |
@{ Old = $OldPlaceholder2; New = $NewPlaceholder2 }, | |
@{ Old = $OldPlaceholder3; New = $NewPlaceholder3 } | |
) | |
foreach ($devDef in $layoutDef.Devices) { | |
$deviceName = $devDef.Name | |
foreach ($rendDef in $devDef.Renderings) { | |
$oldPlaceholder = $rendDef.Placeholder | |
if ([string]::IsNullOrEmpty($oldPlaceholder)) { continue } | |
$newPlaceholder = $null | |
# 4a) Explicit mappings | |
foreach ($mapping in $mappings) { | |
$old = $mapping.Old | |
$new = $mapping.New | |
# Top-level exact match (with or without leading slash) | |
if ($oldPlaceholder -eq $old -or $oldPlaceholder -eq "/$old") { | |
$newPlaceholder = $new | |
break | |
} | |
# Nested mapping: /old/suffix → /new/suffix | |
$prefix = "/$old/" | |
if ($oldPlaceholder.StartsWith($prefix)) { | |
$suffix = $oldPlaceholder.Substring($prefix.Length) | |
$newPlaceholder = "/$new/$suffix" | |
break | |
} | |
} | |
# 4b) Remove leading slash for other single-segment placeholders | |
if (-not $newPlaceholder) { | |
if ($oldPlaceholder -match '^/[^/]+$') { | |
$newPlaceholder = $oldPlaceholder.TrimStart('/') | |
} | |
} | |
# 4c) Apply change if needed | |
if ($newPlaceholder -and $newPlaceholder -ne $oldPlaceholder) { | |
$rendDef.Placeholder = $newPlaceholder | |
$changed = $true | |
$entry = [PSCustomObject]@{ | |
ItemID = $contextItemID | |
Context = $contextName | |
Language = $languageName | |
Device = $deviceName | |
RenderingID = $rendDef.RenderingID | |
OldPlaceholder = $oldPlaceholder | |
NewPlaceholder = $newPlaceholder | |
} | |
$null = $script:logEntries.Add($entry) | |
} | |
} | |
} | |
if ($changed) { return $layoutDef.ToXml() } | |
return $null | |
} | |
# 5) Update Standard Values of the template | |
$templateItem = $db.GetItem($item.TemplateID.ToString()) | |
if (-not $templateItem) { | |
Write-Error "Unable to find template item for ID: $($item.TemplateID)" | |
return | |
} | |
$stdValuesItem = $templateItem.Children | Where-Object { $_.Name -eq "__Standard Values" } | |
if (-not $stdValuesItem) { | |
Write-Error "No __Standard Values found under template: $($templateItem.Paths.FullPath)" | |
} else { | |
# Shared Layout | |
$stdSharedField = $stdValuesItem.Fields["__Renderings"] | |
if ($stdSharedField -and -not [string]::IsNullOrWhiteSpace($stdSharedField.Value)) { | |
$newXml = Replace-PlaceholdersInLayout ` | |
-layoutXml $stdSharedField.Value ` | |
-contextItemID $stdValuesItem.ID.ToString() ` | |
-contextName "Standard Values Shared Layout" ` | |
-languageName "" | |
if ($newXml) { | |
$stdValuesItem.Editing.BeginEdit() | |
try { | |
$stdSharedField.Value = $newXml | |
Write-Host "✅ Standard Values (Shared Layout) updated on template: $($templateItem.Name)" | |
} finally { | |
$stdValuesItem.Editing.EndEdit() | |
} | |
} else { | |
Write-Host "ℹ️ No changes needed in Standard Values Shared Layout." | |
} | |
} | |
# Final Layout | |
$stdFinalField = $stdValuesItem.Fields["__Final Renderings"] | |
if ($stdFinalField -and -not [string]::IsNullOrWhiteSpace($stdFinalField.Value)) { | |
$newXml = Replace-PlaceholdersInLayout ` | |
-layoutXml $stdFinalField.Value ` | |
-contextItemID $stdValuesItem.ID.ToString() ` | |
-contextName "Standard Values Final Layout" ` | |
-languageName "" | |
if ($newXml) { | |
$stdValuesItem.Editing.BeginEdit() | |
try { | |
$stdFinalField.Value = $newXml | |
Write-Host "✅ Standard Values (Final Layout) updated on template: $($templateItem.Name)" | |
} finally { | |
$stdValuesItem.Editing.EndEdit() | |
} | |
} else { | |
Write-Host "ℹ️ No changes needed in Standard Values Final Layout." | |
} | |
} | |
} | |
# 6) Iterate through all languages of the page item | |
foreach ($lang in $item.Languages) { | |
$langName = $lang.Name | |
$versionedItem = $db.GetItem($PageItemPath, $lang) | |
if (-not $versionedItem) { | |
Write-Host "⚠️ Item not in language: $langName. Skipping." | |
continue | |
} | |
# Shared Layout | |
$sharedField = $versionedItem.Fields["__Renderings"] | |
if ($sharedField -and -not [string]::IsNullOrWhiteSpace($sharedField.Value)) { | |
$newXml = Replace-PlaceholdersInLayout ` | |
-layoutXml $sharedField.Value ` | |
-contextItemID $versionedItem.ID.ToString() ` | |
-contextName "Shared Layout" ` | |
-languageName $langName | |
if ($newXml) { | |
$versionedItem.Editing.BeginEdit() | |
try { | |
$sharedField.Value = $newXml | |
Write-Host "✅ [$langName] Shared Layout updated on: $($versionedItem.Paths.FullPath)" | |
} finally { | |
$versionedItem.Editing.EndEdit() | |
} | |
} else { | |
Write-Host "ℹ️ [$langName] No changes in Shared Layout." | |
} | |
} | |
# Final Layout | |
$finalField = $versionedItem.Fields["__Final Renderings"] | |
if ($finalField -and -not [string]::IsNullOrWhiteSpace($finalField.Value)) { | |
$newXml = Replace-PlaceholdersInLayout ` | |
-layoutXml $finalField.Value ` | |
-contextItemID $versionedItem.ID.ToString() ` | |
-contextName "Final Layout" ` | |
-languageName $langName | |
if ($newXml) { | |
$versionedItem.Editing.BeginEdit() | |
try { | |
$finalField.Value = $newXml | |
Write-Host "✅ [$langName] Final Layout updated on: $($versionedItem.Paths.FullPath)" | |
} finally { | |
$versionedItem.Editing.EndEdit() | |
} | |
} else { | |
Write-Host "ℹ️ [$langName] No changes in Final Layout." | |
} | |
} | |
} | |
# 7) Output log | |
if ($script:logEntries.Count -gt 0) { | |
Write-Host "`n========== Placeholder Replacement Log ==========`n" | |
$script:logEntries | | |
Sort-Object Context, Language, Device | | |
Format-Table ` | |
@{Label="Item ID"; Expression={$_.ItemID}},` | |
@{Label="Context"; Expression={$_.Context}},` | |
@{Label="Language"; Expression={$_.Language}},` | |
@{Label="Device"; Expression={$_.Device}},` | |
@{Label="Rendering ID"; Expression={$_.RenderingID}},` | |
@{Label="Old Placeholder";Expression={$_.OldPlaceholder}},` | |
@{Label="New Placeholder";Expression={$_.NewPlaceholder}}` | |
-AutoSize | |
Write-Host "`nTotal changes: $($script:logEntries.Count)`n" | |
} else { | |
Write-Host "`n✅ No matching placeholders found. No changes made.`n" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Successful run:

Nothing to change:
