Sitecore 9.x upgrade and dynamic placeholders

In the previous Sitecore versions dynamic placeholders where not there out of the box, so in case you needed them a custom solution was required. Good news came with Sitecore 9.x as that was integrated and ready to be used OOTB.

That’s great yes, but, there is always a “but” when it comes to solutions upgrade, the way we were generating the dynamic placeholders key could potentially be different to what Sitecore is doing now with the builtin feature.

One of the most common approaches was to use the solution based on the DynamicPlaceholders.Mvc nuget package, you might be familiar with the approach that Habitat solution was following:

@using Sitecore.Feature.Teasers
@using Sitecore.Foundation.SitecoreExtensions.Extensions
@using Sitecore.Foundation.Theming.Extensions
@using Sitecore.Mvc.Presentation
@model Sitecore.Feature.Teasers.Models.DynamicTeaserModel

@using (Html.BeginEditFrame(Model.Item.ID.ToString(), ""))
  var options = RenderingContext.Current.Rendering.GetCarouselOptions();
  <div class="owl-carousel" data-options='{"items": @options.ItemsShown, "navigation": @(options.ShowNavigation ? "true" : "false"), "navigationText": ["<", ">"], "autoPlay": @(options.AutoPlay ? "true" : "false") }'>
    @for (var i = 0; i < Model.Items.Count(); i++)
        @Html.Sitecore().DynamicPlaceholder($"teaser-placeholder-{i + 1}")

All good, so now the problems! After we finished with the upgrade, we noted that the content from Dynamic Placeholders was gone. We did some research and noticed that now the generated key was different:

Before we had something like that:


And now Sitecore is generating the keys like that:


Powershell to the rescue!!

We decided to go with what we think is the better approach to work with this kind of bulk content update, powershell. You can find the script here in Github.

function ProcessRendering{
    [parameter(Mandatory=$true, Position=0)]
    [parameter(Mandatory=$true, Position=1)]
    [parameter(Mandatory=$false, Position=2)]
	$phMatches = [regex]::Matches($_.Placeholder,'(_[0-9a-fA-F]{8}[-][0-9a-fA-F]{4}[-][0-9a-fA-F]{4}[-][0-9a-fA-F]{4}[-][0-9a-fA-F]{12})')

	if ($phMatches.Success) {
		Write-Host "Match found in item - [$($item.Paths.FullPath)]"
		$replacePh = $rendering.Placeholder
		$phMatches | ForEach-Object {
			$renderingId = $_.Value
			$replacePh = $replacePh.Replace($renderingId, "{$($renderingId.ToUpper())}-0")

		$replacePh = $replacePh.Replace('{_', "-{")
		$rendering.Placeholder = $replacePh
		Write-Host "Replacing [$($rendering.Placeholder)] with [$($replacePh)]"
		Set-Rendering -Item $item -Instance $rendering -FinalLayout:$param

$allPaths = "/sitecore/templates", "/sitecore/content"

New-UsingBlock (New-Object Sitecore.Data.BulkUpdateContext) {
	$allPaths | ForEach-Object -Process {
		Get-ChildItem -Path $_ -Version * -Recurse | ForEach-Object {
			$item = $_;
			Write-Host "Processing shared layout for item $($_.ID)" 
			Get-Rendering -Item $item | ForEach-Object {
				ProcessRendering $item $_ $false
			Write-Host "Processing final layout for item $($_.ID)" 
			Get-Rendering -Item $item -FinalLayout | ForEach-Object {
				ProcessRendering $item $_ $true

After running it you will get all your dynamic placeholder keys updated on your templates and content items.

I hope it helps you if you face a similar issue.

Happy upgrade!

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s