How do I get content by slug/path without Xpath now that it's deprecated?
t
From v13 methods such as umbracohelpers
ContentSingleAtXPath
is being deprecated. For example, we get our global settings node as such:
var globalSettings = (GlobalSettings)_umbracoHelper.ContentSingleAtXPath("//globalsettings");
How can we get the same published content but adhering to current conventions? Looking at the documentation there is a method
Content
that takes a
guid
, but we do not wish to rely on a hard coded guid for this scenario. We need to base this on what the slug is named within the backoffice. And yes, we know there might be other approaches that do not rely on the slug to solve this, but this is our current scenario and not the only instance we need to cater to.
s
Use the Guid! ๐Ÿ˜‚ ๐Ÿ˜‰
They're unique and don't change per environment.. unless you recreate the content in all environments manually every time. ๐Ÿ˜…
Of course there's also still the option to traverse the tree
_umbracoHelper.GetContentAtRoot().First(x => x.Alias == "globalsettings")
(hardcoding an alias instead of a Guid.. up to you). Untested code, don't expect it to work without some tweaking ๐Ÿ™‚
d
I have been using
GetByContentType( ... )
to replace that specific xpath query.
s
Good one! If you know whereabouts it lives in the tree then this is a bit more effecient. Otherwise we just have to iterate until we find a page of that type.. won't make a huge difference I would guess though.
t
Is that on UmbracoHelper?
d
Not sure. It's definitely on the
IUmbracoContext
though
I stopped using umbraco helper tbh, because outside of razor pages, I don't really trust it anymore
t
I think I found a decent solution for now, something like:
Copy code
var globalSettings =
                (GlobalSettings)(from node in _umbracoHelper.ContentAtRoot()
                where node.ContentType.Alias == "globalSettings"
                select node).First();
Although Sebastiaans variant looks smoother
s
Think that translates to
Copy code
csharp
var globalSettings = _umbracoHelper
                     .ContentAtRoot()
                     .First(x => x.ContentType.Alias == "globalSettings")
                     as GlobalSettings;
m
To avoid using magic strings (assuming you're using generated models), you can use
GlobalSettings.ModelTypeAlias
, though
umbracoHelper.ContentAtRoot().OfType<GlobalSettings>().First()
would be my go-to solution
m
What we seem to have lost with the removal of xpath type queries though is that
//doctype
xpath of get the first one anywhere in the tree without me knowing where it is and so having to go traversing. I guess we fallback to examine for that? or is linq traversal now just a quick?
d
GetByContentType
on the UmbracoContext object does the same as that specific xpath query as far as I know.
m
Was aware of that one..
Copy code
public virtual IEnumerable<IPublishedContent> GetByContentType(IPublishedContentType contentType) =>

        // this is probably not super-efficient, but works
        // some cache implementation may want to override it, though
        GetAtRoot()
            .SelectMany(x => x.DescendantsOrSelf(_variationContextAccessor!))
            .Where(x => x.ContentType.Id == contentType.Id);
First comment says it all ๐Ÿ™‚ ... and it was the
ContentSingleAtXPath("//doctype")
.. I guess is the same as
GetByContentType().FirstorDefault()
though would this enumerate the entire content tree rather than stop once it found the first item? Also I've come a cropper over that first here isn't always equivalent to first in xpath... think it traverses down each sub tree to the very bottom descendant before moving on.. where as the xpath traverses siblings first, before then moving onto the next tier of descendants? But might be mistaken.... ๐Ÿ˜‰
d
This sounds familiar. I also heard that variations of
.Descendants
did a depth-first search instead of breadth-first
244 Views