4

I'm writing an SPE script and am looping over my site nodes. For each site node, I want to check if a particular descendant exists and if not then create it. I have the list of top-level nodes, but cannot figure out how to query each of those nodes for a descendant.

If I was writing in regular query syntax, I could write something like this:

var sites = database.SelectItems("fast:/sitecore/content/Master/*[@@templatename='Website']");
foreach (var site in sites)
{
    var settingsItem = site.Axes.SelectItem("descendant::*[@@templatename='Settings']");
    //now check if SettingsItem is null, if so create etc
}

What I have in my SPE script:

#get the list of top-level site nodes
$sites = Get-Item master: -Query "fast:/sitecore/content/Master//*[@@templatename='Website']";
foreach ($site in $sites)
{
    # get descendant of each $site item that inherits from "Settings" template 
    $settings = ???
    if ($settings == null) {
        #create settings item etc...
    }   
}
4

In your code, $site will be of the type Sitecore.Data.Items.BaseItem, so it has all the standard API available.

You can achieve the desired behavior like this:

$settings =
    $site.Axes.GetDescendants() |
        ? { $_.TemplateName -eq "Settings" } |
        select -first 1

if($settings -eq $null) {
    # create settings etc
}

If performance is important for you, you can use Fast Query:

$query = "fast:" + $site.Paths.Path + "//*[@@templateid='{your-template-id-here}']"

$settings = Get-Item master: -Query $query | select -first 1

Note that I used the ID of the template instead of its name. This reduces the need for SQL joins and makes the query much faster.

  • Cool, I didn't know about calling methods like that. $site.Axes.GetDescendants() will be a bit of a killer though won't it.. Presume I could also do $site.Axes.SelectSingleItem() right? – Matthew Dresser Nov 24 '16 at 21:58
  • 1
    @MatthewDresser Your original SelectSingleItem query will perform exactly the same as GetDescendants. See my updated answer for a faster solution. – Dmytro Shevchenko Nov 25 '16 at 6:16
  • ah ok, thanks for that, I didn't know about that. Thanks for the updated solution. Out of interest, if the site item (or one of its ancestors) was named with a space or underscore or hyphen, would that query still work, or would I need to escape it manually? – Matthew Dresser Nov 25 '16 at 9:17
  • 1
    @MatthewDresser It would work even with whitespaces, underscores and hyphens, yes. – Dmytro Shevchenko Nov 25 '16 at 9:26
2

Try this snippet.

# get descendant of each $site item that inherits from "Settings" template 
# $site = gi .
$settingsBase = "{6669DC16-F106-44B5-96BE-7A31AE82B5B5}"
$settingItems= Get-ChildItem -Path $site.Paths.Path | Where-Object { 
    [Sitecore.Data.Managers.TemplateManager]::GetTemplate($_).InheritsFrom($settingsBase) 
}

$settingsBase is a base settings template ID or base settings template Name.

Be careful. If you have multiple settings it will return an array, so select single (first element) you can use $settingItems | select -First 1

  • I just need to find descendants of the site item based on my "Settings" template. – Matthew Dresser Nov 24 '16 at 22:02
  • Isn't my code doing that? (removed -Recurse switch) – Alan Płócieniak Nov 24 '16 at 22:08
  • Apologies, my question was badly worded, it should have said "...of an item using a template" – Matthew Dresser Nov 24 '16 at 22:15
  • No worries. I am glad you've got a solution for your problem. – Alan Płócieniak Nov 24 '16 at 22:19
0

Dmytro Shevchenko's answer did what was needed, but the Axes.GetDescendants() call will, as the name suggests, retrieve all items which is a pretty expensive operation. The code below seems to work ok:

$settings = $site.Axes.SelectSingleItem("descendant::*[@@templatename='Settings']")
  • It doesn't meet that criteria: "get a descendant of an item inheriting from a template", which is important if your solution must work on instances where somebody wants to override Settings template. – Alan Płócieniak Nov 24 '16 at 22:13
  • 1
    Please note that, since your query is not a Fast Query, this solution will be equivalent to .GetDescendants(), i.e. it will iterate through each item's children recursively. If you really need good performance, you can try converting your query to a Fast Query. Keep in mind that descendant:: won't work with Fast Query unless you change the value of the FastQueryDescendantsDisabled setting to true in the Sitecore.config. – Dmytro Shevchenko Nov 25 '16 at 5:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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