diff --git a/src/Umbraco.Abstractions/PublishedContentExtensions.cs b/src/Umbraco.Abstractions/PublishedContentExtensions.cs
index 11444a274b..53618ea632 100644
--- a/src/Umbraco.Abstractions/PublishedContentExtensions.cs
+++ b/src/Umbraco.Abstractions/PublishedContentExtensions.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using Umbraco.Core.Composing;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
+using Umbraco.Web.PublishedCache;
namespace Umbraco.Core
{
@@ -101,7 +101,6 @@ namespace Umbraco.Core
return culture != "" && content.Cultures.TryGetValue(culture, out var infos) ? infos.Date : DateTime.MinValue;
}
-
///
/// Gets the children of the content item.
///
@@ -137,6 +136,8 @@ namespace Umbraco.Core
: children.Where(x => x.IsInvariantOrHasCulture(culture));
}
+ #region Writer and creator
+
public static string GetCreatorName(this IPublishedContent content, IUserService userService)
{
var user = userService.GetProfileById(content.CreatorId);
@@ -148,5 +149,713 @@ namespace Umbraco.Core
var user = userService.GetProfileById(content.WriterId);
return user?.Name;
}
+
+ #endregion
+
+ #region Axes: ancestors, ancestors-or-self
+
+ // as per XPath 1.0 specs �2.2,
+ // - the ancestor axis contains the ancestors of the context node; the ancestors of the context node consist
+ // of the parent of context node and the parent's parent and so on; thus, the ancestor axis will always
+ // include the root node, unless the context node is the root node.
+ // - the ancestor-or-self axis contains the context node and the ancestors of the context node; thus,
+ // the ancestor axis will always include the root node.
+ //
+ // as per XPath 2.0 specs �3.2.1.1,
+ // - the ancestor axis is defined as the transitive closure of the parent axis; it contains the ancestors
+ // of the context node (the parent, the parent of the parent, and so on) - The ancestor axis includes the
+ // root node of the tree in which the context node is found, unless the context node is the root node.
+ // - the ancestor-or-self axis contains the context node and the ancestors of the context node; thus,
+ // the ancestor-or-self axis will always include the root node.
+ //
+ // the ancestor and ancestor-or-self axis are reverse axes ie they contain the context node or nodes that
+ // are before the context node in document order.
+ //
+ // document order is defined by �2.4.1 as:
+ // - the root node is the first node.
+ // - every node occurs before all of its children and descendants.
+ // - the relative order of siblings is the order in which they occur in the children property of their parent node.
+ // - children and descendants occur before following siblings.
+
+ ///
+ /// Gets the ancestors of the content.
+ ///
+ /// The content.
+ /// The ancestors of the content, in down-top order.
+ /// Does not consider the content itself.
+ public static IEnumerable Ancestors(this IPublishedContent content)
+ {
+ return content.AncestorsOrSelf(false, null);
+ }
+
+ ///
+ /// Gets the ancestors of the content, at a level lesser or equal to a specified level.
+ ///
+ /// The content.
+ /// The level.
+ /// The ancestors of the content, at a level lesser or equal to the specified level, in down-top order.
+ /// Does not consider the content itself. Only content that are "high enough" in the tree are returned.
+ public static IEnumerable Ancestors(this IPublishedContent content, int maxLevel)
+ {
+ return content.AncestorsOrSelf(false, n => n.Level <= maxLevel);
+ }
+
+ ///
+ /// Gets the ancestors of the content, of a specified content type.
+ ///
+ /// The content.
+ /// The content type.
+ /// The ancestors of the content, of the specified content type, in down-top order.
+ /// Does not consider the content itself. Returns all ancestors, of the specified content type.
+ public static IEnumerable Ancestors(this IPublishedContent content, string contentTypeAlias)
+ {
+ return content.AncestorsOrSelf(false, n => n.ContentType.Alias.InvariantEquals(contentTypeAlias));
+ }
+
+ ///
+ /// Gets the ancestors of the content, of a specified content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The ancestors of the content, of the specified content type, in down-top order.
+ /// Does not consider the content itself. Returns all ancestors, of the specified content type.
+ public static IEnumerable Ancestors(this IPublishedContent content)
+ where T : class, IPublishedContent
+ {
+ return content.Ancestors().OfType();
+ }
+
+ ///
+ /// Gets the ancestors of the content, at a level lesser or equal to a specified level, and of a specified content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The level.
+ /// The ancestors of the content, at a level lesser or equal to the specified level, and of the specified
+ /// content type, in down-top order.
+ /// Does not consider the content itself. Only content that are "high enough" in the trees, and of the
+ /// specified content type, are returned.
+ public static IEnumerable Ancestors(this IPublishedContent content, int maxLevel)
+ where T : class, IPublishedContent
+ {
+ return content.Ancestors(maxLevel).OfType();
+ }
+
+ ///
+ /// Gets the content and its ancestors.
+ ///
+ /// The content.
+ /// The content and its ancestors, in down-top order.
+ public static IEnumerable AncestorsOrSelf(this IPublishedContent content)
+ {
+ return content.AncestorsOrSelf(true, null);
+ }
+
+ ///
+ /// Gets the content and its ancestors, at a level lesser or equal to a specified level.
+ ///
+ /// The content.
+ /// The level.
+ /// The content and its ancestors, at a level lesser or equal to the specified level,
+ /// in down-top order.
+ /// Only content that are "high enough" in the tree are returned. So it may or may not begin
+ /// with the content itself, depending on its level.
+ public static IEnumerable AncestorsOrSelf(this IPublishedContent content, int maxLevel)
+ {
+ return content.AncestorsOrSelf(true, n => n.Level <= maxLevel);
+ }
+
+ ///
+ /// Gets the content and its ancestors, of a specified content type.
+ ///
+ /// The content.
+ /// The content type.
+ /// The content and its ancestors, of the specified content type, in down-top order.
+ /// May or may not begin with the content itself, depending on its content type.
+ public static IEnumerable AncestorsOrSelf(this IPublishedContent content, string contentTypeAlias)
+ {
+ return content.AncestorsOrSelf(true, n => n.ContentType.Alias.InvariantEquals(contentTypeAlias));
+ }
+
+ ///
+ /// Gets the content and its ancestors, of a specified content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The content and its ancestors, of the specified content type, in down-top order.
+ /// May or may not begin with the content itself, depending on its content type.
+ public static IEnumerable AncestorsOrSelf(this IPublishedContent content)
+ where T : class, IPublishedContent
+ {
+ return content.AncestorsOrSelf().OfType();
+ }
+
+ ///
+ /// Gets the content and its ancestor, at a lever lesser or equal to a specified level, and of a specified content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The level.
+ /// The content and its ancestors, at a level lesser or equal to the specified level, and of the specified
+ /// content type, in down-top order.
+ /// May or may not begin with the content itself, depending on its level and content type.
+ public static IEnumerable AncestorsOrSelf(this IPublishedContent content, int maxLevel)
+ where T : class, IPublishedContent
+ {
+ return content.AncestorsOrSelf(maxLevel).OfType();
+ }
+
+ ///
+ /// Gets the ancestor of the content, ie its parent.
+ ///
+ /// The content.
+ /// The ancestor of the content.
+ /// This method is here for consistency purposes but does not make much sense.
+ public static IPublishedContent Ancestor(this IPublishedContent content)
+ {
+ return content.Parent;
+ }
+
+ ///
+ /// Gets the nearest ancestor of the content, at a lever lesser or equal to a specified level.
+ ///
+ /// The content.
+ /// The level.
+ /// The nearest (in down-top order) ancestor of the content, at a level lesser or equal to the specified level.
+ /// Does not consider the content itself. May return null.
+ public static IPublishedContent Ancestor(this IPublishedContent content, int maxLevel)
+ {
+ return content.EnumerateAncestors(false).FirstOrDefault(x => x.Level <= maxLevel);
+ }
+
+ ///
+ /// Gets the nearest ancestor of the content, of a specified content type.
+ ///
+ /// The content.
+ /// The content type alias.
+ /// The nearest (in down-top order) ancestor of the content, of the specified content type.
+ /// Does not consider the content itself. May return null.
+ public static IPublishedContent Ancestor(this IPublishedContent content, string contentTypeAlias)
+ {
+ return content.EnumerateAncestors(false).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
+ }
+
+ ///
+ /// Gets the nearest ancestor of the content, of a specified content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The nearest (in down-top order) ancestor of the content, of the specified content type.
+ /// Does not consider the content itself. May return null.
+ public static T Ancestor(this IPublishedContent content)
+ where T : class, IPublishedContent
+ {
+ return content.Ancestors().FirstOrDefault();
+ }
+
+ ///
+ /// Gets the nearest ancestor of the content, at the specified level and of the specified content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The level.
+ /// The ancestor of the content, at the specified level and of the specified content type.
+ /// Does not consider the content itself. If the ancestor at the specified level is
+ /// not of the specified type, returns null.
+ public static T Ancestor(this IPublishedContent content, int maxLevel)
+ where T : class, IPublishedContent
+ {
+ return content.Ancestors(maxLevel).FirstOrDefault();
+ }
+
+ ///
+ /// Gets the content or its nearest ancestor.
+ ///
+ /// The content.
+ /// The content.
+ /// This method is here for consistency purposes but does not make much sense.
+ public static IPublishedContent AncestorOrSelf(this IPublishedContent content)
+ {
+ return content;
+ }
+
+ ///
+ /// Gets the content or its nearest ancestor, at a lever lesser or equal to a specified level.
+ ///
+ /// The content.
+ /// The level.
+ /// The content or its nearest (in down-top order) ancestor, at a level lesser or equal to the specified level.
+ /// May or may not return the content itself depending on its level. May return null.
+ public static IPublishedContent AncestorOrSelf(this IPublishedContent content, int maxLevel)
+ {
+ return content.EnumerateAncestors(true).FirstOrDefault(x => x.Level <= maxLevel);
+ }
+
+ ///
+ /// Gets the content or its nearest ancestor, of a specified content type.
+ ///
+ /// The content.
+ /// The content type.
+ /// The content or its nearest (in down-top order) ancestor, of the specified content type.
+ /// May or may not return the content itself depending on its content type. May return null.
+ public static IPublishedContent AncestorOrSelf(this IPublishedContent content, string contentTypeAlias)
+ {
+ return content.EnumerateAncestors(true).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
+ }
+
+ ///
+ /// Gets the content or its nearest ancestor, of a specified content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The content or its nearest (in down-top order) ancestor, of the specified content type.
+ /// May or may not return the content itself depending on its content type. May return null.
+ public static T AncestorOrSelf(this IPublishedContent content)
+ where T : class, IPublishedContent
+ {
+ return content.AncestorsOrSelf().FirstOrDefault();
+ }
+
+ ///
+ /// Gets the content or its nearest ancestor, at a lever lesser or equal to a specified level, and of a specified content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The level.
+ ///
+ public static T AncestorOrSelf(this IPublishedContent content, int maxLevel)
+ where T : class, IPublishedContent
+ {
+ return content.AncestorsOrSelf(maxLevel).FirstOrDefault();
+ }
+
+ public static IEnumerable AncestorsOrSelf(this IPublishedContent content, bool orSelf, Func func)
+ {
+ var ancestorsOrSelf = content.EnumerateAncestors(orSelf);
+ return func == null ? ancestorsOrSelf : ancestorsOrSelf.Where(func);
+ }
+
+ ///
+ /// Enumerates ancestors of the content, bottom-up.
+ ///
+ /// The content.
+ /// Indicates whether the content should be included.
+ /// Enumerates bottom-up ie walking up the tree (parent, grand-parent, etc).
+ internal static IEnumerable EnumerateAncestors(this IPublishedContent content, bool orSelf)
+ {
+ if (content == null) throw new ArgumentNullException(nameof(content));
+ if (orSelf) yield return content;
+ while ((content = content.Parent) != null)
+ yield return content;
+ }
+
+ #endregion
+
+ #region Axes: descendants, descendants-or-self
+
+ ///
+ /// Returns all DescendantsOrSelf of all content referenced
+ ///
+ ///
+ /// Variation context accessor.
+ ///
+ /// The specific culture to filter for. If null is used the current culture is used. (Default is null)
+ ///
+ ///
+ /// This can be useful in order to return all nodes in an entire site by a type when combined with TypedContentAtRoot
+ ///
+ public static IEnumerable DescendantsOrSelfOfType(this IEnumerable parentNodes, IVariationContextAccessor variationContextAccessor, string docTypeAlias, string culture = null)
+ {
+ return parentNodes.SelectMany(x => x.DescendantsOrSelfOfType(variationContextAccessor, docTypeAlias, culture));
+ }
+
+ ///
+ /// Returns all DescendantsOrSelf of all content referenced
+ ///
+ ///
+ /// Variation context accessor.
+ /// The specific culture to filter for. If null is used the current culture is used. (Default is null)
+ ///
+ ///
+ /// This can be useful in order to return all nodes in an entire site by a type when combined with TypedContentAtRoot
+ ///
+ public static IEnumerable DescendantsOrSelf(this IEnumerable parentNodes, IVariationContextAccessor variationContextAccessor, string culture = null)
+ where T : class, IPublishedContent
+ {
+ return parentNodes.SelectMany(x => x.DescendantsOrSelf(variationContextAccessor, culture));
+ }
+
+
+ // as per XPath 1.0 specs �2.2,
+ // - the descendant axis contains the descendants of the context node; a descendant is a child or a child of a child and so on; thus
+ // the descendant axis never contains attribute or namespace nodes.
+ // - the descendant-or-self axis contains the context node and the descendants of the context node.
+ //
+ // as per XPath 2.0 specs �3.2.1.1,
+ // - the descendant axis is defined as the transitive closure of the child axis; it contains the descendants of the context node (the
+ // children, the children of the children, and so on).
+ // - the descendant-or-self axis contains the context node and the descendants of the context node.
+ //
+ // the descendant and descendant-or-self axis are forward axes ie they contain the context node or nodes that are after the context
+ // node in document order.
+ //
+ // document order is defined by �2.4.1 as:
+ // - the root node is the first node.
+ // - every node occurs before all of its children and descendants.
+ // - the relative order of siblings is the order in which they occur in the children property of their parent node.
+ // - children and descendants occur before following siblings.
+
+ public static IEnumerable Descendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null)
+ {
+ return content.DescendantsOrSelf(variationContextAccessor, false, null, culture);
+ }
+
+ public static IEnumerable Descendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string culture = null)
+ {
+ return content.DescendantsOrSelf(variationContextAccessor, false, p => p.Level >= level, culture);
+ }
+
+ public static IEnumerable DescendantsOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string culture = null)
+ {
+ return content.DescendantsOrSelf(variationContextAccessor, false, p => p.ContentType.Alias.InvariantEquals(contentTypeAlias), culture);
+ }
+
+ public static IEnumerable Descendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null)
+ where T : class, IPublishedContent
+ {
+ return content.Descendants(variationContextAccessor, culture).OfType();
+ }
+
+ public static IEnumerable Descendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string culture = null)
+ where T : class, IPublishedContent
+ {
+ return content.Descendants(variationContextAccessor, level, culture).OfType();
+ }
+
+ public static IEnumerable DescendantsOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null)
+ {
+ return content.DescendantsOrSelf(variationContextAccessor, true, null, culture);
+ }
+
+ public static IEnumerable DescendantsOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string culture = null)
+ {
+ return content.DescendantsOrSelf(variationContextAccessor, true, p => p.Level >= level, culture);
+ }
+
+ public static IEnumerable DescendantsOrSelfOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string culture = null)
+ {
+ return content.DescendantsOrSelf(variationContextAccessor, true, p => p.ContentType.Alias.InvariantEquals(contentTypeAlias), culture);
+ }
+
+ public static IEnumerable DescendantsOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null)
+ where T : class, IPublishedContent
+ {
+ return content.DescendantsOrSelf(variationContextAccessor, culture).OfType();
+ }
+
+ public static IEnumerable DescendantsOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string culture = null)
+ where T : class, IPublishedContent
+ {
+ return content.DescendantsOrSelf(variationContextAccessor, level, culture).OfType();
+ }
+
+ public static IPublishedContent Descendant(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null)
+ {
+ return content.Children(variationContextAccessor, culture).FirstOrDefault();
+ }
+
+ public static IPublishedContent Descendant(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string culture = null)
+ {
+ return content.EnumerateDescendants(variationContextAccessor, false, culture).FirstOrDefault(x => x.Level == level);
+ }
+
+ public static IPublishedContent DescendantOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string culture = null)
+ {
+ return content.EnumerateDescendants(variationContextAccessor, false, culture).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
+ }
+
+ public static T Descendant(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null)
+ where T : class, IPublishedContent
+ {
+ return content.EnumerateDescendants(variationContextAccessor, false, culture).FirstOrDefault(x => x is T) as T;
+ }
+
+ public static T Descendant(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string culture = null)
+ where T : class, IPublishedContent
+ {
+ return content.Descendant(variationContextAccessor, level, culture) as T;
+ }
+
+ public static IPublishedContent DescendantOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null)
+ {
+ return content;
+ }
+
+ public static IPublishedContent DescendantOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string culture = null)
+ {
+ return content.EnumerateDescendants(variationContextAccessor, true, culture).FirstOrDefault(x => x.Level == level);
+ }
+
+ public static IPublishedContent DescendantOrSelfOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string culture = null)
+ {
+ return content.EnumerateDescendants(variationContextAccessor, true, culture).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
+ }
+
+ public static T DescendantOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null)
+ where T : class, IPublishedContent
+ {
+ return content.EnumerateDescendants(variationContextAccessor, true, culture).FirstOrDefault(x => x is T) as T;
+ }
+
+ public static T DescendantOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string culture = null)
+ where T : class, IPublishedContent
+ {
+ return content.DescendantOrSelf(variationContextAccessor, level, culture) as T;
+ }
+
+ internal static IEnumerable DescendantsOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, bool orSelf, Func func, string culture = null)
+ {
+ return content.EnumerateDescendants(variationContextAccessor, orSelf, culture).Where(x => func == null || func(x));
+ }
+
+ internal static IEnumerable EnumerateDescendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, bool orSelf, string culture = null)
+ {
+ if (content == null) throw new ArgumentNullException(nameof(content));
+ if (orSelf) yield return content;
+
+ foreach (var desc in content.Children(variationContextAccessor, culture).SelectMany(x => x.EnumerateDescendants(variationContextAccessor, culture)))
+ yield return desc;
+ }
+
+ internal static IEnumerable EnumerateDescendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null)
+ {
+ yield return content;
+
+ foreach (var desc in content.Children(variationContextAccessor, culture).SelectMany(x => x.EnumerateDescendants(variationContextAccessor, culture)))
+ yield return desc;
+ }
+
+ #endregion
+
+ #region Axes: children
+
+ ///
+ /// Gets the children of the content, filtered by a predicate.
+ ///
+ /// The content.
+ /// Published snapshot instance
+ /// The predicate.
+ /// The specific culture to filter for. If null is used the current culture is used. (Default is null)
+ /// The children of the content, filtered by the predicate.
+ ///
+ /// Children are sorted by their sortOrder.
+ ///
+ public static IEnumerable Children(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Func predicate, string culture = null)
+ {
+ return content.Children(variationContextAccessor, culture).Where(predicate);
+ }
+
+ ///
+ /// Gets the children of the content, of any of the specified types.
+ ///
+ /// The content.
+ /// Published snapshot instance
+ /// The specific culture to filter for. If null is used the current culture is used. (Default is null)
+ /// The content type alias.
+ /// The children of the content, of any of the specified types.
+ public static IEnumerable ChildrenOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string culture = null)
+ {
+ return content.Children(variationContextAccessor, x => x.ContentType.Alias.InvariantEquals(contentTypeAlias), culture);
+ }
+
+ ///
+ /// Gets the children of the content, of a given content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// Published snapshot instance
+ /// The specific culture to filter for. If null is used the current culture is used. (Default is null)
+ /// The children of content, of the given content type.
+ ///
+ /// Children are sorted by their sortOrder.
+ ///
+ public static IEnumerable Children(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null)
+ where T : class, IPublishedContent
+ {
+ return content.Children(variationContextAccessor, culture).OfType();
+ }
+
+ public static IPublishedContent FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null)
+ {
+ return content.Children(variationContextAccessor, culture).FirstOrDefault();
+ }
+
+ ///
+ /// Gets the first child of the content, of a given content type.
+ ///
+ public static IPublishedContent FirstChildOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string culture = null)
+ {
+ return content.ChildrenOfType(variationContextAccessor, contentTypeAlias, culture).FirstOrDefault();
+ }
+
+ public static IPublishedContent FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Func predicate, string culture = null)
+ {
+ return content.Children(variationContextAccessor, predicate, culture).FirstOrDefault();
+ }
+
+ public static IPublishedContent FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Guid uniqueId, string culture = null)
+ {
+ return content.Children(variationContextAccessor, x => x.Key == uniqueId, culture).FirstOrDefault();
+ }
+
+ public static T FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null)
+ where T : class, IPublishedContent
+ {
+ return content.Children(variationContextAccessor, culture).FirstOrDefault();
+ }
+
+ public static T FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Func predicate, string culture = null)
+ where T : class, IPublishedContent
+ {
+ return content.Children(variationContextAccessor, culture).FirstOrDefault(predicate);
+ }
+
+ #endregion
+
+ #region Axes: parent
+
+ // Parent is native
+
+ ///
+ /// Gets the parent of the content, of a given content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The parent of content, of the given content type, else null.
+ public static T Parent(this IPublishedContent content)
+ where T : class, IPublishedContent
+ {
+ if (content == null) throw new ArgumentNullException(nameof(content));
+ return content.Parent as T;
+ }
+
+ #endregion
+
+ #region Axes: Siblings
+
+ ///
+ /// Gets the siblings of the content.
+ ///
+ /// The content.
+ /// Published snapshot instance
+ /// Variation context accessor.
+ /// The specific culture to filter for. If null is used the current culture is used. (Default is null)
+ /// The siblings of the content.
+ ///
+ /// Note that in V7 this method also return the content node self.
+ ///
+ public static IEnumerable Siblings(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string culture = null)
+ {
+ return SiblingsAndSelf(content, publishedSnapshot, variationContextAccessor, culture).Where(x => x.Id != content.Id);
+ }
+
+ ///
+ /// Gets the siblings of the content, of a given content type.
+ ///
+ /// The content.
+ /// Published snapshot instance
+ /// Variation context accessor.
+ /// The specific culture to filter for. If null is used the current culture is used. (Default is null)
+ /// The content type alias.
+ /// The siblings of the content, of the given content type.
+ ///
+ /// Note that in V7 this method also return the content node self.
+ ///
+ public static IEnumerable SiblingsOfType(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string culture = null)
+ {
+ return SiblingsAndSelfOfType(content, publishedSnapshot, variationContextAccessor, contentTypeAlias, culture).Where(x => x.Id != content.Id);
+ }
+
+ ///
+ /// Gets the siblings of the content, of a given content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// Published snapshot instance
+ /// Variation context accessor.
+ /// The specific culture to filter for. If null is used the current culture is used. (Default is null)
+ /// The siblings of the content, of the given content type.
+ ///
+ /// Note that in V7 this method also return the content node self.
+ ///
+ public static IEnumerable Siblings(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string culture = null)
+ where T : class, IPublishedContent
+ {
+ return SiblingsAndSelf(content, publishedSnapshot, variationContextAccessor, culture).Where(x => x.Id != content.Id);
+ }
+
+ ///
+ /// Gets the siblings of the content including the node itself to indicate the position.
+ ///
+ /// The content.
+ /// Published snapshot instance
+ /// Variation context accessor.
+ /// The specific culture to filter for. If null is used the current culture is used. (Default is null)
+ /// The siblings of the content including the node itself.
+ public static IEnumerable SiblingsAndSelf(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string culture = null)
+ {
+ return content.Parent != null
+ ? content.Parent.Children(variationContextAccessor, culture)
+ : publishedSnapshot.Content.GetAtRoot().WhereIsInvariantOrHasCulture(variationContextAccessor, culture);
+ }
+
+ ///
+ /// Gets the siblings of the content including the node itself to indicate the position, of a given content type.
+ ///
+ /// The content.
+ /// Published snapshot instance
+ /// Variation context accessor.
+ /// The specific culture to filter for. If null is used the current culture is used. (Default is null)
+ /// The content type alias.
+ /// The siblings of the content including the node itself, of the given content type.
+ public static IEnumerable SiblingsAndSelfOfType(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string culture = null)
+ {
+ return content.Parent != null
+ ? content.Parent.ChildrenOfType(variationContextAccessor, contentTypeAlias, culture)
+ : publishedSnapshot.Content.GetAtRoot().OfTypes(contentTypeAlias).WhereIsInvariantOrHasCulture(variationContextAccessor, culture);
+ }
+
+ ///
+ /// Gets the siblings of the content including the node itself to indicate the position, of a given content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// Published snapshot instance
+ /// Variation context accessor.
+ /// The specific culture to filter for. If null is used the current culture is used. (Default is null)
+ /// The siblings of the content including the node itself, of the given content type.
+ public static IEnumerable SiblingsAndSelf(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string culture = null)
+ where T : class, IPublishedContent
+ {
+ return content.Parent != null
+ ? content.Parent.Children(variationContextAccessor, culture)
+ : publishedSnapshot.Content.GetAtRoot().OfType().WhereIsInvariantOrHasCulture(variationContextAccessor, culture);
+ }
+
+ #endregion
+
+ #region Axes: custom
+
+ ///
+ /// Gets the root content for this content.
+ ///
+ /// The content.
+ /// The 'site' content ie AncestorOrSelf(1).
+ public static IPublishedContent Root(this IPublishedContent content)
+ {
+ return content.AncestorOrSelf(1);
+ }
+
+ #endregion
}
}
diff --git a/src/Umbraco.Abstractions/PublishedElementExtensions.cs b/src/Umbraco.Abstractions/PublishedElementExtensions.cs
new file mode 100644
index 0000000000..77b6b1516a
--- /dev/null
+++ b/src/Umbraco.Abstractions/PublishedElementExtensions.cs
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+using System.Linq;
+using Umbraco.Core;
+using Umbraco.Core.Models.PublishedContent;
+
+namespace Umbraco.Core
+{
+ ///
+ /// Provides extension methods for IPublishedElement.
+ ///
+ public static class PublishedElementExtensions
+ {
+ #region OfTypes
+
+ // the .OfType() filter is nice when there's only one type
+ // this is to support filtering with multiple types
+ public static IEnumerable OfTypes(this IEnumerable contents, params string[] types)
+ where T : IPublishedElement
+ {
+ if (types == null || types.Length == 0) return Enumerable.Empty();
+
+ return contents.Where(x => types.InvariantContains(x.ContentType.Alias));
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Umbraco.Infrastructure.PublishedCache/PublishedCacheBase.cs b/src/Umbraco.Infrastructure.PublishedCache/PublishedCacheBase.cs
index 50ee48e1ba..28bc218f54 100644
--- a/src/Umbraco.Infrastructure.PublishedCache/PublishedCacheBase.cs
+++ b/src/Umbraco.Infrastructure.PublishedCache/PublishedCacheBase.cs
@@ -10,6 +10,13 @@ namespace Umbraco.Web.PublishedCache
{
abstract class PublishedCacheBase : IPublishedCache
{
+ private readonly IVariationContextAccessor _variationContextAccessor;
+
+ public PublishedCacheBase(IVariationContextAccessor variationContextAccessor)
+ {
+ _variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor));
+
+ }
public bool PreviewDefault { get; }
protected PublishedCacheBase(bool previewDefault)
@@ -94,14 +101,11 @@ namespace Umbraco.Web.PublishedCache
public virtual IEnumerable GetByContentType(IPublishedContentType contentType)
{
- // TODO: move this extension method and get working again.
-
// this is probably not super-efficient, but works
// some cache implementation may want to override it, though
- return Enumerable.Empty();
- //return GetAtRoot()
- // .SelectMany(x => x.DescendantsOrSelf())
- // .Where(x => x.ContentType.Id == contentType.Id);
+ return GetAtRoot()
+ .SelectMany(x => x.DescendantsOrSelf(_variationContextAccessor))
+ .Where(x => x.ContentType.Id == contentType.Id);
}
}
}
diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs
index 0eaabe0ff6..fe42d5a165 100644
--- a/src/Umbraco.Web/PublishedContentExtensions.cs
+++ b/src/Umbraco.Web/PublishedContentExtensions.cs
@@ -365,305 +365,6 @@ namespace Umbraco.Web
#endregion
- #region Axes: ancestors, ancestors-or-self
-
- // as per XPath 1.0 specs �2.2,
- // - the ancestor axis contains the ancestors of the context node; the ancestors of the context node consist
- // of the parent of context node and the parent's parent and so on; thus, the ancestor axis will always
- // include the root node, unless the context node is the root node.
- // - the ancestor-or-self axis contains the context node and the ancestors of the context node; thus,
- // the ancestor axis will always include the root node.
- //
- // as per XPath 2.0 specs �3.2.1.1,
- // - the ancestor axis is defined as the transitive closure of the parent axis; it contains the ancestors
- // of the context node (the parent, the parent of the parent, and so on) - The ancestor axis includes the
- // root node of the tree in which the context node is found, unless the context node is the root node.
- // - the ancestor-or-self axis contains the context node and the ancestors of the context node; thus,
- // the ancestor-or-self axis will always include the root node.
- //
- // the ancestor and ancestor-or-self axis are reverse axes ie they contain the context node or nodes that
- // are before the context node in document order.
- //
- // document order is defined by �2.4.1 as:
- // - the root node is the first node.
- // - every node occurs before all of its children and descendants.
- // - the relative order of siblings is the order in which they occur in the children property of their parent node.
- // - children and descendants occur before following siblings.
-
- ///
- /// Gets the ancestors of the content.
- ///
- /// The content.
- /// The ancestors of the content, in down-top order.
- /// Does not consider the content itself.
- public static IEnumerable Ancestors(this IPublishedContent content)
- {
- return content.AncestorsOrSelf(false, null);
- }
-
- ///
- /// Gets the ancestors of the content, at a level lesser or equal to a specified level.
- ///
- /// The content.
- /// The level.
- /// The ancestors of the content, at a level lesser or equal to the specified level, in down-top order.
- /// Does not consider the content itself. Only content that are "high enough" in the tree are returned.
- public static IEnumerable Ancestors(this IPublishedContent content, int maxLevel)
- {
- return content.AncestorsOrSelf(false, n => n.Level <= maxLevel);
- }
-
- ///
- /// Gets the ancestors of the content, of a specified content type.
- ///
- /// The content.
- /// The content type.
- /// The ancestors of the content, of the specified content type, in down-top order.
- /// Does not consider the content itself. Returns all ancestors, of the specified content type.
- public static IEnumerable Ancestors(this IPublishedContent content, string contentTypeAlias)
- {
- return content.AncestorsOrSelf(false, n => n.ContentType.Alias.InvariantEquals(contentTypeAlias));
- }
-
- ///
- /// Gets the ancestors of the content, of a specified content type.
- ///
- /// The content type.
- /// The content.
- /// The ancestors of the content, of the specified content type, in down-top order.
- /// Does not consider the content itself. Returns all ancestors, of the specified content type.
- public static IEnumerable Ancestors(this IPublishedContent content)
- where T : class, IPublishedContent
- {
- return content.Ancestors().OfType();
- }
-
- ///
- /// Gets the ancestors of the content, at a level lesser or equal to a specified level, and of a specified content type.
- ///
- /// The content type.
- /// The content.
- /// The level.
- /// The ancestors of the content, at a level lesser or equal to the specified level, and of the specified
- /// content type, in down-top order.
- /// Does not consider the content itself. Only content that are "high enough" in the trees, and of the
- /// specified content type, are returned.
- public static IEnumerable Ancestors(this IPublishedContent content, int maxLevel)
- where T : class, IPublishedContent
- {
- return content.Ancestors(maxLevel).OfType();
- }
-
- ///
- /// Gets the content and its ancestors.
- ///
- /// The content.
- /// The content and its ancestors, in down-top order.
- public static IEnumerable AncestorsOrSelf(this IPublishedContent content)
- {
- return content.AncestorsOrSelf(true, null);
- }
-
- ///
- /// Gets the content and its ancestors, at a level lesser or equal to a specified level.
- ///
- /// The content.
- /// The level.
- /// The content and its ancestors, at a level lesser or equal to the specified level,
- /// in down-top order.
- /// Only content that are "high enough" in the tree are returned. So it may or may not begin
- /// with the content itself, depending on its level.
- public static IEnumerable AncestorsOrSelf(this IPublishedContent content, int maxLevel)
- {
- return content.AncestorsOrSelf(true, n => n.Level <= maxLevel);
- }
-
- ///
- /// Gets the content and its ancestors, of a specified content type.
- ///
- /// The content.
- /// The content type.
- /// The content and its ancestors, of the specified content type, in down-top order.
- /// May or may not begin with the content itself, depending on its content type.
- public static IEnumerable AncestorsOrSelf(this IPublishedContent content, string contentTypeAlias)
- {
- return content.AncestorsOrSelf(true, n => n.ContentType.Alias.InvariantEquals(contentTypeAlias));
- }
-
- ///
- /// Gets the content and its ancestors, of a specified content type.
- ///
- /// The content type.
- /// The content.
- /// The content and its ancestors, of the specified content type, in down-top order.
- /// May or may not begin with the content itself, depending on its content type.
- public static IEnumerable AncestorsOrSelf(this IPublishedContent content)
- where T : class, IPublishedContent
- {
- return content.AncestorsOrSelf().OfType();
- }
-
- ///
- /// Gets the content and its ancestor, at a lever lesser or equal to a specified level, and of a specified content type.
- ///
- /// The content type.
- /// The content.
- /// The level.
- /// The content and its ancestors, at a level lesser or equal to the specified level, and of the specified
- /// content type, in down-top order.
- /// May or may not begin with the content itself, depending on its level and content type.
- public static IEnumerable AncestorsOrSelf(this IPublishedContent content, int maxLevel)
- where T : class, IPublishedContent
- {
- return content.AncestorsOrSelf(maxLevel).OfType();
- }
-
- ///
- /// Gets the ancestor of the content, ie its parent.
- ///
- /// The content.
- /// The ancestor of the content.
- /// This method is here for consistency purposes but does not make much sense.
- public static IPublishedContent Ancestor(this IPublishedContent content)
- {
- return content.Parent;
- }
-
- ///
- /// Gets the nearest ancestor of the content, at a lever lesser or equal to a specified level.
- ///
- /// The content.
- /// The level.
- /// The nearest (in down-top order) ancestor of the content, at a level lesser or equal to the specified level.
- /// Does not consider the content itself. May return null.
- public static IPublishedContent Ancestor(this IPublishedContent content, int maxLevel)
- {
- return content.EnumerateAncestors(false).FirstOrDefault(x => x.Level <= maxLevel);
- }
-
- ///
- /// Gets the nearest ancestor of the content, of a specified content type.
- ///
- /// The content.
- /// The content type alias.
- /// The nearest (in down-top order) ancestor of the content, of the specified content type.
- /// Does not consider the content itself. May return null.
- public static IPublishedContent Ancestor(this IPublishedContent content, string contentTypeAlias)
- {
- return content.EnumerateAncestors(false).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
- }
-
- ///
- /// Gets the nearest ancestor of the content, of a specified content type.
- ///
- /// The content type.
- /// The content.
- /// The nearest (in down-top order) ancestor of the content, of the specified content type.
- /// Does not consider the content itself. May return null.
- public static T Ancestor(this IPublishedContent content)
- where T : class, IPublishedContent
- {
- return content.Ancestors().FirstOrDefault();
- }
-
- ///
- /// Gets the nearest ancestor of the content, at the specified level and of the specified content type.
- ///
- /// The content type.
- /// The content.
- /// The level.
- /// The ancestor of the content, at the specified level and of the specified content type.
- /// Does not consider the content itself. If the ancestor at the specified level is
- /// not of the specified type, returns null.
- public static T Ancestor(this IPublishedContent content, int maxLevel)
- where T : class, IPublishedContent
- {
- return content.Ancestors(maxLevel).FirstOrDefault();
- }
-
- ///
- /// Gets the content or its nearest ancestor.
- ///
- /// The content.
- /// The content.
- /// This method is here for consistency purposes but does not make much sense.
- public static IPublishedContent AncestorOrSelf(this IPublishedContent content)
- {
- return content;
- }
-
- ///
- /// Gets the content or its nearest ancestor, at a lever lesser or equal to a specified level.
- ///
- /// The content.
- /// The level.
- /// The content or its nearest (in down-top order) ancestor, at a level lesser or equal to the specified level.
- /// May or may not return the content itself depending on its level. May return null.
- public static IPublishedContent AncestorOrSelf(this IPublishedContent content, int maxLevel)
- {
- return content.EnumerateAncestors(true).FirstOrDefault(x => x.Level <= maxLevel);
- }
-
- ///
- /// Gets the content or its nearest ancestor, of a specified content type.
- ///
- /// The content.
- /// The content type.
- /// The content or its nearest (in down-top order) ancestor, of the specified content type.
- /// May or may not return the content itself depending on its content type. May return null.
- public static IPublishedContent AncestorOrSelf(this IPublishedContent content, string contentTypeAlias)
- {
- return content.EnumerateAncestors(true).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
- }
-
- ///
- /// Gets the content or its nearest ancestor, of a specified content type.
- ///
- /// The content type.
- /// The content.
- /// The content or its nearest (in down-top order) ancestor, of the specified content type.
- /// May or may not return the content itself depending on its content type. May return null.
- public static T AncestorOrSelf(this IPublishedContent content)
- where T : class, IPublishedContent
- {
- return content.AncestorsOrSelf().FirstOrDefault();
- }
-
- ///
- /// Gets the content or its nearest ancestor, at a lever lesser or equal to a specified level, and of a specified content type.
- ///
- /// The content type.
- /// The content.
- /// The level.
- ///
- public static T AncestorOrSelf(this IPublishedContent content, int maxLevel)
- where T : class, IPublishedContent
- {
- return content.AncestorsOrSelf(maxLevel).FirstOrDefault();
- }
-
- public static IEnumerable AncestorsOrSelf(this IPublishedContent content, bool orSelf, Func func)
- {
- var ancestorsOrSelf = content.EnumerateAncestors(orSelf);
- return func == null ? ancestorsOrSelf : ancestorsOrSelf.Where(func);
- }
-
- ///
- /// Enumerates ancestors of the content, bottom-up.
- ///
- /// The content.
- /// Indicates whether the content should be included.
- /// Enumerates bottom-up ie walking up the tree (parent, grand-parent, etc).
- internal static IEnumerable EnumerateAncestors(this IPublishedContent content, bool orSelf)
- {
- if (content == null) throw new ArgumentNullException(nameof(content));
- if (orSelf) yield return content;
- while ((content = content.Parent) != null)
- yield return content;
- }
-
- #endregion
-
#region Axes: descendants, descendants-or-self
///
@@ -678,7 +379,7 @@ namespace Umbraco.Web
///
public static IEnumerable DescendantsOrSelfOfType(this IEnumerable parentNodes, string docTypeAlias, string culture = null)
{
- return parentNodes.SelectMany(x => x.DescendantsOrSelfOfType(docTypeAlias, culture));
+ return parentNodes.DescendantsOrSelfOfType(VariationContextAccessor, docTypeAlias, culture);
}
///
@@ -693,176 +394,110 @@ namespace Umbraco.Web
public static IEnumerable DescendantsOrSelf(this IEnumerable parentNodes, string culture = null)
where T : class, IPublishedContent
{
- return parentNodes.SelectMany(x => x.DescendantsOrSelf(culture));
+ return parentNodes.DescendantsOrSelf(VariationContextAccessor, culture);
}
-
-
- // as per XPath 1.0 specs �2.2,
- // - the descendant axis contains the descendants of the context node; a descendant is a child or a child of a child and so on; thus
- // the descendant axis never contains attribute or namespace nodes.
- // - the descendant-or-self axis contains the context node and the descendants of the context node.
- //
- // as per XPath 2.0 specs �3.2.1.1,
- // - the descendant axis is defined as the transitive closure of the child axis; it contains the descendants of the context node (the
- // children, the children of the children, and so on).
- // - the descendant-or-self axis contains the context node and the descendants of the context node.
- //
- // the descendant and descendant-or-self axis are forward axes ie they contain the context node or nodes that are after the context
- // node in document order.
- //
- // document order is defined by �2.4.1 as:
- // - the root node is the first node.
- // - every node occurs before all of its children and descendants.
- // - the relative order of siblings is the order in which they occur in the children property of their parent node.
- // - children and descendants occur before following siblings.
-
+
public static IEnumerable Descendants(this IPublishedContent content, string culture = null)
{
- return content.DescendantsOrSelf(false, null, culture);
+ return content.Descendants(VariationContextAccessor, culture);
}
public static IEnumerable Descendants(this IPublishedContent content, int level, string culture = null)
{
- return content.DescendantsOrSelf(false, p => p.Level >= level, culture);
+ return content.Descendants(VariationContextAccessor, level, culture);
}
public static IEnumerable DescendantsOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
{
- return content.DescendantsOrSelf(false, p => p.ContentType.Alias.InvariantEquals(contentTypeAlias), culture);
+ return content.DescendantsOfType(VariationContextAccessor, contentTypeAlias, culture);
}
public static IEnumerable Descendants(this IPublishedContent content, string culture = null)
where T : class, IPublishedContent
{
- return content.Descendants(culture).OfType();
+ return content.Descendants(VariationContextAccessor, culture);
}
public static IEnumerable Descendants(this IPublishedContent content, int level, string culture = null)
where T : class, IPublishedContent
{
- return content.Descendants(level, culture).OfType();
+ return content.Descendants(VariationContextAccessor, level, culture);
}
public static IEnumerable DescendantsOrSelf(this IPublishedContent content, string culture = null)
{
- return content.DescendantsOrSelf(true, null, culture);
+ return content.DescendantsOrSelf(VariationContextAccessor, culture);
}
public static IEnumerable DescendantsOrSelf(this IPublishedContent content, int level, string culture = null)
{
- return content.DescendantsOrSelf(true, p => p.Level >= level, culture);
+ return content.DescendantsOrSelf(VariationContextAccessor, level, culture);
}
public static IEnumerable DescendantsOrSelfOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
{
- return content.DescendantsOrSelf(true, p => p.ContentType.Alias.InvariantEquals(contentTypeAlias), culture);
+ return content.DescendantsOrSelfOfType(VariationContextAccessor, contentTypeAlias, culture);
}
public static IEnumerable DescendantsOrSelf(this IPublishedContent content, string culture = null)
where T : class, IPublishedContent
{
- return content.DescendantsOrSelf(culture).OfType();
+ return content.DescendantsOrSelf(VariationContextAccessor, culture);
}
public static IEnumerable DescendantsOrSelf(this IPublishedContent content, int level, string culture = null)
where T : class, IPublishedContent
{
- return content.DescendantsOrSelf(level, culture).OfType();
+ return content.DescendantsOrSelf(VariationContextAccessor, level, culture);
}
public static IPublishedContent Descendant(this IPublishedContent content, string culture = null)
{
- return content.Children(VariationContextAccessor, culture).FirstOrDefault();
+ return content.Descendant(VariationContextAccessor, culture);
}
public static IPublishedContent Descendant(this IPublishedContent content, int level, string culture = null)
{
- return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x.Level == level);
+ return content.Descendant(VariationContextAccessor, level, culture);
}
public static IPublishedContent DescendantOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
{
- return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
+ return content.DescendantOfType(VariationContextAccessor, contentTypeAlias, culture);
}
public static T Descendant(this IPublishedContent content, string culture = null)
where T : class, IPublishedContent
{
- return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x is T) as T;
+ return content.Descendant(VariationContextAccessor, culture);
}
public static T Descendant(this IPublishedContent content, int level, string culture = null)
where T : class, IPublishedContent
{
- return content.Descendant(level, culture) as T;
- }
-
- public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string culture = null)
- {
- return content;
+ return content.Descendant(VariationContextAccessor, level, culture);
}
public static IPublishedContent DescendantOrSelf(this IPublishedContent content, int level, string culture = null)
{
- return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x.Level == level);
+ return content.DescendantOrSelf(VariationContextAccessor, level, culture);
}
public static IPublishedContent DescendantOrSelfOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
{
- return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
+ return content.DescendantOrSelfOfType(VariationContextAccessor, contentTypeAlias, culture);
}
public static T DescendantOrSelf(this IPublishedContent content, string culture = null)
where T : class, IPublishedContent
{
- return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x is T) as T;
+ return content.DescendantOrSelf(VariationContextAccessor, culture);
}
public static T DescendantOrSelf(this IPublishedContent content, int level, string culture = null)
where T : class, IPublishedContent
{
- return content.DescendantOrSelf(level, culture) as T;
- }
-
- internal static IEnumerable DescendantsOrSelf(this IPublishedContent content, bool orSelf, Func func, string culture = null)
- {
- return content.EnumerateDescendants(orSelf, culture).Where(x => func == null || func(x));
- }
-
- internal static IEnumerable EnumerateDescendants(this IPublishedContent content, bool orSelf, string culture = null)
- {
- if (content == null) throw new ArgumentNullException(nameof(content));
- if (orSelf) yield return content;
-
- foreach (var desc in content.Children(VariationContextAccessor, culture).SelectMany(x => x.EnumerateDescendants(culture)))
- yield return desc;
- }
-
- internal static IEnumerable EnumerateDescendants(this IPublishedContent content, string culture = null)
- {
- yield return content;
-
- foreach (var desc in content.Children(VariationContextAccessor, culture).SelectMany(x => x.EnumerateDescendants(culture)))
- yield return desc;
- }
-
- #endregion
-
- #region Axes: parent
-
- // Parent is native
-
- ///
- /// Gets the parent of the content, of a given content type.
- ///
- /// The content type.
- /// The content.
- /// The parent of content, of the given content type, else null.
- public static T Parent(this IPublishedContent content)
- where T : class, IPublishedContent
- {
- if (content == null) throw new ArgumentNullException(nameof(content));
- return content.Parent as T;
+ return content.DescendantOrSelf(VariationContextAccessor, level, culture);
}
#endregion
@@ -893,7 +528,7 @@ namespace Umbraco.Web
/// The children of the content, of any of the specified types.
public static IEnumerable ChildrenOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
{
- return content.Children(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias), culture);
+ return content.Children(VariationContextAccessor, x => x.ContentType.Alias.InvariantEquals(contentTypeAlias), culture);
}
///
@@ -922,29 +557,29 @@ namespace Umbraco.Web
///
public static IPublishedContent FirstChildOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
{
- return content.ChildrenOfType(contentTypeAlias, culture).FirstOrDefault();
+ return content.ChildrenOfType(VariationContextAccessor, contentTypeAlias, culture).FirstOrDefault();
}
public static IPublishedContent FirstChild(this IPublishedContent content, Func predicate, string culture = null)
{
- return content.Children(predicate, culture).FirstOrDefault();
+ return content.Children(VariationContextAccessor, predicate, culture).FirstOrDefault();
}
public static IPublishedContent FirstChild(this IPublishedContent content, Guid uniqueId, string culture = null)
{
- return content.Children(x=>x.Key == uniqueId, culture).FirstOrDefault();
+ return content.Children(VariationContextAccessor, x => x.Key == uniqueId, culture).FirstOrDefault();
}
public static T FirstChild(this IPublishedContent content, string culture = null)
where T : class, IPublishedContent
{
- return content.Children(culture).FirstOrDefault();
+ return content.Children(VariationContextAccessor, culture).FirstOrDefault();
}
public static T FirstChild(this IPublishedContent content, Func predicate, string culture = null)
where T : class, IPublishedContent
{
- return content.Children(culture).FirstOrDefault(predicate);
+ return content.Children(VariationContextAccessor, culture).FirstOrDefault(predicate);
}
///
@@ -1040,7 +675,7 @@ namespace Umbraco.Web
///
public static IEnumerable Siblings(this IPublishedContent content, string culture = null)
{
- return SiblingsAndSelf(content, culture).Where(x => x.Id != content.Id);
+ return content.Siblings(PublishedSnapshot, VariationContextAccessor, culture);
}
///
@@ -1055,7 +690,7 @@ namespace Umbraco.Web
///
public static IEnumerable SiblingsOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
{
- return SiblingsAndSelfOfType(content, contentTypeAlias, culture).Where(x => x.Id != content.Id);
+ return content.SiblingsOfType(PublishedSnapshot, VariationContextAccessor, contentTypeAlias, culture);
}
///
@@ -1071,7 +706,7 @@ namespace Umbraco.Web
public static IEnumerable Siblings(this IPublishedContent content, string culture = null)
where T : class, IPublishedContent
{
- return SiblingsAndSelf(content, culture).Where(x => x.Id != content.Id);
+ return content.Siblings(PublishedSnapshot, VariationContextAccessor, culture);
}
///
@@ -1082,9 +717,7 @@ namespace Umbraco.Web
/// The siblings of the content including the node itself.
public static IEnumerable SiblingsAndSelf(this IPublishedContent content, string culture = null)
{
- return content.Parent != null
- ? content.Parent.Children(VariationContextAccessor, culture)
- : PublishedSnapshot.Content.GetAtRoot().WhereIsInvariantOrHasCulture(VariationContextAccessor, culture);
+ return content.SiblingsAndSelf(PublishedSnapshot, VariationContextAccessor, culture);
}
///
@@ -1096,9 +729,7 @@ namespace Umbraco.Web
/// The siblings of the content including the node itself, of the given content type.
public static IEnumerable SiblingsAndSelfOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
{
- return content.Parent != null
- ? content.Parent.ChildrenOfType(contentTypeAlias, culture)
- : PublishedSnapshot.Content.GetAtRoot().OfTypes(contentTypeAlias).WhereIsInvariantOrHasCulture(VariationContextAccessor, culture);
+ return content.SiblingsAndSelfOfType(PublishedSnapshot, VariationContextAccessor, contentTypeAlias, culture);
}
///
@@ -1111,23 +742,7 @@ namespace Umbraco.Web
public static IEnumerable SiblingsAndSelf(this IPublishedContent content, string culture = null)
where T : class, IPublishedContent
{
- return content.Parent != null
- ? content.Parent.Children(culture)
- : PublishedSnapshot.Content.GetAtRoot().OfType().WhereIsInvariantOrHasCulture(VariationContextAccessor, culture);
- }
-
- #endregion
-
- #region Axes: custom
-
- ///
- /// Gets the root content for this content.
- ///
- /// The content.
- /// The 'site' content ie AncestorOrSelf(1).
- public static IPublishedContent Root(this IPublishedContent content)
- {
- return content.AncestorOrSelf(1);
+ return content.SiblingsAndSelf(PublishedSnapshot, VariationContextAccessor, culture);
}
#endregion
diff --git a/src/Umbraco.Web/PublishedElementExtensions.cs b/src/Umbraco.Web/PublishedElementExtensions.cs
index 982f5566f5..661c740d90 100644
--- a/src/Umbraco.Web/PublishedElementExtensions.cs
+++ b/src/Umbraco.Web/PublishedElementExtensions.cs
@@ -157,20 +157,6 @@ namespace Umbraco.Web
#endregion
- #region OfTypes
-
- // the .OfType() filter is nice when there's only one type
- // this is to support filtering with multiple types
- public static IEnumerable OfTypes(this IEnumerable contents, params string[] types)
- where T : IPublishedElement
- {
- if (types == null || types.Length == 0) return Enumerable.Empty();
-
- return contents.Where(x => types.InvariantContains(x.ContentType.Alias));
- }
-
- #endregion
-
#region IsSomething
///
diff --git a/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs b/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs
index fcf6f55f44..dffb956b1a 100644
--- a/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs
+++ b/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Events;