Fix for the issue with renaming local data sources resulting in broken links
Sitecore introduced local/page data sources with SXA. The local data sources allow better organisation of your page specific and shared data sources. However, one challenge with local data sources is, the links to them won't automatically get updated when you rename them. This is because Sitecore uses the path instead of ID to link to local data sources. If you inspect the raw value of final renderings field of a page with module that has local data source you can see the path "local:/Data/...".
For this reason Sitecore warns about renaming local data sources manually. The documentation clearly says you need to convert your local data source paths to IDs using the out of the box scripts provided before renaming the local data source item.
(Source: https://doc.sitecore.com/xp/en/developers/sxa/93/sitecore-experience-accelerator/data-sources.html#rename-local-data-sources) |
The script works fine in most cases, except for when not all your data sources are direct children of the page data folder. The script only looks for data source items directly under the page data folder item and convert the references to IDs. In Sitecore JSS implementations and in some SXA implementations it is normal to store the page data sources for complex modules in a hierarchical structure for better organisation and grouping.
For example, I have Content Cards module which is a complex module with its own data source and a nested placeholder to add Content Card renderings. Before you ask, the reason for having separate Content Card rendering is to have the ability to personalise individual Content Card inside the module. For better organisation I store the data sources of individual content cards under the parent data source item as shown in the screenshot below.
<r xmlns:p="p" xmlns:s="s" p:p="1"> | |
<d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}"> | |
<r uid="{1AB520A5-290F-463B-B6EF-E200A5E36844}" p:before="*" s:ds="local:/Data/Content Cards/Card1" s:id="{DB437FBF-6A68-45E1-84B2-CEC78A71D58D}" s:par="Reset Caching Options&GridParameters=%7B7465D855-992E-4DC2-9855-A03250DFA74B%7D&FieldNames=%7BB4AE42C3-7FBF-40E8-8FC6-DB5F6F63E289%7D&Styles&CacheClearingBehavior=Clear%20on%20publish&RenderingIdentifier&DynamicPlaceholderId=2" s:ph="/main/scphcontentcards-1-1" /> | |
<r uid="{604B37B0-91E8-4FA8-BAC8-473718702DB7}" p:after="r[@uid='{1AB520A5-290F-463B-B6EF-E200A5E36844}']" s:ds="local:/Data/Content Cards/Card2" s:id="{DB437FBF-6A68-45E1-84B2-CEC78A71D58D}" s:par="Reset Caching Options&GridParameters=%7B7465D855-992E-4DC2-9855-A03250DFA74B%7D&FieldNames=%7BB4AE42C3-7FBF-40E8-8FC6-DB5F6F63E289%7D&Styles&CacheClearingBehavior=Clear%20on%20publish&RenderingIdentifier&DynamicPlaceholderId=3" s:ph="/main/scphcontentcards-1-1" /> | |
<r uid="{B4AFD366-D615-4E64-8BA7-BC6990A962C2}" p:after="r[@uid='{604B37B0-91E8-4FA8-BAC8-473718702DB7}']" s:ds="local:/Data/Content Cards/Card3" s:id="{DB437FBF-6A68-45E1-84B2-CEC78A71D58D}" s:par="Reset Caching Options&GridParameters=%7B7465D855-992E-4DC2-9855-A03250DFA74B%7D&FieldNames=%7BB4AE42C3-7FBF-40E8-8FC6-DB5F6F63E289%7D&Styles&CacheClearingBehavior=Clear%20on%20publish&RenderingIdentifier&DynamicPlaceholderId=4" s:ph="/main/scphcontentcards-1-1" /> | |
<r uid="{35E23988-BDA3-4F9C-BAE7-479C8ACFB81A}" p:after="*[1=2]" s:ds="local:/Data/Content Cards" s:id="{0B178615-3D4F-4773-A385-697F24AC1B30}" s:par="Reset Caching Options&GridParameters=%7B7465D855-992E-4DC2-9855-A03250DFA74B%7D&FieldNames=%7BFF0BBF5D-9225-47DA-9218-033731F21DAF%7D&Styles&RenderingIdentifier&DynamicPlaceholderId=1" s:ph="main" s:ccb="Clear on publish" /> | |
</d> | |
</r> |
And this is the value after running the out of the box PowerShell script provided by Sitecore.
<r xmlns:p="p" xmlns:s="s" p:p="1"> | |
<d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}"> | |
<r uid="{1AB520A5-290F-463B-B6EF-E200A5E36844}" p:before="*" s:ds="local:/Data/Content Cards/Card1" s:id="{DB437FBF-6A68-45E1-84B2-CEC78A71D58D}" s:par="Reset Caching Options&GridParameters=%7B7465D855-992E-4DC2-9855-A03250DFA74B%7D&FieldNames=%7BB4AE42C3-7FBF-40E8-8FC6-DB5F6F63E289%7D&Styles&RenderingIdentifier&DynamicPlaceholderId=2" s:ph="/main/scphcontentcards-1-1" s:ccb="Clear on publish" /> | |
<r uid="{604B37B0-91E8-4FA8-BAC8-473718702DB7}" p:after="r[@uid='{1AB520A5-290F-463B-B6EF-E200A5E36844}']" s:ds="local:/Data/Content Cards/Card2" s:id="{DB437FBF-6A68-45E1-84B2-CEC78A71D58D}" s:par="Reset Caching Options&GridParameters=%7B7465D855-992E-4DC2-9855-A03250DFA74B%7D&FieldNames=%7BB4AE42C3-7FBF-40E8-8FC6-DB5F6F63E289%7D&Styles&CacheClearingBehavior=Clear%20on%20publish&RenderingIdentifier&DynamicPlaceholderId=3" s:ph="/main/scphcontentcards-1-1" /> | |
<r uid="{B4AFD366-D615-4E64-8BA7-BC6990A962C2}" p:after="r[@uid='{604B37B0-91E8-4FA8-BAC8-473718702DB7}']" s:ds="local:/Data/Content Cards/Card3" s:id="{DB437FBF-6A68-45E1-84B2-CEC78A71D58D}" s:par="Reset Caching Options&GridParameters=%7B7465D855-992E-4DC2-9855-A03250DFA74B%7D&FieldNames=%7BB4AE42C3-7FBF-40E8-8FC6-DB5F6F63E289%7D&Styles&CacheClearingBehavior=Clear%20on%20publish&RenderingIdentifier&DynamicPlaceholderId=4" s:ph="/main/scphcontentcards-1-1" /> | |
<r uid="{35E23988-BDA3-4F9C-BAE7-479C8ACFB81A}" p:after="*[1=2]" s:ds="{295E6E40-5DD1-4C71-A418-439049864C3E}" s:id="{0B178615-3D4F-4773-A385-697F24AC1B30}" s:par="Reset Caching Options&GridParameters=%7B7465D855-992E-4DC2-9855-A03250DFA74B%7D&FieldNames=%7BFF0BBF5D-9225-47DA-9218-033731F21DAF%7D&Styles&RenderingIdentifier&DynamicPlaceholderId=1" s:ph="main" s:ccb="Clear on publish" /> | |
</d> | |
</r> |
So, to fix this I decided to write my own script that gets not just the direct children of the data folder, but all the descendants. I used the original script as base, instead of importing the out of the box Get-NestedDatasource function, I created my own version that looks for children recursively.
Here is the script I came up with
Import-Function Test-ItemIsPageData | |
Import-Function Edit-FieldValue | |
Import-Function Get-RelativeDatasourcePath | |
function Get-NestedDatasource { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory = $true, Position = 0 )] | |
[Item]$DataFolder | |
) | |
begin { | |
Write-Verbose "Cmdlet Get-NestedDatasource - Begin" | |
} | |
process { | |
Write-Verbose "Cmdlet Get-NestedDatasource - Process" | |
$children = Get-ChildItem -Path $DataFolder.Paths.Path | |
$children | ? { [Sitecore.Data.Managers.TemplateManager]::GetTemplate($_).InheritsFrom([Sitecore.TemplateIDs]::Folder) -eq $false } | |
$children | % { | |
Get-NestedDatasource $_ | |
} | |
} | |
end { | |
Write-Verbose "Cmdlet Get-NestedDatasource - End" | |
} | |
} | |
function Update-Presentation { | |
param ( | |
$dataSources, | |
$dataSourcesNames, | |
$item | |
) | |
$dsItems = $dataSources | ? { | |
$ds = $_ | |
($dataSourcesNames | ? { $ds.Paths.Path.EndsWith($_) }) -ne $null | |
} | |
$dsItems | % { | |
$dsItem = $_ | |
$dsValue = $dataSourcesNames | ? { $dsItem.Paths.Path.EndsWith($_) } | Select-Object -First 1 | |
$pattern = "ds=`"local:$($dsValue)`"" | |
$replacement = "ds=`"$($dsItem.ID)`"" | |
Edit-FieldValue $item "__Renderings" $pattern $replacement | |
Edit-FieldValue $item "__Final Renderings" $pattern $replacement | |
} | |
} | |
$item = Get-Item . | |
if ((Test-ItemIsPageData $item) -eq $true) { | |
$item = $item.Parent | Wrap-Item | |
} | |
$dataFolder = Get-ChildItem -Path $item.Paths.Path | ? { Test-ItemIsPageData $_ } | |
if ($dataFolder -ne $null) { | |
$dataSources = Get-NestedDatasource $dataFolder | |
Get-Item -Path $item.Paths.Path -Language * | % { | |
$dataSourcesNames = Get-RelativeDatasourcePath $_ | |
Write-Verbose "Item: "$_.FullPath | |
Write-Verbose "Datasources: " $dataSources.FullPath | |
Write-Verbose "Datasource names: " $dataSourcesNames | |
Update-Presentation $dataSources $dataSourcesNames $_ | |
} | |
} |
To add this script to the context menu, I created the following custom menu structure mimicking the out of the box script menu.
<r xmlns:p="p" xmlns:s="s" p:p="1"> | |
<d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}"> | |
<r uid="{1AB520A5-290F-463B-B6EF-E200A5E36844}" p:before="*" s:ds="{075C8FA4-AA94-409B-A86C-878C215B87FC}" s:id="{DB437FBF-6A68-45E1-84B2-CEC78A71D58D}" s:par="Reset Caching Options&GridParameters=%7B7465D855-992E-4DC2-9855-A03250DFA74B%7D&FieldNames=%7BB4AE42C3-7FBF-40E8-8FC6-DB5F6F63E289%7D&Styles&RenderingIdentifier&DynamicPlaceholderId=2" s:ph="/main/scphcontentcards-1-1" s:ccb="Clear on publish" /> | |
<r uid="{604B37B0-91E8-4FA8-BAC8-473718702DB7}" p:after="r[@uid='{1AB520A5-290F-463B-B6EF-E200A5E36844}']" s:ds="{FB095A9B-9955-4BED-8BE6-2C7D108437F5}" s:id="{DB437FBF-6A68-45E1-84B2-CEC78A71D58D}" s:par="Reset Caching Options&GridParameters=%7B7465D855-992E-4DC2-9855-A03250DFA74B%7D&FieldNames=%7BB4AE42C3-7FBF-40E8-8FC6-DB5F6F63E289%7D&Styles&CacheClearingBehavior=Clear%20on%20publish&RenderingIdentifier&DynamicPlaceholderId=3" s:ph="/main/scphcontentcards-1-1" /> | |
<r uid="{B4AFD366-D615-4E64-8BA7-BC6990A962C2}" p:after="r[@uid='{604B37B0-91E8-4FA8-BAC8-473718702DB7}']" s:ds="{EA288C10-79A8-43DC-BA3E-A998F383BF07}" s:id="{DB437FBF-6A68-45E1-84B2-CEC78A71D58D}" s:par="Reset Caching Options&GridParameters=%7B7465D855-992E-4DC2-9855-A03250DFA74B%7D&FieldNames=%7BB4AE42C3-7FBF-40E8-8FC6-DB5F6F63E289%7D&Styles&CacheClearingBehavior=Clear%20on%20publish&RenderingIdentifier&DynamicPlaceholderId=4" s:ph="/main/scphcontentcards-1-1" /> | |
<r uid="{35E23988-BDA3-4F9C-BAE7-479C8ACFB81A}" p:after="*[1=2]" s:ds="{295E6E40-5DD1-4C71-A418-439049864C3E}" s:id="{0B178615-3D4F-4773-A385-697F24AC1B30}" s:par="Reset Caching Options&GridParameters=%7B7465D855-992E-4DC2-9855-A03250DFA74B%7D&FieldNames=%7BFF0BBF5D-9225-47DA-9218-033731F21DAF%7D&Styles&RenderingIdentifier&DynamicPlaceholderId=1" s:ph="main" s:ccb="Clear on publish" /> | |
</d> | |
</r> |
Comments
Post a Comment