diff --git a/src/Umbraco.Core/Constants-Content.cs b/src/Umbraco.Core/Constants-Content.cs
index b9d0691454..3f12ece6dc 100644
--- a/src/Umbraco.Core/Constants-Content.cs
+++ b/src/Umbraco.Core/Constants-Content.cs
@@ -32,6 +32,16 @@
/// Fallback to other languages.
///
public const int Language = 2;
+
+ ///
+ /// Recurse up the tree. If content not found, fallback to other languages.
+ ///
+ public const int RecurseThenLanguage = 3;
+
+ ///
+ /// Fallback to other languages. If content not found, recurse up the tree.
+ ///
+ public const int LanguageThenRecurse = 4;
}
}
}
diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs
index 0b0f4dea51..d5e01fd424 100644
--- a/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs
+++ b/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Moq;
@@ -66,9 +67,9 @@ namespace Umbraco.Tests.PublishedContent
var contentType1 = factory.CreateContentType(1, "ContentType1", Enumerable.Empty(), props);
var prop1 = new SolidPublishedPropertyWithLanguageVariants
- {
- Alias = "welcomeText",
- };
+ {
+ Alias = "welcomeText",
+ };
prop1.SetSourceValue("en-US", "Welcome", true);
prop1.SetValue("en-US", "Welcome", true);
prop1.SetSourceValue("de", "Willkommen");
@@ -77,16 +78,16 @@ namespace Umbraco.Tests.PublishedContent
prop1.SetValue("nl", "Welkom");
var prop2 = new SolidPublishedPropertyWithLanguageVariants
- {
- Alias = "welcomeText2",
- };
+ {
+ Alias = "welcomeText2",
+ };
prop2.SetSourceValue("en-US", "Welcome", true);
prop2.SetValue("en-US", "Welcome", true);
var prop3 = new SolidPublishedPropertyWithLanguageVariants
- {
- Alias = "welcomeText",
- };
+ {
+ Alias = "welcomeText",
+ };
prop3.SetSourceValue("en-US", "Welcome", true);
prop3.SetValue("en-US", "Welcome", true);
@@ -202,5 +203,32 @@ namespace Umbraco.Tests.PublishedContent
var value = content.Value("welcomeText2", fallback: Core.Constants.Content.ValueFallback.Recurse);
Assert.AreEqual("Welcome", value);
}
+
+ [Test]
+ public void Can_Get_Content_With_Recursive_Priority()
+ {
+ var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First();
+ var value = content.Value("welcomeText", "nl", fallback: Core.Constants.Content.ValueFallback.RecurseThenLanguage);
+
+ // No Dutch value is directly assigned. Check has fallen back to Dutch value from parent.
+ Assert.AreEqual("Welkom", value);
+ }
+
+ [Test]
+ public void Can_Get_Content_With_Fallback_Language_Priority()
+ {
+ var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First();
+ var value = content.Value("welcomeText", "nl", fallback: Core.Constants.Content.ValueFallback.LanguageThenRecurse);
+
+ // No Dutch value is directly assigned. Check has fallen back to English value from language variant.
+ Assert.AreEqual("Welcome", value);
+ }
+
+ [Test]
+ public void Throws_For_Non_Supported_Fallback()
+ {
+ var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First();
+ Assert.Throws(() => content.Value("welcomeText", "nl", fallback: 999));
+ }
}
}
diff --git a/src/Umbraco.Web/Models/PublishedContent/PublishedValueFallback.cs b/src/Umbraco.Web/Models/PublishedContent/PublishedValueFallback.cs
index 71bbe9577a..02e809025a 100644
--- a/src/Umbraco.Web/Models/PublishedContent/PublishedValueFallback.cs
+++ b/src/Umbraco.Web/Models/PublishedContent/PublishedValueFallback.cs
@@ -70,6 +70,14 @@ namespace Umbraco.Web.Models.PublishedContent
return TryGetValueWithRecursiveFallback(content, alias, culture, segment, defaultValue, out var value1) ? value1 : defaultValue;
case ValueFallback.Language:
return TryGetValueWithLanguageFallback(content, alias, culture, segment, defaultValue, out var value2) ? value2 : defaultValue;
+ case ValueFallback.RecurseThenLanguage:
+ return TryGetValueWithRecursiveFallback(content, alias, culture, segment, defaultValue, out var value3)
+ ? value3
+ : TryGetValueWithLanguageFallback(content, alias, culture, segment, defaultValue, out var value4) ? value4 : defaultValue;
+ case ValueFallback.LanguageThenRecurse:
+ return TryGetValueWithLanguageFallback(content, alias, culture, segment, defaultValue, out var value5)
+ ? value5
+ : TryGetValueWithRecursiveFallback(content, alias, culture, segment, defaultValue, out var value6) ? value6 : defaultValue;
default:
throw new NotSupportedException($"Fallback {GetType().Name} does not support policy code '{fallback}'.");
}