Created
May 3, 2024 15:04
-
-
Save hfloyd/f25cc07318003e59a6045f2d4f8febcc to your computer and use it in GitHub Desktop.
Umbraco v13+ 404 Error IContentLastChanceFinder - Supporting multiple sites at root
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace MYSITE.Web; | |
using Umbraco.Cms.Core.Composing; | |
using Umbraco.Cms.Core.DependencyInjection; | |
using Umbraco.Cms.Core.Models.PublishedContent; | |
using Umbraco.Cms.Core.Routing; | |
using Umbraco.Cms.Core.Web; | |
using Umbraco.Extensions; | |
using MYSITE.Web.Models; //For the 'ErrorPage' Content Type Model | |
public class Error404Page : IContentLastChanceFinder | |
{ | |
private readonly IUmbracoContextAccessor _contextAccessor; | |
public Error404Page(IUmbracoContextAccessor contextAccessor) | |
{ | |
_contextAccessor = contextAccessor; | |
} | |
public Task<bool> TryFindContent(IPublishedRequestBuilder request) | |
{ | |
// In the rare case that an umbracoContext cannot be build from the request, we will not be able to find the page | |
if (_contextAccessor.TryGetUmbracoContext(out var umbracoContext) == false) | |
{ | |
return Task.FromResult(false); | |
} | |
// Find the first notFound page at root level through the published content cache by its documentTypeAlias | |
// You can make this search as complex as you want, you can return different pages based on anything in the original request | |
IPublishedContent? notFoundPage = null; | |
//var rootContentNodes = umbracoContext.Content?.GetAtRoot(); | |
var currentCulture = request.Culture; | |
var realPage = GetClosestContent(umbracoContext, request.Uri); //Include currentCulture param if multi-lingual | |
var site = realPage.AncestorOrSelf(1); //Website is at Level 1 (usually) | |
var errorPages = site.Descendants<ErrorPage>().ToList(); // you can also use .Where(c => c.ContentType.Alias == "myErrorPageTypeAlias") | |
if (errorPages.Count() == 1) | |
{ | |
notFoundPage = errorPages.First(); | |
} | |
else if (errorPages.Count() > 1) | |
{ | |
var match404 = errorPages.First(n => n.Name == "404"); | |
if (match404 != null) | |
{ | |
notFoundPage = match404; | |
} | |
else | |
{ | |
notFoundPage = errorPages.First(); | |
} | |
} | |
if (notFoundPage != null) | |
{ | |
// set the content on the request and mark our search as successful | |
request.SetPublishedContent(notFoundPage); | |
return Task.FromResult(true); | |
} | |
//Couldn't find anything | |
return Task.FromResult(false); | |
} | |
private IPublishedContent GetClosestContent(IUmbracoContext UmbracoContext, Uri RequestUri, | |
string? CurrentCulture = null) | |
{ | |
//Loop backwards testing each possible ancestral path until a real content node is found | |
for (int i = RequestUri.Segments.Length - 1; i <= 0; i--) | |
{ | |
var path = string.Join("/", RequestUri.Segments.Take(i)); | |
var node = UmbracoContext.Content?.GetByRoute(path, false, CurrentCulture); | |
if (node != null) | |
{ | |
return node; | |
} | |
} | |
//if we get here, just return the first root node | |
return UmbracoContext.Content?.GetAtRoot().FirstOrDefault(); | |
} | |
} | |
// ContentFinders need to be registered into the DI container through a composer | |
public class Error404PageComposer : IComposer | |
{ | |
public void Compose(IUmbracoBuilder builder) | |
{ | |
builder.SetContentLastChanceFinder<Error404Page>(); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment