Sunday, April 30, 2023

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!

No comments:

Post a Comment

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...