From f81199123fd3a5a75ea6563a83613c9fb8bdfbed Mon Sep 17 00:00:00 2001 From: Sven Geusens Date: Mon, 27 Oct 2025 15:00:37 +0100 Subject: [PATCH 1/7] Start of article --- 17/umbraco-cms/extending/single-block-migration.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 17/umbraco-cms/extending/single-block-migration.md diff --git a/17/umbraco-cms/extending/single-block-migration.md b/17/umbraco-cms/extending/single-block-migration.md new file mode 100644 index 00000000000..c1d1acb9246 --- /dev/null +++ b/17/umbraco-cms/extending/single-block-migration.md @@ -0,0 +1,8 @@ +V17 introduces the single block property editor. It's purpose is to replace the "single mode" option that exists in the blocklist property editor. This is part off the more general effort to ensure type consistency within core propertyeditors. + + +### Optional migration + +### Extending the migration +If you have a non core propertyEditor that allows nesting content within it and stores that content within it's own value, then you will need to extend the migration. To do this you will need create and register a class that implements `ITypedSingleBlockListProcessor` + From 48f67d1f979314da44d4cd8b2823ed1a3718b367 Mon Sep 17 00:00:00 2001 From: Sven Geusens Date: Sun, 2 Nov 2025 23:39:34 +0100 Subject: [PATCH 2/7] Finished article with examples --- .../extending/single-block-migration.md | 86 ++++++++++++++++++- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/17/umbraco-cms/extending/single-block-migration.md b/17/umbraco-cms/extending/single-block-migration.md index c1d1acb9246..bfb98ff20f4 100644 --- a/17/umbraco-cms/extending/single-block-migration.md +++ b/17/umbraco-cms/extending/single-block-migration.md @@ -1,8 +1,88 @@ +## Introduction V17 introduces the single block property editor. It's purpose is to replace the "single mode" option that exists in the blocklist property editor. This is part off the more general effort to ensure type consistency within core propertyeditors. +## Included migration +V17 ships with a migration to +- update all block list data types that have been properly configured in "single" mode. +- update all (nested) property data that uses this data type. -### Optional migration +We will not be enabling this migration until at least V18 -### Extending the migration -If you have a non core propertyEditor that allows nesting content within it and stores that content within it's own value, then you will need to extend the migration. To do this you will need create and register a class that implements `ITypedSingleBlockListProcessor` +## Pre running the migration +You can run the migration at any time by using your own migration plan as shown in the example below. If you run this migration yourself and we later enable it trough the default umbraco migration, then our run should not update any data as it only changes data that is in the old format. +```csharp +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Migrations; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.Scoping; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Infrastructure.Migrations; +using Umbraco.Cms.Infrastructure.Migrations.Upgrade; +using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_18_0_0; + +namespace SingleBlockMigrationRunner; + +public class TestMigrationComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.AddNotificationAsyncHandler(); + } +} + +public class RunTestMigration : INotificationAsyncHandler +{ + private readonly IMigrationPlanExecutor _migrationPlanExecutor; + private readonly ICoreScopeProvider _coreScopeProvider; + private readonly IKeyValueService _keyValueService; + private readonly IRuntimeState _runtimeState; + + public RunTestMigration( + ICoreScopeProvider coreScopeProvider, + IMigrationPlanExecutor migrationPlanExecutor, + IKeyValueService keyValueService, + IRuntimeState runtimeState) + { + _migrationPlanExecutor = migrationPlanExecutor; + _coreScopeProvider = coreScopeProvider; + _keyValueService = keyValueService; + _runtimeState = runtimeState; + } + + public async Task HandleAsync(UmbracoApplicationStartingNotification notification, CancellationToken cancellationToken) + { + if (_runtimeState.Level < RuntimeLevel.Run) + { + return; + } + + // One-off migration plan + var migrationPlan = new MigrationPlan("Single Block Migration"); + + // define the step + migrationPlan.From(string.Empty) + .To("test-run-singleBlock-migration"); + + // Go and upgrade our site (Will check if it needs to do the work or not) + // Based on the current/latest step + var upgrader = new Upgrader(migrationPlan); + await upgrader.ExecuteAsync( + _migrationPlanExecutor, + _coreScopeProvider, + _keyValueService); + } +} + +``` + +## Extending the migration +If you have a non core propertyEditor that allows nesting content within it and stores that content within it's own value, then you will need to extend the migration. To do this you will need create and register a class that implements `ITypedSingleBlockListProcessor` and register it. You can see how we register the build in types at `Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_18_0_0.SingleBlockList.MigrateSingleBlockListComposer`. The interface needs the following properties and methods: +- `IEnumerable PropertyEditorAliases`: The alias of the property editor as defined on its DataEditor attribute. Since a processor can support multiple editors if they use the same model, it takes an IEnumerable over a single string. These alias are used to limit the amount of data fetched from the database. +- `Type PropertyEditorValueType`: The type of the value the propertyEditor would return when `valueEditor.ToEditor()` would be called. +- `Func, Func, bool> Process` The function to run when the main processor detects a value that matches your processor. The function needs to suport the following parameters + - `object?`: The value being passed in from the outer caller or the top level processor + - `Func` The function the processor needs to call when it detects nested content. This is passed in from the top level processor. + - `Func` The function that needs to be called when the outer layer of the current value is a blockList that needs to be converted to singleblock. This should only ever be called from the core processors. It is passed around to make recursion just the little bit easier. \ No newline at end of file From 25065f3a6da69ad914afbe883b00770534c4aa45 Mon Sep 17 00:00:00 2001 From: Esha Noronha <82437098+eshanrnh@users.noreply.github.com> Date: Tue, 4 Nov 2025 09:38:22 +0100 Subject: [PATCH 3/7] Update 17/umbraco-cms/extending/single-block-migration.md --- 17/umbraco-cms/extending/single-block-migration.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/17/umbraco-cms/extending/single-block-migration.md b/17/umbraco-cms/extending/single-block-migration.md index bfb98ff20f4..fb164c74861 100644 --- a/17/umbraco-cms/extending/single-block-migration.md +++ b/17/umbraco-cms/extending/single-block-migration.md @@ -1,5 +1,6 @@ ## Introduction -V17 introduces the single block property editor. It's purpose is to replace the "single mode" option that exists in the blocklist property editor. This is part off the more general effort to ensure type consistency within core propertyeditors. + +Version 17 introduces the single block property editor. Its purpose is to replace the "single mode" option that exists in the blocklist property editor. This is part of the more general effort to ensure type consistency within core property editors. ## Included migration V17 ships with a migration to From cec66d6541b0f80e0792ed3349e6c02870eb94a4 Mon Sep 17 00:00:00 2001 From: Esha Noronha <82437098+eshanrnh@users.noreply.github.com> Date: Tue, 4 Nov 2025 09:38:44 +0100 Subject: [PATCH 4/7] Update 17/umbraco-cms/extending/single-block-migration.md --- 17/umbraco-cms/extending/single-block-migration.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/17/umbraco-cms/extending/single-block-migration.md b/17/umbraco-cms/extending/single-block-migration.md index fb164c74861..2d3f5c7c22c 100644 --- a/17/umbraco-cms/extending/single-block-migration.md +++ b/17/umbraco-cms/extending/single-block-migration.md @@ -3,11 +3,11 @@ Version 17 introduces the single block property editor. Its purpose is to replace the "single mode" option that exists in the blocklist property editor. This is part of the more general effort to ensure type consistency within core property editors. ## Included migration -V17 ships with a migration to -- update all block list data types that have been properly configured in "single" mode. -- update all (nested) property data that uses this data type. +Version 17 ships with a migration to: +- Update all block list Data Types that have been properly configured in "single" mode. +- Update all (nested) property data that uses this Data Type. -We will not be enabling this migration until at least V18 +This migration will not be enabled until at least version 18. ## Pre running the migration You can run the migration at any time by using your own migration plan as shown in the example below. If you run this migration yourself and we later enable it trough the default umbraco migration, then our run should not update any data as it only changes data that is in the old format. From 2c707ee5c6d72b15bd36bf91e6a4e1df632d9a14 Mon Sep 17 00:00:00 2001 From: Esha Noronha <82437098+eshanrnh@users.noreply.github.com> Date: Tue, 4 Nov 2025 09:38:51 +0100 Subject: [PATCH 5/7] Update 17/umbraco-cms/extending/single-block-migration.md --- 17/umbraco-cms/extending/single-block-migration.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/17/umbraco-cms/extending/single-block-migration.md b/17/umbraco-cms/extending/single-block-migration.md index 2d3f5c7c22c..f0e990b80d9 100644 --- a/17/umbraco-cms/extending/single-block-migration.md +++ b/17/umbraco-cms/extending/single-block-migration.md @@ -10,7 +10,8 @@ Version 17 ships with a migration to: This migration will not be enabled until at least version 18. ## Pre running the migration -You can run the migration at any time by using your own migration plan as shown in the example below. If you run this migration yourself and we later enable it trough the default umbraco migration, then our run should not update any data as it only changes data that is in the old format. + +You can run the migration at any time by using your own migration plan, as shown in the example below. If you run this migration yourself, the default Umbraco migration won't update any data. It only changes data in the old format. ```csharp using Umbraco.Cms.Core; From 3f5b3a2643971451e08b6bdc7f290442ba3e82d4 Mon Sep 17 00:00:00 2001 From: Esha Noronha <82437098+eshanrnh@users.noreply.github.com> Date: Tue, 4 Nov 2025 09:38:57 +0100 Subject: [PATCH 6/7] Update 17/umbraco-cms/extending/single-block-migration.md --- 17/umbraco-cms/extending/single-block-migration.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/17/umbraco-cms/extending/single-block-migration.md b/17/umbraco-cms/extending/single-block-migration.md index f0e990b80d9..c8cb731a5e4 100644 --- a/17/umbraco-cms/extending/single-block-migration.md +++ b/17/umbraco-cms/extending/single-block-migration.md @@ -81,7 +81,8 @@ public class RunTestMigration : INotificationAsyncHandler PropertyEditorAliases`: The alias of the property editor as defined on its DataEditor attribute. Since a processor can support multiple editors if they use the same model, it takes an IEnumerable over a single string. These alias are used to limit the amount of data fetched from the database. - `Type PropertyEditorValueType`: The type of the value the propertyEditor would return when `valueEditor.ToEditor()` would be called. - `Func, Func, bool> Process` The function to run when the main processor detects a value that matches your processor. The function needs to suport the following parameters From 45522e4900baf19c3c92a86ae1dab0e454a88fa0 Mon Sep 17 00:00:00 2001 From: Esha Noronha <82437098+eshanrnh@users.noreply.github.com> Date: Tue, 4 Nov 2025 09:39:05 +0100 Subject: [PATCH 7/7] Update 17/umbraco-cms/extending/single-block-migration.md --- 17/umbraco-cms/extending/single-block-migration.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/17/umbraco-cms/extending/single-block-migration.md b/17/umbraco-cms/extending/single-block-migration.md index c8cb731a5e4..7169ecf0722 100644 --- a/17/umbraco-cms/extending/single-block-migration.md +++ b/17/umbraco-cms/extending/single-block-migration.md @@ -83,9 +83,9 @@ public class RunTestMigration : INotificationAsyncHandler PropertyEditorAliases`: The alias of the property editor as defined on its DataEditor attribute. Since a processor can support multiple editors if they use the same model, it takes an IEnumerable over a single string. These alias are used to limit the amount of data fetched from the database. -- `Type PropertyEditorValueType`: The type of the value the propertyEditor would return when `valueEditor.ToEditor()` would be called. -- `Func, Func, bool> Process` The function to run when the main processor detects a value that matches your processor. The function needs to suport the following parameters - - `object?`: The value being passed in from the outer caller or the top level processor - - `Func` The function the processor needs to call when it detects nested content. This is passed in from the top level processor. - - `Func` The function that needs to be called when the outer layer of the current value is a blockList that needs to be converted to singleblock. This should only ever be called from the core processors. It is passed around to make recursion just the little bit easier. \ No newline at end of file +- `IEnumerable PropertyEditorAliases`: The alias of the property editor as defined in its DataEditor attribute. Since a processor can support multiple editors if they use the same model, it takes an IEnumerable rather than a single string. These aliases are used to limit the amount of data fetched from the database. +- `Type PropertyEditorValueType`: The type of value the property editor would return when `valueEditor.ToEditor()` is called. +- `Func, Func, bool> Process` The function to run when the main processor detects a value that matches your processor. The function must support the following parameters: + - `object?`: The value passed in from the outer caller or the top-level processor. + - `Func` The function the processor calls when it detects nested content. This is passed in from the top-level processor. + - `Func` The function called when the outer layer of the current value is a block list that needs to be converted to a single block. This should only be called from the core processors. It is passed around to make recursion a little easier. \ No newline at end of file