Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 76 additions & 60 deletions 16/umbraco-cms/tutorials/custom-error-page.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,45 +28,58 @@

## 404 Errors

{% hint style="warning" %}

Check warning on line 31 in 16/umbraco-cms/tutorials/custom-error-page.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐢 [UmbracoDocs.SentenceLength] Write shorter sentences (less than 25 words). Raw Output: {"message": "[UmbracoDocs.SentenceLength] Write shorter sentences (less than 25 words).", "location": {"path": "16/umbraco-cms/tutorials/custom-error-page.md", "range": {"start": {"line": 31, "column": 4}}}, "severity": "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:

Expand All @@ -78,7 +91,7 @@
"Error404Collection": [
{
"Culture": "default",
"ContentKey": "9c2b5196-30cd-4416-ae30-94ac2afb1011"
"ContentKey": "06cf09c8-c83a-4dd7-84e5-6d98d51e4d12"
}
]
}
Expand All @@ -87,11 +100,11 @@
}
```

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": [
Expand All @@ -112,61 +125,64 @@

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;
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<bool> 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<bool> TryFindContent(IPublishedRequestBuilder request)
{
using var scope = _serviceProvider.CreateScope();

var umbracoContextAccessor = scope.ServiceProvider.GetRequiredService<IUmbracoContextAccessor>();

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<Error404Page>();
}
public void Compose(IUmbracoBuilder builder)
{
builder.SetContentLastChanceFinder<PageNotFound>();
}
}

```
{% endcode %}

Expand All @@ -188,10 +204,10 @@
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**.
Expand All @@ -201,9 +217,9 @@
### 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.

Expand Down
Binary file added 16/umbraco-cms/tutorials/images/container.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 16/umbraco-cms/tutorials/images/content-node.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading