4

We have a problem with orphaned rendering in pages.

Content editors are directly removing the parent Components instead of deleting both parent and child rendering in the Experience Editor. This ends up with many orphans (Child) rendering on the page because of deleting only the parent component (Like containers, etc.,).

We need to clean up orphans rendering on the page using PowerShell script. Some of the parent components are having both static and dynamic placeholders as well.

Could you please help with any script reference?

2
  • Out of curiosity, why do you need to do that?
    – MStodd
    Commented Jun 11, 2023 at 1:10
  • 1
    Content authors while editing any page through experience editor, they are not removing unnecessary rendering on the page, this increases the page load and also we use third party translator provider where they will charge based on page word count. these unnecessary data sources are also getting added and increasing our cost. Commented Jun 12, 2023 at 16:09

3 Answers 3

2

You can try out this script that Identifies and Removing Unknown Renderings. I think this would be a good start to what you are looking for and extend it.

The script utilizes the Get-Item command from SPE to retrieve the target item. It then examines the layout definition and iterates through the renderings associated with the item. For each rendering, the script verifies the existence of the referenced Item ID within Sitecore. If an Unknown Rendering is detected, it is removed from the layout definition, preventing broken links and ensuring a consistent rendering experience for end-users.


$itemPath = "<your-path>"
$item = Get-Item -Path $itemPath

#Shared or Final Layout?
$sharedLayout = $true

# Get the layout field
if($sharedLayout) {
    $layoutField = New-Object Sitecore.Data.Fields.LayoutField -ArgumentList $item.Fields[[Sitecore.FieldIDs]::LayoutField]
} else {
    $layoutField = New-Object Sitecore.Data.Fields.LayoutField -ArgumentList $item.Fields[[Sitecore.FieldIDs]::FinalLayoutField]
}

# Parse the layout definition
$layoutDefinition = [Sitecore.Layouts.LayoutDefinition]::Parse($layoutField.Value)

# Get the device definition (in that case the Default)
$ddef = $layoutDefinition.GetDevice("{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}")

# Get the array of all renderings for the target page item
$renderingsArray = $ddef.Renderings | ForEach-Object { [Sitecore.Layouts.RenderingDefinition]$_ }

# Create lists to manipulate the Rendering list
$originalRenderingsList = [System.Collections.Generic.List[Sitecore.Layouts.RenderingDefinition]]($renderingsArray)
$newRenderingsList = [System.Collections.Generic.List[Sitecore.Layouts.RenderingDefinition]]($renderingsArray)

#For each rendering, checks if the item exist ()
$originalRenderingsList | Where { 
    $renderingItem = Get-Item -Path "master:" -ID $_.ItemId -ErrorAction SilentlyContinue
    
    if(!$renderingItem) {
        Write-Host $_.ItemId - "Unknown Rendering Found"
        $newRenderingsList.Remove($_)
    } 
}

# Update the renderings array in the device definition
$ddef.Renderings = $newRenderingsList.ToArray()

# Save the layout changes
$item.Editing.BeginEdit()
$layoutField.Value = $layoutDefinition.ToXml()
$item.Editing.EndEdit()

Credit : Identifying and Removing Unknown Renderings

Hope it helps!

2
  • 1
    I'm looking out to remove orphan rendering which were added in any dynamic placeholder not the unknown renderings. Anyways thanks for your response! Commented Jun 12, 2023 at 16:10
  • Thank you for the credits =) unfortunately, it doesn't do what Sudheer needs. Commented Aug 18, 2023 at 14:56
2

Well, in this case, I think there are only 2 options available: identify these orphans' renderings by placeholder name or by rendering ID or both.

Try this:

$itemPath = "<your-path>"
$item = Get-Item -Path $itemPath

#Shared or Final Layout?
$sharedLayout = $true

# Get the layout field
if($sharedLayout) {
    $layoutField = New-Object Sitecore.Data.Fields.LayoutField -ArgumentList $item.Fields[[Sitecore.FieldIDs]::LayoutField]
} else {
    $layoutField = New-Object Sitecore.Data.Fields.LayoutField -ArgumentList $item.Fields[[Sitecore.FieldIDs]::FinalLayoutField]
}

# Parse the layout definition
$layoutDefinition = [Sitecore.Layouts.LayoutDefinition]::Parse($layoutField.Value)

# Get the device definition (in that case the Default)
$ddef = $layoutDefinition.GetDevice("{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}")

# Get the array of all renderings for the target page item
$renderingsArray = $ddef.Renderings | ForEach-Object { [Sitecore.Layouts.RenderingDefinition]$_ }

# Create lists to manipulate the Rendering list
$originalRenderingsList = [System.Collections.Generic.List[Sitecore.Layouts.RenderingDefinition]]($renderingsArray)
$newRenderingsList = [System.Collections.Generic.List[Sitecore.Layouts.RenderingDefinition]]($renderingsArray)

#For each rendering, checks if the item exist ()
$originalRenderingsList | Where {
    
    #Change here the placeholder name and/or the ItemID - The ItemID means the ID of the rendering
    if($_.Placeholder -eq "main" -or $_.ItemID -eq "{CE4ADCFB-7990-4980-83FB-A00C1E3673DB}") {
        Write-Host $_.ItemId - "Orphan Rendering Found"
        $newRenderingsList.Remove($_)
    } 
}

# Update the renderings array in the device definition
$ddef.Renderings = $newRenderingsList.ToArray()

# Save the layout changes
$item.Editing.BeginEdit()
$layoutField.Value = $layoutDefinition.ToXml()
$item.Editing.EndEdit()
1

Cleaning up orphaned renderings in Sitecore, especially when content editors remove parent components without also removing child renderings, can be a challenging task. This is particularly true when dealing with both static and dynamic placeholders. Here’s a PowerShell script that you can use to find and clean up orphaned renderings on a Sitecore page.

Here's a PowerShell script to get you started:

# Define the root path of the pages where orphaned renderings need to be cleaned up
$rootPath = "/sitecore/content/Home"

# Get the root item
$rootItem = Get-Item -Path $rootPath

# Function to find and remove orphaned renderings
function Remove-OrphanedRenderings {
    param (
        [Sitecore.Data.Items.Item]$item
    )
    
    # Get all renderings (static and dynamic)
    $renderings = @()
    $placeholders = $item.Visualization.Renderings
    
    foreach ($placeholder in $placeholders) {
        foreach ($rendering in $placeholder) {
            $renderings += $rendering
        }
    }

    # Process each rendering
    foreach ($rendering in $renderings) {
        $componentItem = Get-Item -Path $rendering.DataSource
        if ($componentItem -eq $null -or -not $componentItem.Exists) {
            # If the parent component does not exist, remove the rendering
            Write-Host "Orphaned rendering found: $($rendering.Id) at $($item.Paths.FullPath)"
            Remove-Rendering -Item $item -Rendering $rendering
        }
    }
}

# Function to remove a specific rendering
function Remove-Rendering {
    param (
        [Sitecore.Data.Items.Item]$item,
        [Sitecore.Mvc.Presentation.Rendering]$rendering
    )

    # Find and remove the rendering from the item
    $placeholder = $item.Visualization.Renderings | Where-Object { $_.Contains($rendering) }
    if ($placeholder) {
        $placeholder.Remove($rendering)
        Write-Host "Removed rendering $($rendering.Id) from $($item.Paths.FullPath)"
    }
}

# Recursively process items under the root item
$itemsToProcess = Get-Item -Path $rootPath -Recurse

foreach ($item in $itemsToProcess) {
    Remove-OrphanedRenderings -item $item
}

Write-Host "Orphaned rendering cleanup completed."

If you have specific requirements or additional complexities (like custom placeholder types or specific rendering setups), you might need to further adjust the script accordingly.

New contributor
jammy is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.

Your Answer

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

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