Using Sitecore Item IDs in Code

At the core of every item in Sitecore is its template. Whether creating a new rendering or overriding a pipeline processor, accessing an item's fields or checking its template is unavoidable.

Even though Sitecore allows for getting field value by its name and makes it easy to check an item's template by comparing its name to a string, the solution is far from perfect. Relying on item's names might cause some problems as it is possible for one template to include two fields with the same name (usually in separate sections or through template inheritance). In that case, getting the value of the proper field may prove difficult.

Fortunately, instead of using names, Sitecore IDs can be used. As they are unique to each item (and therefore field), the aforementioned problem is nipped in the bud. Another great argument in favour of using IDs is that they are generally more stable than names (i.e. it is less likely for them to change over time). What's more, in Sitecore 9.1 a new method for checking if an item is derived from a particular template became available - DescendsFrom, which expects the base template's ID as its parameter. You can read more about its greatness in my previous post.

So what's the best way to store template IDs in a solution? The one seen in Sitecore itself is pretty untidy as the IDs are thrown into one static TemplateIds class. The solution shown in Helix documentation and practised in Habitat is much cleaner and more pleasant to use. In essence, it features a Templates struct (or a static class) filled with structs representing templates introduced in the Helix module.

For me personally, the biggest pain has always been writing those structs by hand and copy-pasting the IDs into the ID class constructor calls. Sometimes my fingers jammed and I copied the wrong ID or instead of pasting, I copied. So I decided to do what any developer with a tedious task in front of them would do - I automated it.

Naturally, I chose Sitecore PowerShell Extensions as my weapon of choice (by the way - if you're still not using it, start now, thank me later). The script is not complicated in any way, so there does not seem to be any merit in going over it section by section. Here it is in its entirety:

$outerFormat = "public static class {0}"
$innerFormat = "public static readonly ID {0} = new ID(`"{1}`");"

function AppendIndentedLine($sb, $text = "", $indent = 0)
{
    for ($i = 0; $i -lt $indent; ++$i)
    {
        [void]$sb.Append("`t")
    }
    [void]$sb.AppendLine($text)
}

function NormalizeName($name)
{
    $name -replace " ",""
}

$item = Get-Item .
if ($item.TemplateName -ne "Template")
{
    $item = $item.Template
}

$fields = Get-ChildItem -Recurse $item.ID |? { $_.TemplateName -eq "Template field" }
$sb = [System.Text.StringBuilder]::new()
AppendIndentedLine $sb  ($outerFormat -f (NormalizeName $item.Name))
AppendIndentedLine $sb "{"
AppendIndentedLine $sb ($innerFormat -f "ID", $item.ID) 1
AppendIndentedLine $sb
AppendIndentedLine $sb  ($outerFormat -f "Fields") 1
AppendIndentedLine $sb "{" 1
foreach ($field in $fields)
{
    AppendIndentedLine $sb ($innerFormat -f (NormalizeName $field.Name), $field.ID) 2
}
AppendIndentedLine $sb "}" 1
AppendIndentedLine $sb "}"
Write-Host $sb
Show-Result -Text

Here's what the result looks like:

This little exercise also taught me how easy it is to put a script in the context menu of Content Editor. Simply save the script under /sitecore/system/Modules/PowerShell/Script Library/SPE/Tools/Authoring Instrumentation/Content Editor/Context Menu and that's it, a new option should be available in the Scripts submenu.

Here is a Sitecore package containing the script in the appropriate location.

Known Issue:
The Script Execution Result window may wrap the code with newline characters so that it has to be fixed manually after pasting.
Solution:
Open PowerShell ISE from Launchpad, go to Settings ribbon tab, select Settings Results and set the Host Width property to a bigger value, e.g. 1000.

Yes, I do see the irony in using the Template field template's name instead of its ID in the script 😉

Cover photo by Andrea Muti on Unsplash