diff --git a/src/Umbraco.Web.Common/DependencyInjection/StaticServiceProvider.cs b/src/Umbraco.Web.Common/DependencyInjection/StaticServiceProvider.cs
new file mode 100644
index 0000000000..c73685b41d
--- /dev/null
+++ b/src/Umbraco.Web.Common/DependencyInjection/StaticServiceProvider.cs
@@ -0,0 +1,25 @@
+using System;
+using System.ComponentModel;
+
+namespace Umbraco.Cms.Web.Common.DependencyInjection
+{
+ ///
+ /// INTERNAL Service locator. Should only be used if no other ways exist.
+ ///
+ ///
+ /// It is created with only two goals in mind
+ /// 1) Continue to have the same extension methods on IPublishedContent and IPublishedElement as in V8. To make migration easier.
+ /// 2) To have a tool to avoid breaking changes in minor versions. All methods using this should in theory be obsolete.
+ ///
+ /// Keep in mind, every time this is used, the code becomes basically untestable.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal static class StaticServiceProvider
+ {
+ ///
+ /// The service locator.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal static IServiceProvider Instance { get; set; }
+ }
+}
diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoStartupFilter.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoStartupFilter.cs
index d843bfb4aa..f8ca73e283 100644
--- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoStartupFilter.cs
+++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoStartupFilter.cs
@@ -19,6 +19,7 @@ namespace Umbraco.Cms.Web.Common.DependencyInjection
public Action Configure(Action next) =>
app =>
{
+ StaticServiceProvider.Instance = app.ApplicationServices;
_options.Value.PreUmbracoPipeline(app);
app.UseUmbraco();
diff --git a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs
new file mode 100644
index 0000000000..b9cdddfdeb
--- /dev/null
+++ b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs
@@ -0,0 +1,537 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using Examine;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using Umbraco.Cms.Core;
+using Umbraco.Cms.Core.Configuration.Models;
+using Umbraco.Cms.Core.Models.PublishedContent;
+using Umbraco.Cms.Core.PublishedCache;
+using Umbraco.Cms.Core.Routing;
+using Umbraco.Cms.Core.Services;
+using Umbraco.Cms.Core.Web;
+using Umbraco.Cms.Web.Common.DependencyInjection;
+
+namespace Umbraco.Extensions
+{
+ public static class FriendlyPublishedContentExtensions
+ {
+ private static IVariationContextAccessor VariationContextAccessor { get; } =
+ StaticServiceProvider.Instance.GetRequiredService();
+
+ private static IPublishedModelFactory PublishedModelFactory { get; } =
+ StaticServiceProvider.Instance.GetRequiredService();
+
+ private static IPublishedUrlProvider PublishedUrlProvider { get; } =
+ StaticServiceProvider.Instance.GetRequiredService();
+
+ private static IUserService UserService { get; } =
+ StaticServiceProvider.Instance.GetRequiredService();
+
+ private static IUmbracoContextAccessor UmbracoContextAccessor { get; } =
+ StaticServiceProvider.Instance.GetRequiredService();
+
+ private static ISiteDomainHelper SiteDomainHelper { get; } =
+ StaticServiceProvider.Instance.GetRequiredService();
+
+ private static IExamineManager ExamineManager { get; } =
+ StaticServiceProvider.Instance.GetRequiredService();
+
+ private static IFileService FileService { get; } =
+ StaticServiceProvider.Instance.GetRequiredService();
+
+ private static IOptions WebRoutingSettings { get; } =
+ StaticServiceProvider.Instance.GetRequiredService>();
+
+ private static IContentTypeService ContentTypeService { get; } =
+ StaticServiceProvider.Instance.GetRequiredService();
+
+ private static IPublishedValueFallback PublishedValueFallback { get; } =
+ StaticServiceProvider.Instance.GetRequiredService();
+
+ private static IPublishedSnapshot PublishedSnapshot => UmbracoContextAccessor.UmbracoContext?.PublishedSnapshot;
+
+ private static IMediaTypeService MediaTypeService { get; } =
+ StaticServiceProvider.Instance.GetRequiredService();
+
+
+ private static IMemberTypeService MemberTypeService { get; } =
+ StaticServiceProvider.Instance.GetRequiredService();
+
+
+ ///
+ /// Creates a strongly typed published content model for an internal published content.
+ ///
+ /// The internal published content.
+ /// The strongly typed published content model.
+ public static IPublishedContent CreateModel(
+ this IPublishedContent content)
+ => content.CreateModel(PublishedModelFactory);
+
+ ///
+ /// Gets the name of the content item.
+ ///
+ /// The content item.
+ /// The specific culture to get the name for. If null is used the current culture is used (Default is null).
+ public static string Name(
+ this IPublishedContent content,
+ string culture = null)
+ => content.Name(VariationContextAccessor, culture);
+
+ ///
+ /// Gets the URL segment of the content item.
+ ///
+ /// The content item.
+ /// The specific culture to get the URL segment for. If null is used the current culture is used (Default is null).
+ public static string UrlSegment(
+ this IPublishedContent content,
+ string culture = null)
+ => content.UrlSegment(VariationContextAccessor, culture);
+
+ ///
+ /// Gets the culture date of the content item.
+ ///
+ /// The content item.
+ /// The specific culture to get the name for. If null is used the current culture is used (Default is null).
+ public static DateTime CultureDate(
+ this IPublishedContent content,
+ string culture = null)
+ => content.CultureDate(VariationContextAccessor, culture);
+
+ ///
+ /// Returns the current template Alias
+ ///
+ /// Empty string if none is set.
+ public static string GetTemplateAlias(this IPublishedContent content)
+ => content.GetTemplateAlias(FileService);
+
+ public static bool IsAllowedTemplate(this IPublishedContent content, int templateId)
+ => content.IsAllowedTemplate(ContentTypeService, WebRoutingSettings.Value, templateId);
+
+ public static bool IsAllowedTemplate(
+ this IPublishedContent content,
+ bool disableAlternativeTemplates,
+ bool validateAlternativeTemplates,
+ int templateId)
+ => content.IsAllowedTemplate(
+ ContentTypeService,
+ disableAlternativeTemplates,
+ validateAlternativeTemplates,
+ templateId);
+
+ public static bool IsAllowedTemplate(
+ this IPublishedContent content,
+ bool disableAlternativeTemplates,
+ bool validateAlternativeTemplates,
+ string templateAlias)
+ => content.IsAllowedTemplate(
+ FileService,
+ ContentTypeService,
+ disableAlternativeTemplates,
+ validateAlternativeTemplates,
+ templateAlias);
+
+
+ ///
+ /// Gets a value indicating whether the content has a value for a property identified by its alias.
+ ///
+ /// The content.
+ /// The property alias.
+ /// The variation language.
+ /// The variation segment.
+ /// Optional fallback strategy.
+ /// A value indicating whether the content has a value for the property identified by the alias.
+ /// Returns true if HasValue is true, or a fallback strategy can provide a value.
+ public static bool HasValue(
+ this IPublishedContent content,
+ string alias,
+ string culture = null,
+ string segment = null,
+ Fallback fallback = default)
+ =>
+ content.HasValue(PublishedValueFallback, alias, culture, segment, fallback);
+
+ ///
+ /// Gets the value of a content's property identified by its alias, if it exists, otherwise a default value.
+ ///
+ /// The content.
+ /// The property alias.
+ /// The variation language.
+ /// The variation segment.
+ /// Optional fallback strategy.
+ /// The default value.
+ /// The value of the content's property identified by the alias, if it exists, otherwise a default value.
+ public static object Value(this IPublishedContent content, string alias, string culture = null, string segment = null, Fallback fallback = default, object defaultValue = default)
+ => content.Value(PublishedValueFallback, alias, culture, segment, fallback, defaultValue);
+
+ ///
+ /// Gets the value of a content's property identified by its alias, converted to a specified type.
+ ///
+ /// The target property type.
+ /// The content.
+ /// The property alias.
+ /// The variation language.
+ /// The variation segment.
+ /// Optional fallback strategy.
+ /// The default value.
+ /// The value of the content's property identified by the alias, converted to the specified type.
+ public static T Value(this IPublishedContent content, string alias, string culture = null, string segment = null, Fallback fallback = default, T defaultValue = default)
+ => content.Value(PublishedValueFallback, alias, culture, segment, fallback, defaultValue);
+
+ ///
+ /// Returns all DescendantsOrSelf of all content referenced
+ ///
+ ///
+ ///
+ /// 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, string docTypeAlias, string culture = null)
+ => parentNodes.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,
+ string culture = null)
+ where T : class, IPublishedContent
+ => parentNodes.DescendantsOrSelf(VariationContextAccessor, culture);
+
+ public static IEnumerable Descendants(this IPublishedContent content, string culture = null)
+ => content.Descendants(VariationContextAccessor, culture);
+
+ public static IEnumerable Descendants(this IPublishedContent content, int level, string culture = null)
+ => content.Descendants(VariationContextAccessor, level, culture);
+
+ public static IEnumerable DescendantsOfType(this IPublishedContent content,
+ string contentTypeAlias, string culture = null)
+ => content.DescendantsOfType(VariationContextAccessor, contentTypeAlias, culture);
+
+ public static IEnumerable Descendants(this IPublishedContent content, string culture = null)
+ where T : class, IPublishedContent
+ => content.Descendants(VariationContextAccessor, culture);
+
+ public static IEnumerable Descendants(this IPublishedContent content, int level, string culture = null)
+ where T : class, IPublishedContent
+ => content.Descendants(VariationContextAccessor, level, culture);
+
+ public static IEnumerable DescendantsOrSelf(this IPublishedContent content, string culture = null)
+ => content.DescendantsOrSelf(VariationContextAccessor, culture);
+
+
+ public static IEnumerable DescendantsOrSelf(this IPublishedContent content, int level, string culture = null)
+ => content.DescendantsOrSelf(VariationContextAccessor, level, culture);
+
+ public static IEnumerable DescendantsOrSelfOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
+ => content.DescendantsOrSelfOfType(VariationContextAccessor, contentTypeAlias, culture);
+
+ public static IEnumerable DescendantsOrSelf(this IPublishedContent content, string culture = null)
+ where T : class, IPublishedContent
+ => content.DescendantsOrSelf(VariationContextAccessor, culture);
+
+ public static IEnumerable DescendantsOrSelf(this IPublishedContent content, int level, string culture = null)
+ where T : class, IPublishedContent
+ => content.DescendantsOrSelf(VariationContextAccessor, level, culture);
+
+ public static IPublishedContent Descendant(this IPublishedContent content, string culture = null)
+ => content.Descendant(VariationContextAccessor, culture);
+
+ public static IPublishedContent Descendant(this IPublishedContent content, int level, string culture = null)
+ => content.Descendant(VariationContextAccessor, level, culture);
+
+
+ public static IPublishedContent DescendantOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
+ => content.DescendantOfType(VariationContextAccessor, contentTypeAlias, culture);
+
+ public static T Descendant(this IPublishedContent content, string culture = null)
+ where T : class, IPublishedContent
+ => content.Descendant(VariationContextAccessor, culture);
+
+
+ public static T Descendant(this IPublishedContent content, int level, string culture = null)
+ where T : class, IPublishedContent
+ => content.Descendant(VariationContextAccessor, level, culture);
+
+ public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string culture = null)
+ => content.DescendantOrSelf(VariationContextAccessor, culture);
+
+ public static IPublishedContent DescendantOrSelf(this IPublishedContent content, int level, string culture = null)
+ => content.DescendantOrSelf(VariationContextAccessor, level, culture);
+
+ public static IPublishedContent DescendantOrSelfOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
+ => content.DescendantOrSelfOfType(VariationContextAccessor, contentTypeAlias, culture);
+
+ public static T DescendantOrSelf(this IPublishedContent content, string culture = null)
+ where T : class, IPublishedContent
+ => content.DescendantOrSelf(VariationContextAccessor, culture);
+
+ public static T DescendantOrSelf(this IPublishedContent content, int level, string culture = null)
+ where T : class, IPublishedContent
+ => content.DescendantOrSelf(VariationContextAccessor, level, culture);
+
+
+ ///
+ /// Gets the children of the content item.
+ ///
+ /// The content item.
+ ///
+ /// The specific culture to get the URL children for. Default is null which will use the current culture in
+ ///
+ ///
+ /// Gets children that are available for the specified culture.
+ /// Children are sorted by their sortOrder.
+ ///
+ /// For culture,
+ /// if null is used the current culture is used.
+ /// If an empty string is used only invariant children are returned.
+ /// If "*" is used all children are returned.
+ ///
+ ///
+ /// If a variant culture is specified or there is a current culture in the then the Children returned
+ /// will include both the variant children matching the culture AND the invariant children because the invariant children flow with the current culture.
+ /// However, if an empty string is specified only invariant children are returned.
+ ///
+ ///
+ public static IEnumerable Children(this IPublishedContent content, string culture = null)
+ => content.Children(VariationContextAccessor, culture);
+
+ ///
+ /// Gets the children of the content, filtered by a predicate.
+ ///
+ /// The content.
+ /// 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, Func predicate, string culture = null)
+ => content.Children(VariationContextAccessor, predicate, culture);
+
+ ///
+ /// Gets the children of the content, of any of the specified types.
+ ///
+ /// The content.
+ /// 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, string contentTypeAlias, string culture = null)
+ => content.ChildrenOfType(VariationContextAccessor, contentTypeAlias, culture);
+
+ ///
+ /// Gets the children of the content, of a given content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// 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, string culture = null)
+ where T : class, IPublishedContent
+ => content.Children(VariationContextAccessor, culture);
+
+ public static IPublishedContent FirstChild(this IPublishedContent content, string culture = null)
+ => content.FirstChild(VariationContextAccessor, culture);
+
+ ///
+ /// Gets the first child of the content, of a given content type.
+ ///
+ public static IPublishedContent FirstChildOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
+ => content.FirstChildOfType(VariationContextAccessor, contentTypeAlias, culture);
+
+ public static IPublishedContent FirstChild(this IPublishedContent content, Func predicate, string culture = null)
+ => content.FirstChild(VariationContextAccessor, predicate, culture);
+
+ public static IPublishedContent FirstChild(this IPublishedContent content, Guid uniqueId, string culture = null)
+ => content.FirstChild(VariationContextAccessor, uniqueId, culture);
+
+
+ public static T FirstChild(this IPublishedContent content, string culture = null)
+ where T : class, IPublishedContent
+ => content.FirstChild(VariationContextAccessor, culture);
+
+ public static T FirstChild(this IPublishedContent content, Func predicate, string culture = null)
+ where T : class, IPublishedContent
+ => content.FirstChild(VariationContextAccessor, predicate, culture);
+
+ ///
+ /// Gets the siblings of the content.
+ ///
+ /// The content.
+ /// 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, string culture = null)
+ => content.Siblings(PublishedSnapshot, VariationContextAccessor, culture);
+
+ ///
+ /// Gets the siblings of the content, of a given content type.
+ ///
+ /// The content.
+ /// The content type alias.
+ /// 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 SiblingsOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
+ => content.SiblingsOfType(PublishedSnapshot, VariationContextAccessor, contentTypeAlias, culture);
+
+ ///
+ /// Gets the siblings of the content, of a given content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// 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, string culture = null)
+ where T : class, IPublishedContent
+ => content.Siblings(PublishedSnapshot, VariationContextAccessor, culture);
+
+ ///
+ /// Gets the siblings of the content including the node itself to indicate the position.
+ ///
+ /// The content.
+ /// 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, string culture = null)
+ => content.SiblingsAndSelf(PublishedSnapshot, VariationContextAccessor, culture);
+
+ ///
+ /// Gets the siblings of the content including the node itself to indicate the position, of a given content type.
+ ///
+ /// The content.
+ /// 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, string contentTypeAlias, string culture = null)
+ => content.SiblingsAndSelfOfType(PublishedSnapshot, VariationContextAccessor, contentTypeAlias, 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.
+ /// 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, string culture = null)
+ where T : class, IPublishedContent
+ => content.SiblingsAndSelf(PublishedSnapshot, VariationContextAccessor, culture);
+
+
+ ///
+ /// Gets the url of the content item.
+ ///
+ ///
+ /// If the content item is a document, then this method returns the url of the
+ /// document. If it is a media, then this methods return the media url for the
+ /// 'umbracoFile' property. Use the MediaUrl() method to get the media url for other
+ /// properties.
+ /// The value of this property is contextual. It depends on the 'current' request uri,
+ /// if any. In addition, when the content type is multi-lingual, this is the url for the
+ /// specified culture. Otherwise, it is the invariant url.
+ ///
+ public static string Url(this IPublishedContent content, string culture = null, UrlMode mode = UrlMode.Default)
+ => content.Url(PublishedUrlProvider, culture, mode);
+
+ ///
+ /// Gets the children of the content in a DataTable.
+ ///
+ /// The content.
+ /// Variation context accessor.
+ /// The content type service.
+ /// The media type service.
+ /// The member type service.
+ /// The published url provider.
+ /// An optional content type alias.
+ /// The specific culture to filter for. If null is used the current culture is used. (Default is null)
+ /// The children of the content.
+ public static DataTable ChildrenAsTable(this IPublishedContent content, string contentTypeAliasFilter = "", string culture = null)
+ => content.ChildrenAsTable(VariationContextAccessor, ContentTypeService, MediaTypeService, MemberTypeService, PublishedUrlProvider, contentTypeAliasFilter, culture);
+
+ ///
+ /// Gets the url for a media.
+ ///
+ /// The content item.
+ /// The culture (use current culture by default).
+ /// The url mode (use site configuration by default).
+ /// The alias of the property (use 'umbracoFile' by default).
+ /// The url for the media.
+ ///
+ /// The value of this property is contextual. It depends on the 'current' request uri,
+ /// if any. In addition, when the content type is multi-lingual, this is the url for the
+ /// specified culture. Otherwise, it is the invariant url.
+ ///
+ public static string MediaUrl(
+ this IPublishedContent content,
+ string culture = null,
+ UrlMode mode = UrlMode.Default,
+ string propertyAlias = Constants.Conventions.Media.File)
+ => content.MediaUrl(PublishedUrlProvider, culture, mode, propertyAlias);
+
+ ///
+ /// Gets the name of the content item creator.
+ ///
+ /// The content item.
+ public static string CreatorName(this IPublishedContent content) =>
+ content.CreatorName(UserService);
+
+ ///
+ /// Gets the name of the content item writer.
+ ///
+ /// The content item.
+ public static string WriterName(this IPublishedContent content) =>
+ content.WriterName(UserService);
+
+ ///
+ /// Gets the culture assigned to a document by domains, in the context of a current Uri.
+ ///
+ /// The document.
+ /// An optional current Uri.
+ /// The culture assigned to the document by domains.
+ ///
+ /// In 1:1 multilingual setup, a document contains several cultures (there is not
+ /// one document per culture), and domains, withing the context of a current Uri, assign
+ /// a culture to that document.
+ ///
+ public static string GetCultureFromDomains(
+ this IPublishedContent content,
+ Uri current = null)
+ => content.GetCultureFromDomains(UmbracoContextAccessor, SiteDomainHelper, current);
+
+
+ public static IEnumerable SearchDescendants(
+ this IPublishedContent content,
+ string term,
+ string indexName = null)
+ => content.SearchDescendants(ExamineManager, UmbracoContextAccessor, term, indexName);
+
+
+ public static IEnumerable SearchChildren(
+ this IPublishedContent content,
+ string term,
+ string indexName = null)
+ => content.SearchChildren(ExamineManager, UmbracoContextAccessor, term, indexName);
+
+
+ }
+}
diff --git a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedElementExtensions.cs b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedElementExtensions.cs
new file mode 100644
index 0000000000..bbb896fe8b
--- /dev/null
+++ b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedElementExtensions.cs
@@ -0,0 +1,74 @@
+using Microsoft.Extensions.DependencyInjection;
+using Umbraco.Cms.Core.Models.PublishedContent;
+using Umbraco.Cms.Web.Common.DependencyInjection;
+
+namespace Umbraco.Extensions
+{
+ public static class FriendlyPublishedElementExtensions
+ {
+ private static IPublishedValueFallback PublishedValueFallback { get; } =
+ StaticServiceProvider.Instance.GetRequiredService();
+
+ ///
+ /// Gets the value of a content's property identified by its alias.
+ ///
+ /// The content.
+ /// The property alias.
+ /// The variation language.
+ /// The variation segment.
+ /// Optional fallback strategy.
+ /// The default value.
+ /// The value of the content's property identified by the alias, if it exists, otherwise a default value.
+ ///
+ /// The value comes from IPublishedProperty field Value ie it is suitable for use when rendering content.
+ /// If no property with the specified alias exists, or if the property has no value, returns .
+ /// If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter.
+ /// The alias is case-insensitive.
+ ///
+ public static object Value(
+ this IPublishedElement content,
+ string alias,
+ string culture = null,
+ string segment = null,
+ Fallback fallback = default,
+ object defaultValue = default)
+ => content.Value(PublishedValueFallback, alias, culture, segment, fallback, defaultValue);
+
+ ///
+ /// Gets the value of a content's property identified by its alias, converted to a specified type.
+ ///
+ /// The target property type.
+ /// The content.
+ /// The property alias.
+ /// The variation language.
+ /// The variation segment.
+ /// Optional fallback strategy.
+ /// The default value.
+ /// The value of the content's property identified by the alias, converted to the specified type.
+ ///
+ /// The value comes from IPublishedProperty field Value ie it is suitable for use when rendering content.
+ /// If no property with the specified alias exists, or if the property has no value, or if it could not be converted, returns default(T).
+ /// If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter.
+ /// The alias is case-insensitive.
+ ///
+ public static T Value(
+ this IPublishedElement content,
+ string alias,
+ string culture = null,
+ string segment = null,
+ Fallback fallback = default,
+ T defaultValue = default)
+ => content.Value(PublishedValueFallback, alias, culture, segment, fallback, defaultValue);
+
+ ///
+ /// Gets a value indicating whether the content is visible.
+ ///
+ /// The content.
+ /// A value indicating whether the content is visible.
+ /// A content is not visible if it has an umbracoNaviHide property with a value of "1". Otherwise,
+ /// the content is visible.
+ public static bool IsVisible(this IPublishedElement content) => content.IsVisible(PublishedValueFallback);
+
+
+ }
+}
diff --git a/src/Umbraco.Web.Website/Extensions/PublishedContentExtensions.cs b/src/Umbraco.Web.Common/Extensions/PublishedContentExtensions.cs
similarity index 99%
rename from src/Umbraco.Web.Website/Extensions/PublishedContentExtensions.cs
rename to src/Umbraco.Web.Common/Extensions/PublishedContentExtensions.cs
index c33d5e6ef3..c02e609372 100644
--- a/src/Umbraco.Web.Website/Extensions/PublishedContentExtensions.cs
+++ b/src/Umbraco.Web.Common/Extensions/PublishedContentExtensions.cs
@@ -3,12 +3,12 @@ using System.Collections.Generic;
using System.Web;
using Examine;
using Microsoft.AspNetCore.Html;
+using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.Examine;
-using Constants = Umbraco.Cms.Core.Constants;
namespace Umbraco.Extensions
{
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/templatehelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/templatehelper.service.js
index 2e71ef0bf5..1a2f0735ce 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/templatehelper.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/templatehelper.service.js
@@ -25,7 +25,7 @@
"\t@foreach (var item in selection)\n" +
"\t{\n" +
"\t\t\n" +
- "\t\t\t@item.Name\n" +
+ "\t\t\t@item.Name()\n" +
"\t\t\n" +
"\t}\n" +
"\n\n";
@@ -43,11 +43,11 @@
function getAddSectionSnippet(sectionName) {
return "@section " + sectionName + "\r\n{\r\n\r\n\t{0}\r\n\r\n}\r\n";
}
-
+
function getGeneralShortcuts(){
var keys = [
- "shortcuts_generalHeader",
- "buttons_undo",
+ "shortcuts_generalHeader",
+ "buttons_undo",
"buttons_redo",
"buttons_save"
];
@@ -61,7 +61,7 @@
labels.save = data[3];
return {
- "name": labels.header,
+ "name": labels.header,
"shortcuts": [
{
"description": labels.undo,
@@ -77,14 +77,14 @@
}
]
};
- });
+ });
}
function getEditorShortcuts(){
var keys = [
- "shortcuts_editorHeader",
- "shortcuts_commentLine",
+ "shortcuts_editorHeader",
+ "shortcuts_commentLine",
"shortcuts_removeLine",
"shortcuts_copyLineUp",
"shortcuts_copyLineDown",
@@ -126,7 +126,7 @@
"keys": {
"win": [{ "key": "alt" }, { "key": "shift" }, { "key": "down" }],
"mac": [{ "key": "cmd" }, { "key": "alt" }, { "key": "down" }]
- }
+ }
},
{
"description": labels.movelineup,
@@ -138,13 +138,13 @@
}
]
};
- });
+ });
}
function getTemplateEditorShortcuts(){
var keys = [
- "template_insert",
- "template_insertPageField",
+ "template_insert",
+ "template_insertPageField",
"template_insertPartialView",
"template_insertDictionaryItem",
"template_insertMacro",
@@ -198,13 +198,13 @@
}
]
};
- });
+ });
}
function getPartialViewEditorShortcuts(){
var keys = [
- "template_insert",
- "template_insertPageField",
+ "template_insert",
+ "template_insertPageField",
"template_insertDictionaryItem",
"template_insertMacro",
"template_queryBuilder"
@@ -242,7 +242,7 @@
};
});
-
+
}
////////////
diff --git a/src/Umbraco.Web.UI.Client/test/unit/common/services/template-helper.spec.js b/src/Umbraco.Web.UI.Client/test/unit/common/services/template-helper.spec.js
index 08a69b7e80..316cfa7c59 100644
--- a/src/Umbraco.Web.UI.Client/test/unit/common/services/template-helper.spec.js
+++ b/src/Umbraco.Web.UI.Client/test/unit/common/services/template-helper.spec.js
@@ -50,7 +50,7 @@ describe('service: templateHelper', function () {
var snippet = '@Html.Partial("Folder with spaces/Footer")';
expect(templateHelper.getInsertPartialSnippet(parentId, nodeName)).toBe(snippet);
});
-
+
});
describe('getQuerySnippet', function () {
@@ -62,14 +62,14 @@ describe('service: templateHelper', function () {
"\t@foreach (var item in selection)\n" +
"\t{\n" +
"\t\t\n" +
- "\t\t\t@item.Name\n" +
+ "\t\t\t@item.Name()\n" +
"\t\t\n" +
"\t}\n" +
"\n\n";
expect(templateHelper.getQuerySnippet(queryExpression)).toBe(snippet);
});
-
+
});
describe('getRenderBodySnippet', function () {
@@ -78,7 +78,7 @@ describe('service: templateHelper', function () {
var snippet = '@RenderBody()';
expect(templateHelper.getRenderBodySnippet()).toBe(snippet);
});
-
+
});
describe('getRenderSectionSnippet', function () {
@@ -92,7 +92,7 @@ describe('service: templateHelper', function () {
var snippet = '@RenderSection("sectionName", true)';
expect(templateHelper.getRenderSectionSnippet("sectionName", true)).toBe(snippet);
});
-
+
});
describe('getAddSectionSnippet', function () {
@@ -102,7 +102,7 @@ describe('service: templateHelper', function () {
var snippet = "@section " + sectionName + "\r\n{\r\n\r\n\t{0}\r\n\r\n}\r\n";
expect(templateHelper.getAddSectionSnippet(sectionName)).toEqual(snippet);
});
-
+
});
-});
\ No newline at end of file
+});