diff --git a/src/Umbraco.Core/ContentVariationExtensions.cs b/src/Umbraco.Core/ContentVariationExtensions.cs
index 092de4d6d6..d18fb4b091 100644
--- a/src/Umbraco.Core/ContentVariationExtensions.cs
+++ b/src/Umbraco.Core/ContentVariationExtensions.cs
@@ -75,6 +75,26 @@ namespace Umbraco.Core
///
public static bool VariesByCultureAndSegment(this PublishedContentType contentType) => contentType.Variations.VariesByCultureAndSegment();
+ ///
+ /// Determines whether the property type is invariant.
+ ///
+ public static bool VariesByNothing(this PublishedPropertyType propertyType) => propertyType.Variations.VariesByNothing();
+
+ ///
+ /// Determines whether the property type varies by culture.
+ ///
+ public static bool VariesByCulture(this PublishedPropertyType propertyType) => propertyType.Variations.VariesByCulture();
+
+ ///
+ /// Determines whether the property type varies by segment.
+ ///
+ public static bool VariesBySegment(this PublishedPropertyType propertyType) => propertyType.Variations.VariesBySegment();
+
+ ///
+ /// Determines whether the property type varies by culture and segment.
+ ///
+ public static bool VariesByCultureAndSegment(this PublishedPropertyType propertyType) => propertyType.Variations.VariesByCultureAndSegment();
+
///
/// Determines whether a variation is invariant.
///
diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs
index d33372ce53..5350e05ef9 100644
--- a/src/Umbraco.Web/PublishedContentExtensions.cs
+++ b/src/Umbraco.Web/PublishedContentExtensions.cs
@@ -229,6 +229,17 @@ namespace Umbraco.Web
#endregion
+ #region Variations
+
+ ///
+ /// Determines whether the content has a culture.
+ ///
+ /// Culture is case-insensitive.
+ public static bool HasCulture(this IPublishedContent content, string culture)
+ => content.Cultures.ContainsKey(culture);
+
+ #endregion
+
#region Search
public static IEnumerable Search(this IPublishedContent content, string term, bool useWildCards = true, string indexName = null)
diff --git a/src/Umbraco.Web/Routing/AliasUrlProvider.cs b/src/Umbraco.Web/Routing/AliasUrlProvider.cs
index 900c41e1ff..8c851d139f 100644
--- a/src/Umbraco.Web/Routing/AliasUrlProvider.cs
+++ b/src/Umbraco.Web/Routing/AliasUrlProvider.cs
@@ -54,25 +54,36 @@ namespace Umbraco.Web.Routing
public IEnumerable GetOtherUrls(UmbracoContext umbracoContext, int id, Uri current)
{
var node = umbracoContext.ContentCache.GetById(id);
- if (node == null)
- return Enumerable.Empty();
+ if (node == null) return Enumerable.Empty();
if (!node.HasProperty(Constants.Conventions.Content.UrlAlias))
return Enumerable.Empty();
var domainHelper = umbracoContext.GetDomainHelper(_siteDomainHelper);
+ // look for domains, walking up the tree
var n = node;
var domainUris = domainHelper.DomainsForNode(n.Id, current, false);
while (domainUris == null && n != null) // n is null at root
{
// move to parent node
n = n.Parent;
- domainUris = n == null ? null : domainHelper.DomainsForNode(n.Id, current, false);
+ domainUris = n == null ? null : domainHelper.DomainsForNode(n.Id, current, excludeDefault: false);
}
+ // determine whether the alias property varies
+ var varies = node.GetProperty(Constants.Conventions.Content.UrlAlias).PropertyType.VariesByCulture();
+
if (domainUris == null)
{
+ // no domain
+ // if the property is invariant, then url "/" is ok
+ // if the property varies, then what are we supposed to do?
+ // the content finder may work, depending on the 'current' culture,
+ // but there's no way we can return something meaningful here
+ if (varies)
+ return Enumerable.Empty();
+
var umbracoUrlName = node.Value(Constants.Conventions.Content.UrlAlias);
if (string.IsNullOrWhiteSpace(umbracoUrlName))
return Enumerable.Empty();
@@ -83,10 +94,20 @@ namespace Umbraco.Web.Routing
}
else
{
+ // some domains: one url per domain, which is "/"
var result = new List();
foreach(var domainUri in domainUris)
{
- var umbracoUrlName = node.Value(Constants.Conventions.Content.UrlAlias, culture: domainUri.Culture.Name);
+ // if the property is invariant, get the invariant value, url is "/"
+ // if the property varies, get the variant value, url is "/"
+
+ // but! only if the culture is published, else ignore
+ if (varies && !node.HasCulture(domainUri.Culture.Name)) continue;
+
+ var umbracoUrlName = varies
+ ? node.Value(Constants.Conventions.Content.UrlAlias, culture: domainUri.Culture.Name)
+ : node.Value(Constants.Conventions.Content.UrlAlias);
+
if (!string.IsNullOrWhiteSpace(umbracoUrlName))
{
var path = "/" + umbracoUrlName;
diff --git a/src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs b/src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs
index 11de879bc8..59e30cc8b0 100644
--- a/src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs
+++ b/src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs
@@ -38,6 +38,7 @@ namespace Umbraco.Web.Routing
{
node = FindContentByAlias(frequest.UmbracoContext.ContentCache,
frequest.HasDomain ? frequest.Domain.ContentId : 0,
+ frequest.Culture.Name,
frequest.Uri.GetAbsolutePathDecoded());
if (node != null)
@@ -50,7 +51,7 @@ namespace Umbraco.Web.Routing
return node != null;
}
- private static IPublishedContent FindContentByAlias(IPublishedContentCache cache, int rootNodeId, string alias)
+ private static IPublishedContent FindContentByAlias(IPublishedContentCache cache, int rootNodeId, string culture, string alias)
{
if (alias == null) throw new ArgumentNullException(nameof(alias));
@@ -62,7 +63,7 @@ namespace Umbraco.Web.Routing
// can we normalize the values so that they contain no whitespaces, and no leading slashes?
// and then the comparisons in IsMatch can be way faster - and allocate way less strings
- const string propertyAlias = "umbracoUrlAlias";
+ const string propertyAlias = Constants.Conventions.Content.UrlAlias;
var test1 = alias.TrimStart('/') + ",";
var test2 = ",/" + test1; // test2 is ",/alias,"
@@ -78,12 +79,26 @@ namespace Umbraco.Web.Routing
// ")]"
if (!c.HasProperty(propertyAlias)) return false;
- var v = c.Value(propertyAlias);
+ var p = c.GetProperty(propertyAlias);
+ var varies = p.PropertyType.VariesByCulture();
+ string v;
+ if (varies)
+ {
+ if (!c.HasCulture(culture)) return false;
+ v = c.Value(propertyAlias, culture);
+ }
+ else
+ {
+ v = c.Value(propertyAlias);
+ }
if (string.IsNullOrWhiteSpace(v)) return false;
v = "," + v.Replace(" ", "") + ",";
return v.Contains(a1) || v.Contains(a2);
}
+ // fixme - even with Linq, what happens below has to be horribly slow
+ // but the only solution is to entirely refactor url providers to stop being dynamic
+
if (rootNodeId > 0)
{
var rootNode = cache.GetById(rootNodeId);
diff --git a/src/Umbraco.Web/Routing/DefaultUrlProvider.cs b/src/Umbraco.Web/Routing/DefaultUrlProvider.cs
index 9e89459774..fb9cdfa9bd 100644
--- a/src/Umbraco.Web/Routing/DefaultUrlProvider.cs
+++ b/src/Umbraco.Web/Routing/DefaultUrlProvider.cs
@@ -80,8 +80,11 @@ namespace Umbraco.Web.Routing
public virtual IEnumerable GetOtherUrls(UmbracoContext umbracoContext, int id, Uri current)
{
var node = umbracoContext.ContentCache.GetById(id);
+ if (node == null) return Enumerable.Empty();
+
var domainHelper = umbracoContext.GetDomainHelper(_siteDomainHelper);
+ // look for domains, walking up the tree
var n = node;
var domainUris = domainHelper.DomainsForNode(n.Id, current, false);
while (domainUris == null && n != null) // n is null at root
diff --git a/src/Umbraco.Web/Routing/UrlProviderExtensions.cs b/src/Umbraco.Web/Routing/UrlProviderExtensions.cs
index ce09bdc645..b8671b5735 100644
--- a/src/Umbraco.Web/Routing/UrlProviderExtensions.cs
+++ b/src/Umbraco.Web/Routing/UrlProviderExtensions.cs
@@ -110,11 +110,14 @@ namespace Umbraco.Web.Routing
foreach (var (text, infos) in dmsg)
ret.Add(UrlInfo.Message(text, infos.Count == cultures.Count ? null : string.Join(", ", infos.Select(x => x.Culture))));
- // fixme - need to add 'others' urls
- // but, when?
- //// get the 'other' urls
- //foreach(var otherUrl in urlProvider.GetOtherUrls(content.Id))
- // urls.Add(otherUrl);
+ // get the 'other' urls - ie not what you'd get with GetUrl() but urls that would route to the document, nevertheless.
+ // for these 'other' urls, we don't check whether they are routable, collide, anything - we just report them.
+ // also, we are not dealing with cultures at all - that will have to wait
+ foreach(var otherUrl in umbracoContext.UrlProvider.GetOtherUrls(content.Id))
+ {
+ if (urls.Any(x => x.IsUrl && x.Text == otherUrl)) continue;
+ ret.Add(UrlInfo.Url(otherUrl));
+ }
return ret;
}