7

I'm looking for migration solution from Fortis DynamicPlaceholders to Sitecore 9 DynamicPlaceholders.

Fortis DynamicPlaceholder looks like:

/main/content_container_ec526a7d-7838-4563-95a0-915bd2840dd8/grid_12_3f351279-e9a1-4c33-9b79-0defea684d18

Sitecore 9 DynamicPlaceholder looks like:

/main/content_container-{EC526A7D-7838-4563-95A0-915BD2840DD8}-0/grid_12-{3F351279-E9A1-4C33-9B79-0DEFEA684D18}-0

I need to update all content to Sitecore 9 DynamicPlaceholders

Maybe someone already did the same migration and has quick solution for it (Powershell script, aspx page)?

4 Answers 4

12

This is the script I've used in the past:

# specify your path here. It is most likely be page templates and page content
$startPath = "/sitecore/content"
Get-ChildItem -Path $startPath -Recurse | ForEach-Object {
    $item = $_;    

    Get-Rendering -Item $_  | ForEach-Object {
        $rendering = $_;
        $matches = [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 ($matches.Success) {
            Write-Host "Match found in item - [$($item.Paths.FullPath)]"
            Write-Host "Old Placeholder - [$($rendering.Placeholder)]"

            $newPlaceholder = $rendering.Placeholder

            $matches | ForEach-Object {
                $renderingId = $_.Value
                $newPlaceholder = $newPlaceholder.Replace($renderingId, "{$($renderingId.ToUpper())}-0")
            }

            $newPlaceholder = $newPlaceholder.Replace('{_', "-{")
            Write-Host "New Placeholder - [$($newPlaceholder)]"

            # comment following 2 lines if you don't want to do replacement, but want to have log of upcoming placeholder changes
            $rendering.Placeholder = $newPlaceholder
            Set-Rendering -Item $item -Instance $rendering 
        }
    }
}

It does changes only for the shared layout. In case you also need changes for Final Layout, then replace

Get-Rendering -Item $_  | ForEach-Object {

with

Get-Rendering -Item $_ -FinalLayout | ForEach-Object {

and

Set-Rendering -Item $item -Instance $rendering

with

Set-Rendering -Item $item -Instance $rendering -FinalLayout
2
  • This is great. Thanks @vzaverugo. One thing I found is that in my use of Fortis Dynamic Placeholders is that I had a case where I had multiple placeholders with the same name on one single rendering. In this case Fortis will append a suffix to the end of the placeholder key as an incremental seed value to ensure it is unique. So in my case I had to account for that. I modified your script and am putting that one as a separate answer.
    – Mike M
    Oct 30, 2018 at 22:07
  • @MikeM, thanks for pointing! this is a good case I haven't had in my configuration. Thanks for submitting your version here!
    – vzaverugo
    Oct 31, 2018 at 8:13
8

Here is a modified version of @vzaverugo's script to account for when you have multiple placeholders with the same name in a single rendering. Fortis will append an incremental seed suffix. Sitecore 9 also has a concept of an incremental seed suffix. This modified script can account for that, as long as you setup your Sitecore 9 seeds to match the same increments that Fortis uses.

# specify your path here. It is most likely be page templates and page content
$startPath = "/sitecore/content"
Get-ChildItem -Path $startPath -Recurse | ForEach-Object {
    $item = $_;    
    Get-Rendering -Item $_ -FinalLayout | ForEach-Object {
        $rendering = $_;
        $matches = [regex]::Matches($_.Placeholder,'(?<guid>_[\d\w]{8}\-(?:[\d\w]{4}\-){3}[\d\w]{12})(?<seed>_?\d?)')

        if ($matches.Success) {

            Write-Host "Match found in item - [$($item.Paths.FullPath)]"
            Write-Host "Old Placeholder - [$($rendering.Placeholder)]"

            $newPlaceholder = $rendering.Placeholder

            $matches | ForEach-Object {
                $match = $_
                $renderingId = $match.Value

                if (!([string]::IsNullOrEmpty($match.Groups["seed"])))
                {
                    $seedSuffix = $match.Groups["seed"].ToString()
                    $seedValue = $seedSuffix.Trim("_")

                    # trim seed suffix off end 
                    $unsuffixedRenderingId = $renderingId.ToString().TrimEnd($seedSuffix)
                    # add seed value to end 
                    $newPlaceholder = $newPlaceholder.Replace($renderingId, "{$($unsuffixedRenderingId.ToUpper())}-$seedValue")
                }
                else
                {
                    $newPlaceholder = $newPlaceholder.Replace($renderingId, "{$($renderingId.ToUpper())}-0")
                }
            }

            $newPlaceholder = $newPlaceholder.Replace('{_', "-{")
            Write-Host "New Placeholder - [$($newPlaceholder)]"

            # comment following 2 lines if you don't want to do replacement, but want to have log of upcoming placeholder changes
            $rendering.Placeholder = $newPlaceholder
            Set-Rendering -Item $item -Instance $rendering -FinalLayout
        }
    }
}
1

In above script there was a problem in below logic

$renderingId.ToString().TrimEnd($seedSuffix)

This will truncate the last three character if have same number before and after underscore like below example:

$renderingId = "5c43afaf-958c-4d79-8395-41ad5aefd371_1" and $seedSuffix = "_1" then output of $renderingId.ToString().TrimEnd($seedSuffix) will be "5c43afaf-958c-4d79-8395-41ad5aefd37"

I have updated the script to handle this issue which is working fine now.

# specify your path here. It is most likely be page templates and page content
$startPath = "/sitecore/content"
Get-ChildItem -Path $startPath -Recurse | ForEach-Object {
    $item = $_;    
    Get-Rendering -Item $_ -FinalLayout | ForEach-Object {
        $rendering = $_;
        $matches = [regex]::Matches($_.Placeholder,'(?<guid>_[\d\w]{8}\-(?:[\d\w]{4}\-){3}[\d\w]{12})(?<seed>_?\d?)')

        if ($matches.Success) {

            Write-Host "Match found in item - [$($item.Paths.FullPath)]"
            Write-Host "Old Placeholder - [$($rendering.Placeholder)]"

            $newPlaceholder = $rendering.Placeholder

            $matches | ForEach-Object {
                $match = $_
                $renderingId = $match.Value

                if (!([string]::IsNullOrEmpty($match.Groups["seed"])))
                {
                    $seedSuffix = $match.Groups["seed"].ToString()
                    $seedValue = $seedSuffix.Trim("_")

                    # trim seed suffix off end 
                    
                    if($renderingId.ToString().lastIndexOf($seedSuffix) -ge 0)
                    {
                        $unsuffixedRenderingId = $renderingId.ToString().Substring(0, $renderingId.ToString().lastIndexOf($seedSuffix))
                    }
                    else
                    {
                        $unsuffixedRenderingId = $renderingId.ToString()
                    }
                    
                    # add seed value to end 
                    $newPlaceholder = $newPlaceholder.Replace($renderingId, "{$($unsuffixedRenderingId.ToUpper())}-$seedValue")
                }
                else
                {
                    $newPlaceholder = $newPlaceholder.Replace($renderingId, "{$($renderingId.ToUpper())}-0")
                }
            }

            $newPlaceholder = $newPlaceholder.Replace('{_', "-{")
            Write-Host "New Placeholder - [$($newPlaceholder)]"

            # comment following 2 lines if you don't want to do replacement, but want to have log of upcoming placeholder changes
            $rendering.Placeholder = $newPlaceholder
            Set-Rendering -Item $item -Instance $rendering -FinalLayout
        }
    }
}
0

I wrote an aspx page for this which i used for migrating my project which can be found here https://github.com/jeroendegroot/MigrateDynamicPlaceholders It is been a while ago but all existing solutions i found then did not deal with final layouts and nested dynamic placeholders correctly.

1
  • Hi @Jeroen, I think I may have come across your solution in my search for this problem. Thanks for sharing. I believe that vzaverugo's solution accounts for both final layouts and nested placeholders. Just, FYI, I also believe that your solution would need to be updated to account for the case where Fortis adds the incremental seed suffix to ensure a unique placeholder key inside of an individual rendering.
    – Mike M
    Nov 1, 2018 at 14:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.