Insights

Sitecore 10 Upgrade Gotcha: Dynamic Placeholders

From Custom Work to Out of the Box

Dynamic placeholders are a huge help in a component-driven system. They let you nest custom components inside each other and reuse components on the same page. A good example is accordions. For a long time, Sitecore didn't have these! But now they do; in fact, this was introduced in Sitecore 9. But there are a lot of older Sitecore instances out there that need to be updated from before that time and quite reasonably have their own version of dynamic placeholders.

Several most commonly used libraries conflict with the new Sitecore dynamic placeholders. Even if yours don't, it's good to switch to the OOTB version for future-proofing and support.

How Do We Check?

The simplest way to check is to look at a rendering that you know uses dynamic placeholders already. Load that page in the Content Editor and open up the presentation details.

Sitecore 10 Upgrade Gotcha: Dynamic Placeholders 

Click on the rendering you are checking out and read the placeholder text. Sitecore's new placeholders look like "accordion-{7a943e27-b649-400c-986d-33d07f0f50ca}-0".

So if yours look like that, then nothing needs to be done. If they don't, well, it needs fixing. But you don't want to fix hundreds of pages by hand.

PowerShell to the Rescue!

Below is a script to fix all dynamic placeholders, with many customizable options. First, though, a little bit of explanation.

The guid in Sitecore's placeholder format is the rendering unique id. Most, if not all, of the custom dynamic placeholder implementations, out there use this, too, so that's great.

Usually, the guid is in a slightly different format, so we'll want to fix that. This script assumes a placeholder format like keyname_12345678-1234-1234-1234-123456789012, the most common I've seen.

If yours is different, change the regex to match.

Before running this script, decide how you want to migrate your Sitecore content. You can move all the pages to your new instance first and run the script there, leaving your old instance exactly as it was.

$defaultLayout = Get-LayoutDevice -Default
Get-ChildItem "master:\content\mysite\home\services" -Language "en", "de-DE", "fr-FR" -Recurse | `
    Where-Object { $_.TemplateName -eq "Service Page"} | `
        ForEach-Object {
            Write-Host 
            Write-Host $_.ID $_.Name $_.Language
            $item = $_
            Get-Rendering -Item $item -Device $defaultLayout -FinalLayout | `
            ForEach-Object {
                $regex = [Regex]::new("_([0-9a-f]{8}[-][0-9a-f]{4}[-][0-9a-f]{4}[-][0-9a-f]{4}[-][0-9a-f]{12})")
                $match = $regex.Match($_.Placeholder)
                if ($match.Success){
                    $newPlaceholderLine = ""
                    $placeholderList = $_.Placeholder -split "/"
                    ForEach($placeholder in $placeholderList){
                        $itemmatch = $regex.Match($placeholder)
                        if ($itemmatch.Success){
                            $renderingId = $itemmatch.Value.ToUpper() -replace "_", ""
                            $renderingId = "-{" + $renderingId + "}-0"
                            $newPlaceholder = $placeholder -replace $itemmatch.Value, $renderingId
                            $placeholder = $newPlaceholder
                        }
                        if ($placeholder){
                            $newPlaceholderLine = $newPlaceholderLine + "/" + $placeholder
                        }

                    }
                   
                    $_.Placeholder = $newPlaceholderLine
                   Set-Rendering -Item $item -Instance $_ -Device $defaultLayout -FinalLayout
                   Write-Host "Updated: " $item.ID $_.Placeholder
                }
            }
        }

This loads up the pages from a folder, then the renderings from each page walks through each entry to find placeholders that need updating writes out what it does, and saves the changes.

How to Use It Best

I found it simplest to first update the standard values for each page type. That you can do by pointing the Get-ChildItem line to your template folders and replacing:

Where-Object { $_.TemplateName -eq "Service Page"} | `

with:

Where-Object { $_.Name -eq "__Standard Values"} | `

You might find it necessary to run it a few times for different folders, depending on how you store your page templates.

What's Next?

Now that all your page templates are updated, you can run it on the actual pages, just change the folder location and the template name as necessary. We found it works better to go section by section because it can be slow for large sites to do the entire thing. If you need to change the placeholders in the shared layout of a page, and that wasn't handled by the standard values change, take out the -FinalLayout switch.

Check that against a couple of the standard values, too. Sometimes you need to update their shared layout depending on how they were made.

That's it! Now your pages are all updated, and you are ready to go.

👋 Hey Sitecore Enthusiasts!

Sign up to our bi-weekly newsletter for a bite-sized curation of valuable insight from the Sitecore community.

What’s in it for you?

  • Stay up-to-date with the latest Sitecore news
  • New to Sitecore? Learn tips and tricks to help you navigate this powerful tool
  • Sitecore pro? Expand your skill set and discover troubleshooting tips
  • Browse open careers and opportunities
  • Get a chance to be featured in upcoming editions
  • Learn our secret handshake
  • And more!
Sitecore Snack a newsletter by Fishtank Consulting
 

Meet Ryan Allan

Senior Developer

⚙️💻👪

Ryan is a seasoned Senior Developer at Fishtank and is Sitecore Developer Certified. In a nutshell, he describes his role as "building extremely fancy websites". Ryan has a degree in Mechanical Engineering and previously worked on power plants and compressors, and now builds websites for the same company as a client! Outside of work, his interests are science + physics and spending time with his kids.

Connect with Ryan