From 714137bbe2e9ce67756a58c3b2a079d42adaa022 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Mon, 20 Jan 2025 12:51:55 +0100 Subject: [PATCH 1/9] Added details of content type filters. --- 15/umbraco-cms/SUMMARY.md | 1 + .../reference/content-type-filters.md | 73 +++++++++++++++++ .../sendingallowedchildrennotifications.md | 80 +------------------ 3 files changed, 76 insertions(+), 78 deletions(-) create mode 100644 15/umbraco-cms/reference/content-type-filters.md diff --git a/15/umbraco-cms/SUMMARY.md b/15/umbraco-cms/SUMMARY.md index ac5ad4aa02f..9ed1f6a3c49 100644 --- a/15/umbraco-cms/SUMMARY.md +++ b/15/umbraco-cms/SUMMARY.md @@ -413,6 +413,7 @@ * [Setup OAuth using Postman](reference/management-api/postman-setup-swagger.md) * [Custom Swagger API](reference/custom-swagger-api.md) * [Umbraco Flavored Markdown](reference/umbraco-flavored-markdown.md) +* [Content Type Filters](reference/content-type-filters.md) ## Tutorials diff --git a/15/umbraco-cms/reference/content-type-filters.md b/15/umbraco-cms/reference/content-type-filters.md new file mode 100644 index 00000000000..4e3765b1c5c --- /dev/null +++ b/15/umbraco-cms/reference/content-type-filters.md @@ -0,0 +1,73 @@ +--- +description: Describes how to use content type filters to restrict the allowed content options available to editors. +--- + +# Filtering Allowed Content Types + +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. + +Sometimes implementors or packages have a requirement to use some additional logic to determine which options are available. + +This is possible using content type filters. + +{% hint style="info" %} +The uses cases supported here are similar to those where the `SendingAllowedChildrenNotification` would be used in Umbraco 13 or earlier. +{% endhint %} + +## Implementing a Content Type Filter + +To create a content type filter you use a class that implements the `IContentTypeFilter` interface (found in the `Umbraco.Cms.Core.Services.Filters` namespace). + +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. + +If you don't want to filter for one or other method, you can just return the provided collection unmodified. + +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. + +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: + +```csharp +internal class OneHomePageOnlyContentTypeFilter : IContentTypeFilter +{ + private readonly IContentService _contentService; + + public OneHomePageOnlyContentTypeFilter(IContentService contentService) => _contentService = contentService; + + public Task> FilterAllowedAtRootAsync(IEnumerable contentTypes) + where TItem : IContentTypeComposition + { + var docTypeAliasesToExclude = new List(); + + const string HomePageDocTypeAlias = "homePage"; + var docTypeAliasesAtRoot = _contentService.GetRootContent() + .Select(x => x.ContentType.Alias) + .Distinct() + .ToList(); + if (docTypeAliasesAtRoot.Contains(HomePageDocTypeAlias)) + { + docTypeAliasesToExclude.Add(HomePageDocTypeAlias); + } + + return Task.FromResult(contentTypes + .Where(x => docTypeAliasesToExclude.Contains(x.Alias) is false)); + } + + public Task> FilterAllowedChildrenAsync(IEnumerable contentTypes, Guid parentKey) + => Task.FromResult(contentTypes); +} +``` + +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. + +You use a composer to register the filters: + +```csharp +public class MyComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.ContentTypeFilters() + .Append(); + } +} +``` diff --git a/15/umbraco-cms/reference/notifications/sendingallowedchildrennotifications.md b/15/umbraco-cms/reference/notifications/sendingallowedchildrennotifications.md index eeaf242650a..8603360e63a 100644 --- a/15/umbraco-cms/reference/notifications/sendingallowedchildrennotifications.md +++ b/15/umbraco-cms/reference/notifications/sendingallowedchildrennotifications.md @@ -4,82 +4,6 @@ description: Example of how to use a SendingAllowedChildren Notification # Sending Allowed Children Notification -The `SendingAllowedChildrenNotification` enables you to manipulate the Document Types that will be shown in the create menu when adding new content in the backoffice. +The `SendingAllowedChildrenNotification` is no longer available in Umbraco 15. -## Usage - -With the example below we can ensure that a Document Type cannot be selected if the type already exists in the Content tree. - -```csharp -using System.Web; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Notifications; - -namespace Umbraco.Docs.Samples.Web.Notifications; - -public class SendingAllowedChildrenNotificationHandler : INotificationHandler -{ - public void Handle(SendingAllowedChildrenNotification notification) - { - const string contentIdKey = "contentId"; - - // Try get the id from the content item in the backoffice - var queryStringCollection = HttpUtility.ParseQueryString(notification.UmbracoContext.OriginalRequestUrl.Query); - - if (!queryStringCollection.ContainsKey(contentIdKey)) - { - return; - } - - var contentId = queryStringCollection[contentIdKey].TryConvertTo().ResultOr(-1); - - if (contentId == -1) - { - return; - } - - var content = notification.UmbracoContext.Content?.GetById(true, contentId); - - if (content is null) - { - return; - } - - // Allowed children as configured in the backoffice - var allowedChildren = notification.Children.ToList(); - - if (content.ChildrenForAllCultures is not null) - { - // Get all children of current page - var childNodes = content.ChildrenForAllCultures.ToList(); - - // If there is a Settings page already created, then don't allow it anymore - // You can also use the ModelTypeAlias property from your PublishedModel for comparison, - // like Settings.ModelTypeAlias if you have set models builder to generate SourceCode models - if (childNodes.Any(x => x.ContentType.Alias == "settings")) - { - allowedChildren.RemoveAll(x => x.Alias == "settings"); - } - } - - // Update the allowed children - notification.Children = allowedChildren; - } -} -``` - -You also need to register this notification handler. You can achieve this by updating the `Program` class like: - -```csharp -builder.CreateUmbracoBuilder() - .AddBackOffice() - .AddWebsite() - .AddDeliveryApi() - .AddComposers() - .AddNotificationHandler() - .Build(); -``` - -{% hint style="info" %} -For more information about registering notifications read the [Registering notification handlers](./) article. -{% endhint %} +Please see [content type filters](../content-type-filters.md) as the supported alternative for use cases that previously relied on this notification. \ No newline at end of file From 8e360c6075302b7ab89a623e24e0f27b4d7714a9 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Mon, 20 Jan 2025 12:56:14 +0100 Subject: [PATCH 2/9] Linting --- 15/umbraco-cms/reference/content-type-filters.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/15/umbraco-cms/reference/content-type-filters.md b/15/umbraco-cms/reference/content-type-filters.md index 4e3765b1c5c..38f63b27cfc 100644 --- a/15/umbraco-cms/reference/content-type-filters.md +++ b/15/umbraco-cms/reference/content-type-filters.md @@ -1,5 +1,5 @@ --- -description: Describes how to use content type filters to restrict the allowed content options available to editors. +description: Describes how to use Content Type Filters to restrict the allowed content options available to editors. --- # Filtering Allowed Content Types @@ -20,9 +20,9 @@ To create a content type filter you use a class that implements the `IContentTyp 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. -If you don't want to filter for one or other method, you can just return the provided collection unmodified. +If you don't want to filter for one or other method, you can return the provided collection unmodified. -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. +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. 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: @@ -57,7 +57,7 @@ internal class OneHomePageOnlyContentTypeFilter : IContentTypeFilter } ``` -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. +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. You use a composer to register the filters: From 199e4e2cf011fe1d07f511b2ab5c736f580acaee Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Mon, 20 Jan 2025 13:53:03 +0100 Subject: [PATCH 3/9] Updated page for 14 --- .../sendingallowedchildrennotifications.md | 80 +------------------ 1 file changed, 2 insertions(+), 78 deletions(-) diff --git a/14/umbraco-cms/reference/notifications/sendingallowedchildrennotifications.md b/14/umbraco-cms/reference/notifications/sendingallowedchildrennotifications.md index eeaf242650a..04182943dac 100644 --- a/14/umbraco-cms/reference/notifications/sendingallowedchildrennotifications.md +++ b/14/umbraco-cms/reference/notifications/sendingallowedchildrennotifications.md @@ -4,82 +4,6 @@ description: Example of how to use a SendingAllowedChildren Notification # Sending Allowed Children Notification -The `SendingAllowedChildrenNotification` enables you to manipulate the Document Types that will be shown in the create menu when adding new content in the backoffice. +The `SendingAllowedChildrenNotification` is no longer available in Umbraco 14 and no replacement is available for this major version. -## Usage - -With the example below we can ensure that a Document Type cannot be selected if the type already exists in the Content tree. - -```csharp -using System.Web; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Notifications; - -namespace Umbraco.Docs.Samples.Web.Notifications; - -public class SendingAllowedChildrenNotificationHandler : INotificationHandler -{ - public void Handle(SendingAllowedChildrenNotification notification) - { - const string contentIdKey = "contentId"; - - // Try get the id from the content item in the backoffice - var queryStringCollection = HttpUtility.ParseQueryString(notification.UmbracoContext.OriginalRequestUrl.Query); - - if (!queryStringCollection.ContainsKey(contentIdKey)) - { - return; - } - - var contentId = queryStringCollection[contentIdKey].TryConvertTo().ResultOr(-1); - - if (contentId == -1) - { - return; - } - - var content = notification.UmbracoContext.Content?.GetById(true, contentId); - - if (content is null) - { - return; - } - - // Allowed children as configured in the backoffice - var allowedChildren = notification.Children.ToList(); - - if (content.ChildrenForAllCultures is not null) - { - // Get all children of current page - var childNodes = content.ChildrenForAllCultures.ToList(); - - // If there is a Settings page already created, then don't allow it anymore - // You can also use the ModelTypeAlias property from your PublishedModel for comparison, - // like Settings.ModelTypeAlias if you have set models builder to generate SourceCode models - if (childNodes.Any(x => x.ContentType.Alias == "settings")) - { - allowedChildren.RemoveAll(x => x.Alias == "settings"); - } - } - - // Update the allowed children - notification.Children = allowedChildren; - } -} -``` - -You also need to register this notification handler. You can achieve this by updating the `Program` class like: - -```csharp -builder.CreateUmbracoBuilder() - .AddBackOffice() - .AddWebsite() - .AddDeliveryApi() - .AddComposers() - .AddNotificationHandler() - .Build(); -``` - -{% hint style="info" %} -For more information about registering notifications read the [Registering notification handlers](./) article. -{% endhint %} +Please see [content type filters](../../../../15/umbraco-cms/reference/content-type-filters.md) as the supported alternative in Umbraco 15 for use cases that previously relied on this notification. \ No newline at end of file From 8592fca1fa986b749c11ffbcc7034cd0532aafdb Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Mon, 20 Jan 2025 14:06:06 +0100 Subject: [PATCH 4/9] docs: adds new condition type `Umb.Condition.CurrentUser.GroupId` --- .../customizing/extending-overview/extension-conditions.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/15/umbraco-cms/customizing/extending-overview/extension-conditions.md b/15/umbraco-cms/customizing/extending-overview/extension-conditions.md index 2ac598e17f8..0e58834410c 100644 --- a/15/umbraco-cms/customizing/extending-overview/extension-conditions.md +++ b/15/umbraco-cms/customizing/extending-overview/extension-conditions.md @@ -38,7 +38,7 @@ When declaring multiple conditions all of them must be permitted for the extensi The following conditions are available out of the box, for all extension types that support Conditions. * `Umb.Condition.Switch` - Toggles on and off based on the `frequency` set in seconds. -* `Umb.Condition.MultipleAppLanguages` - Requires the app to have more than one language, i.e. a multi-language site. +* `Umb.Condition.MultipleAppLanguages` - Requires the app to have more than one language, that is a multi-language site. * `Umb.Condition.SectionAlias` - Requires the current Section Alias to match the one specified. * `Umb.Condition.MenuAlias` - Requires the current Menu Alias to match the one specified. * `Umb.Condition.WorkspaceAlias` - Requires the current Workspace Alias to match the one specified. @@ -51,7 +51,8 @@ The following conditions are available out of the box, for all extension types t * `Umb.Condition.EntityIsNotTrashed` - Requires the current entity to not be trashed. * `Umb.Condition.SectionUserPermission` - Requires the current user to have permissions to the given Section Alias. * `Umb.Condition.UserPermission.Document` - Requires the current user to have specific Document permissions. Example: 'Umb.Document.Save'. -* `Umb.Condition.CurrentUser.IsAdmin` - Requires the current user to be an admin as defined by the backend, i.e. belongs to the Administrator group. +* `Umb.Condition.CurrentUser.GroupId` - Requires the current user to belong to a specific group by GUID. Accepts **match** (GUID), **oneOf** (array), **allOf** (array), and **noneOf** (array). Example: '8d2b3c4d-4f1f-4b1f-8e3d-4a6b7b8c4f1e'. +* `Umb.Condition.CurrentUser.IsAdmin` - Requires the current user to be an admin as defined by the backend, for example that they belong to the Administrator group. ## Condition Configuration From 393cec0d8e5d8b52df00e5c7088c3a4fa31de828 Mon Sep 17 00:00:00 2001 From: Lee Kelleher Date: Thu, 30 Jan 2025 19:55:51 +0000 Subject: [PATCH 5/9] Adds `BackOfficeLogo` to the `ContentSettings` (#6836) --- 15/umbraco-cms/reference/configuration/contentsettings.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/15/umbraco-cms/reference/configuration/contentsettings.md b/15/umbraco-cms/reference/configuration/contentsettings.md index 3bd9eee297e..fb7599f626c 100644 --- a/15/umbraco-cms/reference/configuration/contentsettings.md +++ b/15/umbraco-cms/reference/configuration/contentsettings.md @@ -26,6 +26,7 @@ The following snippet will give an overview of the keys and values in the conten "DisallowedUploadFiles": ["ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd", "xamlx"], "DisallowedUploadedFileExtensions": ["ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd", "xamlx"], "Error404Collection": [], + "BackOfficeLogo": "../media/qyci4xti/logo.png", "HideBackOfficeLogo": false, "Imaging": { "ImageFileTypes": ["jpeg", "jpg", "gif", "bmp", "png", "tiff", "tif"], @@ -128,6 +129,10 @@ If you have multiple sites, with different cultures, setup in your tree then you If you have more than two sites and forget to add a 404 page and a culture, the default page will act as fallback. Same happens if you for some reason forget to define a hostname on a site. +### Backoffice logo + +This setting can be used to set a custom image path to replace the Umbraco logo in backoffice. + ### Hide backoffice logo This setting can be used to hide the Umbraco logo in backoffice. From cd75b244341abe1eaad4e078e9b2acd5434e65eb Mon Sep 17 00:00:00 2001 From: sofietoft Date: Wed, 5 Feb 2025 09:30:55 +0100 Subject: [PATCH 6/9] Minor formatting --- .../customizing/extending-overview/extension-conditions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/15/umbraco-cms/customizing/extending-overview/extension-conditions.md b/15/umbraco-cms/customizing/extending-overview/extension-conditions.md index 0e58834410c..d550ef8dcf3 100644 --- a/15/umbraco-cms/customizing/extending-overview/extension-conditions.md +++ b/15/umbraco-cms/customizing/extending-overview/extension-conditions.md @@ -51,8 +51,8 @@ The following conditions are available out of the box, for all extension types t * `Umb.Condition.EntityIsNotTrashed` - Requires the current entity to not be trashed. * `Umb.Condition.SectionUserPermission` - Requires the current user to have permissions to the given Section Alias. * `Umb.Condition.UserPermission.Document` - Requires the current user to have specific Document permissions. Example: 'Umb.Document.Save'. -* `Umb.Condition.CurrentUser.GroupId` - Requires the current user to belong to a specific group by GUID. Accepts **match** (GUID), **oneOf** (array), **allOf** (array), and **noneOf** (array). Example: '8d2b3c4d-4f1f-4b1f-8e3d-4a6b7b8c4f1e'. -* `Umb.Condition.CurrentUser.IsAdmin` - Requires the current user to be an admin as defined by the backend, for example that they belong to the Administrator group. +* `Umb.Condition.CurrentUser.GroupId` - Requires the current user to belong to a specific group by GUID. Accepts `match` (GUID), `oneOf` (array), `allOf` (array), and `noneOf` (array). Example: '8d2b3c4d-4f1f-4b1f-8e3d-4a6b7b8c4f1e'. +* `Umb.Condition.CurrentUser.IsAdmin` - Requires the current user to be an admin as defined by the backend, for example, that they belong to the Administrator group. ## Condition Configuration From 998e20c716853f3394347392e07a3662f3ee44cf Mon Sep 17 00:00:00 2001 From: sofietoft Date: Wed, 5 Feb 2025 09:32:13 +0100 Subject: [PATCH 7/9] Update contentsettings.md --- 15/umbraco-cms/reference/configuration/contentsettings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/15/umbraco-cms/reference/configuration/contentsettings.md b/15/umbraco-cms/reference/configuration/contentsettings.md index fb7599f626c..e035ec2faaa 100644 --- a/15/umbraco-cms/reference/configuration/contentsettings.md +++ b/15/umbraco-cms/reference/configuration/contentsettings.md @@ -131,7 +131,7 @@ If you have more than two sites and forget to add a 404 page and a culture, the ### Backoffice logo -This setting can be used to set a custom image path to replace the Umbraco logo in backoffice. +This setting can be used to set a custom image path to replace the Umbraco logo in the backoffice. ### Hide backoffice logo From b461fcc236036530556bfe81fc3291a711985dc5 Mon Sep 17 00:00:00 2001 From: sofietoft Date: Wed, 5 Feb 2025 09:39:58 +0100 Subject: [PATCH 8/9] Updated some grammar etc --- .../reference/content-type-filters.md | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/15/umbraco-cms/reference/content-type-filters.md b/15/umbraco-cms/reference/content-type-filters.md index 38f63b27cfc..8d3e970b474 100644 --- a/15/umbraco-cms/reference/content-type-filters.md +++ b/15/umbraco-cms/reference/content-type-filters.md @@ -4,27 +4,32 @@ description: Describes how to use Content Type Filters to restrict the allowed c # Filtering Allowed Content Types -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. +When content editors add new content they are presented with a dialog where they must 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. -Sometimes implementors or packages have a requirement to use some additional logic to determine which options are available. +Implementors and package creators can add additional logic to determine which options are available to the editors. -This is possible using content type filters. +This is possible using Content Type Filters. {% hint style="info" %} -The uses cases supported here are similar to those where the `SendingAllowedChildrenNotification` would be used in Umbraco 13 or earlier. +The use cases supported here are similar to those where the `SendingAllowedChildrenNotification` would be used in Umbraco 13 or earlier. {% endhint %} ## Implementing a Content Type Filter -To create a content type filter you use a class that implements the `IContentTypeFilter` interface (found in the `Umbraco.Cms.Core.Services.Filters` namespace). +To create a Content Type Filter you use a class that implements the `IContentTypeFilter` interface (found in the `Umbraco.Cms.Core.Services.Filters` namespace). -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. +There are two methods you can implement: -If you don't want to filter for one or other method, you can return the provided collection unmodified. +* One for filtering the content types allowed at the content root +* One for the content types allowed below a given parent node. + +If you don't want to filter using one of the two approaches, you can return the provided collection unmodified. + +### Example Use case 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. -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: +The code below is querying the existing content available at the root. Normally you can create a "Home Page" here, but if one already exists that option is removed: ```csharp internal class OneHomePageOnlyContentTypeFilter : IContentTypeFilter @@ -57,9 +62,9 @@ internal class OneHomePageOnlyContentTypeFilter : IContentTypeFilter } ``` -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. +Content Type Filters are registered as a collection, making it possible to have more than one in the solution or an installed package. -You use a composer to register the filters: +The filters need to be registered in a composer: ```csharp public class MyComposer : IComposer From c7887b493f2d55ab3c6b6ff364a2fcee360894e3 Mon Sep 17 00:00:00 2001 From: sofietoft Date: Wed, 5 Feb 2025 10:41:58 +0100 Subject: [PATCH 9/9] Update 15/umbraco-cms/reference/content-type-filters.md Co-authored-by: Andy Butland --- 15/umbraco-cms/reference/content-type-filters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/15/umbraco-cms/reference/content-type-filters.md b/15/umbraco-cms/reference/content-type-filters.md index 8d3e970b474..cbfa5fc4dfb 100644 --- a/15/umbraco-cms/reference/content-type-filters.md +++ b/15/umbraco-cms/reference/content-type-filters.md @@ -25,7 +25,7 @@ There are two methods you can implement: If you don't want to filter using one of the two approaches, you can return the provided collection unmodified. -### Example Use case +### Example Use Case 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.