Skip to content

Commit 714137b

Browse files
committed
Added details of content type filters.
1 parent 53af04c commit 714137b

File tree

3 files changed

+76
-78
lines changed

3 files changed

+76
-78
lines changed

15/umbraco-cms/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@
413413
* [Setup OAuth using Postman](reference/management-api/postman-setup-swagger.md)
414414
* [Custom Swagger API](reference/custom-swagger-api.md)
415415
* [Umbraco Flavored Markdown](reference/umbraco-flavored-markdown.md)
416+
* [Content Type Filters](reference/content-type-filters.md)
416417

417418
## Tutorials
418419

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
---
2+
description: Describes how to use content type filters to restrict the allowed content options available to editors.
3+
---
4+
5+
# Filtering Allowed Content Types
6+
7+
When creating content editors are presented with a dialog where they select the type of content they want to create. The options available are defined when setting up the document, media and member types in the _Settings_ section.
8+
9+
Sometimes implementors or packages have a requirement to use some additional logic to determine which options are available.
10+
11+
This is possible using content type filters.
12+
13+
{% hint style="info" %}
14+
The uses cases supported here are similar to those where the `SendingAllowedChildrenNotification` would be used in Umbraco 13 or earlier.
15+
{% endhint %}
16+
17+
## Implementing a Content Type Filter
18+
19+
To create a content type filter you use a class that implements the `IContentTypeFilter` interface (found in the `Umbraco.Cms.Core.Services.Filters` namespace).
20+
21+
There are two methods you can implement. One is for filtering the content types allowed at the content root. The other is for the content types allowed below a given parent node.
22+
23+
If you don't want to filter for one or other method, you can just return the provided collection unmodified.
24+
25+
The following example shows a typical use case. Often websites will have a "Home Page" document type which is created at the root. Normally, only one of these is required. You can enforce that using the following content type filter.
26+
27+
Here we are querying the existing content available at the root. Normally we can create a "Home Page" here, but if one already exists, we remove the option:
28+
29+
```csharp
30+
internal class OneHomePageOnlyContentTypeFilter : IContentTypeFilter
31+
{
32+
private readonly IContentService _contentService;
33+
34+
public OneHomePageOnlyContentTypeFilter(IContentService contentService) => _contentService = contentService;
35+
36+
public Task<IEnumerable<TItem>> FilterAllowedAtRootAsync<TItem>(IEnumerable<TItem> contentTypes)
37+
where TItem : IContentTypeComposition
38+
{
39+
var docTypeAliasesToExclude = new List<string>();
40+
41+
const string HomePageDocTypeAlias = "homePage";
42+
var docTypeAliasesAtRoot = _contentService.GetRootContent()
43+
.Select(x => x.ContentType.Alias)
44+
.Distinct()
45+
.ToList();
46+
if (docTypeAliasesAtRoot.Contains(HomePageDocTypeAlias))
47+
{
48+
docTypeAliasesToExclude.Add(HomePageDocTypeAlias);
49+
}
50+
51+
return Task.FromResult(contentTypes
52+
.Where(x => docTypeAliasesToExclude.Contains(x.Alias) is false));
53+
}
54+
55+
public Task<IEnumerable<ContentTypeSort>> FilterAllowedChildrenAsync(IEnumerable<ContentTypeSort> contentTypes, Guid parentKey)
56+
=> Task.FromResult(contentTypes);
57+
}
58+
```
59+
60+
Content type filters are registered as a collection, so it's possible to have more than one either in the solution or an installed package.
61+
62+
You use a composer to register the filters:
63+
64+
```csharp
65+
public class MyComposer : IComposer
66+
{
67+
public void Compose(IUmbracoBuilder builder)
68+
{
69+
builder.ContentTypeFilters()
70+
.Append<OneHomePageOnlyContentTypeFilter>();
71+
}
72+
}
73+
```

15/umbraco-cms/reference/notifications/sendingallowedchildrennotifications.md

Lines changed: 2 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -4,82 +4,6 @@ description: Example of how to use a SendingAllowedChildren Notification
44

55
# Sending Allowed Children Notification
66

7-
The `SendingAllowedChildrenNotification` enables you to manipulate the Document Types that will be shown in the create menu when adding new content in the backoffice.
7+
The `SendingAllowedChildrenNotification` is no longer available in Umbraco 15.
88

9-
## Usage
10-
11-
With the example below we can ensure that a Document Type cannot be selected if the type already exists in the Content tree.
12-
13-
```csharp
14-
using System.Web;
15-
using Umbraco.Cms.Core.Events;
16-
using Umbraco.Cms.Core.Notifications;
17-
18-
namespace Umbraco.Docs.Samples.Web.Notifications;
19-
20-
public class SendingAllowedChildrenNotificationHandler : INotificationHandler<SendingAllowedChildrenNotification>
21-
{
22-
public void Handle(SendingAllowedChildrenNotification notification)
23-
{
24-
const string contentIdKey = "contentId";
25-
26-
// Try get the id from the content item in the backoffice
27-
var queryStringCollection = HttpUtility.ParseQueryString(notification.UmbracoContext.OriginalRequestUrl.Query);
28-
29-
if (!queryStringCollection.ContainsKey(contentIdKey))
30-
{
31-
return;
32-
}
33-
34-
var contentId = queryStringCollection[contentIdKey].TryConvertTo<int>().ResultOr(-1);
35-
36-
if (contentId == -1)
37-
{
38-
return;
39-
}
40-
41-
var content = notification.UmbracoContext.Content?.GetById(true, contentId);
42-
43-
if (content is null)
44-
{
45-
return;
46-
}
47-
48-
// Allowed children as configured in the backoffice
49-
var allowedChildren = notification.Children.ToList();
50-
51-
if (content.ChildrenForAllCultures is not null)
52-
{
53-
// Get all children of current page
54-
var childNodes = content.ChildrenForAllCultures.ToList();
55-
56-
// If there is a Settings page already created, then don't allow it anymore
57-
// You can also use the ModelTypeAlias property from your PublishedModel for comparison,
58-
// like Settings.ModelTypeAlias if you have set models builder to generate SourceCode models
59-
if (childNodes.Any(x => x.ContentType.Alias == "settings"))
60-
{
61-
allowedChildren.RemoveAll(x => x.Alias == "settings");
62-
}
63-
}
64-
65-
// Update the allowed children
66-
notification.Children = allowedChildren;
67-
}
68-
}
69-
```
70-
71-
You also need to register this notification handler. You can achieve this by updating the `Program` class like:
72-
73-
```csharp
74-
builder.CreateUmbracoBuilder()
75-
.AddBackOffice()
76-
.AddWebsite()
77-
.AddDeliveryApi()
78-
.AddComposers()
79-
.AddNotificationHandler<SendingAllowedChildrenNotification, SendingAllowedChildrenNotificationHandler>()
80-
.Build();
81-
```
82-
83-
{% hint style="info" %}
84-
For more information about registering notifications read the [Registering notification handlers](./) article.
85-
{% endhint %}
9+
Please see [content type filters](../content-type-filters.md) as the supported alternative for use cases that previously relied on this notification.

0 commit comments

Comments
 (0)