Sunday, April 30, 2023

Add rendering to the existing page and change the datasource using Powershell Script in Sitecore

  This blog can help you to work with Sitecore CMS and work with PowerShell script more efficiently. The following code snippet will be used to add rendering to the page and change the datasource to the rendering programmatically using the PowerShell script.

This code should work with any version of Sitecore. 

Open - Development Tools -> PowerShell ISE and paste the following code.

Modify the paths and fields according to your template fields.


1. Add rendering to the existing page

    PowerShell script code:    

$masterdatabase = "master"
$webdatabase = "web"
$root = Get-Item -Path (@{$true="$($masterdatabase):\sitecore\content\AKWeb\Home\Articles"; $false="$($masterdatabase):\content"}[(Test-Path -Path "$($masterdatabase):\content\home")])
$RenderingItem = Get-Item -Path (@{$true="$($masterdatabase):\sitecore\layout\Renderings\Feature\SubHeader";$false="$($masterdatabase):\content"}[(Test-Path -Path "$($masterdatabase):\content\home")])
$DatasourcePath = Get-Item -Path (@{$true="$($masterdatabase):\sitecore\content\AKWeb\Shared\Datasources\SubHeader\SubHeader";$false="$($masterdatabase):\content"}[(Test-Path -Path "$($masterdatabase):\content\home")])
$placeholderH = "header"
#Find the rendering item and convert to a rendering
$renderingItemWithPlaceholder = $RenderingItem | New-Rendering -Placeholder "header"
$IsRenderingAdded= $true
$count=0
$changedItems=New-Object System.Collections.ArrayList
$props = @{
    Parameters = @(
        @{Name="root"; Title="Choose the report root"; Tooltip="Only items from this root will be returned."; }
        @{Name="RenderingItem"; Title="Choose the Rendering"; Tooltip="Only items from this root will be returned."; }
        @{Name="DatasourcePath"; Title="Choose the Datasource"; Tooltip="Only items from this root will be returned."; }
           )
    Title = "Add Rendering to Article Pages"
    Description = "Choose the criteria for the report."
    Width = 550
    Height = 300
    ShowHints = $true
    Icon = [regex]::Replace($PSScript.Appearance.Icon, "Office", "OfficeWhite", [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
}

$result = Read-Variable @props

if($result -eq "cancel") {
    exit
}

filter Where-Addrendering {
    param(
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [Sitecore.Data.Items.Item]$item
    )
    
    if ($item) {
		$defaultLayout = Get-LayoutDevice "Default"
        $AllRenderingsInPlaceholder= Get-Rendering -Item $item -Rendering $RenderingItem -Placeholder "*header*" -Device $defaultLayout -FinalLayout
        foreach($rItem in $AllRenderingsInPlaceholder){
    if($rItem.ItemId -eq $RenderingItem.Id){
       #$count+=1
       #if($count -eq 1)
       #{
                    #$renderingItem = Get-Item -Path $rendering.ItemID
                    Write-Host "Removing Rendering: $($rItem) for Item $($item.Name)"
                    Remove-Rendering -Item $item -Instance $rItem -Device $defaultLayout -FinalLayout
                    
            Write-Host "Removing Rendering: $($rItem) for Item $($item.Name)"
           #$count=0;
       #}
    }
}
             $sidebarComponentInPlaceholder= Get-Rendering -Item $item -Rendering $RenderingItem -Placeholder "*header*" -Device $defaultLayout -FinalLayout
		   if($sidebarComponentInPlaceholder -eq $null){
		  # if($IsRenderingAdded){
		        Add-Rendering -Item $item -PlaceHolder "header" -Instance $renderingItemWithPlaceholder -Index 1 -Datasource $DatasourcePath.Paths.Path -Device $defaultLayout -FinalLayout
		    	$count+=1;
		    	Write-Host "Removing Rendering: $($rItem) for Item $($item.Name)"
		    	#$IsRenderingAdded=$false
		    	$changedItem=New-Object PSObject -Property @{
		    	    Name=$item.Name
		    	    ItemPath=$item.Paths.Path
		    	    RenderingName=$RenderingItem.Name
		    	    DatasourcePath=$DatasourcePath.Paths.Path
		    	}
		    	$changedItems.Add($changedItem)
		   }
        #}
    }
}

$items = @($root) + @(($root.Axes.GetDescendants())) | Where-Object {$_.TemplateName -eq "Article Page"} | Initialize-Item
$finalitems = $items | Where-Addrendering

if($changedItems.Count -eq 0) {
    Show-Alert "Zero Renderings added."
} else {
      #$finalitems = $items | Where-Addrendering
    $props = @{
        Title = "Rendering Added on Items"
        InfoTitle = "Rendering Added on Items  $($count)"
        InfoDescription = "Rendering Added on Items  $($changedItems.Count)"
        PageSize = 25
    }
    
    $changedItems |
        Show-ListView @props -Property @{Label="Icon"; Expression={$_.__Icon} },
            @{Label="Name"; Expression={$_.Name} },
            @{Label="RenderingName"; Expression={$RenderingItem.Name} },
            @{Label="Datasource Path"; Expression={$DatasourcePath.Paths.Path} },
            @{Label="ItemPath"; Expression={$_.ItemPath} }
}

Close-Window

2. Change the datasource to the rendering

    PowerShell script code:    

$masterdatabase = "master"
$webdatabase = "web"
$root = Get-Item -Path (@{$true="$($masterdatabase):\sitecore\content\AKWeb\Home"; $false="$($masterdatabase):\content"}[(Test-Path -Path "$($masterdatabase):\content\home")])
$RenderingItem = Get-Item -Path (@{$true="$($masterdatabase):\sitecore\layout\Renderings\Feature\AKWeb\Components\Banner\Banner Rendering";$false="$($masterdatabase):\content"}[(Test-Path -Path "$($masterdatabase):\content\home")])
$DatasourcePath = Get-Item -Path (@{$true="$($masterdatabase):\sitecore\content\AKWeb\Shared\Datasources\Banner Dark Theme\Test Rendering Datasource";$false="$($masterdatabase):\content"}[(Test-Path -Path "$($masterdatabase):\content\home")])
$placeholderH = "*footer*"
#Find the rendering item and convert to a rendering
$renderingItemWithPlaceholder = $RenderingItem | New-Rendering -Placeholder $placeholderH
$IsRenderingAdded= $true
$count=0
$changedItems=New-Object System.Collections.ArrayList
$props = @{
    Parameters = @(
        @{Name="root"; Title="Choose the report root"; Tooltip="Only items from this root will be returned."; }
        @{Name="RenderingItem"; Title="Choose the Rendering"; Tooltip="Only items from this root will be returned."; }
        @{Name="DatasourcePath"; Title="Choose the Datasource"; Tooltip="Only items from this root will be returned."; }
           )
    Title = "Add Rendering to Article Pages"
    Description = "Choose the criteria for the report."
    Width = 550
    Height = 300
    ShowHints = $true
    Icon = [regex]::Replace($PSScript.Appearance.Icon, "Office", "OfficeWhite", [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
}

$result = Read-Variable @props

if($result -eq "cancel") {
    exit
}

filter Where-Addrendering {
    param(
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [Sitecore.Data.Items.Item]$item
    )
    
    if ($item) {
		$defaultLayout = Get-LayoutDevice "Default"
        $AllRenderingsInPlaceholder= Get-Rendering -Item $item -Placeholder $placeholderH -Device $defaultLayout -FinalLayout
        $sidebarComponentInPlaceholder= Get-Rendering -Item $item -Rendering $RenderingItem -Placeholder $placeholderH -Device $defaultLayout -FinalLayout
        
        if($sidebarComponentInPlaceholder -eq $null)
        {
             Add-Rendering -Item $item -PlaceHolder $placeholderH -Instance $renderingItemWithPlaceholder -Datasource $DatasourcePath.Paths.Path -Device $defaultLayout -FinalLayout
		    	$count+=1;
		    	$changedItem=New-Object PSObject -Property @{
		    	    Name=$item.Name
		    	    ItemPath=$item.Paths.Path
		    	    RenderingName=$RenderingItem.Name
		    	    DatasourcePath=$DatasourcePath.Paths.Path
		    	}
		    	$changedItems.Add($changedItem)
        }
        else{
       # Get-Rendering -Item $item -Placeholder $placeholderH | 
        foreach($rendering in $AllRenderingsInPlaceholder)
        {
		   #if($sidebarComponentInPlaceholder -ne $null){
		   if($rendering.ItemId -eq '{6YUIY897-H67L-4B89-MMA7F-0OJKY78L9}'){
		       $rendering.DataSource = $DatasourcePath.Paths.Path
                Set-Rendering -Item $item -Instance $rendering
		        #Set-Rendering -Item $item -PlaceHolder $placeholderH -Instance $renderingItemWithPlaceholder -Datasource $DatasourcePath.Paths.Path -Device $defaultLayout -FinalLayout
		    	$count+=1;
		    	#$IsRenderingAdded=$false
		    	$changedItem=New-Object PSObject -Property @{
		    	    Name=$item.Name
		    	    ItemPath=$item.Paths.Path
		    	    RenderingName=$rendering.Name
		    	    DatasourcePath=$DatasourcePath.Paths.Path
		    	}
		    	$changedItems.Add($changedItem)
		   }
		       
		   #}
        }
       }
    }
}

$items = @($root) + @(($root.Axes.GetDescendants())) | Where-Object {$_.TemplateName -eq "Article Page"} | Initialize-Item
$finalitems = $items | Where-Addrendering

if($changedItems.Count -eq 0) {
    Show-Alert "Zero Renderings added."
} else {
      #$finalitems = $items | Where-Addrendering
    $props = @{
        Title = "Rendering Added on Items"
        InfoTitle = "Rendering Added on Items  $($count)"
        InfoDescription = "Rendering Added on Items  $($changedItems.Count)"
        PageSize = 25
    }
    
    $changedItems |
        Show-ListView @props -Property @{Label="Icon"; Expression={$_.__Icon} },
            @{Label="Name"; Expression={$_.Name} },
            @{Label="RenderingName"; Expression={$RenderingItem.Name} },
            @{Label="Datasource Path"; Expression={$DatasourcePath.Paths.Path} },
            @{Label="ItemPath"; Expression={$_.ItemPath} }
}

Close-Window


How to identify broken links in Sitecore?

This blog can help you to work with Sitecore CMS and find out broken links more efficiently. The following code snippet will be used to find out the broken links, generate the report and fix the broken links.

This code should work with any version of Sitecore.

Open - Development Tools -> PowerShell ISE and paste the following code.

Modify the paths and fields according to your template fields.

PowerShell Script Code:

$htmlDocument = New-Object -TypeName HtmlAgilityPack.HtmlDocument
function Get-Item-Lookup {
    param(
        [string]$Field,
        [string] $Value
    )
$root = Get-Item -Path ("master:/" + "/sitecore/content/Web/Home");
$TemplateID = "{2R89HJK-4B42-U7ghj-94F9-27899JHKL}"
$fieldForSearch = $Field
$value = $Value
$templateId = [id]::Parse($TemplateID)
$criteria = @(
	@{ Filter = "DescendantOf"; Value = $root.ID }
	@{ Filter = "Equals" ; Field = $fieldForSearch; Value = $value }
	@{ Filter = "Equals"; Field = "_template"; Value = $templateId }
)
$props = @{
	Index = "sitecore_master_index"
	Criteria = $criteria
}
$Item = Find-Item @props -First 1 | Initialize-Item
$Item

}

filter HasBrokenLink {
	param(
		[Parameter(Mandatory = $true,ValueFromPipeline = $true)]
		[Sitecore.Data.Items.Item]$Item,

		[Parameter()]
		[bool]$IncludeAllVersions
	)
	if ($Item)
	{
		try {
			$content = $Item["Content"];
			# logic to find all internal links from anchor tag
			$htmlDocument.LoadHtml($content)
			$anchors = $htmlDocument.DocumentNode.Descendants("A");
			$allLinks = ""; $replaceWith = ""; $postId = "";
			foreach ($link in $anchors)
			{
				#logic to filter out only internal links
				$foundHref = $link.Attributes["href"].Value;
				$urlPattern = '(\/|/?)post/[0-9]+';
				#$urlPattern = '(/)post/[0-9]+';
				#	$urlPattern='^post.*'
				if ($foundHref -match $urlPattern) {
					$postId += $foundHref.Substring($foundHref.lastIndexOf('/') + 1) + "<br/>"
					$allLinks += $foundHref + "<br/>"
					#TBD-Look for Article with Post ID.
					#create a funtion to do lookup by passing post id
					# after Artcile found. replace it with broken link to point to internal article item
					$pageItem = $Item # TBD- replace it with actual Article ID. 
					#	$replaceWith += "href=`"~/link.aspx?_id=" + $pageItem.ID.Guid.ToString("N").ToUpper() + "&amp;_z=z`"" + "<br/>"
					$replaceWith = "~/link.aspx?_id=" + $pageItem.ID.Guid.ToString("N").ToUpper() + "&amp;_z=z"
					$content = $content.Replace($foundHref,$replaceWith);
						<#	$Item.Editing.BeginEdit()
                   $Item["Content"] = $content.Replace($foundHref, $replaceWith);
                  $Item.Editing.EndEdit() | Out-Null
                  #>


				}
			}
			if (!$allLinks) { return }

			$brokenItem = [pscustomobject]@{
				"ID" = $Item.ID
				"Icon" = $Item.__Icon
				"DisplayName" = $Item.DisplayName
				"ItemPath" = $Item.ItemPath
				"Version" = $Item.Version
				"Language" = $Item.Language
				"__Updated" = $Item.__Updated
				"__Updated by" = $Item."__Updated by"
				"Link Field" = $fieldItem.Name
				"Rendering" = $brokenRenderingItem.Name
				"Placeholder" = $brokenRendering.Placeholder
				"Target Url" = $allLinks
				"Status Code" = "status code"
				"Broken Link Field" = ""
				"Link Type" = "Internal"
				"Post ID" = $postId
				"Internal  Article Link" = $replaceWith
				"Replaced Content" = $content
			}
			$brokenItem


		}
		catch {


		}
	}
}



$database = "master"
$root = Get-Item -Path (@{ $true = "$($database):\content"; $false = "$($database):\content" }[(Test-Path -Path "$($database):\content\home")])

$versionOptions = [ordered]@{
	"Latest" = "1"
}

$props = @{
	Parameters = @(
		@{ Name = "root"; Title = "Choose the report root"; Tooltip = "Only items in this branch will be returned."; Columns = 9 },
		@{ Name = "searchVersion"; Value = "1"; Title = "Version"; Options = $versionOptions; Tooltip = "Choose a version."; Columns = "3"; Placeholder = "All" }
	)
	Title = "Broken Internal Links Report"
	Description = "Choose the criteria for the report."
	Width = 550
	Height = 300
	ShowHints = $true
}

$result = Read-Variable @props

if ($result -eq "cancel") {
	exit
}

$items = Get-ChildItem -Path $root.ProviderPath -Recurse | Initialize-Item | Where-Object { $_.TemplateID -eq "{2E86CFFC-4B42-4AD9-94F9-2594D3ED607B}" } | HasBrokenLink -IncludeAllVersions (!$searchVersion)

if ($items.Count -eq 0) {
	Show-Alert "There are no items found which have broken internal links in the current language."
} else {
	$props = @{
		Title = "Broken Internal Links Report With Additional Info"
		InfoTitle = "$($items.Count) items with broken internal links found!"
		InfoDescription = "The report checked for internal links in $(@('all versions','latest versions')[[byte]($searchVersion='1')]) of items."
		MissingDataMessage = "There are no items found which have broken internal links in the current language."
		PageSize = 25
	}

	$items |
	Show-ListView @props -Property "ID","Status Code","Broken Link Field","Target Url","Post ID","Internal  Article Link","Replaced Content",
	@{ Label = "Name"; Expression = { $_.DisplayName } },
	@{ Label = "Path"; Expression = { $_.ItemPath } },
	"Version",
	"Language",
	@{ Label = "Updated"; Expression = { $_.__Updated } },
	@{ Label = "Updated by"; Expression = { $_."__Updated by" } }

}
Close-Window
$ArticleItem=Get-Item-Lookup -Field  "Title" -Value "Article Page"
$ArticleItem


                                                        Happy learning!

How to Create a Public Link Using the Sitecore Content Hub REST API

Creating a public link using the Sitecore Content Hub REST API is a straightforward process that enables you to share content externally whi...