diff --git a/16/umbraco-cms/tutorials/custom-error-page.md b/16/umbraco-cms/tutorials/custom-error-page.md index c8b4dccfd9b..f425db2360e 100644 --- a/16/umbraco-cms/tutorials/custom-error-page.md +++ b/16/umbraco-cms/tutorials/custom-error-page.md @@ -28,45 +28,58 @@ This has been moved to a separate article: [Create a custom maintenance page](cr ## 404 Errors +{% hint style="warning" %} +To follow this guide successfully, ensure you're using Umbraco version 16.1 or later, as it fixes a regression from version 16.0. For more details, see the [Breaking changes](https://our.umbraco.com/download/releases/1610) section in the Release Notes. +{% endhint %} + A 404 error occurs when a requested page cannot be found, usually due to deleted content, a changed URL, or an invalid path. In Umbraco, you can create and configure custom 404 pages using content from the backoffice. -### Create a 404 page in the backoffice +### Create a Page Not Found page in the backoffice -1. Go to the **Settings** section in the Umbraco backoffice. +1. Go to the **Settings** section in the backoffice. 2. Create a new **Document Type with Template**. -3. Name the Document Type *ErrorPage404*. -4. [Optional] Add any custom properties you want — though most 404 pages are static. +3. Name the Document Type *Page Not Found*. +4. [Optional] Add custom properties (for example, title, message), though most 404 pages are static. 5. Click **Save**. -6. Go to the **Templates** folder. -7. Add your custom markup and design for the error page in the template. In this case, *ErrorPage404*. +6. Go to the **Templates** folder and edit the generated template. +7. Add your custom markup and design for the error page in the template. 8. Click **Save**. -### Create a Container for Status Code Pages +### [Optional] Create a Container for Error Pages + +You can create a *Page Not Found* page directly in your content tree, or organize it within a container for error pages. Using a container allows for better content organization, especially if you plan to handle multiple status codes (for example, 404, 500, maintenance, and so on). Both options work as long as the page ID is referenced correctly in the `appsettings.json` file. 1. Create a new **Document Type**. -2. Name it **Statuscodes**. +2. Name it *Error Pages Container*. 3. Go to the **Structure** Workspace view. * Enable **Allow at root**. - * Add the *ErrorPage404* Document Type as an **Allowed child node types**. + * Add the *Page Not Found* Document Type as an **Allowed child node types**. * Click **Choose**. 4. Click **Save**. +![Container Config](images/container.png) + ### Add the Content 1. Go to the **Content** section. -2. Create a new content node based on the **Statuscodes** Document Type and name it **Statuscodes**. +2. Create a new content node based on the *Error Pages Container* Document Type. For example *Home Page*. 3. Click **Save** or **Save and Publish**. -4. Under it, create a child node using the *ErrorPage404* Document Type. -5. Name it *Page 404 Not Found* or similar. + +![Parent Content Node](images/content-node.png) + +4. Create a child node, using the *Page Not Found* Document Type. +5. Name it *Page Not Found* or similar. * This will be the content shown when a 404 error occurs. 6. Click **Save** or **Save and Publish**. +![Child Node](images/page-not-found.png) + ### Configure the Error Page in `appsettings.json` file -After publishing the 404 page, you’ll need to connect it in your configuration. +After publishing the *Page Not Found* page, connect it in the configuration: -1. Go to the **Info** tab of your *Page 404 Not Found* content item in the Backoffice. -2. Copy the **Id** of the page (for example: 9c2b5196-30cd-4416-ae30-94ac2afb1011). +1. Go to the **Info** tab of the *Page Not Found* content item in the Backoffice. +2. Copy the **Id** of the page (for example: 06cf09c8-c83a-4dd7-84e5-6d98d51e4d12). 3. Go to your project's `appsettings.json` file. 4. Add the `Error404Collection` setting to `Umbraco:CMS:Content`, like shown below: @@ -78,7 +91,7 @@ After publishing the 404 page, you’ll need to connect it in your configuration "Error404Collection": [ { "Culture": "default", - "ContentKey": "9c2b5196-30cd-4416-ae30-94ac2afb1011" + "ContentKey": "06cf09c8-c83a-4dd7-84e5-6d98d51e4d12" } ] } @@ -87,11 +100,11 @@ After publishing the 404 page, you’ll need to connect it in your configuration } ``` -Replace the value for `ContentKey` with the ID of your own 404 page. +Replace the value for `ContentKey` with the ID of your own *Page Not Found* page. #### Support for Multilingual Sites -You can define different 404 pages for each language or culture (such as `en-us`, `da-dk`, and so on): +You can define different error pages for each language or culture (such as `en-us`, `da-dk`, and so on): ```json "Error404Collection": [ @@ -112,12 +125,12 @@ Each entry maps a culture to its specific 404 page using the content’s GUID. It is also possible to set up a 404 error page programmatically using `IContentLastChanceFinder`. To learn more about `IContentLastChanceFinder`, read the [Custom Routing](../implementation/custom-routing/) article. -Before following this example, follow the [Create a 404 page in the backoffice](custom-error-page.md#create-a-404-page-in-the-backoffice) part. The example below will use the *errorPage404* alias of the Document Type to find and display the error page. +Before following this example, follow the [Create a Page Not Found page in the backoffice](#create-a-page-not-found-page-in-the-backoffice) part. The example below will use the *Page Not Found* alias of the Document Type to find and display the error page. -1. Create a new `.cs` file called *Error404Page* at the root of the project. +1. Create a new `.cs` file called *PageNotFound* at the root of the project. 2. Add the following code to the newly created class: -{% code title="Error404Page.cs" lineNumbers="true" %} +{% code title="PageNotFound.cs" lineNumbers="true" %} ```csharp using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Core.Routing; @@ -125,48 +138,51 @@ using Umbraco.Cms.Core.Web; namespace YourProjectNamespace; -public class Error404Page : IContentLastChanceFinder +public class PageNotFound : IContentLastChanceFinder { - private readonly IUmbracoContextAccessor _contextAccessor; - - public Error404Page(IUmbracoContextAccessor contextAccessor) - { - _contextAccessor = contextAccessor; - } - - public Task TryFindContent(IPublishedRequestBuilder request) - { - // In the rare case that an umbracoContext cannot be built from the request, - // we will not be able to find the page - if (_contextAccessor.TryGetUmbracoContext(out var umbracoContext) == false) - { - return Task.FromResult(false); - } + private readonly IServiceProvider _serviceProvider; - // Find the first notFound page at the 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 - var notFoundPage = umbracoContext.Content?.GetAtRoot().FirstOrDefault(c => c.ContentType.Alias == "errorPage404"); - if (notFoundPage == null) - { - return Task.FromResult(false); - } + public PageNotFound(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } - //Set the content on the request and mark our search as successful - request.SetPublishedContent(notFoundPage); - request.SetResponseStatus(404); - return Task.FromResult(true); - } + public Task TryFindContent(IPublishedRequestBuilder request) + { + using var scope = _serviceProvider.CreateScope(); + + var umbracoContextAccessor = scope.ServiceProvider.GetRequiredService(); + + if (!umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext)) + { + return Task.FromResult(false); + } + + var notFoundPage = umbracoContext + .Content + ?.GetAtRoot() + .SelectMany(x => x.DescendantsOrSelf()) + .FirstOrDefault(c => c.ContentType.Alias == "pageNotFound"); + + if (notFoundPage == null) + { + return Task.FromResult(false); + } + + request.SetPublishedContent(notFoundPage); + request.SetResponseStatus(404); + return Task.FromResult(true); + } } -// ContentFinders need to be registered into the DI container through a composer -public class Mycomposer : IComposer +// Register the content finder +public class MyComposer : IComposer { - public void Compose(IUmbracoBuilder builder) - { - builder.SetContentLastChanceFinder(); - } + public void Compose(IUmbracoBuilder builder) + { + builder.SetContentLastChanceFinder(); + } } - ``` {% endcode %} @@ -188,10 +204,10 @@ This section guides you in setting up a custom page for handling internal server 6. Add your custom markup and design for the error page in the template. In this case, *ErrorPage500*. 7. Click **Save**. -### Create a Container for Status Code Pages +### [Optional] Create a Container for Error Pages 1. Create a new **Document Type**. -2. Name it **Statuscodes**. +2. Name it **Error Pages Container**. 3. Go to the **Structure** Workspace view. * Enable **Allow at root**. * Add the *ErrorPage500* Document Type as an **Allowed child node types**. @@ -201,9 +217,9 @@ This section guides you in setting up a custom page for handling internal server ### Add the Content 1. Go to the **Content** section. -2. Create a new content node based on the **Statuscodes** Document Type and name it **Statuscodes**. +2. Create a new content node based on the *Error Pages Container* Document Type. For example *Home Page*. 3. Click **Save** or **Save and Publish**. -4. Under it, create a child node using the *ErrorPage500* Document Type. +4. Create a child node, using the *ErrorPage500* Document Type. 5. Name it *Page 500* or similar. * This will be the content shown when a 500 error occurs. diff --git a/16/umbraco-cms/tutorials/images/container.png b/16/umbraco-cms/tutorials/images/container.png new file mode 100644 index 00000000000..4143e5a7981 Binary files /dev/null and b/16/umbraco-cms/tutorials/images/container.png differ diff --git a/16/umbraco-cms/tutorials/images/content-node.png b/16/umbraco-cms/tutorials/images/content-node.png new file mode 100644 index 00000000000..2ff94c5e789 Binary files /dev/null and b/16/umbraco-cms/tutorials/images/content-node.png differ diff --git a/16/umbraco-cms/tutorials/images/page-not-found.png b/16/umbraco-cms/tutorials/images/page-not-found.png new file mode 100644 index 00000000000..4fdd494b842 Binary files /dev/null and b/16/umbraco-cms/tutorials/images/page-not-found.png differ