Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Introduces upgrades in Umbraco, describing what to consider when planning an upgrade.
When upgrading to a new version of Umbraco, there are four key aspects of the migration to be aware of.
Firstly there's the update of your Umbraco database's schema and how the content is stored. On occasion changes are necessary to support a new feature. This might be adding new tables or columns, or updating the stored data. This is something Umbraco takes care of for you. When Umbraco starts up and is running a newer version, the necessary changes will be detected and applied.
As a developer responsible for the Umbraco website, there's nothing specific you need to do here. We will communicate key migrations that will happen on major version upgrades. As if you have a large site and significant amounts of data need to be updated, the migration could take some time to complete.
Minor or patch versions may contain schema and content updates too, but they won't be extensive.
Secondly you should review your use of property editors to ensure that they are available on the new version. It's rare for these to be removed, but it can happen when better alternatives are available. These are only removed in major versions and with plenty of notice on the announcements repository. Property editors for retirement will also have been indicated as legacy on earlier versions.
The third aspect is determining and verifying that your own code customizations are compatible with the new version. This includes C# server-side functionality, Razor templates and JavaScript backoffice extensions.
Extensive efforts are made to avoid breaking changes that would cause issues for these types of customization other than in a major version update.
Finally you should consider the packages you are using on your project. You will need to verify that the package will work with the new version of Umbraco. Or that a compatible upgrade of the package is available or planned.
As above, breaking changes that would prevent packages from working other than in a major version update are avoided.
For the reasons described, projects always need to be considered case by case when upgrading to new versions.
Umbraco communicates about the breaking changes in release blog posts and on the documented . There will be extended release candidate periods to ensure upgrades can be tested and to help package developers support new major versions.
Breaking changes are minimized but there will be cases when such updates are needed. How straightforward the upgrade will be depends on the breaking changes included in the major and whether your project(s) are impacted by them.
The following lists a few things to be aware of before initiating an upgrade of your Umbraco CMS project.
Sometimes, there are exceptions to general upgrade guidelines. These are listed in the . Be sure to read this article before moving on.
Ensure your setup meets the for the new versions you will be upgrading your project to.
Things may go wrong for different reasons. Be sure to always keep a backup of both your site's files and the database. This way, you can always return to a version that you know works.
- how to upgrade Umbraco across major, minor, and patch versions.
- configure Umbraco to upgrade in an unattended mode, avoiding the need to click through the installation wizard.
- details of changes to be aware of when upgrading to specific versions.
- covers the possibility of downgrading to a previous version and re-running migrations from an upgrade.
A guide to install Umbraco CMS using Visual Studio.
Check the article to ensure you have everything you need to start your Umbraco project.
Install the latest .NET SDK.
Run dotnet new install Umbraco.Templates to install the project templates.
Go to File > New > Project/Solution.
Search for Umbraco in the Search for templates field.
Select Umbraco Project (Umbraco HQ).
Click Next.
Enter a Project name.
Select .Net 10.0 Long-Term Support (LTS) from the Framework dropdown. The rest of the fields are optional.
Click Create.
The Umbraco Project is ready for you.
You can now run the site through Visual Studio using F5 or the Debug button.
Follow the installation wizard and after a few steps, you will get a message saying the installation was a success.
You are now ready to start building your Umbraco project. Have a look below for different resources on the next steps.
Learn how to upgrade your Umbraco 8 project to Umbraco 10.
It is currently not possible to upgrade directly from Umbraco 8 to the latest version.
The recommended approach for upgrading from version 8 to the latest version is to use this guide to upgrade from Umbraco 8 to Umbraco 10. Umbraco 10 contains the that must be upgraded from Umbraco 8. You can then use the steps to upgrade from Umbraco 10 to the latest version.
Since the underlying framework going from Umbraco 8 to the latest version has changed, there is no direct upgrade path. That said, it is possible to re-use the database from your Umbraco 8 project on your new project in order to maintain the content.
It is not possible to migrate the custom code as the underlying web framework has been updated from ASP.NET to ASP.NET Core. All templates and custom code will need to be reimplemented.
You also need to make sure that the packages you are using are available on the latest version.
A Umbraco 8 project running the latest version of Umbraco 8.
A backup of your Umbraco 8 project database.
A clean installation of the latest version of Umbraco.
Create a backup of the database from your Umbraco 8 project (after you have upgraded to the latest version of v8). For this, you can use the .
Import the database backup into SQL Server Management Studio.
Update the connection string in the new projects appsettings.json file so that it connects to the Umbraco 8 database:
Run the new project and login to authorize the upgrade.
Select "Upgrade" when the upgrade wizard appears.
Once the upgrade has been completed, it's recommended to login to the backoffice to verify if your project is upgraded to new version.
The following files/folders need to be copied from the Umbraco 8 project into the new project:
~/Views - Do not overwrite the default Macro and Partial View Macro files unless changes have been made to these.
~/Media - Media folder from v8 needs to be copied over into the wwwroot - media folder
The latest version of Umbraco is different from Umbraco 8 in many ways. With all the files and data migrated it is now time to rewrite and re-implement all custom code and templates.
One of the changes is how published content is rendered through Template files. Due to this, it will be necessary to update all the Template files (.cshtml) to reflect these changes.
Read more about these changes in the section of the Umbraco CMS documentation.
Template files need to inherit from Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ContentModels.HomePage> instead of Umbraco.Web.Mvc.UmbracoViewPage<ContentModels.HomePage>
Template files need to use ContentModels = Umbraco.Cms.Web.Common.PublishedModels instead of ContentModels = Umbraco.Web.PublishedModels
Depending on the extent of the project and the amount of custom code and implementations, this step is going to require a lot of work.
Once the new project runs without errors on a local setup it is time to deploy the website to production.
This concludes this tutorial. Find related information and further reading in the section below.
, for the configuration of Umbraco 7 and 8
Any files/folders related to Stylesheets and JavaScript.
Migrate custom configuration from the Umbraco 8 configuration files (.config) into the appsettings.json file on the new project.
As of Umbraco version 9, the configuration no longer lives in the Web.Config file and has been replaced by the appsettings.json file. Learn more about this in the article.
, if relevant.
As of Umbraco Forms version 9, it is only possible to store Forms data in the database. If Umbraco Forms was used on the Umbraco 8 project, the files need to be migrated to the database.
Run the new project.
It will give you an error screen on the frontend as none of the Template files have been updated. Follow Step 3 to resolve the errors.
"ConnectionStrings": {
"umbracoDbDSN": "Server=YourLocalSQLServerHere;Database=NameOfYourDatabaseHere;User Id=NameOfYourUserHere;Password=YourPasswordHere;TrustServerCertificate=True"
}The video below shows how to complete the upgrade on an Umbraco Cloud project. While the overall process is the same, you must update to the latest supported version on Cloud locally before continuing on Cloud.
Learn more about supported versions in the article.
If you use Umbraco Forms, make sure to have to True before step 1.
This is only content migration and the database will be migrated.
You need to manually update the view files and custom code implementation. For more information, see Step 3 of this guide.
Learn the core workflows in the Umbraco backoffice.
Whether you are an editor managing daily content or a developer configuring the system for the first time, understanding the Backoffice is essential. This section covers the fundamental operations of the Umbraco interface from initial login and content creation to advanced node management.
Once you are familiar with the basics, the Tips and Tricks section covers audit trails, notifications, session timeout, and other useful backoffice features.
Content lifecycle: Create, save, preview, publish, and unpublish content
Node management: Find, edit, sort, move, copy, delete, and restore pages
Umbraco HQ offers training on backoffice workflows, content management, and editorial best practices.
The course is useful for content editors, project managers, and other team members who want a stronger foundation in working with Umbraco.
.
Learn how to delete pages to the Recycle Bin and restore or permanently remove them from your Umbraco project.
If you have pages that are no longer required for your website, you can delete them. Upon deletion, the page is moved to the Recycle Bin and is not deleted permanently.
In case you wish to restore the page, you can restore them from the Recycle Bin. You also have the option to empty the Recycle Bin which permanently deletes all the items.
To delete a page:
Go to Content.
Click ... next to the page you wish to delete.
Select Trash.
Alternatively, click on the ... next to the title field and select Trash.
A window appears confirming if you want to delete the page.
Click OK.
A confirmation message appears. Click OK to dismiss the confirmation message.
The Recycle Bin is a separate tree list which can be found at the bottom of the section tree view. Selecting the Recycle Bin page, opens a list view with all deleted content. Clicking the arrow to the left of the Recycle Bin icon in the tree will also list any pages that have been deleted.
To restore deleted pages from the Recycle Bin:
Click ••• next to the page in the list and select Restore.
You can also click on the ... next to the page in tree and select Restore.
A window appears confirming if you want to restore the page.
Click Restore.
A confirmation message appears. Click OK to dismiss the confirmation message.
If you are confident you no longer require any pages in the Recycle Bin, you can permanently delete it. You can delete pages one by one or empty the Recycle Bin in one go.
To empty the Recycle Bin:
Select the Recycle Bin and click on Empty recycle bin above the list.
A message appears confirming if you want to empty the recycle bin.
Click OK.
Alternatively, click on the ... when hovering the Recycle Bin, and select Empty recycle bin... from the menu.
To delete individual pages from the Recycle Bin:
Select the Recycle Bin to open the list of deleted items.
Click on the trash bin icon next to the content you want to permanently delete.
You can also open the page and click the ... next to the title field and select Delete.
A message appears confirming if you want to delete the page.
Click OK.
A confirmation message appears. Click OK to dismiss the confirmation message.








Learn how to create, save, and publish content pages in the Umbraco backoffice, including scheduling and unpublishing options.
In this article, you get an overview of how to create and save pages. You will also learn more about how to publish and unpublish your content.
If you are a Cloud user, you will also learn how to compare and transfer content between environments. In Umbraco Cloud, an environment is a separate workspace such as Development, Staging, or Live/Production. It lets you preview and test changes before moving them to your live site. For more information about environments, see the Environments article in the Umbraco Cloud documentation.
Select the parent page to create your new page. The parent page can be the home page or any of the sub-pages of the site.
If the parent page allows sub-pages underneath it, follow these steps:
Hover over the name of the parent page in the Content section and click ••• to view the types of pages you can create.
Select the page type you wish to create. The new page is loaded in the editor on the right-hand side.
Enter a Name for the page and click Save.
There are three different options for saving and publishing pages. The options vary depending on whether you’re still in the process of editing the page or you’re ready to publish your changes.
The Save and preview button allows you to save your changes and preview it before publishing the changes to the live site. The Preview feature shows you how the page will look once it is published. This Save and preview feature only saves your page and does not publish your contents to the live site.
The Save button is used for saving the page without publishing the changes to the live site. The Save feature prevents data loss during long-term projects. Use it frequently to protect your ongoing changes.
The Save and publish button is used to publish a previously saved page to the live website or to publish a page without previewing it. The Save and publish feature will save and publish the page to your live website.
The Save and publish button has three options:
The Schedule button allows you to set a time and a date for when your page should be published. The Schedule option lets you keep editing your page. The site will automatically publish at your scheduled date and time.
To set up scheduled publishing, follow these steps:
Navigate to the page you want to publish.
Select the arrow next to the Save and Publish button.
Select Schedule publish.
In the Scheduled Publishing window, set the date and time in the Publish at field.
Select Schedule.
The Publish with descendants button allows you to publish the current page and all the content linked to this page to the live site. Using this option, you can publish the current parent page and its child nodes, previously published, and unpublished content items.
To publish the node with descendants, follow these steps:
Navigate to the page you want to publish.
Select the arrow next to the Save and Publish button.
Select Publish with descendants.
Toggle the option to Include unpublished content items if you wish to. This option includes all unpublished content items for the selected page and the descendant pages.
The Unpublish button allows you to unpublish a page if you do not want a page to be publicly visible.
To unpublish a page, follow these steps:
Navigate to the page you want to unpublish.
Select the arrow next to the Save and Publish button.
Select Unpublish.
Take note of any listed items with dependencies on the content your are unpublishing. This will typically be child items published under the content you have selected.
You can also unpublish your page by setting the date and time using the Schedule feature.
To set up scheduled unpublishing, follow these steps:
Navigate to the page you want to unpublish.
Select the arrow next to the Save and Publish button.
Select Schedule.
In the Scheduled Publishing window, set the date and time in the Unpublish at field.
Select Schedule.






This article will help you migrate content to Umbraco 15, and outline options to skip this content migration
The options in this article apply to the upgrade to Umbraco versions 15 to 17.
Umbraco 18 doesn't include this content migration. Complete the upgrade to Umbraco 17 before you upgrade to Umbraco 18.
Umbraco 15 changes the internal data format of all Block Editors.
If you maintain a large Umbraco site with extensive Block Editor usage, the upgrade to Umbraco 15+ might require a long-running content migration. For the duration of the migration, your site will be unresponsive and unable to serve requests.
You can track the progress of the migration in the logs.
It is advised to clean up old content versions before upgrading. This will make the migration run faster.
It is possible to parallelize the content migration. This will speed up the migration for large sites.
For certain content structures, parallel content migration will fail. Therefore, parallel content migration is strictly opt-in.
If parallel content migration fails, the database state will be rolled back to the last known good state. You can then disable parallel content migration, and try the migration again.
To enable parallel content migration, add an IComposer implementation to configure the ConvertBlockEditorPropertiesOptions before initiating the upgrade process:
It is strongly recommended to let the migration run as part of the upgrade. However, if you are upgrading to Umbraco versions 15, 16, or 17, you can opt out of the migration. Your site will continue to work, albeit with a certain degree of performance degradation.
You can opt out of migrating each Block Editor type individually. To opt-out, add an IComposer implementation to configure the ConvertBlockEditorPropertiesOptions before initiating the upgrade process:
Subsequently, you are responsible for performing the content migration yourself. This must be done before upgrading past Umbraco 17.
Custom code is required to perform the content migration. You can find inspiration in the core migrations:
for Block List properties.
for Block Grid properties.
for Rich Text Editor properties.
Running Umbraco on docker locally using docker compose
This article shows how to run Umbraco locally in Docker using Docker Compose. You can use either SQL Server or SQLite for development.
Before you can run Umbraco in Docker, make sure the following are installed:
.NET SDK with Umbraco Templates v16 or higher
Docker Desktop
To install Umbraco using the provided Dockerfile and Docker Compose setup, follow these steps:
The Umbraco content tree view allows you to navigate web pages through a logical site hierarchy. You can find a page by navigating through the tree itself if you know where the page is stored.
To search across all the content, files, or folders in Umbraco, click the Magnifier icon in the top-right of the screen. Alternatively, you can use the keyboard shortcut CTRL + SPACE to access the Search bar.
Using the search bar, you can enter a search term to search across most content and settings data in the backoffice. This includes:
Document Types
Data Types
Blocks in Rich Text Editors might not work as expected if you opt out of the content migration.
This custom code should not run while editors are working in the Umbraco backoffice.
The site may require a restart once the content migration is complete.
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_15_0_0;
namespace UmbracoDocs.Samples;
public class DisableBlockEditorMigrationComposer : IComposer
{
[Obsolete]
public void Compose(IUmbracoBuilder builder)
=> builder.Services.Configure<ConvertBlockEditorPropertiesOptions>(options =>
{
// setting this to true will parallelize the migration of all Block Editors
options.ParallelizeMigration = true;
});
}using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_15_0_0;
namespace UmbracoDocs.Samples;
public class DisableBlockEditorMigrationComposer : IComposer
{
[Obsolete]
public void Compose(IUmbracoBuilder builder)
=> builder.Services.Configure<ConvertBlockEditorPropertiesOptions>(options =>
{
// setting this to true will skip the migration of all Block List properties
options.SkipBlockListEditors = false;
// setting this to true will skip the migration of all Block Grid properties
options.SkipBlockGridEditors = false;
// setting this to true will skip the migration of all Rich Text Editor properties
options.SkipRichTextEditors = false;
});
}Create a folder and navigate into it:
Create a new Umbraco project with Docker support:
Add Docker Compose files:
The -P flag is required to specify the correct paths in the docker-compose file. The project is now ready to run with Docker Compose.
The folder structure should now look like this:
MyDockerProject/
Database/
Dockerfile
healthcheck.sh
setup.sql
startup.sh
MyDockerProject/
Your project files
Dockerfile
.env
docker-compose.yml
The project now includes docker files for both Umbraco and the SQL server database.
It also includes additional scripts to launch and configure the database and a .env file with the database password.
Run the following command from the root folder (where docker-compose.yml is located):
Access the site at http://localhost:44372.
Create a new folder and navigate into it:
Create a new Umbraco project:
Add a Dockerfile
Build the container:
Run the container:
Access the site at http://localhost:8080.
There are some useful commands you can use to manage the docker containers:
docker compose down --volumes: Deletes containers and the volumes they use. This is useful if you want to start from scratch.
docker compose up --build: Rebuild the images and start the containers. This is useful if you have made changes to the project and want to see them reflected on the running site.
docker compose watch: Start the containers and watch the default models folder. This means that if the project uses a source-code models builder the images are automatically rebuilt and restarts when you change the models.
The docker compose file uses bind mounts for the following folders:
/wwwroot/media
/wwwroot/scripts
/wwwroot/css
/Views
/models
This is not meant to be used in production.
For local development, however, this means that the files necessary for development are available from outside the container in your IDE. This allows development even though the project is running in docker.
The umbraco-compose template supports:
-P or --project-name: The name of the project. This is required and used to set the correct paths in the docker-compose file.
-dbpw or --DatabasePassword: Used to specify the database password. This is stored in the .env file and defaults to: Password1234.
-p or --Port: Used to specify the port the site will run on. Defaults to 44372.
mkdir MyDockerProject
cd MyDockerProjectdotnet new umbraco -n MyDockerProject --add-dockerdotnet new umbraco-compose -P "MyDockerProject"docker compose upmkdir MyDockerSqliteProject
cd MyDockerSqliteProjectdotnet new umbraco -n MyDockerSqliteProjectFROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
WORKDIR /app
EXPOSE 8080
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["MyDockerSqliteProject/MyDockerSqliteProject.csproj", "MyDockerSqliteProject/"]
RUN dotnet restore "MyDockerSqliteProject/MyDockerSqliteProject.csproj"
COPY . .
WORKDIR "/src/MyDockerSqliteProject"
RUN dotnet build "MyDockerSqliteProject.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
RUN dotnet publish "MyDockerSqliteProject.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyDockerSqliteProject.dll"]docker build -t umbraco-sqlite .docker run -p 8080:8080 umbraco-sqliteBe careful with this command, as it deletes your database and all data in it.
Members
Member Types
Dictionary Items
Templates, and more.
The exact set of tabs depends on your version and installed packages, such as Umbraco Forms.
Resources and links for older versions of Umbraco CMS.
This documentation covers the currently supported versions of Umbraco CMS. For legacy or End-of-Life (EOL) versions, use the resources below.
When a major version of Umbraco CMS reaches EOL, its documentation is unpublished one to three months later.
Documentation for all EOL versions remains available on the .
The documentation for Umbraco versions 7 and 8 is available on .
.dockerignore
The Legacy Documentation is no longer being actively maintained.
Learn how to copy a page and its child pages to a different location in the content tree.
Re-use a page or a tree structure you have previously created by copying the parent page and its child pages to a different section within the site structure.
When you copy a parent page all of its child pages are also copied, by default. You can choose if you want to copy the child pages or not. You can also choose whether the links should be automatically updated or continue to link to the original pages.
You can copy a page in two ways:
Go to Content.
Click ... next to the page you wish to copy.
Select Duplicate to.
A window appears on the right side of the screen. Here, you can choose where you want to copy the page in the tree structure.
Toggle Relate to original button if you want to keep the links linked to the original page.
Toggle Include descendants if you want to copy the child pages alongside the parent page.
Click Copy.
Go to Content.
Select the page you wish to copy.
Click ... next to the title of the page.
Select Duplicate to.
A window appears on the right side of the screen. Here, you can choose where you want to copy the page in the tree structure.
Toggle Relate to original button if you want to keep the links linked to the original page.
Toggle Include descendants if you want to copy the child pages alongside the parent page.
Click Copy.



Learn how to start testing a pre-release for the latest version of Umbraco CMS, and find information about new and updated documentation.
The pre-release can be used to test your website and projects against the next major version of Umbraco CMS.
The first phase is a beta version, which is then followed by a Release Candidate.
This article contains all the resources needed for you to start testing.
Ensure you meet the prerequisites and move on to the installation steps outlined below.
The latest .
The .
Install the Umbraco dotnet template for the beta.
Create a new Umbraco project.
Navigate to the newly created folder.
Build and run the project.
This will boot the project and write the log to the console. The website is now running on your local machine and will be available on the ports written in the console.
Here is a list of all the new or updated articles in this version.
ILocalizationServices
Coming soon
dotnet new install Umbraco.Templates::18.0.0-rc3dotnet new umbraco -n MyCustomUmbracoProjectcd MyCustomUmbracoProjectdotnet build
dotnet runLearn how to enable unattended upgrades, allowing your project to upgrade without your interference.
When upgrading your Umbraco project, you can enable the upgrade to run unattended. This means that you will not need to run through the installation wizard when upgrading.
Add the Umbraco:Cms:Unattended:UpgradeUnattended configuration key.
Set the value of the key to true.
{
"Umbraco": {
"CMS": {
"Unattended": {
"UpgradeUnattended": true
}
}
}
}With the correct configuration applied, the project will be upgraded on the next boot.
When the application starts, migrations run in a background service after the web server begins listening. During the migration the RuntimeLevel is Upgrading. The web server is reachable during this time, serving health probe responses and maintenance pages.
Once all migrations complete, the RuntimeLevel transitions to Run and the site operates normally.
While the RuntimeLevel is Upgrading, Umbraco responds differently depending on the request surface:
The returns HTTP 200 during the upgrade, confirming the process is alive. The returns HTTP 503, indicating the site is not yet ready to serve normal traffic.
You can customize the maintenance page shown to frontend visitors by setting the Umbraco:CMS:Global:UpgradingViewPath configuration key. See for details.
Follow the steps outlined below to use unattended upgrades in a load-balanced setup.
.
Deploy to all environments.
Set the Umbraco:CMS:Unattended:UpgradeUnattended configuration key to true for the Main server only.
You can use the to let your load balancer detect when each server has completed its upgrade and is ready to receive traffic.
On this page you will find the media types and Data Types in Umbraco. These types are not created automatically after an upgrade. If you want to use the new types, you can create them yourself.
The UploadArticle Data Type has the following configuration:
Property editor: FileUpload
Accepted file extensions: pdf, docx, doc
The UploadAudio Data Type has the following configuration:
Property editor: FileUpload
Accepted file extensions: mp3, weba, oga, opus
The UploadVectorGraphics Data Type has the following configuration:
Property editor: FileUpload
Accepted file extensions: svg
The UploadVideo Data Type has the following configuration:
Property editor: FileUpload
Accepted file extensions: mp4, webm, ogv
The UmbracoMediaArticle media type has the following properties:
umbracoFile - Upload File
umbracoExtension - Label (string)
umbracoBytes - Label (bigint)
The UmbracoMediaAudio media type has the following properties:
umbracoFile Upload Audio
umbracoExtension Label (string)
umbracoBytes Label (bigint)
The UmbracoMediaVectorGraphics media type has the following properties:
umbracoFile - Upload Vector Graphics
umbracoExtension Label (string)
umbracoBytes Label (bigint)
The UmbracoMediaVideo media type has the following properties:
umbracoFile - Upload Video
umbracoExtension - Label (string)
umbracoBytes - Label (bigint)
Learn about the default data types in Umbraco.
Here's a list of the default Data Types that come installed with Umbraco. There are plenty more that you can create based on the installed .
Adds a list of approved colors. The approved colors are added as hex values by using the color picker. Optionally, you can enable labels to give the colors different names.
Displays a list of preset options as a list of checkbox controls. The preset options are added when configuring a Property Editor using the Data Type. Alternatively, the options can also be updated in the Settings section under Data Types. The value saved is a comma-separated string of IDs.
The Content Picker opens a modal to pick a specific page from the content structure. The value saved is the selected page's ID.
Displays a calendar UI for selecting date and time. The value saved is a standard DateTime value but does not contain time information.
Displays a calendar UI for selecting date and time. The value saved is a standard DateTime value.
Displays a list of preset options as a list where only a single value can be selected. The default Data Type does not contain any predefined options. The value saved is the selected value as a string.
The benefit of using Visual Studio Code is that it is super quick to get up and running. Follow these steps to set up an Umbraco project with Visual Studio Code.
Go to and download Visual Studio Code for free.
Launch Visual Studio Code once the installation is complete.
Click the extensions menu on the left side.




Management API
HTTP 503 JSON ProblemDetails
Delivery API
HTTP 503 JSON ProblemDetails
Wait for the upgrade to complete.
Boot the Read-Only servers and ensure they do not show the “Upgrade Required” screen.
Frontend
HTTP 503 with Upgrading.cshtml view
Surface controllers
HTTP 503 with Upgrading.cshtml view
Backoffice
Upgrade-in-progress screen
Displays a list of preset options as a list where multiple values can be selected. The default Data Type does not contain any predefined options. The value saved is a comma-separated string of IDs.
Allows to upload and crop images by using a focal point. Specific crop definitions can also be added. This Data Type is used by default on the Image Media Type.
The Image Media Picker opens a modal to pick images from the Media tree or images from your Computer. The value saved is the selected media node UDI.
Is a non-editable control and can be used to only display the value. It can also be used in the Media section to load in values related to the node, such as width, height and file size.
There are six Label Data Types:
Label (bigint) - Allows to save a big integer value for a Label.
Label (datetime) - Allows to set a DateTime value for a Label.
Label (decimal) - Allows to set a decimal value for a Label.
Label (integer) - Allows to set an integer value for a Label.
Label (string) - Allows to set a long string value for a Label.
Label (time) - Allows to set time for a Label
This Data Type is used by Document Types that are set to display as a Collection.
This Data Type is used by Media Types that is set to display as a Collection.
This Data Type is used by Member Types that is set to display as a Collection.
The picker opens a modal to pick a specific media item from the Media tree. The value saved is the selected media node UDI.
Displays a dropdown with all the available members. A single member can be selected. The value saved is the ID of the member.
This Data Type allows an editor to add an array of links. These can either be internal Umbraco pages external URLs or links to media in the Media section. The Data Type can be configured by limited number of links it is possible to add.
The picker opens a modal to pick multiple images from the Media tree. The value saved is a comma separated string of media node UDIs.
The picker opens a modal to pick multiple media items from the Media tree. The value saved is a comma separated string of media node UDIs.
A textbox to input a numeric value.
This Data type enables editors to choose from a list of radiobuttons.
A TipTap-based What You See Is What You Get (WYSIWYG) editor. This is the standard editor used to edit a larger amount of text. The editor has a lot of settings, which can be changed on the Richtext editor Data Type in the Settings section.
Learn more about the configuration options in the Rich Text Editor articles.
A textbox that allows you to use multiple tags on a Document Type. You can specify a Tag Group for the Data Type, if you need to use Tags on different sections of your site.
A textarea provides a multi-line plain-text editing control. You can set the maximum allowed characters for the textarea and the number of rows, if any.
A normal HTML input text field.
A checkbox which saves either 0 or 1, depending on the checkbox being checked or not. A common use is to create a property with the 'umbracoNaviHide' alias and the Data Type True/False. This will provide editors with the option to hide nodes in the navigation menu on the website.
Adds an upload field, which allows documents or images to be uploaded to Umbraco. This does not add them to the media library, they are added to the document data.
There are five Upload Data Types:
Upload Article - Used for uploading and storing documents.
Upload Audio - Used for uploading and storing digital audio files.
Upload File - Used for uploading and storing different types of files in the Media section
Upload Vector Graphics - Used for uploading and storing Scalable Vector Graphics (svg) files which are text files containing source code to draw the desired image.
Upload Video - Used for uploading and storing video files.
Search for C# and install it.
Follow the article to create your project folder.
Open your project folder in Visual Studio Code.
Open the command palette using the shortcut Ctrl+Shift+P.
Type Tasks: Configure.
Select Tasks: Configure Task.
Select Create task.json from template.
select .NET Core as your template.
Visual Studio Code creates a folder called .vscode that contains a file called tasks.json. The tasks.json file tells Visual Studio Code how to build your project.
Select the Run and Debug button from the left side menu.
Select the Create a launch.json file link.
Select .NET 5+ and .NET Core.
You'll see a green play button appear with a dropdown where .NET Core Launch (web) is selected.
If you navigate to the Explorer section, a new launch.json file is created in the .vscode folder. When you press F5, the launch.json file tells Visual Studio Code to build your project, run it, and then open a browser.
With that, you're ready to run the project.
Press F5 or click the green play button in the Run and Debug section to run your brand new Umbraco site locally.
This section covers the installation and configuration of Umbraco inside your web browser when you run Umbraco for the first time.
You will see the install screen where you will need to fill in some data before Umbraco can be installed.
When the installation is completed, you will be prompted to enter the login credentials. Enter the credentials you used to install Umbraco.
After entering the credentials, you are logged into the backoffice.
Congratulations, you have now installed an Umbraco site.
This article helps you migrate custom Property Editors to Umbraco 14 and later
Umbraco 14 introduces a split between server-side and client-side Property Editor aliases. The reasoning behind this change is two-fold:
It allows server-side implementations to be reused for multiple client-side Property Editor UIs.
It helps to ensure a better division between client-side and server-side responsibility.
In the Umbraco source code, the change manifests as the EditorUiAlias property on IDataType.
When upgrading from Umbraco 13 to Umbraco 14 and later, Umbraco automatically migrates all Data Types to include an EditorUiAlias value. For custom Property Editors, this migration is based on certain assumptions.
If the Property Editor is built with a :
Assign the package manifest alias to the Data Type EditorUiAlias, and
Convert the Data Type EditorAlias to the alias of a core Data Editor, based on the valueType specified in the package manifest.
The following table contains the applied conversion from valueType to EditorAlias:
If the Property Editor is built with a , we:
Assign the Data Editor Alias to the Data Type EditorUiAlias, and
Retain the Data Type EditorAlias as-is (which is the Data Editor Alias).
The file is a central component for extensions in Umbraco 14+, including Property Editor UIs.
To keep the Property Editor working with migrated properties, ensure that the propertyEditorUi extension is declared with:
The migrated value of EditorUiAlias as its alias, and
The migrated value of EditorAlias as its propertyEditorSchemaAlias (found in the extension meta collection).
For example:
If the Data Type migration yields an undesirable result, you have two options:
Manually change the EditorAlias and/or EditorUiAlias directly in the umbracoDataType table, or
Create a custom migration to update the properties. See the article for inspiration.
Learn how to create and use Document Blueprints in Umbraco.
A Document Blueprint allows editors to preconfigure a content node. It serves as a reusable starting point when creating new content.
Before using this method, make sure you have already .
Go to the Content section and select an existing content node.
Click the ... menu next to the node and choose Create Document Blueprint.
Enter a Name for the new blueprint.
Click Save.
The new blueprint will appear under the Document Blueprints folder in the Settings section.
Go to the Settings section.
Click the ... menu next to the Document Blueprints tree.
Select Create....
Choose the Document Type you want to base the blueprint on.
Enter a Name for the blueprint.
Click Save.
The new blueprint will appear under the Document Blueprints folder in the Settings section.
To edit an existing document blueprint, follow these steps:
Go to the Settings section.
Open the Document Blueprints folder.
Select the blueprint you want to edit.
Make your changes.
Once you have created a document blueprint, you can use it to create new content nodes.
To use a document blueprint, follow these steps:
Go to the Content section.
Click + on the root node and select Create.
Select the Document Type that has an associated blueprint.
Choose how to create the new content:
Use the Document Blueprint
Start with a blank node
Instructions on installing Umbraco on various platforms using various tools.
Open your command line.
Install the Umbraco templates:
Create a new project:
Track current releases, test upcoming versions, and find resources for older versions.
Use this section to follow Umbraco releases and plan your next step.
Find the latest release information, test upcoming versions, or browse older documentation.
Current release information and release history.
Guidance for testing the latest release candidate.
Click Save.
You can only create Document Blueprints from Document Types or Document Types with Templates.







Links to documentation for versions outside active support.
DECIMAL
Umbraco.Plain.Decimal
JSON
Umbraco.Plain.Json
INT
Umbraco.Plain.Integer
STRING
Umbraco.Plain.String
TEXT
Umbraco.Plain.String
TIME
Umbraco.Plain.Time
XML
Umbraco.Plain.String
Property Editor valueType
Resulting EditorAlias
BIGINT
Umbraco.Plain.Integer
DATE
Umbraco.Plain.DateTime
DATETIME
{
"name": "My.Editors",
"version": "1.0.0",
"extensions": [
{
"type": "propertyEditorUi",
"alias": "My.Editor.Alias",
(...)
"meta": {
"propertyEditorSchemaAlias": "Umbraco.Plain.String",
(...)
}
}
]
}This might also impact Property Value Converters
Property Value Converters for package manifest based Property Editors might be impacted by this migration.
It is common practice to pair a Property Editor to a Property Value Converter using the package manifest alias:
public bool IsConverter(IPublishedPropertyType propertyType)
=> propertyType.EditorAlias.Equals("My.Editor.Alias");Since the migration moves the alias to EditorUiAlias, the Umbraco 14 and later equivalent code looks like this:
Umbraco.Plain.DateTime
Navigate to the newly created project folder. It will be the folder containing the .csproj file:
Build and run the newly created Umbraco site:
The console will output a message similar to: [10:57:39 INF] Now listening on: https://localhost:44388
Open your browser and navigate to that URL.
Follow the instructions to finish up the installation of Umbraco. If you chose to use MS SQL Server or Azure, you will need to add your connection string during this setup process to get access to the Umbraco backoffice.
Choose the path that best fits your development environment and workflow.
Windows / Full IDE
The standard wizard-based setup for developers who prefer a full IDE experience on Windows.
Lightweight / Cross-platform
dotnet new install Umbraco.Templatesdotnet new umbraco --name MyProjectBefore you begin
Ensure your environment meets the System Requirements. You must have the latest .NET SDK installed and a compatible database ready.
dotnet new sln
dotnet sln add MyProjectcd MyProjectdotnet runLearn how to move pages to a different location within the content tree.
Move pages within the website through the tree view. Not all pages can be moved depending on your set-up or page permissions. If you need clarification, contact your system administrator.
You can move a page in two ways:
Go to Content.
Click ... next to the page you wish to move.
Select Move to.
A window appears on the right side of the screen. Here, you can choose where you want to move the page in the tree structure.
Click Move.
A confirmation message appears. Click OK to dismiss the confirmation message.
Go to Content.
Select the page you wish to move.
Click Actions in the top-right corner of the screen.
Select Move to from the Actions drop-down menu.
A window appears on the right side of the screen. Here, you can choose where you want to move the page in the tree structure.
Click Move.
A confirmation message appears. Click OK to dismiss the confirmation message.
Learn how to change the sort order of pages within the content tree using the Sort function.
The pages in Umbraco are placed in the tree structure according to a predefined sort order. The most recently created page is placed at the bottom of the tree structure. You can change the order of the pages by using the Sort function.
You can sort pages in two ways:
Go to Content.
Navigate to the parent node whose child nodes you wish to sort.
Click ... next to the page you wish to sort.
Select Sort children of.
A window appears on the right-side of the screen. Here, you can arrange the child nodes in the order you want by dragging them up or down.
Click Save and then Close.
Go to Content.
Select the parent node whose child nodes you wish to sort.
Click Actions in the top-right corner of the screen.
Select Sort children of from the Actions drop-down menu.
A window appears on the right-side of the screen. Here, you can arrange the child nodes in the order you want by dragging them up or down.
Click Save and then Close.
Learn about the data types in Umbraco.
A Data Type defines the type of input for a property. So when adding a property (on Document Types, Media Types and Members) and selecting the Type you are selecting a Data Type. There are preconfigured Data Types available in Umbraco and more can be added in the Settings section.
A Data Type can be something basic such as TextString, Number, True/False and so on. Or it can be more complex such as Multi Node Tree Picker, Image Cropper, Block Grid and so on.
The Data Type references a Property Editor and if the Property Editor has settings these are configured on the Data Type. This means you can have multiple Data Types referencing the same Property Editor.
An example of this could be to have two dropdown Data Types both referencing the same dropdown Property Editor. One configured to show a list of cities, the other a list of countries.
Follow these steps to create a new Dropdown Data Type:
Go to the Settings section within the backoffice.






A streamlined setup for developers using Visual Studio Code on macOS, Linux, or Windows.
Containerization
Spin up Umbraco and its database dependencies quickly in a consistent, isolated environment.
Windows Server
Guidance for hosting and running your local installation on Internet Information Services.
Unix-based Native
Specific environment configurations and steps for running Umbraco natively on non-Windows systems.
Automation & CI/CD
An automation-friendly setup—ideal for Azure Web Apps, build pipelines, and rapid deployments.
Early Adopters
Get early access to the latest "bleeding edge" features and fixes before the official release.
public bool IsConverter(IPublishedPropertyType propertyType)
=> propertyType.EditorUiAlias.Equals("My.Editor.Alias");dotnet dev-certs https --trustdotnet new install Umbraco.Templates --nuget-source "https://api.nuget.org/v3/index.json"Templates Short Name Language Tags
------------------------------------------------------------------------------------------------------
Umbraco Project umbraco [C#] Web/CMS/Umbraco
Umbraco Extension umbraco-extension [C#] Web/CMS/Umbraco/Extension/Plugin/Razor Class Library
Umbraco Docker Compose umbraco-compose Web/CMS/UmbracoUmbraco Project (C#)
Author: Umbraco HQ
Description: An empty Umbraco project ready to get started.
Usage:
dotnet new umbraco [options] [template options]
Options:
-n, --name <name> The name for the output being created. If no name is specified, the name of the output directory is used.
-o, --output <output> Location to place the generated output.
--dry-run Displays a summary of what would happen if the given command line were run if it would result in a template
creation.
--force Forces content to be generated even if it would change existing files.
--no-update-check Disables checking for the template package updates when instantiating a template.
--project <project> The project that should be used for context evaluation.
-lang, --language <C#> Specifies the template language to instantiate.
--type <project> Specifies the template type to instantiate.
Template options:
-r, --release <Latest|LTS> The Umbraco release to use, either latest or latest long term supported
Type: choice
Latest The latest umbraco release
LTS The most recent long term supported version
Default: Latest
-pm, --package-management <choice> Choose how to manage NuGet package versions
Type: choice
Central Use Directory.Packages.props (recommended for new projects)
PerProject Use versions in .csproj (recommended when adding to existing projects)
Default: Central
--use-https-redirect Adds code to Startup.cs to redirect HTTP to HTTPS and enables the UseHttps setting.
Type: bool
Default: false
-da, --use-delivery-api Enables the Delivery API
Type: bool
Default: false
--add-docker Adds a docker file to the project.
Type: bool
Default: false
--no-restore If specified, skips the automatic restore of the project on create.
Type: bool
Default: false
--exclude-gitignore Whether to exclude .gitignore from the generated template.
Type: bool
Default: false
--minimal-gitignore Whether to only include minimal (Umbraco specific) rules in the .gitignore.
Type: bool
Default: false
--connection-string <connection-string> Database connection string used by Umbraco.
Type: string
--connection-string-provider-name Database connection string provider name used by Umbraco.
<connection-string-provider-name> Type: string
Default: Microsoft.Data.SqlClient
--development-database-type <choice> Database type used by Umbraco for development.
Type: choice
None Do not configure a database for development.
SQLite Use embedded SQLite database.
LocalDB Use embedded LocalDB database (requires SQL Server Express with Advanced
Services).
Default: None
--friendly-name <friendly-name> Used to specify the name of the default admin user when using unattended install on
development (stored as plain text).
Type: string
--email <email> Used to specify the email of the default admin user when using unattended install on
development (stored as plain text).
Type: string
--password <password> Used to specify the password of the default admin user when using unattended install on
development (stored as plain text).
Type: string
--telemetry-level <telemetry-level> Used to specify the level of telemetry the installation will report (Minimal, Basic or Detailed).
Type: string
--no-nodes-view-path <no-nodes-view-path> Path to a custom view presented with the Umbraco installation contains no published
content.
Type: string
-dm, --development-mode <choice> Choose the development mode to use for the project.
Type: choice
BackofficeDevelopment Enables backoffice development, allowing you to develop from
within the backoffice, this is the default behaviour.
IDEDevelopment Configures appsettings.Development.json to Development runtime
mode and SourceCodeAuto models builder mode, and configures appsettings.json to
Production runtime mode, Nothing models builder mode, and enables UseHttps
Default: BackofficeDevelopment
-mm, --models-mode <choice> Choose the models builder mode to use for the project. When development mode is set to
IDEDevelopment this only changes the models builder mode appsetttings.development.json
Type: choice
Default Let DevelopmentMode determine the models builder mode.
InMemoryAuto Generate models in memory, automatically updating when a content
type change, this means no need for app rebuild, however models are only available in
views.
SourceCodeManual Generate models as source code, only updating when requested
manually, this means a interaction and rebuild is required when content type(s) change,
however models are available in code.
SourceCodeAuto Generate models as source code, automatically updating when a
content type change, this means a rebuild is required when content type(s) change,
however models are available in code.
Nothing No models are generated, this is recommended for production assuming
generated models are used for development.
Default: Default
-sk, --starter-kit <choice> Choose a starter kit to install.
Type: choice
None No starter kit.
Umbraco.TheStarterKit The Umbraco starter kit.
Default: NoneSelect the + icon to the right of the Data Types folder.
Choose New Data Type....
Name the Data Type.
Click on Select a property editor.
Find and click on the Dropdown editor.
Click Select.
Choose whether to enable multiple selections.
Add options.
Save the Data Type once you have added the required configuration.
When you're happy with the list press Save. It is now possible to select this Data Type for a property on Document Types, Media Types, and Members. Doing this will then create a dropdown list for the editor to choose from and save the choice as a string.
To customize an existing Data Type go to the Settings section, expand the Data Types folder and select the Data Type you want to edit.
Besides the Data Types that are available out of the box there are some additional Property Editors. For example, think of the Slider and Block List.
To view the Data Type reference, go to the Settings section and expand the Data Types folder. Select the Data Type you wish to view the reference for and click the Info tab.
This gives you an overview of the Types that currently use the Data Type.
Learn more about viewing references or implementing tracking in the Tracking References article.
This document should be used as a reference, not a step by step guide. Upgrading will largely depend on what version of Umbraco you are currently running, what packages you have installed and the many
The standard upgrade instructions still apply to this process as well.
It is critical that you back up your website and database before upgrading. There are database changes made during installation and you cannot revert an Umbraco 7 database to an Umbraco 6 database.
Umbraco 7 is built on .Net 4.5 and your development environment will require this version installed in order to operate. Visual Studio users may require 2012 or higher.
Umbraco 7 requires browsers with proper HTML 5 support, these include Chrome, Firefox, IE10+
Before you upgrade be sure to read the list of breaking changes. This is especially recommended if you have removed or modified code in the core or if one of these breaking changes directly affects your installation.
See the list of breaking changes for more details.
It is recommended to rebuild all Examine indexes after completing the upgrade.
You should re-generate the XML cache. This can be done by following the prompts when visiting the following URL:
your-domain.com/umbraco/dialogs/republish.aspx?xml=true
It is recommended that you use a Diff tool to compare the configuration file changes with your own current configuration files.
/web.config updates
Details are listed here:
You will need to compare the new Umbraco 7 web.config with your current web.config. Here is a quick reference of what needs to change:
Umbraco 7+ will no longer support medium trust environments. There are now some assemblies used in the core that do not support medium trust but are used extensively. Plugin scanning now also allows for scanning Umbraco's internal types which requires full trust.
Content, Media, Members, and Data Type trees will no longer raise the legacy tree events (based on BaseTree). It is recommended to change all tree event handlers to use the new tree events that fire for every tree in Umbraco including legacy trees. The new tree events are static events and are found in the class Umbraco.Web.Trees.TreeControllerBase:
MenuRendering
RootNodeRendering
TreeNodesRendering
The Content, Media, Member, and Data Type editors have been re-created and are solely using the new Umbraco Services data layer. This means that operations performed in the backoffice will no longer raise the legacy business logic events (for example, events based on umbraco.cms.businesslogic.web.Document). It is recommended to change your event handlers to subscribe to the new Services data layer events. These are static events and are found in the services. For example: Umbraco.Core.Services.ContentService.Saved.
Legacy property editors (pre-Umbraco 7) will not work with Umbraco 7. During the upgrade installation process, Umbraco will generate a report showing you which legacy property editors are installed. These will all be converted to a readonly Label property editor. No data loss will occur but you'll need to re-assign your existing data types to use a new compatible Umbraco 7 property editor.
Most Umbraco core property editors shipped will be mapped to their equivalent Umbraco 7 editors. The Image cropper editor has not been completed for v7.0.
Since the Related Links property is an advanced property editor, the data format has changed from XML to JSON. This should not have any effect when retrieving the data from razor. If you are outputting Related Links data with XSLT you will need to update your XSLT snippet. Making use of the new library method umbraco.library:JsonToXml and taking into account that the xml structure has also slightly changed.
One of the database changes made in Umbraco 7 is the change of referencing a property editor from a GUID to a string alias. In order to map a legacy property editor to a new Umbraco 7 version you can add your custom "GUID -> Alias" map during application startup. To do this you would add your map using this method: Umbraco.Core.PropertyEditors.LegacyPropertyEditorIdToAliasConverter.CreateMap
Legacy parameter editors (pre-Umbraco 7) will not work with Umbraco 7. If Umbraco detects legacy parameter editor aliases that do not map to a Umbraco 7 parameter editor it will render a textbox in its place. You will need to update your macros to use a compatible Umbraco 7 parameter editor as those that aren't supported.
Previously, parameter editors were registered in an Umbraco database table: cmsMacroPropertyType which no longer exists. Parameter editors in Umbraco 7 are plugins like property editors. During the Umbraco 7 upgrade installation process it will update the new cmsMacroProperty.editorAlias column with the previous parameter editor alias. During this process it will look into the Umbraco.Core.PropertyEditors.LegacyParameterEditorAliasConverter for a map between a legacy alias to a new Umbraco 7 alias.
Custom legacy parameters can be mapped to new Umbraco 7 parameter editor aliases during installation. This can be done by modifying the mapping during application startup using this method: Umbraco.Core.PropertyEditors.LegacyParameterEditorAliasConverter.CreateMap.
All database changes will be taken care of during the upgrade installation process.
For database change details see (including all child tasks):
See above for the database updates made for better tag support.
Tags can now be assigned to a nodes property and not only a node
Multiple tag controls can exist on one page with different data
The legacy API does not support this, the legacy API will effectively, add/update/remove tags for the first property found for the document that is assigned a tag property editor.
There is a new ITagService that can be used to query tags
You should check with the package creator for all installed packages to ensure they are compatible with Umbraco 7.
We see common errors that we cannot fix for you, but we do have recommendations you can follow to fix them:
The TypeFinder has been deprecated since 4.10 and is now found under Umbraco.Core.TypeFinder.
While you need to have JavaScript inside menu actions to trigger a response, it is highly recommended that you use the recommended UmbClientMgr methods. You should not try to override parent.right.document and similar tricks to get to the right-hand frame.
If you have a webforms page, it is recommended to use the built-in ASP.NET controls to render panels, properties and so on. If you use the raw HTML or try to style it to match the backoffice, you will get out of sync. Follow the guidelines set by Umbraco's internal editors and use the ASP.NET custom controls for UI.
When viewing page content in preview mode you have the option to scale the preview window to various device sizes:
Once you have finished editing the page content, click Save and preview.
Select Fit browser to view the different preview modes.
Select the device you would like to scale the preview pane to.
This section explains how the concept of infinite editing using the Sidebar in the Umbraco backoffice works.
This feature enables you to work with your content without losing the context of what you are doing.
Document Types are in different sections than content but the sidebar enables you to make changes to them directly from the content you are editing.
In the example showcased above, new options are being added to a Data Type, without losing the context of the content. The example also shows how you can edit images, without being sent to the 'Media' section.
The Sidebar can be customized to improve the workflow for editors. For more information, see the Extending Overview article.
Since Umbraco 9 it has been possible to run Umbraco CMS natively on Linux or macOS High Sierra 10.13 and newer.
With Umbraco CMS on .NET Core, Linux and macOS is natively supported with SQLite as the database.
In the below section, we describe how to get started with running Umbraco CMS on Linux or macOS.
To get started with Umbraco CMS first have a look at the .
Once you've made sure you meet the requirements it is time to install the Umbraco Templates on your system.
To do this follow the guide.
With the templates installed on your system, it is now possible to create Umbraco projects.
To create a project, there are two options:
Continue creating projects using the .NET CLI.
Create new projects using Visual Studio (only macOS).
To create new projects using Visual Studio, you can use the guide.
Once you create a new project it will use SQLite by default on Linux/macOS.
If you prefer using SQL Server as your database, you can either install it locally or run it via .
Learn how to log in and out of the Umbraco backoffice.
To access the Umbraco Backoffice:
Open your web browser and enter your website domain name followed by /umbraco (for example: http://www.company.com/umbraco/). A login screen appears.
Enter your Email and Password provided by your system administrator.
Click Login.
To log out of the Umbraco Backoffice:
Select the profile picture in the top-right of the screen.
Click Logout.
Get an overview of the Umbraco backoffice interface, including the dashboard, sections menu, and content tree.
After logging in to an Umbraco project you will be presented with a dashboard containing a wide array of buttons and features. Let's quickly go through what each feature does.
By default, there are two dashboards available:
The Welcome to Umbraco dashboard provides helpful information about Umbraco.
The Redirect URL Management dashboard displays the original and redirected links of the published pages which are moved to a new location in your project.
In this article you can learn how to use the build in email property editor
Schema Alias: Umbraco.EmailAddress
UI Alias: Umb.PropertyEditorUi.EmailAddress
Returns: String
Displays an email address.
The Email Address Property Editor does not come with any further configuration. The property can be configured once it has been added to a Document Type.
See the example below to learn how a value can be added or changed programmatically to an Email-address property. To update a value of a property editor you need the .
In this section, an overview is given of how to add and reorder tabs, convert a group to a tab and manage the “Generic” tab.
Using tabs, you can organize properties in the backoffice to provide a tailored and efficient workflow for editors creating and maintaining Content, Media and Members.
Tabs allow you to add horizontal organization in your Document Types, Media Types and Member Types. This is handy for types that need a more defined hierarchy or have many properties and groups.
To add a tab, follow these steps:
Go to Settings.
Create or select a Document Type/Media Type/Member Type
This section focuses on how to create data using the Umbraco backoffice
There are four kinds of content in Umbraco:
The website content that make our the pages on your site exists in the Content section.
Elements are reusable content items that are managed from the Library section.
Media content such as images, videos, and PDFs are stored in the Media section.
Learn how to use the Audit Trail to view the history of actions performed on a content page.
Within the Info content app for pages you can find the Audit Trail in the History section. Here, you can get a quick overview of the actions performed on that node, by whom, when and any additional comments.
The Audit Trail is useful to find out who made changes on a certain date.
To view the audit trail:
Go to the Content section.


Go to the Info Workspace View.
Locate the History box.

Umbraco is set up to automatically log a user out if they have been inactive for over 20 minutes. Don't worry if you are logged out of Umbraco. Log back in using your credentials and continue editing.
The session timeout can be configured in Umbraco's appsettings.json file. You can modify the Timeout setting to extend or reduce the timeout duration based on your site's needs.






@if (Model.HasValue("email"))
{
var emailAddress = Model.Value<string>("email");
<p>@emailAddress</p>
}@if (!string.IsNullOrWhiteSpace(Model.Email))
{
<p>@Model.Email</p>
}@using Umbraco.Cms.Core.Services;
@inject IContentService Services;
@{
// Get access to ContentService
var contentService = Services;
// Create a variable for the GUID of your page
var guid = new Guid("796a8d5c-b7bb-46d9-bc57-ab834d0d1248");
// Get the page using the GUID you've just defined
var content = contentService.GetById(guid);
// Set the value of the property with alias 'email'
content.SetValue("email", "[email protected]");
// Save the change
contentService.Save(content);
}Remove the section name="BaseRestExtensions" section
Remove the section name="FileSystemProviders" section
Remove the sectionGroup name="system.web.webPages.razor" section
Remove the <FileSystemProviders> element
Remove the BaseRestExtensions element
Remove the add key="umbracoUseMediumTrust" element
Remove the system.web.extensions element
Removes the xhtmlConformance element
Remove the system.codedom element
Remove the compilation assemblies, /compilation
Remove the system.web.webPages.razor element
New: sectionGroup name="umbracoConfiguration" section
New: umbracoConfiguration element
Ensure that the targetFramework="4.5" is added to the httpRuntime element
Add add key="ValidationSettings:UnobtrusiveValidationMode" value="None" to the appSettings element
/config/clientdependency.config changes
remove add name="CanvasProvider" element
/views/web.config updates
New macroscripts/web.config
config/umbracoSettings.config
Umbraco is now shipped with minimal settings but the full settings are still available
umbracoSettings is now a true ASP.NET configuration section https://issues.umbraco.org/issue/U4-58
Remove the EnableCanvasEditing element
Remove the webservices element
Removed xsltExtensions.config
/config/applications.config and /config/trees.config have some icon paths and names updated. You need to merge the new changes into your existing config files.
/config/tinyMceConfig.config
The inlinepopups is compatible and supported in Umbraco 7. You need to remove these elements: plugin loadOnFrontend="true", inlinepopups/plugin;
The plugins element that is shipped with Umbraco 7 looks like this:
<plugins>
<plugin loadOnFrontend="true">code</plugin>
<plugin loadOnFrontend="true">paste</plugin>
<plugin loadOnFrontend="true">umbracolink</plugin>
<plugin loadOnFrontend="true">anchor</plugin>
<plugin loadOnFrontend="true">charmap</plugin>
<plugin loadOnFrontend="true">table</plugin>
<plugin loadOnFrontend="true">lists</plugin>
</plugins>You need to merge the changes from the new tinyMceConfig file into yours. The command elements that have changed are: JustifyCenter, JustifyLeft, JustifyRight, JustifyFull, umbracomacro, umbracoembed, mceImage, subscript
/config/dashboard.config
You need to merge the changes from the new dashboard.config into yours. Some of the original dashboard entries that were shipped with Umbraco 6 have been replaced or removed.
Querying for tags in a view (front-end) can be done via the new TagQuery class which is exposed from the UmbracoHelper. For example: @Umbraco.TagQuery.GetTagsForProperty
Could not load type umbraco.BusinessLogic.Utils.TypeFinder from assembly businesslogic, Version=1.0.5031.21336, Culture=neutral, PublicKeyToken=null.The Search bar allows you to search for the content in your entire project.
The Help icon provides different Help options such as Tours, Umbraco Learning Base YouTube videos, Umbraco Documentation, and your System Information.
The profile icon allows you to edit your profile, change the password, and Logout from the application.
The following sections are available in the backoffice:
Content - allows you to manage your content.
Media - allows you to manage images and other media files.
Library - allows you to manage your reusable elements.
Settings - allows you to handle your meta data such as Document Types.
Packages - allows you to manage add-on packages.
Users - allows you to manage the users on the project. To learn more about users, see the article.
Members - allows you to handle the members of the project. If you want to learn more about Members, see the article.
Forms - allows you to create and manage your forms (only available if Umbraco Forms is installed).
Translation - allows you to manage dictionary items.
The menu list will differ depending on your permissions for the project. For example: if you are an editor, then you will only have access to Content, Media, Library, and Forms as per the default settings.
The section tree is different depending on the section you are in.
In this example, you are looking at the content section. The section provides an overview of the nodes contained in the tree.
The Content tab allows you to create content nodes and manage your content tree. When you hover over the sections, it is highlighted with a darker color indicating that you are hovering over it. A button with three dots will show up, left-click or click the + icon to view additional options.
The Recycle Bin contains the deleted content and is available only in the Content, Library and the Media section.

To reorder tabs, follow these steps:
Go to Settings.
Select a Document Type/Media Type/Member Type.
Select Reorder.
You can drag the tab where you want, manually add a numeric value next to the tab name or use the arrows to set a value.
This is important when using compositions, as you want to always display a tab/group at a certain position by setting a manual numeric value.
Select I am done reordering.
Click Save.
To convert a group to a tab, follow these steps:
Go to Settings.
Select a Document Type/Media Type/Member Type.
Select Reorder.
You can drag the group to the Convert to tab option.
Select I am done reordering.
Click Save.
Once you start adding tabs, you might see a “Generic” tab appear. This is done to hold groups and properties that are not assigned to a tab. For example, a group of properties coming from a composition that has no tab. In order to display the groups and properties correctly and have a solid data structure, they will be displayed under the “Generic” tab.
To manage the Generic tab on a Document Type/Media Type:
Go to the Composition Document Type/Media Type.
Click Add tab and enter the Name for the tab. All existing groups and properties are added to the tab.
Go to the Document Type/Media Type, the Generic tab will now be replaced by the tab from the composition.
Finally, Members, are used for user profiles and frontend authentication which you can find in the Members section.
A fundamental principle in Umbraco is that all content types have a definition (Document Types, Media Types, Member Types). These definitions are highly customizable, meaning you can add properties and have complete control over how the data is organized.
Defining Document Types, adding properties, and creating content.
Defining Media Types and uploading files to the media section, using upload fields and image cropper.
Defining Member Types and creating members for authentication and user profiles.
Creating and editing Data Types.
Schedule when content should be published / unpublished automatically.
Overview of how to add and reorder tabs, convert a group to a tab, and manage the “Generic” tab
Control who has access to the Umbraco backoffice and what permissions they have.
An introduction to Relations and Relation Types, creating, and managing relationships between different entities in Umbraco.
Using Dictionary Items, you can store a value for each language. Dictionary Items have a unique key that is used to fetch the value of the Dictionary Item.
How to keep the noise down whilst ensuring your important content versions stick around indefinitely.
Schema Alias: Umbraco.ColorPicker
UI Alias: Umb.PropertyEditorUi.ColorPicker
Returns: String (Hexadecimal)
Returns: Umbraco.Cms.Core.PropertyEditors.ValueConverters.ColorPickerValueConverter.PickedColor (When using labels)
The Color picker allows you to set some predetermined colors that the editor can choose between.
It is possible to add a label to use with the color.
@{
// Model has a property called "Color" which holds a Color Picker editor
var hexColor = Model.Color;
// Define the label if you've included it
String colorLabel = Model.Color.Label;
if (hexColor != null)
{
<div style="background-color: @hexColor">@colorLabel</div>
}
}@using Umbraco.Cms.Core.PropertyEditors.ValueConverters
@{
// Model has a property called "Color" which holds a Color Picker editor
var hexColor = Model.Value("Color");
// Define the label if you've included it
var colorLabel = Model.Value<ColorPickerValueConverter.PickedColor>("Color").Label;
if (hexColor != null)
{
<div style="background-color: @hexColor">@colorLabel</div>
}
}See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the .
Although the use of a GUID is preferable, you can also use the numeric ID to get the page:
If Models Builder is enabled you can get the alias of the desired property without using a magic string:
Learn how to find and edit existing content pages in the Umbraco backoffice.
When you are looking to edit content, locate the page you want to edit in the Content tree on the left-side of the screen.
To edit existing content, follow these steps:
Go to the Content section.
Select the page in the section tree you wish to edit. The content of the page is loaded in the right-side editor.
Edit the contents of the page.
Click Save to save the edits without publishing it.
Click Save and preview to preview the changes.
Click Save and publish to publish the changes. For more information, see the article.
By default, you can view Page layouts in two ways: in a List or in a Grid (default).
When you enable Collection on a page, its child pages are no longer shown as nested items in the content tree. Instead, the parent page appears as a single node in the tree. Selecting it displays all of its child pages in a grid view within the main workspace area. For more information, see the article.
You can switch to a list view by clicking the layout icon in the top-right of the screen:
Schema Alias: Umbraco.Decimal
UI Alias: Umb.PropertyEditorUi.Decimal
Returns: decimal
In the example above the possible values for the input field would be [8, 8.5, 9, 9.5, 10]
All other values will be removed in the content editor when saving or publishing.
If the value of Step Size is not set then all decimal values between 8 and 10 is possible to input in the content editor.
@Model.MyDecimal@Model.Value("MyDecimal")See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the .
Although the use of a GUID is preferable, you can also use the numeric ID to get the page:
If Models Builder is enabled you can get the alias of the desired property without using a magic string:
Schema Alias: Umbraco.Label
UI Alias: Umb.PropertyEditorUi.Label
Returns: String
Label is a non-editable control and can only be used to display a pre-set value.
If you want to set a value other than a String, you can define the data using one of the other available Data Types. These include Decimal, Date/time, Time, Integer, and Big integer.
There is also a Value Type: Long string if you need to set a long string value for your Label.
@{
if (Model.HasValue("pageLabel")){
<p>@(Model.Value("pageLabel"))</p>
}
}@{
if (!string.IsNullOrEmpty(Model.PageLabel))
{
<p>@Model.PageLabel</p>
}
}See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the .
Although the use of a GUID is preferable, you can also use the numeric ID to get the page:
If Models Builder is enabled you can get the alias of the desired property without using a magic string:
Overview of Property Editors in Umbraco, how they work, the built-in editors available, and how to create custom ones.
A Property Editor is what content editors use to input data on a Document Type. When you create a Data Type in the backoffice, you choose a Property Editor and configure it. Umbraco ships with a wide range of built-in Property Editors, and you can create custom ones.
Built-in Property Editors - the full list of Property Editors that ship with Umbraco.
Umbraco Flavored Markdown - a Markdown dialect with Umbraco-specific extensions for rich content editing.
This section provides a few handy tips to work with your Content using Umbraco:
Connect with the Umbraco community and find ways to contribute to the project and documentation.
Schema Alias: Umbraco.TimeOnly
UI Alias: Umb.PropertyEditorUi.TimeOnlyPicker
Returns: TimeOnly?
The Time Only property editor provides an interface for selecting times. It excludes date and time zone information, and returns strongly-typed TimeOnly values.
You can configure this property editor in the same way as any standard property editor, using the Data Types admin interface.
To set up a property using this editor, create a new Data Type and select Time Only from the list of available property editors.
Discusses the possibility of downgrading to a previous version, along with the related topic of re-running the migrations that have occurred during an upgrade
Downgrades are not a supported feature of the Umbraco product.
The primary reason for this is that the Umbraco migration scheme only supports upward migrations.
When updating to a new version, often there are migrations to run that will make changes to the Umbraco schema and data. This is being done to bring the database to a state that will support the functionality of the version being upgraded to.
There isn't an equivalent downward migration that will undo these changes.
Given that, it can't be guaranteed that a database from a later version will work with an earlier one.
If you wish to downgrade to an earlier version of Umbraco, it's best to also revert to a compatible database backup. You will need one from the version you are downgrading to.
Other factors that may preclude downgrading include packages you may be using. They may not be compatible with the lower version or support downgrades themselves.
That said, between some versions, a downgrade may be possible and perfectly safe. There may be no migrations that run between them. Or, as is often the case, migrations are backward compatible (for example, adding a new, nullable field to a database table).
Learn about relations and how to create and manage them.
Umbraco sections are built around the concept of 'trees' and there is an implicit relationship between items in a section tree.
We refer to these relationships in the manner of a 'Family Tree'. One content item might be the 'Parent' of some content items, and those items would be referred to as the 'Children' of that parent. Items within the same branch of the tree can also be described as 'Ancestors' or 'Descendants' of an item.
There are methods available to support querying content items by their relative position to the current page. This is possible using the following concepts: Model.Ancestors(), Model.Children(), or Model.Descendants().
In some cases there are no direct relationships between two items in a tree, but they are still somehow 'related'. This could be the alternate language translation pages of a content page.
In other cases there is a 'relation' between different types of entities. This could be a relation between Content and Member, or Member and MediaFolder. You might need to be able to retrieve and display the uploaded images from a specific logged-in Member.
Schema Alias: Umbraco.MemberGroupPicker
UI Alias: Umb.PropertyEditorUi.MemberGroupPicker
Returns: string
The Member Group Picker opens a panel to pick one or more member groups from the Member section. The value saved is of type string (comma separated IDs).
See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the .
You can also add multiple groups by creating a comma separated string with the desired member group IDs.
An intro to achieving content variance at block level.
In a variant context, a Block Editor behaves like any other Umbraco property editor by default. The Blocks contained within the editor "belong" to the Document variant, and there is no connection between Blocks across variants.
In other words, both Block content and structure can vary between each Document variant.
This is the desired behavior for many cases. However, in some cases it is preferable to have a shared Block structure across all variants, where only the Block content varies.
This is known as Block Level Variance:
Block Level Variance is achieved when:
The
Learn how to configure and use the Element Picker property editor in Umbraco CMS.
Schema Alias: Umbraco.ElementPicker
UI Alias: Umb.PropertyEditorUi.ElementPicker
Returns: IEnumerable<IPublishedElement>
The Element Picker enables you to choose one or more elements to display as part of your content. Elements are based on defined in the Settings section. They are created and managed in the Library section.
Define how many elements should be allowed to pick via the Element Picker.
Choose a start node for the Element Picker. Use this option when your Library section is organized into folders.
Learn how to define and structure content in Umbraco using Document Types, Media Types, Data Types, compositions, and relations.
In Umbraco, all content is defined by a type. Document Types define the fields on a page, Media Types define the properties of media items, and Member Types define user profiles. This section covers how to create and configure these content types and how to build structure through compositions and relations.
- key backoffice concepts: sections, trees, Document Types, Media Types, Data Types, and Property Editors.
- define Document Types, create Media Types, configure Data Types, and manage content in the backoffice.
superscriptstyleselectRemove the command: mceSpellCheck
Contribute
Sustainability Best Practices
Relations - define and manage relationships between different content entities.















You will need to determine this for yourself, likely via reviewing the changes and migrations between versions and testing.
Once you have done that, this article will explain how to proceed with downgrading.
Downgrading the Umbraco application itself is straightforward. In the same way as when upgrading, you update the dependency on Umbraco in your project, you do the same when downgrading:
dotnet add package Umbraco.Cms --version <VERSION>
If you try to start Umbraco, it's likely you will find an exception thrown on boot indicating a problem with the migration state. This is because the version of Umbraco you are running now doesn't recognize the state stored by the higher version you were running previously.
To resolve this, you need to query the Umbraco database.
There are two migration states stored for the CMS - for the core migrations and the pre-migrations (which run at different times on start-up).
You can find the current state of these via:
You then need to find the latest state for the version of Umbraco you want to downgrade to.
To find the earlier states you have to look in the source code, specifically here for the pre-migrations and here for the core ones.
Each migration is commented with the version it was added, so you can read off the latest one for the version you wish to run.
Having found the state you need, you set it via a query of the form:
Then restart Umbraco.
A related topic is if you want to re-run the migrations from a prior version to the version you are on.
This isn't something that should be needed in normal usage of Umbraco. Umbraco handles running the necessary migrations on start-up and keeps track of its state. However, if investigating an upgrade-related issue or testing an upgrade before running it in production, it's useful to know how to do this.
Again you need to manipulate the migration state stored in the database.
You can update these values to an earlier state, and on start-up Umbraco will recognize that it's not at the latest. It will re-run the migrations from the earlier state to the current one.
For example, you are running 18.1 and want to re-run the core migrations for 18. Set the core migration state to the latest one from Umbraco 17:
And then restart Umbraco.
Migrations are written to be idempotent, so they can be run multiple times. If the change the migration is making is already detected to be there, it should skip without throwing an exception.
If Models Builder is enabled you can get the alias of the desired property without using a magic string:


The Element Picker stores an array of Element keys (Guid[]). The example below illustrates how an Element Picker value can be added or changed programmatically.

@using Umbraco.Cms.Core.Services
@inject IContentService ContentService
@{
// Create a variable for the GUID of the page you want to update
var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef");
// Get the page using the GUID you've defined
var content = ContentService.GetById(guid); // ID of your page
// Set the value of the property with alias 'color'.
// The value set here, needs to be one of the colors on the Color Picker
content.SetValue("color", "38761d");
// Save the change
ContentService.Save(content);
}@using Umbraco.Cms.Core.Services
@inject IContentService ContentService
@{
// Create a variable for the GUID of the page you want to update
var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef");
// Get the page using the GUID you've defined
var content = ContentService.GetById(guid); // ID of your page
// Set the value of the property with alias 'color'.
// The value set here, needs to be one of the colors on the Color Picker
content.SetValue("color", "{'value':'000000', 'label':'Black', 'sortOrder':1, 'id':'1'}");
// Save the change
ContentService.Save(content);
}@{
// Get the page using it's id
var content = ContentService.GetById(1234);
}@using Umbraco.Cms.Core.PublishedCache
@inject IPublishedContentTypeCache PublishedContentTypeCache
@{
// Set the value of the property with alias 'color'
content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.Color).Alias, "38761d");
}@using Umbraco.Cms.Core.Services
@inject IContentService ContentService
@{
// Create a variable for the GUID of the page you want to update
var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef");
// Get the page using the GUID you've defined
var content = ContentService.GetById(guid); // ID of your page
// Set the value of the property with alias 'myDecimal'.
content.SetValue("myDecimal", 3);
// Save the change
ContentService.Save(content);
}@{
// Get the page using it's id
var content = ContentService.GetById(1234);
}@using Umbraco.Cms.Core.PublishedCache
@inject IPublishedContentTypeCache PublishedContentTypeCache
@{
// Set the value of the property with alias 'myDecimal'
content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.MyDecimal).Alias, 3);
}@using Umbraco.Cms.Core.Services
@inject IContentService ContentService
@{
// Create a variable for the GUID of the page you want to update
var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef");
// Get the page using the GUID you've defined
var content = ContentService.GetById(guid); // ID of your page
// Set the value of the property with alias 'pageLabel'.
content.SetValue("pageLabel", "A pre-set string value");
// Save the change
ContentService.Save(content);
}@{
// Get the page using it's id
var content = ContentService.GetById(1234);
}@using Umbraco.Cms.Core.PublishedCache
@inject IPublishedContentTypeCache PublishedContentTypeCache
@{
// Set the value of the property with alias 'pageLabel'
content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.MyLabel).Alias, "A pre-set string value");
}select value from umbracoKeyValue where [key] = 'Umbraco.Core.Upgrader.State+Umbraco.Core.Premigrations'
select value from umbracoKeyValue where [key] = 'Umbraco.Core.Upgrader.State+Umbraco.Core'update umbracoKeyValue
set value = '{state value}'
where [key] = 'Umbraco.Core.Upgrader.State+Umbraco.Core'update umbracoKeyValue
set value = '{3A1A8047-74AE-491A-B2C4-0BAE4A1289EC}'
where [key] = 'Umbraco.Core.Upgrader.State+Umbraco.Core'@if (Model.HasValue("memberGroup"))
{
var memberGroup = Model.Value<string>("memberGroup");
<p>@memberGroup</p>
}@if (!string.IsNullOrEmpty(Model.MemberGroup))
{
<p>@Model.MemberGroup</p>
}@using Umbraco.Cms.Core.Services
@inject IContentService ContentService
@{
// Create a variable for the GUID of the page you want to update
var guid = new Guid("796a8d5c-b7bb-46d9-bc57-ab834d0d1248");
// Get the page using the GUID you've defined
var content = ContentService.GetById(guid); // ID of your page
// Set the value of the property with alias 'memberGroup'. The value is the specific ID of the member group
content.SetValue("memberGroup", 1067);
// Save the change
ContentService.Save(content);
}@{
// Set the value of the property with alias 'memberGroup'.
content.SetValue("memberGroup", "1067","1068");
}@{
// Get the page using it's id
var content = ContentService.GetById(1234);
}@using Umbraco.Cms.Core.PublishedCache
@inject IPublishedContentTypeCache PublishedContentTypeCache
@{
// Set the value of the property with alias 'memberGroup'
content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.MemberGroup).Alias, 1067);
}@{
IEnumerable<IPublishedElement>? elements = Model.Value<IEnumerable<IPublishedElement>>("elementPicker");
if (elements != null) {
foreach (var element in elements)
{
<h1>@element.Name</h1>
<p>@element.Value("featuredText")</p>
}
}
}@{
IEnumerable<IPublishedElement>? elements = Model.ElementPicker;
if (elements != null) {
foreach (var element in elements)
{
<h1>@element.Name</h1>
<p>@element.Value("featuredText")</p>
}
}
}using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Documentation;
public class ElementPickerExample
{
private readonly IContentService _contentService;
private readonly IJsonSerializer _jsonSerializer;
public ElementPickerExample(IContentService contentService, IJsonSerializer jsonSerializer)
{
_contentService = contentService;
_jsonSerializer = jsonSerializer;
}
public bool SaveElementPickerValue(Guid contentId, string propertyAlias, Guid[] pickedElementIds)
{
IContent? content = _contentService.GetById(contentId);
if (content is null)
{
return false;
}
content.SetValue(propertyAlias, _jsonSerializer.Serialize(pickedElementIds));
return true;
}
}Time format - Specifies the level of precision for time values shown and stored by the editor.
HH:mm - Displays hours and minutes (e.g., 14:30).
Suitable for most general use cases.
HH🇲🇲ss - Displays hours, minutes, and seconds (e.g., 14:30:45).
Use this when you need more precise timing.
You will be presented with a time input. Unlike date-time editors, this editor focuses only on the time component.
The value returned will have the type TimeOnly?.
With Models Builder:
Without Models Builder:
This property editor stores values as a JSON object. The object contains the time as an ISO 8601 string with a default date and UTC offset.
The property editor stores values in this JSON format:
The property editor handles time-only values. Date is set to a default value (0001-01-01) and offset to +00:00 for storage consistency. The date component is ignored in the Time Only context.
Create a C# model that matches the JSON schema.
using System.Text.Json.Serialization;
namespace UmbracoProject;
public class TimeOnlyValue
{
/// <summary>
/// The time value, represented as a <see cref="DateTimeOffset"/> for storage compatibility.
/// </summary>
[JsonPropertyName("date")]
public DateTimeOffset Date { get; init; }
}Convert your existing time value to DateTimeOffset for storage.
If you have a TimeOnly:
TimeOnly timeOnly = TimeOnly.FromDateTime(DateTime.Now); // Your existing TimeOnly value
DateTimeOffset dateTimeOffset = new DateTimeOffset(DateOnly.MinValue, timeOnly, TimeSpan.Zero);If you have a DateTime:
DateTime dateTime = DateTime.Now; // Your existing DateTime value
TimeOnly timeOnly = TimeOnly.FromDateTime(dateTime);
DateTimeOffset dateTimeOffset = new DateTimeOffset(DateOnly.MinValue, timeOnly, TimeSpan.Zero);Create an instance of the class with the DateTimeOffset value.
Inject the IJsonSerializer and use it to serialize the object.
Inject the IContentService to retrieve and update the value of a property of the desired content item.
@Model.StartHours@Model.Value<TimeOnly?>("startHours"){
"date": "0001-01-01T14:30:00+00:00"
}These are the scenarios where the concept of Umbraco Relations provides a solution.
Umbraco Relations allow you to relate almost any object in Umbraco to almost any other Umbraco object. This is done by defining a new Relation Type.
With a Content, Member, or Media picker the relationship only works as a 1-way street. The content item knows it has 'picked' another content item but that other content item does not know where it has been picked.
Umbraco Relations works as a 2-way street. When creating a relation between two different types of entities, it will be possible to find one entity from the other and vice versa. As an example this provides the option to list out all the pages that a content banner had been picked on.
A Relation Type specifies how two types of entities are related. Two items might be related under multiple Relation Types, and you might only be interested in your 'Related Language Page' Relation Type.
It is possible to view the existing Relation Types from the Umbraco backoffice:
Access the Umbraco Backoffice.
Navigate to the Settings section.
Locate the Advanced group in the sidebar.
Select Relations.
On the dashboard all defined relations will be listed. Select a Relation to view a list of all the objects that have been related for that specific Relation Type.
You can create Relations using the RelationService API via code.
You might want to create a 'Relation' between two objects either as:
A response to a backoffice event. For example, a content item being published that has picked other content items. Storing a relationship between these items would make querying between them easier. Perhaps show all the pages on which a particular 'banner' has been picked.
A logged-in member on the front end of an Umbraco website might have the facility to upload images. In response, the implementation could store the photos programmatically in the Media Section and at the same time, create a Relation to record the relationship between the member and their uploaded pictures. On an image gallery page, it would be possible to display all the gallery images for the current logged-in Member using the relations.
Some of the community packages that use Relations are listed below:
'Relations Picker' - a content picker that automatically creates Relations.
'ContentRelations' - allows you to relate two items via the Backoffice.
'LinkedPages' - Provides a LinkedPages context item to show, edit, and add relations between content pages.

The Block Editor property is not configured for variance, and
The Block Editor property editor is configured to use Element Types that do vary.
When adding a new variant Block to one Document variant, it is automatically added to all variants of the Document.
The Block will start out in an "unexposed" state for all other Document variants than the one where it was added. It will remain like that for each variant until it is edited in that variant.
The "unexposed" state is visualized by a dimmed-down icon and title (or likely a missing title, if Umbraco Flavored Markdown is used):
It is entirely possible to mix and match variance and invariance within the scope of Block Level Variance. Invariance is fully supported, both at Block level and at Block property level.
Invariance within Block Level Variance follows the same rules as invariance at Document level:
Invariant content is added to and updated across all Document variants.
Invariant content is explicitly published for all published Document variants when one or more variants are published.
Consider a Document with English and Danish language variants, which is published in both languages.
An editor opens the English variant.
They add an invariant Block, and
They re-publish the English variant.
Result: The new block will appear in both the English and Danish published content.
An editor opens the Danish variant.
They update an invariant property value in a variant Block, and
They re-publish the Danish variant.
Result: The updated property value appears in both the English and Danish published content.
The Block Editor structure is invariant for Block Level Variance. This means that the structure follows the same rules for invariance as outlined in the section above.
In other words: If an editor changes the order of the Blocks in one Document variant, it changes for all Document variants. The change is applied to all published Document variants, as soon as one or more variants are published.


Setup localization for Document Types in the Umbraco backoffice.
The Umbraco backoffice is localized to match the user's configured UI Culture.
When defining a Document Type, you can apply localization to:
Document Type names and descriptions.
Property names and descriptions.
Custom property validation messages.
Tab and group names.
Setting up localization for Document Types is a three-step process:
Register the Document Type localization files via .
Create the localizations in .
Apply the localizations to the Document Type.
To register Document Type localizations, you must create a new manifest using an umbraco-package.json file.
Once you have registered the Document Type localization, you can add your localization texts for use in Document Types. The following localizations are used for the samples in this article:
The localizations are applied by using the syntax #{area alias}_{key alias}.
Create a Document Type with Template called #contentTypes_article with the alias: articlePage.
Under the newly created Document Type, follow these steps:
Set the description to #contentTypes_article_desc
Add a property called #properties_subTitle with alias subTitle.
Set the description to {#properties_subTitle_desc}.
Use a TextString
When creating and editing the content, you will see that the backoffice now uses the configured localizations.
Create a new "Article" node:
When trying to save the node without adding the mandatory content, you will see a warning as expected:
Schema Alias: Umbraco.CodeEditor
UI Alias: Umb.PropertyEditorUi.CodeEditor
Returns: String
The Code Editor property editor provides an interface for entering and editing code snippets. It offers features like syntax highlighting, line numbering, wrapping code and so on.
The Code Editor can be configured with the following settings:
Language: A dropdown to select the syntax highlighting and validation rules for the editor. Supported languages include C#, CSS, HTML, JavaScript, JSON, Markdown, Razor (CSHTML), and TypeScript.
Height: Allows you to specify the height of the editor in pixels (for example., 400px). This ensures the editor fits well within your content entry forms.
Line Numbers: A toggle to enable or disable the line number on the left side of the editor.
Minimap: A toggle to enable a high-level, zoomed-out visual overview of the code on the right side of the editor for faster navigation in long files.
Word Wrap: A toggle that determines if long lines of code should wrap to the next line or require horizontal scrolling.
See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the .
Although the use of a GUID is preferable, you can also use the numeric ID to get the page:
Schema Alias: Umbraco.CheckBoxList
UI Alias: Umb.PropertyEditorUi.CheckBoxList
Returns: IEnumerable<string>
Displays a list of preset values as a list of checkbox controls. The text saved is an IEnumerable collection of the text values.
@{
if (Model.HasValue("superHeros"))
{
<ul>
@foreach (var item in Model.Value<IEnumerable<string>>("superHeros"))
{
<li>@item</li>
}
</ul>
}
}@{
if (Model.SuperHeros.Any())
{
<ul>
@foreach (var item in Model.SuperHeros)
{
<li>@item</li>
}
</ul>
}
}See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the Content Service.
@using Umbraco.Cms.Core.Serialization
@using Umbraco.Cms.Core.Services
@inject IContentService ContentService
@inject IJsonSerializer Serializer
@{
// Create a variable for the GUID of the page you want to update
var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef");
// Get the page using the GUID you've defined
var content = ContentService.GetById(guid); // ID of your page
// Set the value of the property with alias 'superHeroes'.
content.SetValue("superHeroes", Serializer.Serialize(new[] { "Umbraco", "CodeGarden"}));
// Save the change
ContentService.Save(content);
}Although the use of a GUID is preferable, you can also use the numeric ID to get the page:
@{
// Get the page using it's id
var content = ContentService.GetById(1234);
}If Models Builder is enabled you can get the alias of the desired property without using a magic string:
Learn how to migrate Block List property editors configured in single mode to the new Single Block property editor.
Version 17 introduced the single block property editor. Its purpose is to replace the "single mode" option that exists in the Block List property editor. This is part of the broader effort to ensure type consistency across core property editors.
Umbraco 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.
The migration was added in Umbraco 17 but disabled. It now runs by default during the upgrade to Umbraco 18.
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.
If your non-core property editor nests content and stores it within its own value, you must extend the migration. To do this, create and register a class that implements ITypedSingleBlockListProcessor and register it. See how the built-in types are registered at Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_18_0_0.SingleBlockList.MigrateSingleBlockListComposer. The interface needs the following properties and methods:
IEnumerable<string> 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<object?, Func<object?, bool>, Func<BlockListValue, object>, bool> Process
Learn how to use language variants to output your content in multiple languages.
Language Variants allows you to vary content by culture, so you can allow a content node to exist in multiple languages.
This article will cover the different aspects of enabling and working with language variants on your Umbraco website.
To work with Language Variants you need to have more than one language enabled. This can be done from the Settings section:
Now that there are two languages to vary the content with, it needs to be enabled on the Document Types. To do so:
Go to the Document Type in the structure section.
Open the settings page.
Toggle Allow vary by culture.
All new properties on a Document Type were Allow vary by culture is enabled, will inherit the ability to be varied by culture.
It is also possible to make the properties shared across cultures. This means that the value added to the default language, will also be applied to all other languages.
Set up property sharing, by enabling Shared across cultures in the Variation group when defining your properties:
When you return to your content node you will notice two things:
At the top of the Content tree there will now be a dropdown so you can show the Content tree in the language of your choice.
To the right of the content name there is now a dropdown where you can select a language. You can also open a split view so you can see two languages at once.
To read about how you render variant content in Templates, check out the .
Culture and hostnames must be added to your language sites before the content can be tested for variants:
Click ... next to the Home node and select Culture and Hostnames.
Add a specific URL per language and save. For eg: An English language variant with English (United States) as the language can be given a specific URL https://yourwebsite.com/en-us and a Danish language variant can be given a specific URL https://yourwebsite.com/dk.
The Info content app should now show specific URLs for your language variants.
When you are working with a multilingual site you might want to control who can edit the different variations of the content on the website.
This can be controlled on a User Group level. All default User Groups, except the Sensitive data group, have access to all languages out of the box.
When "Allow access to all languages" is not checked, languages can be added and/or removed. This is to determine which variants the users in the user group have access to.
Schema Alias: Umbraco.ColorPicker.EyeDropper
UI Alias: Umb.PropertyEditorUi.EyeDropper
Returns: string
The Eye Dropper Color picker allows you to choose a color from the full color spectrum using HEX and RGBA.
See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the .
Although the use of a GUID is preferable, you can also use the numeric ID to get the page:
Schema Alias: Umbraco.EntityDataPicker
UI Alias: Umb.PropertyEditorUi.EntityDataPicker
Returns: Umbraco.Cms.Core.Models.EntityDataPickerValue
Supported Data Source Types:
The Entity Data Picker property editor allows editors to pick one or more entities from a configurable data source. The selected entities are stored as an array of strings, where each string represents the ID of the selected entity.
Learn how to set up email notifications for actions performed on content items in the Umbraco backoffice.
You can set up notifications to receive an email when an action is performed on a given content item. To receive notifications, you need to add your email address to your user profile.
To set up notifications for a content item:
Click ... next to the page or select the page and click Actions in the top-right corner of the screen.
Choose Notifications.
Documentation for Umbraco CMS. Install, build, extend, and run Umbraco in production.
Umbraco CMS is a flexible and editor-friendly Content Management System (CMS) that allows you to create beautiful and modern websites. Use the latest version of .NET, integrate with your favorite services, and help your customers launch a website tailored to their specific needs.
Learn more about Umbraco CMS and get an overview of the top features on .
Start with the installation guide, then follow one of the tutorials to build your first project.
Umbraco HQ offers a training course covering the basic concepts and features needed for building an Umbraco CMS website. The course targets frontend and backend developers, designers, and technical users who want to build a website from scratch in Umbraco,




Create a new tab called #tabs_content.
Add a new group called #groups_titles.
Add a property called #properties_title with alias title.
Set the description to {#properties_title_desc}.
Use a TextString editor.
Set the field validation to mandatory.
Under validation add {#properties_title_message}.
Enable Allow at root in the Structure tab.








object?: The value passed in from the outer caller or the top-level processor.
Func<object?, bool> The function the processor calls when it detects nested content. This is passed in from the top-level processor.
Func<BlockListValue, object> 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.


TimeOnlyValue value = new TimeOnlyValue
{
Date = dateTimeOffset
};string jsonValue = _jsonSerializer.Serialize(value);IContent content = _contentService.GetById(contentKey) ?? throw new Exception("Content not found");
// Set the value of the property with alias 'startHours'.
content.SetValue("startHours", jsonValue);
// Save the change
_contentService.Save(content);{
"name": "Document Type Localization",
"extensions": [
{
"type": "localization",
"alias": "DocumentType.Localize.En",
"name": "English",
"meta": {
"culture": "en"
},
"js": "/App_Plugins/DocumentTypeLocalization/doctype-en.js"
}
]
}export default {
contentTypes: {
article: 'Article page',
article_desc: 'A textual, article-like page on the site. Use this as the main type of content.',
landing: 'Landing page',
landing_desc: 'An inviting, very graphical page. Use this as an entry point for a campaign, and supplement with Article pages.'
},
tabs: {
content: 'Page content',
seo: 'SEO configuration',
},
groups: {
titles: 'Page titles'
},
properties: {
title: 'Main title',
title_desc: 'This is the main title of the page.',
title_message: 'The main title is required for this page.',
subTitle: 'Sub title',
subTitle_desc: 'This is the sub title of the page.',
}
};@if (Model.HasValue("codeEditor"))
{
var codeSnippet = Model.Value<string>("codeEditor");
<pre><code>@codeSnippet</code></pre>
}@if (Model != null && !string.IsNullOrEmpty(Model.CodeEditor))
{
<pre><code>@Model.CodeEditor</code></pre>
}@using Umbraco.Cms.Core.Services;
@inject IContentService Services;
@{
// Get access to ContentService
var contentService = Services;
// Create a variable for the GUID of your page
var guid = new Guid("ca4249ed-2b23-4337-b522-63cabe5587d1");
// Get the page using the GUID you've just defined
var content = contentService.GetById(guid);
// Define your code string
string newCode = "body {\n background-color: red;\n}";
// Set the value of the property with alias 'codeEditor'
content.SetValue("codeEditor", newCode);
// Save the change
contentService.Save(content);
}@{
// Get the page using it's id
var content = contentService.GetById(1234);
}@using Umbraco.Cms.Core.PublishedCache
@inject IPublishedContentTypeCache PublishedContentTypeCache
@{
// Set the value of the property with alias 'superHeroes'
content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.SuperHeroes).Alias, Serializer.Serialize(new[] { "Umbraco", "CodeGarden"}));
}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<UmbracoApplicationStartingNotification, RunTestMigration>();
}
}
public class RunTestMigration : INotificationAsyncHandler<UmbracoApplicationStartingNotification>
{
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<MigrateSingleBlockList>("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);
}
}
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<EntityDataPickerTest>
@{
Layout = null;
}
<html lang="en">
<head>
<title>Entity Data Picker</title>
</head>
<body>
@if (Model.MyEntityPicker is null)
{
<p>No entity picker value found</p>
}
else
{
<p>Data source: <strong>@Model.MyEntityPicker.DataSource</strong></p>
<p>Picked IDs:</p>
<ul>
@foreach (string id in Model.MyEntityPicker.Ids)
{
<li>@id</li>
}
</ul>
}
</body>
</html>@using Umbraco.Cms.Core.Models
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
@{
Layout = null;
var entityDataPickerValue = Model.Value<EntityDataPickerValue>("myEntityPicker");
}
<html lang="en">
<head>
<title>Entity Data Picker</title>
</head>
<body>
@if (entityDataPickerValue is null)
{
<p>No entity picker value found</p>
}
else
{
<p>Data source: <strong>@entityDataPickerValue.DataSource</strong></p>
<p>Picked IDs:</p>
<ul>
@foreach (string id in @entityDataPickerValue.Ids)
{
<li>@id</li>
}
</ul>
}
</body>
</html>@{
var color = Model.Color?.ToString();
if (color != null)
{
<body style="background-color: @color"></body>
}
}@{
var color = Model.Value<string>("Color");
if (color != null)
{
<body style="background-color: @color"></body>
}
}@using Umbraco.Cms.Core.Services
@inject IContentService ContentService
@{
// Create a variable for the GUID of the page you want to update
var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef");
// Get the page using the GUID you've defined
var content = ContentService.GetById(guid); // ID of your page
// Set the value of the property with alias 'color'.
content.SetValue("color", "#6fa8dc");
// Save the change
ContentService.Save(content);
}@{
// Get the page using it's id
var content = ContentService.GetById(1234);
}@using Umbraco.Cms.Core.PublishedCache
@inject IPublishedContentTypeCache PublishedContentTypeCache
@{
// Set the value of the property with alias 'color'
content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.Color).Alias, "#6fa8dc");
// Set the value of the property with alias 'theme'
content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.Theme).Alias, "rgba(111, 168, 220, 0.7)");
}Check the actions in which you are interested and you will receive notifications each time the given action occurs.
Click Save.






In this article you can learn more about the various sections you can find within the Umbraco Backoffice.
A section in Umbraco is where you perform specific tasks related to a particular area of Umbraco. For example, Content, Settings, and Users are all sections. You can navigate between the different sections by clicking the corresponding icon in the section menu positioned at the top of the Backoffice.
Below is a short overview of the default sections in Umbraco CMS:
The Content section contains the content nodes that make up the website. Content is displayed as nodes in the Content tree.
Nodes in Umbraco can display the following content states:
Grayed-out nodes are not published yet.
Pages that are currently locked using the Public Access feature.
Pages that contain a collection of pages.
To create content, you must define it using Document Types.
For more information, see the article.
The Media section contains the media for the website. You can create folders and upload media files, such as images and PDFs. Additionally, you can customize the existing Media Types or define your own from the Settings section.
For more information, see the article.
The Library section is a central editorial hub for reusable content. Elements are created and managed here, allowing you to define content once and reuse it across as many pages and documents as needed.
By default, all user groups except Sensitive Data and Translators have access to the Library section.
For more information, see the article.
The Settings section allows you to manage website layout files, languages, media, and content types. It also gives you access to more advanced features such as the Log Viewer and extension insights.
The Settings section consists of:
Structure
Document Types
Media Types
Member Types
Data Types
Templating
Templates (.cshtml files)
Partial views (.cshtml files)
Stylesheets (.css files)
Advanced
Relations
Log Viewer
Extension Insights
Webhooks
The Settings section in the Umbraco backoffice has its own set of default dashboards.
For more information, see the article.
In this section, you can browse the different packages available for your Umbraco solution. You can also get an overview of all the packages you have installed or created.
For more information, see the article.
The Users section allows administrators to manage user accounts, assign permissions, set user roles, and monitor user activity within the backoffice. It provides control over who can access and modify content, media, and settings in the CMS.
For more information, see the article.
The Members section allows you to create and manage member profiles and member groups.
For more information, see the article.
The Translation section is where you create and manage Dictionary Items. By managing these dictionary items, you can ensure consistent and efficient content translation and maintenance across different languages.
For more information, see the article.
To enhance Umbraco's functionality, you can integrate plugins and extensions tailored to specific needs. These add-ons expand Umbraco's capabilities, allowing for a more customized and powerful content management experience.
For example, you can start with core Umbraco features and later decide to integrate additional products. Currently, Umbraco supports add-on products like:
Forms: Simplifies the creation and management of Forms.
Deploy: Facilitates smooth deployment processes.
Workflow: Enhances content workflows and approval processes.
Commerce: Adds e-commerce capabilities to your site.
When you add an add-on product to Umbraco, it appears in the Backoffice as a new section, seamlessly extending your content management capabilities.
If you wish to explore the unique features and use cases of Umbraco products, see the article.
For more information about extending the Umbraco platform through packages and integrations, see the documentation.
The Help section in Umbraco provides documentation and resources to assist in understanding and effectively using the Umbraco CMS. It typically includes the following in the Welcome to Umbraco Dashboard:
Documentation: Comprehensive guides, tutorials, and references covering different aspects of Umbraco.
Community Forums: Access to forums where you can ask questions, share knowledge, and seek assistance from other Umbraco community members.
Resources: Stay updated with the latest news, access documentation, watch free video tutorials, and register for live demos.
Training
The Help section serves as a valuable resource hub in navigating and leveraging the capabilities of the Umbraco CMS effectively.
Along with the default sections that come with Umbraco, you can create your own .
A User can access a particular section based on the User Group permissions.
Learn more about how to configure the permissions in the article about .
In some cases, you might need to install Umbraco instances automatically without having to run through the installation wizard to configure the instance.
You can use the Unattended installs feature to allow for quick installation and set up of Umbraco instances on something like Azure Web Apps.
This article will give you the details you need to install Umbraco unattended.
In order to get a clean instance of Umbraco, follow our installation guide for how to .
As you will not be running through the installation wizard when using this feature, you need to manually tell Umbraco which database to use.
Set up and configure a new database - see for details.
Add the connection string using configuration.
A value is configured for the keyumbracoDbDSN_ProviderName to ensure usage of the Microsoft.Data.SQLite ADO.NET provider.
It is recommended that you make use of the values shown below for the Cache, Foreign Keys and Pooling keywords on your connection string.
The unattended installs feature is disabled by default. In order to enable it, you need to add the following JSON object to a JSON configuration source.
Remember to set the value of InstallUnattended to true.
The UnattendedTelemetryLevel can be set to Minimal, Basic, or Detailed. If omitted, Detailed is the default.
Alternatively you may set your configuration with Environment Variables or other means. Learn more about this in the .
The keys for this would then be as follows:
After completing the steps above you can now initialize the installation by booting up the Umbraco instance.
Once it has completed, you should see the following when visiting the frontend of the site.
Depending on your preferences, you can use any type of configuration to specify the connection string and login information, as well as enable unattended install. With the extending configuration functionality, it is possible to read from all kinds of sources. One example can be using a JSON file or environment variables.
Program.cs has a condition, which if met, an appsettings.Local.json file will be added and configured as a configuration source.
Having intellisense will help you to add your connection string and information needed for the unattended install.
We have added support for unattended installs with Name, Email and Password, and Connection String as CLI params, which are also available in Visual Studio. There you can fill in your information as follows:
For running Umbraco in Docker containers, see article.
Schema Alias: Umbraco.DateOnly
UI Alias: Umb.PropertyEditorUi.DateOnlyPicker
Returns: DateOnly?
The Date Only property editor provides an interface for selecting dates without including time or time zone information. It focuses purely on date selection and returns a DateOnly value.
You can configure this property editor in the same way as any standard property editor, using the Data Types admin interface.
To set up a property using this editor, create a new Data Type and select Date Only from the list of available property editors.
This editor has no configuration options.
You will be presented with a date input.
The value returned will have the type DateOnly?.
With Models Builder:
Without Models Builder:
This property editor stores values as a JSON object. The object contains the date as an ISO 8601 string with midnight time and UTC offset.
The property editor stores values in this JSON format:
The property editor handles date-only values. Time is set to 00:00:00 and offset to +00:00 for storage consistency. These time components are ignored in the Date Only context.
Create a C# model that matches the JSON schema.
Convert your existing date value to DateTimeOffset for storage.
If you have a DateOnly:
If you have a DateTime:
For an example on how to work with DateOnly property using IContentService see the article.
Learn how to use Elements to add reusable content to your website.
Instead of replicating the same content on a per-page basis, Elements allow you to create reusable content. By creating your content once, you can reuse it across as many pages and documents as you need.
Elements are ideal for call-to-action blocks, banners, and other shared content that appears across multiple pages.
Elements are managed from the Library section in the Umbraco Backoffice.
The Library section is a central editorial hub for reusable content. By default all user groups except Sensitive data and Translators have access to the section.
Elements are configured in the Settings section and managed from the Library section. They are referenced in your content using the Element Picker property.
Elements are created as Element Types in the Settings section of the Umbraco backoffice. As with all Element Types, Elements are not routable and are not attached to a Template.
Toggle the Allow in Library option on the Structure Workspace View to turn your Element Type into an Element.
You can add groups, tabs, and properties like you would to any other Element and Document Type.
Since your project will contain different Document Types, group your Elements into a dedicated folder to keep your workspace organized.
With your Element configured, you can start using it to create reusable content in the Library section.
Click the + icon.
Select which Element Type you want to base the Element on.
Fill in the relevant properties.
Save or Save and Publish once the content is ready.
To maintain an overview of your reusable content, it can be a good idea to use folders for organizing the content in your Library.
Use the Info workspace view to find relevant details about the element, such as history and where the element is used.
Once you have created the elements in the Library section, they can be referenced anywhere an Element Picker has been configured.
You can add elements to your content in the Content section using an Element Picker. This needs to be added as a property on the Document Type. Read the article to learn more about how to use and configure it.
Making changes to an Element in the Library section, will update all instances of the content throughout the project.
The Date Time property editors provide interfaces for selecting dates, times, and time zones. Each editor is designed for specific use cases, from basic date selection to comprehensive date/time handling with time zone support.
Umbraco CMS currently ships with four Date Time editors:
The Block Editors are property editors that enabled you to build advanced editor tools using a set of predefined Document Types.
Umbraco CMS currently ships with two Block Editors: the Block List and the Block Grid.
Learn how to create custom views for the blocks used in your Block Grid or Block List property editors.
This guide will show you how to migrate the content from your Umbraco 7 site to a site running Umbraco 8.
Umbraco 8 contains a lot of breaking changes and a lot of code has been cleaned up compared to Umbraco 7. Due to this, it will not be possible to do a direct upgrade from Umbraco 7 to Umbraco 8. You need to migrate your content from your Umbraco 7 site into your Umbraco 8 site and then recreate the rest in the new version.
A content migration tool has been implemented in Umbraco 8.1.0, to help you with the transition.
In this guide you can read more about the tool, its limitations, and how to use it in practice.
In the following section, you can learn more about the limitations of migrating content from Umbraco 7 to Umbraco 8.
The content migration tool is a database migration, which is made for the database schema of Umbraco 7.14+. This means that in order to do the migration you need to ensure your Umbraco 7 site is running at least Umbraco 7.14.
Umbraco 8 does not support MySQL databases. This means that the migration will not work when moving from an Umbraco 7 site using MySQL to Umbraco 8 on SQL Server
The database types that are supported are SQL Server and SQL CE.
Schema Alias: Umbraco.MarkdownEditor
UI Alias: Umb.PropertyEditorUi.MarkdownEditor
Returns: System.Web.HtmlString
This built-in editor allow the user to use the markdown formatting options, from within a rich text editor-like interface.
There are three settings available for manipulating the Markdown editor property.
Schema Alias: Umbraco.ListView
UI Alias: Umb.PropertyEditorUi.Collection
Returns: IEnumerable<IPublishedContent>
Collection/List View can be used on Document Types with children, to display those children as a collection in either a grid or a list.
Once Collections are configured, the parent content item displays its child items in a list view format within the content item itself. If Collections are not configured, the child items are displayed directly in the Content Tree, rather than being grouped within the parent content item.
This article provides details on how to upgrade to the next minor version when using Umbraco 7.
Sometimes there are exceptions to these guidelines, which are listed in the .
It is necessary to run the upgrade installer on each environment of your Umbraco site. If you want to update your staging and live site then you need to repeat the steps below and make sure that you click through the install screens to complete the upgrade.
In this article you will find instructions for 2 different ways of upgrading:

Document Blueprints
.js files)UI Builder: Helps in designing and customizing the user interface.






DateTimeOffset value.Inject the IJsonSerializer and use it to serialize the object.
Inject the IContentService to retrieve and update the value of a property of the desired content item.

string jsonValue = _jsonSerializer.Serialize(value);IContent content = _contentService.GetById(contentKey) ?? throw new Exception("Content not found");
// Set the value of the property with alias 'eventDate'.
content.SetValue("eventDate", jsonValue);
// Save the change
_contentService.Save(content);@Model.EventDate@Model.Value<DateOnly?>("eventDate"){
"date": "2025-01-01T00:00:00+00:00"
}using System.Text.Json.Serialization;
namespace UmbracoProject;
public class DateOnlyValue
{
/// <summary>
/// The date value, represented as a <see cref="DateTimeOffset"/> for storage compatibility.
/// </summary>
[JsonPropertyName("date")]
public DateTimeOffset Date { get; init; }
}DateOnly dateOnly = DateOnly.FromDateTime(DateTime.Today); // Your existing DateOnly value
DateTimeOffset dateTimeOffset = dateOnly.ToDateTime(TimeOnly.MinValue);DateTime dateTime = DateTime.Today; // Your existing DateTime value
DateOnly dateOnly = DateOnly.FromDateTime(dateTime);
DateTimeOffset dateTimeOffset = dateOnly.ToDateTime(TimeOnly.MinValue);DateOnlyValue value = new DateOnlyValue
{
Date = dateTimeOffset
};We are collecting a list of these known issues on our GitHub Issue Tracker. There is a community package: Pre-migration health checks that you can install on your Umbraco 7 site before migration. This will help identify and resolve some of these common issues before triggering the migration steps detailed below.
The migration will transform the data stored in third party editors as well. However, it will be stored as it was in Umbraco 7. If the structure has changed or the property editor doesn't exist, you will still be able to find the data in the database. It will, however, not be available in the backoffice.
When the migrations are running, Umbraco will go through your entire Umbraco 7 database and update it to the format required for Umbraco 8. The schema will be remodeled and transformed into the correct format and your existing compatible data will be transformed to fit with Umbraco 8.
These migrations will be running directly on your database. They are transforming schema and data - not transferring. Therefore always ensure that you have a backup before attempting to do this. In case something goes wrong, you will be able to rollback and try again.
It is highly recommended to clean up your site before running this as it will be quicker.
Empty Content recycle bin
Empty Media recycle bin
Clean up the database version history (can be done with a script or a package like Unversion)
In the following guide we will migrate the content of an Umbraco 7.13.1 site to Umbraco 8.1.0.
Before the content migration can start the site has to run Umbraco 7.14+. Make sure to always take a backup of the database before doing an upgrade, and then check the version specific upgrade instructions.
The site in this example is an Umbraco 7.13.1 site, and we will use Nuget to update it.
Following the general upgrade instructions we will now upgrade via Nuget until we get to this point:
Install the Pre-migration health checks plugin, and run it health check from the Developer section of the backoffice. This is done to identify and resolve some common database schema issues before migration.
Once it is upgraded and you have verified everything is working, move on to the next step.
The first thing to do is to spin up a fresh new Umbraco 8.1+ site. Make sure everything works and that no content is there.
Take a backup of your database from the Umbraco 7.14 site. Take the information for the backup database and add that to the connectionstring for the Umbraco 8.1 site. If you are running SQL CE, you will have to copy the database over to the new site as well.
Once the connectionstring is set, the final step is to change the Umbraco version number in the web.config on the Umbraco 8.1 site. Chang it to 7.14.0. This will indicate that there is an upgrade pending and it needs to run the migration.
The version will be set to 8.1.0, and you need to change it to the version you are currently migrating from.
When you start the site it will ask you to login and then show you this screen:
From here, the automatic migration will take over, and after a little bit you can log in and see your content:
Before moving on to this step, make sure that the Umbraco 8 project is no longer running.
The following files/folders need to be copied into the Umbraco 8 project:
~/Views - do not overwrite the default Macro and Partial View Macro files, unless changes have been made to these.
~/Media
Any files/folders related to Stylesheets and JavaScripts.
Any custom files/folders the Umbraco 7 project uses, that aren't in the ~/Config or ~/bin.
~/App_Data/UmbracoForms - in the case Umbraco Forms was used on the Umbraco 7 site.
Merge the configuration files carefully to ensure any custom settings are migrated while none of the default configurations for Umbraco 8 is overwritten.
You'll have to revisit all templates and custom implementations to get the site up and running, as all markup is still Umbraco 7-specific.
As you are updating your template files and custom implementation, you should also verify your configuration files and settings.
Umbraco 8 contains a few changes regarding the Sections in the Umbraco Backoffice. Because of this, you should also check your User Groups and make sure they have access to the appropriate sections.
Learn more about the Section in the Sections article
When upgrading an old website, check if you are using obsolete properties in your Data Types. These should be changed to their updated counterparts. The migration will fail if you are still using obsolete properties.
The updated properties are:
Content Picker
If you have customized the UsersMembershipProvider on your Umbraco 7 site you need to copy that over to the 8.1 web.config as well. Additionally you need to update the type attribute to be type="Umbraco.Web.Security.Providers.UsersMembershipProvider, Umbraco.Web".
This also includes the attribute useLegacyEncoding value. Make sure that this setting is copied into your new Umbraco 8 site, as it is needed in order to log in.
Default value is inserted if no content has been saved to the Document Type using this property editor.
Overlay Size is used to select the width of the link picker overlay in the content view.
toggle bold text
Ctrl + B
toggle italic text
select all
Ctrl + A
copy
Ctrl + C
paste
The conversion from markdown to HTML is handled by the registered implementation of IMarkdownToHtmlConverter.
To understand this more and how you may customize it to your needs, see the article on Markdown to HTML Conversion.
See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the Content Service.
Although the use of a GUID is preferable, you can also use the numeric ID to get the page:
If Models Builder is enabled you can get the alias of the desired property without using a magic string:

@Model.MyMarkdownEditor@Model.Value("MyMarkdownEditor")@using Umbraco.Cms.Core.Services
@inject IContentService ContentService
@{
// Create a variable for the GUID of the page you want to update
var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef");
// Get the page using the GUID you've defined
var content = ContentService.GetById(guid); // ID of your page
// Create markdown value
var markdownValue = new HtmlString("#heading \n**strong text**");
// Set the value of the property with alias 'myMarkdownEditor'.
content.SetValue("myMarkdownEditor", markdownValue);
// Save the change
ContentService.Save(content);
}@{
// Get the page using it's id
var content = ContentService.GetById(1234);
}@using Umbraco.Cms.Core.PublishedCache
@inject IPublishedContentTypeCache PublishedContentTypeCache
@{
// Set the value of the property with alias 'myMarkdownEditor'
content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.MyMarkdownEditor).Alias, markdownValue);
}It is possible to add more columns to the collection, via adding the properties through the picker modal. These properties are based on the Data Types which are used by the Document Type. The properties will listed for selection.
Once you have selected a column you want to display, define what its heading label should be and what kind of value it should display. You can also move the headers around, re-ordering how they should look. This is done by the move icon on the left side of the alias.
The template section is where you define what kind of value you want to display. The value of the column is in the value variable.
Collection comes with two layouts by default. A list and a grid view. These views can be disabled if you are not interested in any of them.
You can also make your own layout and add it to the settings. For example, if you wanted to change the width or length of the grid, you will be able to do so.
Will sort your collection by the selection you choose in the dropdown. By default it selects "Last edited" and you get the following three columns:
Last edited - When the content node was last edited and saved.
Name - Name of the content node(s).
Created by - This is the user who the content node was created by.
You can add more sorting to this collection by adding more datatypes to the columns in the "Columns Displayed" section.
You can select order of the content nodes displayed, "Ascending [a-z]" or "Descending [z-a]". The order is affected by the "Order By" selection.
Defines how many child content nodes you want to see per page. This will limit how many content items you will see in your collection. If you set it to 5, then only 5 content items will be shown in the collection.
Changes the icon in the backoffice of the collection. By default it will look like the image below.
You can change the name of the collection itself. Default if empty: 'Child Items'.
Enable this to show the Content Workspace View by default instead of the collection's.
This example shows how to use a generic field from a child item and display its value in a collection.
You can use the Umbraco Flavored Markdown syntax to display the label value. Here, the {=value} placeholder retrieves the value of the Email property and displays it in the collection, as shown in the image below:
First, a Content Picker property needs to be present on the content item. In this example, the child item has gotten a Content Picker Data Type with the alias of contentPicker.
The child item has a document and the value that should be displayed is the name of the picked value. The next step is to reconfigure the template value in the collection setting.
This will take the value picked up by the content picker.
And display it in the collection. Shown in the example below:


Open up the Package Console and type: Update-Package UmbracoCms
Choose "No to All" by pressing the "L" when prompted.
If there are any specific configuration changes required for the version you are upgrading to then they will be noted in the version-specific guide.
Alternatively, you can use the Visual Studio NuGet Package Manager to upgrade:
Open the NuGet Package Manager and select the Updates pane to get a list of available updates.
Choose the package called UmbracoCms and select update.
The upgrade will run through all the files and make sure you have the latest changes while leaving the files you have updated.
If you're not upgrading to 7.2.0 or higher then you should follow these extra instructions. If you are upgrading to 7.2.0+ then you can skip this and go to Merge UI.xml and language.
You will be asked to overwrite your web.config file and the files in /config, make sure to answer No to those questions.
For some inexplicable reason, the installation will fail if you click "No to All" (in the GUI) or answer "L" (in the package manager console) to the question: "File 'Web.config' already exists in project 'MySite'. Do you want to overwrite it?" So make sure to only answer "No" (in the GUI) or "N" (in the package manager console).
We will overwrite the web.config file. We'll back it up so don't worry. You can find the backup in App_Data\NuGetBackup\20140320-165450\. The 20140320-165450 bit is the date and time when the backup occurred, which varies. You can then merge your config files and make sure they're up to date.
Download the .zip file for the new version you are upgrading to from https://our.umbraco.com/download
Copy the following folders from inside the .zip file over the existing folders in your site:
/bin
/Umbraco
/Umbraco_Client
You can expect some changes to the following configuration files:
Any file in the /Config folder
The /Global.asax file
The web.config file in the root of your site (Important: make sure to copy back the version number, and the connection string as they were.)
In rare cases, the web.config file in the Views folder
Use a tool like WinMerge to check changes between all of the config files. Depending on when you last did this there may have been updates to a few of them.
There's also the possibility that files in the /Config folder are new or have been removed(we note this in the release notes). WinMerge (and other diff tools) is able to compare folders as well so you can spot these differences.
Up until version 6.0.0 it was necessary to change the version number in ClientDependency.config. This was to clear the cached HTML/CSS/JS files in the backoffice. Change the current version number to one that's higher than that. Make sure not to skip this step as you might get strange behavior in the backoffice otherwise.
Some packages (like Contour and Umbraco Forms) add dialogs to the UI.xml. Make sure to merge those changes back in from your backup during the upgrade so that the packages continue to work. This file can be found in: /Umbraco/Config/Create/UI.xml.
Packages like Contour, Umbraco Forms, and Courier also make changes to the language files located in: /Umbraco/Config/Lang/*.xml (typically en.xml).
After copying the files and making the config changes, you can open your site. You should see the installer which will guide you through the upgrade.
The installer will do two things:
Update the version number in the web.config
Upgrade your database in case there are any changes
We are aware that, currently, the installer is asking you for the database details of a blank database while upgrading. In the near future this will be pre-filled with your existing details and the wording will be updated. So no need to be scared. Enter the details of your existing database and Umbraco will upgrade it to the latest version when necessary.
One important recommendation is to always remove the install folder immediately after upgrading Umbraco and never to upload it to a live server.
Google Chrome has notoriously aggressive caching. If something doesn't seem to work well in the backoffice, make sure to clear cache and cookies thoroughly (for other browsers as well). Normally the browser cache problem is automatically handled in an Umbraco upgrade by modifying the config/ClientDependency.config version number. If you wish to re-force this update you can increment this version number. This will ensure that any server-side cache of JavaScript and stylesheets gets cleared as well.
One way to nudge the cache in Chrome is to open the developer tools (F12) and go to the settings (the cog icon). There will be a checkbox that says "Disable cache (while DevTools is open)". Once this checkbox is on you can refresh the page and the cache should be invalidated. To force it even more, the "reload" button next to your address bar now has extra options when you right-click it. It should have "Normal reload", "Hard reload" and "Empty cache and hard reload" now. The last option is the most thorough and you might want to try that.
{
"ConnectionStrings": {
"umbracoDbDSN": "server=localhost;database=UmbracoUnicore;user id=sa;password='P@ssw0rd'",
"umbracoDbDSN_ProviderName": "System.Data.SqlClient"
}
}{
"ConnectionStrings": {
"umbracoDbDSN": "Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True",
"umbracoDbDSN_ProviderName": "Microsoft.Data.Sqlite"
}
}{
"Umbraco": {
"CMS": {
"Unattended": {
"InstallUnattended": true,
"UnattendedUserName": "FRIENDLY_NAME",
"UnattendedUserEmail": "EMAIL",
"UnattendedUserPassword": "PASSWORD",
"UnattendedTelemetryLevel": "Detailed"
}
}
}
}Umbraco__CMS__Unattended__InstallUnattended
Umbraco__CMS__Unattended__UnattendedUserName
Umbraco__CMS__Unattended__UnattendedUserEmail
Umbraco__CMS__Unattended__UnattendedUserPassword
Umbraco__CMS__Unattended__UnattendedTelemetryLevel#if DEBUG
.ConfigureAppConfiguration(config
=> config.AddJsonFile(
"appsettings.Local.json",
optional: true,
reloadOnChange: true))
#endif{
"ConnectionStrings": {
"umbracoDbDSN": "server=localhost;database=UmbracoUnicore;user id=sa;password='P@ssw0rd'"
},
"Umbraco": {
"CMS": {
"Unattended": {
"InstallUnattended": true,
"UnattendedUserName": "FRIENDLY_NAME",
"UnattendedUserEmail": "EMAIL",
"UnattendedUserPassword": "PASSWORD",
"UnattendedTelemetryLevel": "Detailed"
}
}
}
}dotnet new umbraco -n MyNewProject --friendly-name "Friendly User" --email [email protected] --password password1234 --telemetry-level Detailed --connection-string "Server=(localdb)\Umbraco;Database=MyDatabase;Integrated Security=true" --version 10.0.0Date selection
Birthdays, deadlines, event dates
DateOnly
Time selection
Business hours, schedules, time-based events
TimeOnly
Full date, time, and time zone support
International apps, timezone-aware scheduling
DateTimeOffset
Date and time without a defined time zone
Local events, compatibility with Date Time
DateTime
Schema Alias: Umbraco.MediaPicker3
UI Alias: Umb.PropertyEditorUi.MediaPicker
Returns: IEnumerable<MediaWithCrops> or MediaWithCrops
This property editors returns one of the following:
A collection (IEnumerable<MediaWithCrops>) if the Pick multiple items setting is enabled.
A single MediaWithCrops item if the Pick multiple items setting is disabled.
Use setting to limit the picker to only select Media Items of these types.
Use this setting to enable the property to contain multiple items. When this is enabled the property editor returns an IEnumerable<MediaWithCrops>.
You can still set the maximum amount to 1. Do so when you want to retrieve a collection but only allow the Content Editors to select one Media Item.
Use this setting to enforce a minimum and/or maximum amount of selected Media Items.
This setting is used to limit the Media Picker to certain parts of the Media Tree.
Use this setting to overrule user permissions, to enable any user of this property to pick any Media Item of the chosen Start node.
When this setting is enabled, a user can access the media available under the selected "Start Node" (/Design in this case). This applies even if they normally lack access. The access is granted specifically when using this particular Media Picker.
Enable the focal point setter, do only enable this if the focal point is used or if you have Image crops defined.
Define local image crops. Local image crop data is stored on the document in this property. This means it can differentiate between documents.
This is different from Global crops as they are defined on the Media Item, making the crops shared between all usage of that Media Item.
Global crops are configured on the Image Cropper property of the Image Media Type
Both local and global crops are retrieved using the method GetCropUrl. If crops with identical aliases are defined both locally and globally, the locally defined crops are always prioritized by GetCropUrl.
The following is an example of how to retrieve a crop from a MediaWithCrops entry:
You can retrieve globally defined crops explicitly by using GetCropUrl on the UrlHelper:
See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the .
The following sample will update a single image in a Media Picker.
Although the use of a GUID is preferable, you can also use the numeric ID to get the page:
If Models Builder is enabled you can get the alias of the desired property without using a magic string:
Learn more about the Umbraco backoffice which is the admin side of your Umbraco website
In this article you can learn more about the common terms and concepts that are used throughout the Umbraco backoffice.
When you go to the backoffice for the first time, you're presented with the login screen.
Read more about the login screen.
A section in Umbraco is where you do specific tasks related to that section. For example Content, Settings and Users. You can navigate between the different sections of the backoffice by clicking the corresponding icon in the section menu.
The Section menu is the horizontal menu located on the top of the backoffice.
Read more about the section menu.
A tree is a hierarchical list of items related (and usually restricted) to a specific concept, like for example content or media.
You can expand trees by clicking the side arrow to the left of the node.
A node is an item in a tree. Media section items appear as nodes in the Media tree, while pages and content are displayed in the Content tree, and so on.
A dashboard is the main view you are presented with when entering a section within the backoffice. It can be used to show valuable information to the users of the system.
An editor is what you use to edit different items within the backoffice. There are editors specific to editing stylesheets, there are editors for editing Partial Views, and so forth.
Content is what you find in the Content section. Each item in the tree is called a content node. Each content node in the content tree consists of different fields, and each of them is defined by a Document Type.
Document Types define the types of content nodes that backoffice users can create in the content tree. Each Document Type contains different properties. Each property has a specific Data Type for example text or number.
Every Document Type has properties. These are the fields that the content editor is allowed to edit for the content node.
Each Document Type property has a Data Type that defines the type of input of that property. Data Types reference a Property Editor and are configured in the Umbraco backoffice in the Settings section. A Data Type can be something basic (text string, number, true/false) or more complex (multi-node tree picker, image cropper, etc).
A property editor is a view used by Data Types to insert content into Umbraco. An example of a property editor is the Textarea. It's possible to have many Textarea Data Types with different settings that all use the Textarea property editor.
Media items are used to store assets like images and video within the Media section and can be referenced from your content.
Media Types are similar to Document Types in Umbraco, except they are specifically for media items in the Media section.
Umbraco includes the following default Media Types - Article, Audio, File, Folder, Image, Vector Graphics (SVG), and Video.
A member is someone who has access to signup, register, and login into your public website and is not to be confused with Users.
Similar to a Document Type and a Media Type. You are able to define custom properties to store on a member such as Twitter username or website URL.
A Template is where you define the HTML markup of your website and also where you output the data from your content nodes.
A package is the Umbraco term for an add-on or plugin used to extend the core functionalities in Umbraco. The packages can be found on the , and the can also be browsed directly in the backoffice of the Umbraco CMS.
A user is someone who has access to the Umbraco backoffice and is not to be confused with Members. When Umbraco has been installed a user will automatically be generated with the login (email) and password entered during installation. Users can be created, edited, and managed in the User section.
Document Blueprint provide a blueprint for content nodes based on an existing node.
Schema Alias: Umbraco.DateTimeWithTimeZone
UI Alias: Umb.PropertyEditorUi.DateTimeWithTimeZonePicker
Returns: DateTimeOffset?
The Date Time with Time Zone property editor provides a comprehensive interface for selecting dates, times, and time zones. It stores values as ISO 8601 date/time strings with time zone information. This makes it ideal for applications that need accurate date handling across different time zones.
You can configure this property editor in the same way as any standard property editor, using the Data Types admin interface.
To set up a property using this editor, create a new Data Type. Select Date Time (with time zone) from the list of available property editors.
You will see the configuration options as shown below.
Time format - Specifies the level of precision for time values shown and stored by the editor.
Time zones - Controls how time zones are available in the property editor.
HH:mm - Displays hours and minutes (e.g., 14:30).
Suitable for most general use cases.
HH🇲🇲ss - Displays hours, minutes, and seconds (e.g., 14:30:45).
Use this when you need more precise timing.
All - Displays the full list of time zones (for example, America/New_York, Europe/Stockholm).
Local - Displays only the local time zone of the user's browser/computer. Useful for simplifying the UI when time entries should always be based on the user’s local context.
Custom - Allows you to define a list of time zones. When you select this option, a dropdown appears. You can search and select from the full IANA time zone list. Add multiple zones to restrict user selection to only the zones you specify.
The selected time zone affects how the date/time is displayed and stored.
When you select a time zone, the value will be saved with the corresponding offset (e.g., 2025-01-01T14:30:00+01:00).
Daylight saving time is also taken into account.
You will be presented with date, time, and time zone inputs. The time zone input allows typing, which filters the list of presented time zones.
If your browser time zone appears in the list and no date is stored yet, it will be pre-selected by default.
When you select a time zone different from your browser's local time zone, the editor displays a helpful conversion message. This shows what the selected date and time would be equivalent to in your local time zone, making it easier to understand the time difference.
If only one time zone is available, you will see a label with the time zone name instead.
The value returned will have the type DateTimeOffset?. This allows you to work with the date/time value while preserving time zone information.
With Models Builder:
Without Models Builder:
Convert to local time:
Convert to UTC time:
Convert to DateTime:
This property editor stores values as a JSON object. The object contains both the date (as an ISO 8601 string) and the selected time zone identifier.
The property editor stores values in this JSON format:
Create a C# model that matches the JSON schema.
Create an instance of the created class with the desired values.
Inject the IJsonSerializer and use it to serialize the object.
Inject the IContentService
For an example on how to work with a date property using IContentService see the article.
This article provides details on how to upgrade to the next minor version when using Umbraco 8.
Sometimes there are exceptions to these guidelines, which are listed in the .
It is necessary to run the upgrade installer on each environment of your Umbraco site. If you want to update your staging and live site you need to repeat the steps below. Make sure you click through the install screens so that your upgrade is complete.
In this article you will find instructions for 3 different ways of upgrading:
Schema Alias: Umbraco.DateTime
UI Alias: Umb.PropertyEditorUi.DatePicker
Returns: DateTime
Displays a calendar UI for selecting dates which are saved as a DateTime value.
There is one setting available for manipulating the DateTime property.
The setting involves defining the format. The default date format in the Umbraco backoffice is YYYY-MM-DD HH:mm:ss, but you can change it to a different format. See for the supported formats.
Ctrl + I
insert link
Ctrl + L
This opens the Select Link interface.
toggle quote
Ctrl + Q
toggle code block
Ctrl + K
insert image
Ctrl + G
This opens the Select Media interface.
toggle ordered list
Ctrl + O
toggle unordered list
Ctrl + U
toggle heading
Ctrl + H
This toggles between h1, h2 and off.
toggle a hr
undo
Ctrl + Z
redo
Ctrl + Y
Ctrl + V
































There are 3 options that a developer can choose to do to work around this automatic data conversion:
1: Implement a custom IPreValueMigrator
This option requires you to create a custom C# migrator for each of your custom property editors that store custom configuration data. It will also require that you implement these migrators before you run the Umbraco 8 content migration.
To do this, you will create an implementation of IPreValueMigrator or inherit from the base class DefaultPreValueMigrator.
There are plenty of examples of this in the Umbraco-CMS codebase.
You will then need to register them in a composer:
When running the migrations and encountering a custom configuration, Umbraco will utilize the PreValueMigrator when converting the old pre-values into the new JSON format.
2: Update your Angular configuration (pre-value) and property editor
This option means that you will choose to use the automatically converted JSON data format. In this case, it will mean updating your pre-value and property editors to use the new JSON configuration data. The converted data won't be much different than the original/intended data format so this might not be too much work.
3: Update the Angular configuration (pre-value) editor
With this option the configuration/pre-value editor needs to be updated to transform the JSON converted data into the data structure you want. When this is done and when the Data Type is saved again, the JSON data structure will be saved back to the database. Your property editor will then continue to work.
This will require you to update and save all custom pre-value editors to transform the converted structures back to your intended data structure.
Media Picker
Member Picker
Multinode Treepicker
Nested Content
Folder Browser
Related Links
You can see if your site is using the obsolete properties from the (Obsolete) prefix in their name.






@using Umbraco.Cms.Core.Models
@{
var typedMultiMediaPicker = Model.Value<IEnumerable<MediaWithCrops>>("medias");
foreach (var entry in typedMultiMediaPicker)
{
<img src="@entry.MediaUrl()" />
}
}@using Umbraco.Cms.Core.Models
@{
var listOfImages = Model.Value<IEnumerable<IPublishedContent>>("medias");
foreach (var image in listOfImages)
{
<img src="@image.Url()" />
}
}@{
var typedMultiMediaPicker = Model.Medias;
foreach (var entry in typedMultiMediaPicker)
{
<img src="@entry.MediaUrl()" />
}
}@using Umbraco.Cms.Core.Models
@{
var typedMediaPickerSingle = Model.Value<MediaWithCrops>("media");
if (typedMediaPickerSingle != null)
{
<img src="@typedMediaPickerSingle.MediaUrl()" />
}
}@using Umbraco.Cms.Core.Models
@{
var typedMediaPickerSingle = Model.Media;
if (typedMediaPickerSingle is MediaWithCrops mediaEntry)
{
<img src="@mediaEntry.MediaUrl()" />
}
}@{
foreach (var entry in Model.Medias)
{
<img src="@entry.GetCropUrl("cropAlias")" />
}
}@{
foreach (var entry in Model.Medias)
{
<img src="@Url.GetCropUrl(entry, "cropAlias")" />
}
}@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Services
@inject IContentService ContentService
@{
// Create a variable for the GUID of the page you want to update
var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef");
// Get the page using the GUID you've defined
var content = ContentService.GetById(guid); // ID of your page
// Get the media you want to assign to the media picker
var media = Umbraco.Media("bca8d5fa-de0a-4f2b-9520-02118d8329a8");
// Create an Udi of the media
var udi = Udi.Create(Constants.UdiEntityType.Media, media.Key);
// Set the value of the property with alias 'featuredBanner'.
content.SetValue("featuredBanner", udi.ToString());
// Save the change
ContentService.Save(content);
}@{
// Get the page using it's id
var content = ContentService.GetById(1234);
}@using Umbraco.Cms.Core.PublishedCache
@inject IPublishedContentTypeCache PublishedContentTypeCache
@{
// Set the value of the property with alias 'featuredBanner'
content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.FeaturedBanner).Alias, udi.ToString());
}[RuntimeLevel(MinLevel = RuntimeLevel.Upgrade, MaxLevel = RuntimeLevel.Upgrade)] // only on upgrades
public class PreValueMigratorComposer : IUserComposer
{
public void Compose(Composition composition)
{
composition.WithCollectionBuilder<PreValueMigratorCollectionBuilder>()
// Append all of the migrators required
.Append<MyCustomPreValueMigrator>()
.Append<AnotherPreValueMigrator>();
}
}Example: Selecting the following time zones:
Coordinated Universal Time (UTC)
Europe/Copenhagen
Will result in the following editing experience:
@Model.EventDateTime.Value@Model.Value<DateTimeOffset?>("eventDateTime")DateTimeOffset? localTime = Model.EventDateTime?.ToLocalTime();DateTimeOffset? utcTime = Model.EventDateTime?.ToUniversalTime();DateTime? dateTime = Model.EventDateTime?.DateTime;
DateTime? utcDateTime = Model.EventDateTime?.UtcDateTime;{
"date": "2025-01-01T00:01:00+01:00",
"timeZone": "Europe/Copenhagen"
}using System.Text.Json.Serialization;
namespace UmbracoProject;
public class DateTimeWithTimeZone
{
/// <summary>
/// The date and time value, represented as a <see cref="DateTimeOffset"/>.
/// </summary>
[JsonPropertyName("date")]
public DateTimeOffset Date { get; init; }
/// <summary>
/// The identifier of the time zone to pre-select in the editor. E.g., "Europe/Copenhagen".
/// </summary>
[JsonPropertyName("timeZone")]
public string TimeZone { get; init; }
}var value = new DateTimeWithTimeZone
{
Date = DateTimeOffset.Now, // The date and time value to store.
TimeZone = "Europe/Copenhagen" // The time zone to pre-select in the editor.
};var jsonValue = _jsonSerializer.Serialize(value);


IContent content = _contentService.GetById(contentKey) ?? throw new Exception("Content not found");
// Set the value of the property with alias 'eventDateTime'.
content.SetValue("eventDateTime", jsonValue);
// Save the change
_contentService.Save(content);Open up the Package Console and type: Update-Package UmbracoCms
Choose "No to All" by pressing the "L" when prompted.
If there are any specific configuration changes required for the version you are upgrading to then they will be noted in the version-specific guide.
Alternatively, you can use the Visual Studio NuGet Package Manager to upgrade:
Open the NuGet Package Manager and select the Updates pane to get a list of available updates.
Choose the package called UmbracoCms and select update.
The upgrade will run through all the files and make sure you have the latest changes while leaving files you have updated.
Download the .zip file for the new version you are upgrading to from https://our.umbraco.com/download
Copy the following folders from inside the .zip file over the existing folders in your site:
/bin
/Umbraco
You can expect some changes to the following configuration files:
Any file in the /Config folder
The /Global.asax file
The web.config file in the root of your site (Important: make sure to copy back the version number, and the connection string as they were.)
In rare cases, the web.config file in the /Views folder
Use a tool like WinMerge to check changes between all of the config files. Depending on when you last did this there may have been updates to few of them.
There's also the possibility that some files in the /Config folder are new or some have been removed (we do make a note of this in the release notes). WinMerge (and other diff tools) can compare folders as well so you can spot these differences.
Some packages like Umbraco Forms add dialogs to the UI.xml. Make sure to merge those changes back in from your backup during the upgrade so that the packages continue to work. This file can be found in: /Umbraco/Config/Create/UI.xml.
Packages like Umbraco Forms and Courier also make changes to the language files located in: /Umbraco/Config/Lang/*.xml (typically en.xml).
After copying the files and making the config changes, you can open your site. You should see the installer which will guide you through the upgrade.
The installer will do two things:
Update the version number in the web.config
Upgrade your database in case there are any changes
We are aware that, currently, the installer is asking you for the database details of a blank database while upgrading. In the near future this will be pre-filled with your existing details and the wording will be updated. So no need to be scared. Enter the details of your existing database and Umbraco will upgrade it to the latest version when necessary.
When upgrading your Umbraco project to Umbraco v8.12+ it is possible to enable the upgrade to run unattended. This means that you will not need to run through the installation wizard when upgrading.
Below you will find the steps you need to take in order to upgrade your project unattended.
Add the Umbraco.Core.RuntimeState.UpgradeUnattended key to appSettings in your web.config file.
Set the value of the key to true.
In order to trigger the actual upgrade, the correct version number needs to be set.
It is important to use the version number of the version that you are upgrading to. If this is not set, the upgrade will not run even if the UpgradeUnattended key has been set to true.
Locate the ConfigurationStatus key in the appSettings section in your web.config file.
Update the value to match the Umbraco version that you are upgrading to.
With the correct configuration applied, the project will be upgraded on the next boot.
The Runtime level will use Run instead of Upgrade in order to allow the website to continue to boot up directly after the migration is run, instead of initiating the otherwise required restart.
Follow the steps outlined below to use run unattended upgrades in a load balanced setup.
Upgrade Umbraco via NuGet in Visual Studio. Make sure the Umbraco.Core.ConfigurationStatus key in appSetting in the web.config file is updated to match the target version.
Deploy to all environments, including the updated appSetting for Umbraco.Core.ConfigurationStatus.
Set the Umbraco.Core.RuntimeState.UpgradeUnattended key in appSetting in the web.config to true for the Main server only.
Request a page on the Main server and the upgrade will run automatically.
Wait for the upgrade to complete.
Browse the Read-Only servers and make sure they do not show the “upgrade required” screen.
One important recommendation is to always remove the install folder immediately after upgrading Umbraco and never to upload it to a live server.
Google Chrome has notoriously aggressive caching, so if something doesn't seem to work well in the backoffice, make sure to clear cache and cookies thoroughly (for other browsers as well). Normally the browser cache problem is automatically handled in an Umbraco upgrade by modifying the config/ClientDependency.config version number. If you however wish to re-force this update you can increment this version number which will ensure that any server-side cache of JavaScript and stylesheets gets cleared as well.
One way to nudge the cache in Chrome is to open the developer tools (F12) and go to the settings (the cog icon). There will be a checkbox that says "Disable cache (while DevTools is open)". Once this checkbox is on you can refresh the page and the cache should be invalidated. To force it even more, the "reload" button next to your address bar now has extra options when you right-click it. It should have "Normal reload", "Hard reload" and "Empty cache and hard reload" now. The last option is the most thorough and you might want to try that.
<add key="Umbraco.Core.RuntimeState.UpgradeUnattended" value="true" /><add key="Umbraco.Core.ConfigurationStatus" value="x.x.x"/>See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the Content Service.
Although the use of a GUID is preferable, you can also use the numeric ID to get the page:
If Models Builder is enabled you can get the alias of the desired property without using a magic string:

@Model.DatePicker@Model.Value("datePicker")@using Umbraco.Cms.Core.Services
@inject IContentService ContentService
@{
// Create a variable for the GUID of the page you want to update
var guid = new Guid("32e60db4-1283-4caa-9645-f2153f9888ef");
// Get the page using the GUID you've defined
var content = ContentService.GetById(guid); // ID of your page
// Set the value of the property with alias 'datePicker'
content.SetValue("datePicker", DateTime.Now);
// Save the change
ContentService.Save(content);
}@{
// Get the page using it's id
var content = ContentService.GetById(1234);
}@using Umbraco.Cms.Core.PublishedCache
@inject IPublishedContentTypeCache PublishedContentTypeCache
@{
// Set the value of the property with alias 'datePicker'
content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.DatePicker).Alias, DateTime.Now);
}Schema Alias: Umbraco.DropDown.Flexible
UI Alias: Umb.PropertyEditorUi.Dropdown
Returns: String or IEnumerable<string>
Displays a list of preset values. Either a single value or multiple values (formatted as a collection of strings) can be returned.
If enabled, editors will be able to select multiple values from the dropdown otherwise only a single value can be selected.
Options are the values which are shown in the dropdown list. You can add, edit, or remove values here.
See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the .
Although the use of a GUID is preferable, you can also use the numeric ID to get the page:
If Models Builder is enabled you can get the alias of the desired property without using a magic string:
Schema Alias: Umbraco.DateTimeUnspecified
UI Alias: Umb.PropertyEditorUi.DateTimePicker
Returns: DateTime?
The Date Time (Unspecified) property editor provides an interface for selecting dates and times without including time zone information.
You can configure this property editor in the same way as any standard property editor, using the Data Types admin interface.
To set up a property using this editor, create a new Data Type and select Date Time (Unspecified) from the list of available property editors.
You will see the configuration options as shown below.
Time format - Specifies the level of precision for time values shown and stored by the editor.
HH:mm - Displays hours and minutes (e.g., 14:30).
Suitable for most general use cases.
HH🇲🇲ss - Displays hours, minutes, and seconds (e.g., 14:30:45).
Use this when you need more precise timing.
You will be presented with a date and time input. This editor focuses only on the date and time components, unlike the time zone version.
The value returned will have the type DateTime?.
With Models Builder:
Without Models Builder:
This property editor stores values as a JSON object. The object contains the date as an ISO 8601 string.
The property editor stores values in this JSON format:
The property editor handles unspecified date and time values without time zone information. The value is stored with offset +00:00 for consistency. The offset is ignored unless you replace this editor with the Date Time (with time zone) version.
Create a C# model that matches the JSON schema.
Convert your existing DateTime value to DateTimeOffset for storage.
Create an instance of the class with the DateTimeOffset value.
For an example on how to work with a date property using IContentService see the article.
Schema Alias: Umbraco.UploadField
UI Alias: Umb.PropertyEditorUi.UploadField
Returns: string
Adds an upload field, which allows documents or images to be uploaded to Umbraco.
You can define which file types should be accepted through the upload field.
In code, the property is a string, which references the location of the file.
Example: "/media/o01axaqu/guidelines-on-remote-working.pdf"
Schema Alias: Umbraco.ContentPicker
UI Alias: Umb.PropertyEditorUi.DocumentPicker
Returns: IPublishedContent
The Document Picker opens a panel to pick a specific page from the content structure. The value saved is the selected nodes .
See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the .
Although the use of a GUID is preferable, you can also use the numeric ID to get the page:
Learn how to manually reload the content tree to reflect changes made by other editors.
When editing content, the content tree will refresh itself when the content is saved.
You can also manually reload parts of or the entire content tree to refresh it or to load changes made by other editors.
To reload the content tree:
Click ... next to the Content heading.
Choose Reload children.






IJsonSerializer and use it to serialize the object.Inject the IContentService to retrieve and update the value of a property of the desired content item.


See the example below to see how a value can be added or changed programmatically. To update a value of this property editor you need the Content Service and the Media Service.
If Models Builder is enabled you can get the alias of the desired property without using a magic string:





@if (Model.HasValue("category"))
{
<p>@(Model.Value<string>("category"))</p>
}@if (Model.HasValue("categories"))
{
var categories = Model.Value<IEnumerable<string>>("categories");
<ul>
@foreach (var category in categories)
{
<li>@category</li>
}
</ul>
}@if (!Model.HasValue(Model.Category))
{
<p>@Model.Category</p>
}@if (Model.Categories.Any())
{
<ul>
@foreach (var category in Model.Categories)
{
<li>@category</li>
}
</ul>
}@using Umbraco.Cms.Core.Serialization
@using Umbraco.Cms.Core.Services
@inject IContentService ContentService
@inject IJsonSerializer Serializer
@{
// Create a variable for the GUID of the page you want to update
var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef");
// Get the page using the GUID you've defined
var content = ContentService.GetById(guid); // ID of your page
// Set the value of the property with alias 'categories'.
content.SetValue("categories", Serializer.Serialize(new[] { "News" }));
// Save the change
ContentService.Save(content);
}@{
// Get the page using it's id
var content = ContentService.GetById(1234);
}@using Umbraco.Cms.Core.PublishedCache
@inject IPublishedContentTypeCache PublishedContentTypeCache
@{
// Set the value of the property with alias 'categories'
content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.Categories).Alias, Serializer.Serialize(new[] { "News" }));
}IContent content = _contentService.GetById(contentKey) ?? throw new Exception("Content not found");
// Set the value of the property with alias 'eventDateTime'.
content.SetValue("eventDateTime", jsonValue);
// Save the change
_contentService.Save(content);@Model.EventDateTime.Value@Model.Value<DateTime?>("eventDateTime"){
"date": "2025-01-01T00:00:00+00:00"
}using System.Text.Json.Serialization;
namespace UmbracoProject;
public class DateTimeUnspecified
{
/// <summary>
/// The date and time value, represented as a <see cref="DateTimeOffset"/> for storage compatibility.
/// </summary>
[JsonPropertyName("date")]
public DateTimeOffset Date { get; init; }
}DateTime dateTime = DateTime.Now; // Your existing DateTime value
DateTimeOffset dateTimeOffset = dateTime; // Explicit conversionvar value = new DateTimeUnspecified
{
Date = dateTimeOffset
};string jsonValue = _jsonSerializer.Serialize(value);@if (Model.HasValue("myFile"))
{
var myFile = Model.Value<string>("myFile");
<a href="@myFile">@System.IO.Path.GetFileName(myFile)</a>
}@if (Model.HasValue("myFile"))
{
<a href="@Model.MyFile">@System.IO.Path.GetFileName(Model.MyFile)</a>
}@using System.Net
@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Services
@using Umbraco.Cms.Core.PropertyEditors
@using Umbraco.Cms.Core.IO
@using Umbraco.Cms.Core.Serialization
@using Umbraco.Cms.Core.Strings
@inject MediaFileManager MediaFileManager
@inject IShortStringHelper ShortStringHelper
@inject IContentTypeBaseServiceProvider ContentTypeBaseServiceProvider
@inject IContentService ContentService
@inject IMediaService MediaService
@inject IJsonSerializer Serializer
@inject MediaUrlGeneratorCollection MediaUrlGeneratorCollection
@{
// Create a variable for the GUID of the parent where you want to add a child item
var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef");
// Get the page using the GUID you've defined
var content = ContentService.GetById(guid); // ID of your page
// Create a variable for the file you want to upload, in this case the Our Umbraco logo
var imageUrl = "https://our.umbraco.com/assets/images/logo.svg";
// Create a request to get the file
var request = WebRequest.Create(imageUrl);
var webResponse = request.GetResponse();
var responseStream = webResponse.GetResponseStream();
// Get the file name
var lastIndex = imageUrl.LastIndexOf("/", StringComparison.Ordinal) + 1;
var filename = imageUrl.Substring(lastIndex, imageUrl.Length - lastIndex);
// Create a media file
var media = MediaService.CreateMediaWithIdentity("myImage", -1, "File");
media.SetValue(MediaFileManager, MediaUrlGeneratorCollection, ShortStringHelper, ContentTypeBaseServiceProvider, Constants.Conventions.Media.File, filename, responseStream);
// Save the created media
MediaService.Save(media);
// Get the published version of the media (IPublishedContent)
var publishedMedia = Umbraco.Media(media.Id);
// Set the value of the property with alias 'myFile'
content.SetValue("myFile", publishedMedia.Url());
// Save the child item
ContentService.Save(content);
}@using Umbraco.Cms.Core.PublishedCache
@inject IPublishedContentTypeCache PublishedContentTypeCache
@{
// Set the value of the property with alias 'myFile'
content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.MyFile).Alias, publishedMedia.Url();
}@{
IPublishedContent typedContentPicker = Model.Value<IPublishedContent>("featurePicker");
if (typedContentPicker != null)
{
<p>@typedContentPicker.Name</p>
}
}@{
IPublishedContent typedContentPicker = Model.FeaturePicker;
if (typedContentPicker != null)
{
<p>@typedContentPicker.Name</p>
}
}@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Services
@inject IContentService ContentService
@{
// Create a variable for the GUID of the page you want to update
var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef");
// Get the page using the GUID you've defined
var content = ContentService.GetById(guid); // ID of your page
// Get the page you want to assign to the document picker
var page = Umbraco.Content("665d7368-e43e-4a83-b1d4-43853860dc45");
// Create an Udi of the page
var udi = Udi.Create(Constants.UdiEntityType.Document, page.Key);
// Set the value of the property with alias 'featurePicker'.
content.SetValue("featurePicker", udi.ToString());
// Save the change
ContentService.Save(content);
}@{
// Get the page using it's id
var content = ContentService.GetById(1234);
}@using Umbraco.Cms.Core.PublishedCache
@inject IPublishedContentTypeCache PublishedContentTypeCache
@{
// Set the value of the property with alias 'featurePicker'
content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.FeaturePicker).Alias, udi.ToString());
}Schema Alias: Umbraco.ImageCropper
UI Alias: Umb.PropertyEditorUi.ImageCropper
Returns: MediaWithCrops
Returns a path to an image, along with information about focal point and available crops.
When the Image Cropper is used on a Media Type the crops are shared between all usages of a Media Item. This is called global crops.
If the Image Cropper is used on a Document Type, the file and crops will be local to the Document.
Notice that it is possible make local crops on shared Media Items via the Media Picker Property Editor.
You can add, edit & delete crop presets the cropper UI can use.
The Image Cropper provides a UI to upload an image, set a focal point on the image, and use predefined crops.
By default, images in the Image Cropper will be shown based on a set focal point and only use specific crops if they are available.
The Image Cropper comes with 3 modes:
Uploading an image
Setting a focal point
Cropping the image to predefined crops
The editor exposes a drop area for files. Select it to upload an image.
By default, the Image Cropper allows the editor to set a focal point on the uploaded image.
All the preset crops are shown to give the editor a preview of what the image will look like on the frontend.
The editor can fit the crop to the image to ensure that the image is presented as intended.
is image processing middleware for ASP.NET.
We bundle this package with Umbraco and you can therefore take full advantage of all its features for resizing and format changing. Learn more about the built in processing commands in .
The Image Cropper comes with an API to generate crop URLs. You can also access the raw data directly as a dynamic object.
For rendering a cropped media item, the .GetCropUrl is used:
The third parameter is HtmlEncode and is by default set to true. This means you only need to define the parameter if you want to disable HTML encoding.
Or, alternatively using the MediaWithCrops extension method:
Set the htmlEncode to false so that the URL is not HTML encoded
To update a content property value you need the .
The following sample demonstrates how to add or change the value of an Image Cropper property programmatically. The sample creates an API controller with an action, which must be invoked via a POST request to the URL written above the action.
If you use Models Builder to generate source code (modes SourceCodeAuto or SourceCodeManual), you can use nameof([generated property name]) to access the desired property without using a magic string:
Crop URLs are not limited to usage within a view. IPublishedContent has a GetCropUrl extension method, which can be used to access crop URLs anywhere.
The following sample demonstrates how to use GetCropUrl to retrieve URLs for all crops defined on a specific image:
Below the example to output a PNG using ImageSharp.Web command.
Information on using the Umbraco log viewer
Umbraco ships with a built-in Log Viewer feature. This allows you to filter, view log entries, perform complex search queries, and analyze logs for debugging. You can find the Log viewer in the Settings section of the Umbraco backoffice.
Umbraco's Log Viewer uses structured logging and a query language, so you can search for specific scenarios instead of scanning raw text. For example, finding every log entry tied to one request ID, or every entry where Duration exceeds 1000ms. This makes debugging and pattern-spotting easier.
Here are some example queries to help you get started. For more details on the syntax, see the project.
Find all logs that are from the namespace 'Umbraco.Core' StartsWith(SourceContext, 'Umbraco.Core')
Learn how to work with different types of Media content on your Umbraco website.
Media in Umbraco CMS is handled the same way as content. You define Media Types that act as a base for media items. The following default Media Types are available:
Article - used for uploading and storing documents.
Audio - used for uploading and storing digital audio files.
File - used for uploading and storing different types of files in the Media section.




<img src="@Url.GetCropUrl(Model.Photo,"square", true)" /><img src="@Url.GetCropUrl(Model.SecondaryPhoto, "customCropper", "banner")" /><img src="@Model.SecondaryPhoto.GetCropUrl("customCropper", "banner")" />@if (Model.Photo is not null)
{
<img src="@Url.GetCropUrl(Model.Photo, height: 300, width: 400)" alt="@Model.Photo.Name" />
}@if (Model.Photo is not null)
{
var cropUrl = Url.GetCropUrl(Model.Photo, "square", false);
<style>
.myCssClass {
background-image: url("@cropUrl");
height: 400px;
width: 400px;
}
</style>
<div class="product-image-container myCssClass"></div>
}using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Docs.Samples.Web.Property_Editors_Add_Values;
[ApiController]
[Route("/umbraco/api/createimagecroppervalues")]
public class CreateImageCropperValuesController : Controller
{
private readonly IContentService _contentService;
private readonly IMediaService _mediaService;
private readonly MediaUrlGeneratorCollection _mediaUrlGeneratorCollection;
private readonly IJsonSerializer serializer;
public CreateImageCropperValuesController(
IContentService contentService,
IMediaService mediaService,
MediaUrlGeneratorCollection mediaUrlGeneratorCollection, IJsonSerializer serializer)
{
_contentService = contentService;
_mediaService = mediaService;
_mediaUrlGeneratorCollection = mediaUrlGeneratorCollection;
this.serializer = serializer;
}
// /Umbraco/Api/CreateImageCropperValues/CreateImageCropperValues
[HttpPost("createimagecroppervalues")]
public ActionResult<bool> CreateImageCropperValues()
{
// Create a variable for the GUID of the page you want to update
var contentKey = Guid.Parse("89974f8b-e213-4c32-9f7a-40522d87aa2f");
// Get the page using the GUID you've defined
IContent? content = _contentService.GetById(contentKey);
if (content == null)
{
return false;
}
// Create a variable for the GUID of the media item you want to use
var mediaKey = Guid.Parse("b6d4e98a-07c0-45f9-bfcc-52994f2806b6");
// Get the desired media file
IMedia? media = _mediaService.GetById(mediaKey);
if (media == null)
{
return false;
}
// Create a variable for the image cropper and set the source
var imageCropperValue = new ImageCropperValue
{
Src = media.GetUrl("umbracoFile", _mediaUrlGeneratorCollection)
};
// Serialize the image cropper value
var propertyValue = serializer.Serialize(imageCropperValue);
// Set the value of the property with alias "cropper"
// - remember to add the "culture" parameter if "cropper" is set to vary by culture
content.SetValue("cropper", propertyValue);
return _contentService.Save(content).Success;
}
}// Set the value of the "Cropper" property on content of type MyContentType
// - remember to add the "culture" parameter if "cropper" is set to vary by culture
content.SetValue(nameof(MyContentType.Cropper).ToFirstLowerInvariant(), propertyValue);public Dictionary<string, string> GetCropUrls(IPublishedContent image)
{
// Get the Image Cropper property value for property with alias "umbracoFile"
ImageCropperValue? imageCropperValue = image.Value<ImageCropperValue>("umbracoFile");
if (imageCropperValue?.Crops == null)
{
return new Dictionary<string, string>();
}
// Return all crop aliases and their corresponding crop URLs as a dictionary
var cropUrls = new Dictionary<string, string>();
foreach (ImageCropperValue.ImageCropperCrop crop in imageCropperValue.Crops)
{
// Get the cropped URL and add it to the dictionary that I will return
var cropUrl = crop.Alias != null
? image.GetCropUrl(crop.Alias)
: null;
if (cropUrl != null)
{
cropUrls.Add(crop.Alias!, cropUrl);
}
}
return cropUrls;
}<img src="@Url.GetCropUrl(Model.Photo, 500, 300, furtherOptions: "&format=png")" />Find all logs that have the property 'Duration' and the duration is greater than 1000ms Has(Duration) and Duration > 1000
Find all logs where the message has localhost in it with SQL like @Message like '%localhost%'
If you frequently use a custom query, you can save it for quick access. Type your query in the search box and click the heart icon to save it with a friendly name. Saved queries are stored in the umbracoLogViewerQuery table in the database.
Umbraco allows you to implement a custom ILogViewerRepository and ILogViewerService to fetch logs from alternative sources, such as Azure Table Storage.
To fetch logs from Azure Table Storage, extend the LogViewerRepositoryBase class from Umbraco.Cms.Infrastructure.Services.Implement.
Azure Table Storage requires entities to implement the ITableEntity interface. Since Umbraco's default log entity does not implement this, a custom entity (AzureTableLogEntity) must be created to ensure logs are correctly fetched.
Create a new implementation of ILogViewerService. Amongst other things, this is responsible for figuring out whether a provided log query is allowed. Again a base class is available.
Umbraco needs to be made aware that there is a new implementation of an ILogViewerRepository and an ILogViewerService. These need to replace the default ones that are shipped with Umbraco.
With the above three classes, the setup is in place to view logs from an Azure Table. However, logs are not yet persisted into the Azure Table Storage account. To enable persistence, configure the Serilog logging pipeline to store logs in Azure Table Storage.
Install Serilog.Sinks.AzureTableStorage from NuGet.
Add a new sink to appsettings.json with credentials to persist logs to Azure.
The following sink needs to be added to the Serilog:WriteTo array.
This example uses the same Azurite-compatible connection string as the repository above, so the two stay in sync for local testing.
Replace it with your real Azure Storage connection string when deploying, for example: DefaultEndpointsProtocol=https;AccountName=ACCOUNT_NAME;AccountKey=KEY;EndpointSuffix=core.windows.net. Update the repository's connection string to match.
For more in-depth information about logging and how to configure it, see the Logging article.
Compact Log Viewer. A desktop tool is available for viewing and querying JSON log files in the same way as the built-in Log Viewer in Umbraco.
using Azure;
using Azure.Data.Tables;
using Serilog.Events;
using Serilog.Formatting.Compact.Reader;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Logging.Viewer;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.Logging.Serilog;
using Umbraco.Cms.Infrastructure.Services.Implement;
using LogLevel = Umbraco.Cms.Core.Logging.LogLevel;
namespace My.Website;
public class AzureTableLogsRepository : LogViewerRepositoryBase
{
private readonly IJsonSerializer _jsonSerializer;
public AzureTableLogsRepository(UmbracoFileConfiguration umbracoFileConfig, IJsonSerializer jsonSerializer) : base(
umbracoFileConfig)
{
_jsonSerializer = jsonSerializer;
}
protected override IEnumerable<ILogEntry> GetLogs(LogTimePeriod logTimePeriod, ILogFilter logFilter)
{
// This example uses a connection string compatible with the Azurite emulator
// https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azurite
var client =
new TableClient(
"UseDevelopmentStorage=true",
"LogEventEntity");
// Filter by timestamp to avoid retrieving all logs from the table, preventing memory and performance issues
IEnumerable<AzureTableLogEntity> results = client.Query<AzureTableLogEntity>(
entity => entity.Timestamp >= logTimePeriod.StartTime.Date &&
entity.Timestamp <= logTimePeriod.EndTime.Date.AddDays(1).AddSeconds(-1));
// Read the data and apply logfilters
IEnumerable<LogEvent> filteredData = results.Select(x => LogEventReader.ReadFromString(x.Data))
.Where(logFilter.TakeLogEvent);
return filteredData.Select(x => new LogEntry
{
Timestamp = x.Timestamp,
Level = Enum.Parse<LogLevel>(x.Level.ToString()),
MessageTemplateText = x.MessageTemplate.Text,
Exception = x.Exception?.ToString(),
Properties = MapLogMessageProperties(x.Properties),
RenderedMessage = x.RenderMessage(),
});
}
private IReadOnlyDictionary<string, string?> MapLogMessageProperties(
IReadOnlyDictionary<string, LogEventPropertyValue>? properties)
{
var result = new Dictionary<string, string?>();
if (properties is not null)
{
foreach (KeyValuePair<string, LogEventPropertyValue> property in properties)
{
string? value;
if (property.Value is ScalarValue scalarValue)
{
value = scalarValue.Value?.ToString();
}
else if (property.Value is StructureValue structureValue)
{
var textWriter = new StringWriter();
structureValue.Render(textWriter);
value = textWriter.ToString();
}
else
{
value = _jsonSerializer.Serialize(property.Value);
}
result.Add(property.Key, value);
}
}
return result;
}
public class AzureTableLogEntity : ITableEntity
{
public required string Data { get; set; }
public required string PartitionKey { get; set; }
public required string RowKey { get; set; }
public DateTimeOffset? Timestamp { get; set; }
public ETag ETag { get; set; }
}
}using System.Collections.ObjectModel;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Logging.Viewer;
using Umbraco.Cms.Core.Persistence.Repositories;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
using LogLevel = Umbraco.Cms.Core.Logging.LogLevel;
namespace My.Website;
public class AzureTableLogsService : LogViewerServiceBase
{
public AzureTableLogsService(
ILogViewerQueryRepository logViewerQueryRepository,
ICoreScopeProvider provider,
ILogViewerRepository logViewerRepository)
: base(logViewerQueryRepository, provider, logViewerRepository)
{
}
protected override string LoggerName => "AzureTableStorage";
// Change this to what you think is sensible.
// As an example, check whether more than 5 days of logs are requested.
public override Task<Attempt<bool, LogViewerOperationStatus>> CanViewLogsAsync(LogTimePeriod logTimePeriod)
{
return logTimePeriod.EndTime - logTimePeriod.StartTime < TimeSpan.FromDays(5)
? Task.FromResult(Attempt.SucceedWithStatus(LogViewerOperationStatus.Success, true))
: Task.FromResult(Attempt.FailWithStatus(LogViewerOperationStatus.CancelledByLogsSizeValidation, false));
}
public override ReadOnlyDictionary<string, LogLevel> GetLogLevelsFromSinks()
{
var configuredLogLevels = new Dictionary<string, LogLevel>
{
{ "Global", GetGlobalMinLogLevel() },
{ "AzureTableStorage", LogViewerRepository.RestrictedToMinimumLevel() },
};
return configuredLogLevels.AsReadOnly();
}
}using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Infrastructure.DependencyInjection;
using Umbraco.Cms.Core.Services;
namespace My.Website;
public class AzureTableLogsComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
builder.Services.AddUnique<ILogViewerRepository, AzureTableLogsRepository>();
builder.Services.AddUnique<ILogViewerService, AzureTableLogsService>();
}
}{
"Name": "AzureTableStorage",
"Args": {
"storageTableName": "LogEventEntity",
"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact",
"connectionString": "UseDevelopmentStorage=true"
}
}The connection string above must match the one used by the Serilog sink configured in . If the two point at different storage accounts, this repository queries a table that was never written to. The Log Viewer then fails with an error stating the table does not exist. Read the connection string from configuration rather than hardcoding it, so both sides always agree.
Folder - a container for organizing media items in the Media section tree.
Image - used for uploading and storing images.
Vector Graphics (SVG) - used for uploading and storing Scalable Vector Graphics (SVG) files which are text files containing source code to draw the desired image.
Video - used for uploading and storing video files.
The default Media Types aim to cover most needs for media on a website. You do not need to define your Media Types to start using the Media section. The tools for organizing and uploading the media are already in place.
You can upload media in two different ways:
From the Media section in the Umbraco backoffice, you can add new media items by following either of the approaches defined below:
Use the Create dialog to create a new Media item in the Media section
The Media item will be created based on the type you choose.
Upload the image or file, give the Media item a name, and click Save.
Use the Drag and drop feature to add your files to the Media section.
Umbraco will automatically detect the Media Type and create the Media item.
You can drop entire folder structures to recreate that same structure in the Media section.
New media items can be added to your site without interrupting the content creation flow. This can be done following either of the two approaches outlined below.
Drag and drop the image(s) from your file explorer directly into the Media Picker property on the Content page.
Images added this way is automatically added to the user's start node in the Media section of the Umbraco backoffice.
Select the "+" icon to open the "Select media" dialog where you can add images from your file explorer directly or using drag and drop.
It is always a good idea to start by creating a folder for your media items. It can be a good idea to align these folders with the content on your website. This will give the editors a better overview of the files and enable them to upload media items in the correct place.
Follow these steps to create a folder in the Media section:
Go to the Media section.
Select ... next to Media.
Select Create.
Select Folder.
Enter a name for the folder and select Save in the bottom-right corner.
The Image Media Type has 5 properties: Upload Image, Width, Height, Size, and Type. These are populated once the image is uploaded. The properties can be viewed in the Media section and accessed in your Templates.
Except for the Folder Media Type, the other Media Types have 3 properties: Upload Image, Type, and Size.
Learn more about each Media Type in the article about default Media Types.
The default view for the Media section is a card view that lets you preview the different files that have been uploaded.
By selecting multiple media items it is possible to perform bulk operations like moving or deleting the items.
To edit properties on a single media item, click the name of the item, which you will see once you hover over the item.
From the top-right corner of the Media section, you can toggle between the list and grid view. There is also an option to search for the items in the Media section.
By adding a Media Picker property to a Document Type the editor will have the ability to select media items when creating content.
You can create custom Media Types and control the structure of the Media tree as you would with Document Types. This means you can store information that is specific to the media on the item itself.
A Media Type is created in the Settings section using the Media Type editor.
Go to the Settings section.
Click ... next to Media Types.
Click Create > New Media Type.
Name the new Media Type Employee Image.
Choose an icon by selecting the icon left of the name field.
You will now see the Media Type editor. It is similar to the editor used for creating Document Types.
Before we start adding properties to the Media Type we need to add a group to put these in.
Click on Add group.
Call the group Image.
We need to add the same properties as on the default Image Media Type. These are:
umbracoFile
umbracoWidth
umbracoHeight
umbracoBytes
umbracoExtension
Follow the steps outlined below to add the properties to the Media Type:
Click Add property.
Name it Upload image.
Change the alias to umbracoFile.
Click Select property editor.
Select Image cropper.
Rename the editor Employee Image Cropper.
Add two new crops called Thumbnail (200px x 350px) and wideThumbnail (350px x 200px).
8. Click Save. 9. Click Add. 10. Name the remaining four properties Width, Height, Size, and Type, and give them the aliases as mentioned above. They should all use the Label editor.
As mentioned before these properties will automatically be populated once an image has been uploaded.
Next up, we will create a folder to hold the employee images. We could use the existing Folder Media Type but that would mean editors can upload employee images to any folder of that type. If we create a folder specifically for employee images there is only one place to put them.
Go back to the Settings section and create a new Media Type.
Name it Employee Images.
Select the folder icon by clicking the icon to the left of the name.
Navigate to the Structure tab.
Click Configure as a Collection under Presentation.
Choose List view - Media.
Click Save.
The new folder is created under the Media Types folder. We also need to only allow the Employee Image Media Type in our new folder. Both of these configurations can be set on the Structure tab.
Go to the Structure tab of the Employee Images folder.
Toggle the Allow at root.
Click Choose in the Allowed Child Node Types.
Select Employee Image.
Click Choose.
Go to the Media section.
Select ... next to Media.
Click Create > Employee Images folder.
Name it Employee Images.
Click Save.
If you select an image that has been uploaded to the folder you will see the full image and the two defined crops.
Moving the focal point circle on the image will update the crops to focus accordingly. You can also edit the individual crops by selecting them and moving the image or adjusting the slider to zoom.
In this article you can learn the various ways of customizing the Umbraco backoffice login screen and form.
To access the backoffice, you will need to login. You can do this by adding /umbraco at the end of your website URL, for example http://mywebsite.com/umbraco.
You will be presented with a login form similar to this:
The login screen contains a short greeting, a login form and an optional Forgotten password link.
Below, you will find instructions on how to customize the login screen.
The login screen features a greeting text: The "Welcome" headline. This can be personalized by overriding the existing language translation keys.
Register a 'localization' manifest for the default language of your Umbraco site (default: en-US).
Provide the new strings inline under meta.localizations:
Adding the code above will override the default greetings with the ones you provide. The login screen will now display "Happy super Sunday" on Sundays instead of "Welcome".
You can customize other text on the login screen as well. Grab the default values and keys from the dictionary in the Umbraco CMS GitHub repository — look under the login group. Then copy the ones you want to translate into your en-us.js file.
The Forgotten password? link allows your backoffice users to reset their password. To use this feature, you will need to add the following key to the Umbraco.Cms.Security section in the appsettings.json file:
Set it to true to enable the password reset feature, and false to disable the feature.
You will also need to configure a Simple Mail Transfer Protocol (SMTP) server in your appsettings.json file. When you get a successful result on the SMTP configuration when running a health check in the backoffice, you are good to go!
An example:
It is possible to customize the background image and the logo for the backoffice login screen by adding the "Content" section in the appsettings.json file:
The LoginBackgroundImage, LoginLogoImage, and LoginLogoImageAlternative are referenced from the /wwwroot/umbraco/ folder.
The LoginLogoImage is displayed on top of the LoginBackgroundImage and the LoginLogoImageAlternative is displayed when the LoginLogoImage is not available, for example on small resolutions.
You can also customize the login screen by adding a custom CSS file. To do this, you will need to add a new file inside the ~/App_Plugins folder, for example ~/App_Plugins/Login/my-custom-login-screen.css.
You can then add your custom CSS to the file:
This will change the color of the SVG graphics (curves) shown on the login screen. You can also hide the curves by adding the following CSS:
To tell Umbraco about your custom CSS file, you will need to add a umbraco-package.json file. The umbraco-package.json file should look like this:
Next add a JavaScript file, for example ~/App_Plugins/Login/my-custom-login-screen.js, and add the following code to load the custom CSS file:
This will load the custom CSS file into Umbraco.
The following CSS properties are available for customization:
The CSS custom properties may change in future versions of Umbraco. You can always find the latest values in the in the Umbraco CMS GitHub repository.
The time out screen is displayed when the user has been inactive for a certain amount of time. The screen resembles the login screen in many ways and the two are sometimes confused. The most notable difference is that the time out screen does not have a login form. It only has a message and a button to log in again with Umbraco.
If you have added more than one login provider, the users will also see this screen first. This is because they need to choose which provider to use first. In that case, the screen is also referred to as the Choose provider screen.
You can customize the timeout screen in the same way as the login screen. Both screens share the same backoffice localization dictionary. The login.* keys you override for the login screen automatically apply to the timeout screen as well.
The greeting on the time out screen uses the same login.greeting0..6 and login.instruction keys as the login screen — override them as shown in the section above. The instruction key is shown when the user has timed out, and the greeting0..6 keys are shown when the user has to choose a login provider.
You can update the image on the time out screen through a custom CSS variable. The default value is --umb-login-image and it is set to the same value as the login screen. You can override this value in your custom CSS file:
Describes how to upgrade existing installations to new versions.
In this article, you will find everything you need to upgrade your Umbraco CMS project.
If you are new to upgrades, be sure to read the upgrade introduction article first.
You can upgrade to a new major version of Umbraco CMS directly by using NuGet.
You must upgrade to the closest version before upgrading to the latest version. For Umbraco 13, the closest long-term support version is Umbraco 17. Once the project is on Umbraco 17, you can move on to Umbraco 18.
Umbraco 18 can't upgrade from versions older than 16.4, so a project on Umbraco 13 must upgrade to Umbraco 17 first.
Use the table below to determine which .NET version to upgrade to when going through the steps below.
It's recommended that you upgrade the site offline and test the upgrade fully before deploying it to the production environment.
Stop your site in IIS to prevent any changes from being made while you are upgrading.
Open your Umbraco project in Visual Studio.
Right-click on the project name in the Solution Explorer and select Properties.
Select the .NET version from the Target Framework drop-down.
Make sure that your connection string has TrustServerCertificate=True to complete the upgrade successfully:
Restart your site in IIS, then build and run your project to finish the installation.
If you receive an error that a deploy license is missing even though you have a valid license, follow the guide below.
Google Chrome has aggressive caching, so when experiencing startup issues, clear the cache and cookies thoroughly. Ideally, this should be done for other browsers as well.
Nudge the cache in Chrome following these steps:
Open the developer tools (F12).
Go to the settings (Cog icon).
Ensure that "Disable cache (while DevTools is open)" is checked.
Refresh the page, and the cache will be invalidated.
All caches and cookies have now been cleared from your Google Chrome browser. Generally, it is a good thing to do occasionally.
NuGet installs the latest version of the package when you use the dotnet add package command unless you specify a package version:
dotnet add package Umbraco.Cms --version <VERSION>
Add a package reference to your project by executing the dotnet add package Umbraco.Cms command in the directory that contains your project file.
Run dotnet restore to install the package.
When the command completes, open the .csproj file to make sure the package reference was updated:
The steps outlined in this article apply to Umbraco version 10 and later versions.
Are you upgrading to a minor version for Umbraco 6, 7, or 8? You can find the appropriate guide below:
Instructions on installing nightly builds of Umbraco.
Nightly builds are pre-releases and may be unstable. Do not use them in production environments.
This article covers how to get the latest builds of Umbraco. You can do this in three steps:
The nightly builds are available on the following NuGet feed: https://www.myget.org/F/umbraconightly/api/v3/index.json.
You can either add the feed through the command line or use an IDE of your choice.
This article covers the following options:
Follow these steps to add the nightly feed using the command line:
Open a command prompt of your choice.
Run the following command:
Now the feed is added as a source named Umbraco Nightly.
Follow these steps to add the nightly feed using Visual Studio:
Open Visual Studio.
Go to Tools > NuGet Package Manager > Package Manager Settings.
Select the Package Sources option in the NuGet Package Manager section.
Click the +
Now the feed is added as a source named Umbraco Nightly.
Follow these steps to add the nightly feed using Rider:
Open Rider.
Go to View > Tool Windows > NuGet.
Go to Sources tab.
Select the global NuGet.Config
Click OK.
Now the feed is added as a source named Umbraco Nightly.
The next step is to identify which nightly build to install.
However, which version do you choose? This is especially relevant when creating a new site using the dotnet template. The dotnet command does not allow for using wildcard characters to install the newest version.
Using an IDE, you can see a list of available versions in both Visual Studio and Rider. Use these versions to install the template you need.
The following steps apply to creating a new site using the dotnet template. The approach is the same if you're updating an existing site. You'll click the Update button for the Umbraco.Cms package instead of installing the template through the terminal.
Find the latest version of the nightly build using either of the following options:
Use the package manager in Visual Studio to browse the available template versions.
Open Visual Studio.
Go to Tools > NuGet Package Manager > Manage NuGet Packages For Solution...
Select Umbraco Nightly from the Package source dropdown in the NuGet - Solution window.
Use the NuGet window in Rider to browse the available template versions.
Open Rider.
Go to the Packages tab in the NuGet window.
Select Umbraco Nightly from the All Feeds dropdown.
Check the Prerelease checkbox.
To install the latest nightly version template:
Open the command prompt/terminal.
Run the following command, replacing the version with the one you noted in the previous step:
You can now create a site using the dotnet new umbraco -n MyAwesomeNightlySite command.
For more information about installing Umbraco, see the article.
The Umbraco Rich Text Editor (RTE) is a field where you, as an editor, can be creative. You can select how much you want to do yourself. You can work on text content, format the text, or leave it the way it is. If you want to do more, you can insert images, create tables, or create links to other pages/documents.
The functionality varies depending on how the editor is set up. Here, we describe the default editor with all the options enabled. Contact your system administrator for details regarding your editor.
By default, the following editor buttons are available. Your system administrator can determine which buttons are displayed in different templates. You therefore might have access to more or fewer buttons than those shown here.
The Rich Text Editor is like any other word-processing program. You write the text and the text wraps around when the line reaches the end. Use the following keyboard shortcuts in the editor to add:
Space between paragraphs - press ENTER
Here you'll find an explanation of how content is defined in Umbraco
Before a piece of content can be created in the Umbraco backoffice, first it needs to be defined. That is why, when opening a blank installation of Umbraco, it is not possible to create content in the Content section.
All content needs a blueprint that holds information about what kind of data can be stored on the content node or which editors are used.
Additionally, it also needs information on how it is organized, where in the structure it is allowed, and so forth. This blueprint or definition is called a Document Type.
Document Types define what kind of content can be created in the Content section and what an end-user sees and can interact with.
It can define entire pages or more limited content that can be reused on other nodes ie. a Search Engine Optimization (SEO) group. This means that you are in complete control of what type of content can be created and where.
Another example is if there is a "Blog post" Document Type that has some properties containing a thumbnail, a name, and an author image. Then all blog posts using the "Blog post
15
9.0
14
8.0
13
8.0
12
7.0
11
7.0
10
6.0.5
Go to Tools > NuGet Package Manager > Manage NuGet Packages for Solution...
Go to the Installed tab in the NuGet Package Manager.
Upgrade Umbraco.Cms.
a. Select the correct version from the Version drop-down.
b. Click Install to upgrade your project.
Right-click the "reload" button next to your address bar and choose "Empty cache and hard reload".
18
10.0
17
10.0
16
Switching to a new major version of Umbraco CMS also means switching to a new .NET version. Ensure that any packages used on your site are compatible with this version before upgrading.
The package compatibility can be checked on the package's download page. Locate the Project compatibility area and select View details to check version-specific compatibility.
If your database experiences timeout issues after an upgrade, it might be due to the ASP.NET Core Module's startupTimeLimit configuration.
To fix the issue, try increasing the startupTimeLimit in the web.config file. Additionally, you can set the Connection Timeout value in the ConnectionString in the appsettings.json file.
For Umbraco 9
If you are using SQL CE in your project, you need to run dotnet add package Umbraco.Cms.SqlCe --version <VERSION> before the dotnet restore command. From Umbraco 10, SQL CE has been replaced with SQLite, so a dotnet restore should be sufficient. If this is not working, then you need to run dotnet add package Umbraco.Cms.Persistence.Sqlite --version <VERSION> , and then dotnet restore.
9.0
Enter the desired name for the feed in the Name field.
Enter the link https://www.myget.org/F/umbraconightly/api/v3/index.json into the Source field.
Click OK.
Click the green + button in the New Feed field.
Enter the desired name in the Name field.
Enter https://www.myget.org/F/umbraconightly/api/v3/index.json in the URL field.
Search for Umbraco.Templates in the Browse field.
Choose that package.
Click on the Version dropdown and see the available nightly builds.
Choose the applicable version and note down the version number.
Search for Umbraco.Templates in the Search field.
Choose that package.
Click on the Version drop down and see the available nightly builds.
Choose the applicable version and note down the version number.
"ConnectionStrings": {
"umbracoDbDSN": "Server=YourLocalSQLServerHere;Database=NameOfYourDatabaseHere;User Id=NameOfYourUserHere;Password=YourPasswordHere;TrustServerCertificate=True"
}<ItemGroup>
<PackageReference Include="Umbraco.Cms" Version="x.x.x" />
</ItemGroup>dotnet nuget add source "https://www.myget.org/F/umbraconightly/api/v3/index.json" -n "Umbraco Nightly"dotnet new install Umbraco.Templates::X.Y.Z--build.N#283a97
--umb-login-text-color
The color of the text
#000
--umb-login-header-font-size
The font-size of the headline
3rem
--umb-login-header-font-size-large
The font-size of the headline on large screens
4rem
--umb-login-header-secondary-font-size
The font-size of the secondary headline
2.4rem
--umb-login-image
The background of the image wrapper
The value of the setting
--umb-login-image-display
The display of the image wrapper
flex
--umb-login-image-border-radius
The border-radius of the image wrapper
38px
--umb-login-content-background
The background of the content wrapper
none
--umb-login-content-display
The display of the content wrapper
flex
--umb-login-content-width
The width of the content wrapper
100%
--umb-login-content-height
The height of the content wrapper
100%
--umb-login-content-border-radius
The border-radius of the content wrapper
0
--umb-login-align-items
The align-items of the main wrapper
unset
--umb-login-button-border-radius
The border-radius of the buttons
45px
--umb-login-curves-color
The color of the curves
#f5c1bc
--umb-login-curves-display
The display of the curves
inline
{
"alias": "login.extensions",
"name": "Login extensions",
"version": "1.0.0",
"allowPublicAccess": true,
"extensions": [
{
"type": "localization",
"alias": "Login.Localize.EnUS",
"name": "English",
"meta": {
"culture": "en-US",
"localizations": {
"login": {
"instruction": "Log in again to continue",
"greeting0": "Happy super Sunday",
"greeting1": "Happy manic Monday",
"greeting2": "Happy tubular Tuesday",
"greeting3": "Happy wonderful Wednesday",
"greeting4": "Happy thunderous Thursday",
"greeting5": "Happy funky Friday",
"greeting6": "Happy Caturday"
}
}
}
}
]
}"Umbraco": {
"CMS": {
"Security": {
"AllowPasswordReset": true
}
}
}"Umbraco": {
"CMS": {
"Global": {
"Id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"Smtp": {
"From": "[email protected]",
"Host": "127.0.0.1",
"Username": "username",
"Password": "password"
}
}
}
}"Umbraco": {
"CMS": {
"Content": {
"LoginBackgroundImage": "../myImagesFolder/myLogin.jpg",
"LoginLogoImage": "../myImagesFolder/myLogo.svg",
"LoginLogoImageAlternative": "../myImagesFolder/myLogo.svg"
}
}
}:root {
--umb-login-curves-color: rgba(0, 0, 0, 0.1);
}:root {
--umb-login-curves-display: none;
}{
"alias": "login.extensions",
"name": "Login extensions",
"version": "1.0.0",
"allowPublicAccess": true,
"extensions": [
{
"type": "appEntryPoint",
"alias": "MyCustomLoginScreen",
"name": "My Custom Login Screen",
"js": "/App_Plugins/Login/my-custom-login-screen.js"
}
]
}const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = '/App_Plugins/Login/my-custom-login-screen.css';
document.head.appendChild(link);--umb-login-background
The background of the layout
#f4f4f4
--umb-login-primary-color
:root {
--umb-login-image: url(../myImagesFolder/myTimeout.jpg);
}Be aware that the custom CSS file will be loaded on all Umbraco screens, not only the login screen.


The color of the headline
Line breaks - press SHIFT + ENTER.
To make your work easier, there are shortcut keys for certain editor functions. Use the following shortcut keys to carry out certain commands:
Ctrl + A
Cmd + A
Select all
Ctrl + B
Cmd + B
Only a few keyboard shortcuts are listed here. For a detailed list of available shortcuts, see the Tiptap Documentation.
If you are proficient in HTML, you can switch to HTML mode to create your page. You can also check the code and make minor adjustments to get the page exactly as you want.
Certain elements such as scripts are not recognized by the HTML view of the Rich Text Editor. You can enter the scripts directly in the text view of the editor.
You can apply formatting via the Formats drop-down list. The Formats drop-down list provides predefined styles that can be applied to text while maintaining a consistent look and feel throughout the site.
These styles incorporate advanced formatting functionality which can be applied to provide a different look for certain elements such as links, headings, and sub-headings. For example, you can use a format style to change a link into a call-to-action button.
To apply pre-defined styles:
Select the text you want to apply the style.
Choose the style from the Format drop-down list.
For more information on how to create styles, see the Style Menu article.
You do not normally need to spend much time formatting text because Umbraco takes care of the formatting. However, the editor provides some options for controlling the text styles.
The most familiar way to control formatting is by using the formatting buttons. With these buttons, you can apply basic formatting such as Bold, Italic, aligning text, creating bulleted and numbered lists, and applying indents.
To apply a format using the formatting buttons:
Select the text you want to apply the formatting.
Click the desired format button.
While pasting content, the original text styles are preserved which can lead to different font faces, sizes, and colors displaying on the website when viewed.
If you have already formatted a paragraph or selection using the formatting buttons, you can remove the formatting rule.
To remove formatting:
Select the text you want to remove the style from.
Click the relevant formatting button to remove the formatting rule.
You can also add a Remove format button in your toolbar. To add the Remove format button:
Navigate to your Rich Text Editor in the Document Type.
Click the cog wheel.
Click Edit next to the Rich Text Editor Data Type.
Select Remove format under the Toolbar Configuration.
Click Submit.
Click Save.
The Insert/Edit Link button is used to add or update links to internal pages, external pages, media files, email links, and anchors. The process for inserting a hyperlink differs depending on the type of hyperlink you wish to create.
To insert different types of hyperlinks, follow these steps:
To display images on a page the images must be uploaded to your Umbraco media library.
Many administrators set up a media library containing images that editors can use on their pages. Others allow their editor's free use of their images. The procedure for uploading an image varies slightly depending on which method your administrators have setup. Check with your system administrator for more information about this.
Tables are used to format information in a grid-based structure. When you insert a table, you select how many rows and columns the table should comprise of. Additionally, you can fill in some optional formatting properties. These values can be changed later, so it is not important to know exactly what your table will look like when you create it.
When you place the mouse courser within the table, you will see three dots either horizontally or vertically placed on the edges of the table. Click these to open configuration options for that specific row or column.
To edit the table properties after creating it follow these steps:
Place the mouse courser in the table.
Click on the Table button in the Rich Text Editor toolbar.
Select Table Properties.
Clicking on Table Properties gives you different options for modifying the table’s appearance. However, the developer of the website may have already created table styles for you so you may not need to adjust these settings.
There are other options available for modifying cells, rows, and columns such as width, height, alignment, border, and so on.
The Rich Text Editor in Umbraco can be configured in many different ways.
For more information, see the Rich Text Editor Configuration article.

A Document Type contains fieldsets (or groups) where you can apply rules about where the content can be created, allowed template(s), backoffice icons, etc.
A Document Type is created using the Document Type editor in the Settings section.
Go to the Settings section in the backoffice.
On the Document Types node click the + to bring up the Create menu.
Here choose Document Type with Template. This will create a new Document Type with a template. The Template can be found under Templates in the Settings section which will be assigned as the default template for the Document Type.
You can also choose to create a Document Type without a template and create Folders to organize your Document Types. Other options are to create Compositions and Element types, which you can read more about in the Document Type Options section.
First, we're prompted to give the Document Type a name. This first Document Type will be the root node for our content, name it "Home".
Having a root node lets you quickly query content as you know everything will be under the root node.
Choosing appropriate icons for your content nodes is a good way to give editors a better overview of the content tree.
To set an icon for the Document Type click the document icon in the top left corner. This will open the icon select dialog. Search for "Home"and select the icon. This icon will be used in the content tree.
This will allow this Document Type to be created as the first content in the Content section.
Go to the Structure tab
Tick the Allow as root toggle
Save the Document Type by clicking save in the bottom right corner.
Now that we have the Document Type in place, we can create the content.
Go to the Content section
Click on + next to Content.
Select the "Home" Document Type. Name it "Home"
Click Save and Publish.
As we haven't created our properties, all we can see on the "Home" node is the Properties tab. This tab contains the default properties that are available on all content nodes in Umbraco.
Let's add some properties of our own.
In order to add the option to create different content on the same Document Type, some groups and properties need to be added.
Groups
Groups are a way to organize and structure the properties within the content, making it more manageable. It also makes it more user-friendly for content editors when creating or editing content on a website.
A name can be added to the group and after properties can be added.
Properties
Each field on a Document Type is called a property. The property is given a name, an alias (used to output the properties contained in a template), and an editor.
The editor determines what type of data the property will store and the input method. There is a wide range of default property editors available and you can customize additional editors.
Some editors require configuration where a configured editor is saved as a Data Type and can be reused for multiple properties and document types. These can be seen in the Settings section under Data Types.
Go to the Settings section.
Expand Document Types by clicking the arrow to the left.
Select the "Home" Document Type.
It is recommended to sort the properties into groups, however this is not a requirement.
Create a group to hold the first properties for the Home Document Type:
Click Add group and name the group "Content".
To convert a group to a tab, see the Convert a group to a tab section in the Using Tabs article.
Now that we have created a group we can start adding properties. Let's add a Rich Text editor to the Content group.
Click the Add property link in the Content group. This opens the property settings dialog. Here you can set the metadata for each property (name, alias, description)
Choose which Property Editor to use, and add validation if needed.
Give the property a name. The name will be shown to the editor to make it relevant and understandable. Notice the alias is automatically generated based on the name. We'll name this "Body Text".
Clicking Select Editor will open the Select Editor dialog. Here, you can choose between all the available editors on the Create a new Configuration tab. This will create a new configuration or already configured editors in the Available Configurations tab.
To make it easier to find what you need use the search field to filter by typing "Rich". Filtering will display configured properties first (under Available configurations) and all available editors under that.
Select the Rich Text editor under Create new. This will let you configure the editor settings - the Rich Text editor for this property.
Let's rename it to "Basic Rich Text editor" and only select the most necessary options.
bold
italic
alignLeft
alignCenter
link
umbMediaPicker
When you are happy with the settings click Submit.
Save the Document Type.
If you go to the Content section and click on the Home node you will now see the Contentgroup with the Body Text property.
The description of the property is not necessary, but it´s a best practice as it guides the editor to use the property correctly. The property description supports some markdown and one custom collapse syntax:
Now if we put it all together we get something like this:
Next up we'll create a text page Document Type that will be used for subpages on the site.
Go back to the Settings section
Create a new Document Type
Name it "Text Page".
Add a group called "Content"
This time we'll add two properties:
First, make a property called "Summary" using the Textarea editor
Secondly, create a property called "Body Text" and reuse the Rich Text Editor Data Type.
Before creating a Text Page in Content section, allow the Text Page Document Type to be created as a child node to the Home node.
Select the "Home" Document Type
Go to the Structure group.
Click Choose
Select "Text Page".
Go to the Content section
Click the menu icon (•••) next to the "Home" node
Select the "Text page" Document Type. We'll name the page "About us". We now have a basic content structure.
Document Types are flexible and can be used for defining pieces of reusable content or an entire page, to act as a container or repository.
You can export Document Types from an already existing project/installation and import them into another project/installation.
Go to the Settings section
Click ... next to the Document type
Select Export. When you click on the Export button, the Document Type is saved as a *.udt file.
To import a Document Type:
Go to the Settings section
Click ... next to the Document type
Select Import Document Type
Click on the Import button and browse to the Document Type you exported. The Name and Alias of the Document Type are displayed.
Click Import to complete the process.
This is **bold**
This is *italic*
[This is an absolute link](https://umbraco.com/)
[This is a relative link](/umbraco/section/media)
<details>
<summary>Read more</summary>

</details>













This article covers the topic of composing in Umbraco.
Customising the behaviour of an Umbraco Application at 'start up'. for example adding, removing, or replacing the core functionality of Umbraco or registering custom code to subscribe to notifications.
An Umbraco application is a Composition made of many different 'collections' and single items of specific functionality/implementation logic/components (eg. UrlProviders, ContentFinders - see below for a full list). These collections are populated when the Umbraco Application starts up.
'Composing' is the term used to describe the process of curating which pieces of functionality should be included in a particular collection. The code that implements these choices at start up is called a Composer.
A Component is a generic wrapper for writing custom code during composition, it has two methods: Initialize() and Terminate()
A guide displaying the options available in the Settings section in Umbraco CMS backoffice.
The Settings section of the Umbraco backoffice has its own set of default dashboards. In this article, you can get an overview of each dashboard available in the Settings section:












This is **bold**This is *italic*[This is an absolute link](https://umbraco.com/)
[This is a relative link](/umbraco/section/media)<details>
<summary>This is displayed</summary>
This is hidden.
</details>Enter the URL of the web page you wish to link to in the Link field.
Enter the text that will be displayed as the link title in the Link Title field.
This is important information for everyone reading the website with different accessibility aids.
Select the Target field to open the link in a new window or tab.
Click Submit.
Select a page from the Link to page field.
This will populate the Link and Link Title fields automatically.
Select the Target field to open the link in a new window or tab.
Click Submit.
Select the Link to Media button to select the media item.
Click Select.
This will automatically populate the Link and Link Title fields with the media item information.
By default, the Link field contains the media file name and cannot be edited.
Select the Target field to open the link in a new window or tab.
Click Submit.
Enter the text mailto: followed by the email address you wish to link to in the Link field. For example, mailto:[email protected].
Enter the text that will be displayed as the link title in the Link Title field.
Select the Target field to open the link in a new window or tab.
Click Submit.
Enter your anchor name in the ID field.
You should avoid special characters and spaces.
Click Save.
You will see a small anchor icon where you previously had the editor cursor.
To delete the anchor:
Select the anchor icon.
Press your Delete key.
Linking to an Anchor
Select the text to which you wish to add the anchor link to.
Click the Insert link button to open the link properties slide-out menu.
Add a hash symbol (#) followed by the name of your anchor in the Anchor/querystring field.
Enter the text that will be displayed as the link title in the Link Title field.
Click Submit.
Select the image that will form the hyperlink.
Enter the URL of the web page you wish to link to in the Link field.
Enter the text that will be displayed as the link title in the Link Title field.
Select the Target field to open the link in a new window or tab.
Click Submit.
Click the Remove Link button which will remove the hyperlink.
Alternatively, you can click the Insert/Edit Link button and remove the link from the Link field.
Select the folder in which the image is.
Click the thumbnail of your chosen image to open the image properties menu.
Enter a name/description for the image in the Caption (optional) field.
It is important to add descriptive titles to images as these are used to assist visually impaired users.
Click Select.
Click the Upload button which is located in the top right-hand corner of the menu.
Select the chosen image from the pop-up window.
Enter a name/description for the image in the Caption (optional) field.
Click Select.
The image disappears from the page but is not deleted from the Umbraco Media library.
Bold
Ctrl + I
Cmd + I
Italic
Ctrl + U
Cmd + U
Underline
Ctrl + C
Cmd + C
Copy
Ctrl + V
Cmd + V
Paste
Ctrl + Shift + V
Cmd + Shift + V
Paste without formatting
Ctrl + X
Cmd + X
Cut
Ctrl + Z
Cmd + Z
Undo
Ctrl + Shift + Y
Cmd + Shift + Z
Redo














ComponentUmbracoApplicationStartingNotificationUmbracoApplicationStoppingNotificationHow are the collections populated? - Either by scanning the codebase for c# classes that inherit from a particular base class or implement a particular interface (typed scanned) or by being explicitly registered via a Composer.
Umbraco setup the default set of components and collections that deliver the core 'out of the box' Umbraco behaviour. These default collections can be removed, reordered, replaced, etc. by implementing IComposer's and IComponents to customise and extend Umbraco's behaviour.
This example shows how to create a component and a notification handler for the ContentSavingNotification, (perhaps to check for explicit words, or some custom business logic that needs to run before the content item is saved in Umbraco).
We create a new C# class that implements IComposer and use it register our notification handler.
This example shows a custom 'Spotify' OEmbed Provider which will allow Spotify URLs to be used via the 'embed' button in the Rich Text Editors. As the collection for OEmbedProviders is not 'typed scanned', we need to explicitly register the provider in the collection of OEmbedProviders. We create a C# class which implements IComposer and append our new Spotify OEmbedProvider to the EmbedProvidersCollection:
See a list of collections below to determine which are 'type scanned' and which require explicit registration.
It's an implementation of IComposer, that provides a quicker way to add a custom component to the Component's collection. Creating a C# class that inherits from ComponentComposer<YourComponentType> will automatically add YourComponentType to the collection of Components. In the example above, the SubscribeToContentServiceSavingComposer for the SubscribeToContentServiceSavingComponent could have been written more conveniently as:
"Collections of elements", for example, the ContentFinders collection. - Collections are another concept that Umbraco uses to make things simpler, on top of DI. A collection builder builds a collection, allowing users to add and remove types before anything is registered into DI.
Below is a list of collections with their corresponding 'collection type' and how items for this collection 'out of the box' are registered.
Actions
Lazy
Type scanned for IAction
Set
SetCollectionBuilderBase
The base class for collection builders that do not order their items explicitly.
Ordered
OrderedCollectionBuilderBase
This example shows how to control which Healthchecks are available to run in the Umbraco backoffice. Create a C# class which implements IComposer, the Compose method gives access to the HealthChecks collection of the Umbraco Composition - first we clear all HealthChecks from the collection, then add back in the ones we want to keep:
Umbraco has some useful C# attributes to decorate your composer classes or Types used in collections, to give you further control on how and when your Composers will 'compose'.
A finer-grain mechanism can then be used to refine the order of composition. Each composer can specify that it should compose before or after another composer, using the ComposeBefore and ComposeAfter attributes. For instance:
ThisComposer will 'compose' before ThatOtherComposer.
This attribute is used only for WeightedCollectionBuilders (see list above). It specifies an integer ordinal value for each item to be added to the weighted collection which controls their sort order. The weighting attribute is not applied to the Composers.
This is used to hide a type from being auto-scanned/added to a collection as in some cases certain items/types may need to be added to a collection manually. For example, a Search package may make it optional whether to replace the 'backoffice search' with an ISearchableTree implementation. Type scanning would make this change automatically at start up if the custom implementation was detected via type scanning. This attribute could hide the class from the scanner.
These attributes allow you to disable a particular implementation of a composer or class - Let's say Umbraco ships with two different ways of doing "something" (for instance, two front-end caches). Each way has its own composer, which registers all the relevant elements. Keep in mind that if both composers are detected, there will be some sort of collision. Ideally, we want to disable one of them. That can be achieved with the Disable attribute:
When used without arguments, these attributes apply to the composer they are marking. But, and this is where it becomes interesting, they can be used with an argument to act on another component. Therefore, should a user want to replace our "something" with theirs, they would write the following code:
But maybe they want to swap our two "something" implementations? In this case, assembly-level attributes can be used:
The Umbraco.Cms.Core.RuntimeLevel enum contains the following values:
BootFailed
The runtime has failed to boot and cannot run.
Unknown
The level is unknown.
Boot
The runtime is booting.
Install
The runtime has detected that Umbraco is not installed at all, ie. there is no database, and is currently installing Umbraco.
Upgrade
The runtime has detected an Umbraco install which needed to be upgraded, and is currently upgrading Umbraco.
Run
The runtime has detected an up-to-date Umbraco install and is running.
BootFailed
The runtime has failed to boot and cannot run.
Unknown
The level is unknown.
Boot
You may wish to create an Umbraco package that allows package consumers to extend and add additional functionality. In this example, we show how you can use the OrderedCollectionBuilderBase.
You may wish to create an Umbraco package that allows package consumers to extend and add additional functionality. In this example, we show how you can use the LazyCollectionBuilderBase to scan assemblies that implement your interface by using the TypeLoader
using System.Linq;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Extensions;
namespace My.Website;
public class SubscribeToContentServiceSavingComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
builder.AddNotificationHandler<ContentSavingNotification, CustomContentSavingNotificationHandler>();
}
}
public class CustomContentSavingNotificationHandler : INotificationHandler<ContentSavingNotification>
{
public void Handle(ContentSavingNotification notification)
{
foreach (var content in notification.SavedEntities
// Check if the content item type has a specific alias
.Where(c => c.ContentType.Alias.InvariantEquals("MyContentType")))
{
// Do something if the content is using the MyContentType doctype
}
}
}using Umbraco.Cms.Core.Media.EmbedProviders;
using Umbraco.Cms.Core.Serialization;
namespace My.Website;
public class SpotifyEmbedProvider : OEmbedProviderBase
{
public SpotifyEmbedProvider(IJsonSerializer jsonSerializer)
: base(jsonSerializer)
{
}
public override string ApiEndpoint => "https://embed.spotify.com/oembed/";
// Playlist
// https://open.spotify.com/user/spotify/playlist/37i9dQZF1E4sNI4jZloSZr?si=cueBooBfTnqCGriSa4N_Kg
// spotify:user:spotify:playlist:37i9dQZF1E4sNI4jZloSZr
// Artist
// https://open.spotify.com/artist/0iirUbtgwt9jEkc2Grin8C?si=TLeUR2cHR-KPRJJhW6YiVg
// spotify:artist:0iirUbtgwt9jEkc2Grin8C
// Album
// https://open.spotify.com/album/0lvtdqkqIln6uDBBUT7DHL?si=XTVJIEmnS_OVv9l6ktPFiw
// spotify:album:0lvtdqkqIln6uDBBUT7DHL
// Track
// https://open.spotify.com/track/7aCk4XfXIEJM2MecU6Gmf2?si=vESDzI0xTNeA9FQ_dvf1eQ
// spotify:track:7aCk4XfXIEJM2MecU6Gmf2
public override string[] UrlSchemeRegex => new[]
{
@".*.spotify.com/.*",
@"spotify:.*"
};
public override Dictionary<string, string> RequestParams => new();
public override string? GetMarkup(string url, int maxWidth = 0, int maxHeight = 0)
{
string requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight);
OEmbedResponse? oembed = base.GetJsonResponse<OEmbedResponse>(requestUrl);
return oembed?.GetHtml();
}
}using Umbraco.Cms.Core.Composing;
namespace My.Website;
public class RegisterEmbedProvidersComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
// Change the EmbedProvidersCollection
// by adding our new EmbedProvider for Spotify
builder.EmbedProviders().Append<SpotifyEmbedProvider>();
}
}public class SubscribeToContentServiceSavingComposer : ComponentComposer<SubscribeToContentServiceSavingComponent>
{ }using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.HealthChecks.Checks.Permissions;
using Umbraco.Cms.Core.HealthChecks.Checks.Security;
namespace My.Website;
public class MyComposer: IComposer
{
public void Compose(IUmbracoBuilder builder)
{
// Remove all HealthChecks
builder.HealthChecks().Clear();
// Explicitly add back the ones we want to use
builder.HealthChecks().Add<FolderAndFilePermissionsCheck>();
builder.HealthChecks().Add<ExcessiveHeadersCheck>();
}
}[ComposeBefore(typeof(ThatOtherComposer))]
public class ThisComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
}
}using System;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Dashboards;
namespace Umbraco.Web.Dashboards;
[Weight(10)]
public class FormsDashboard : IDashboard
{
public string Alias => "formsInstall";
public string[] Sections => new [] { Constants.Applications.Forms };
public string View => "views/dashboard/forms/formsdashboardintro.html";
public IAccessRule[] AccessRules => Array.Empty<IAccessRule>();
}[Disable]
public class Way2Composer : IComposer
{
//...
}[Disable(typeof(Way1Composer))]
public class MyComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
// ...
}
}[assembly:DisableComposer(typeof(Way1Composer))]
[assembly:EnableComposer(typeof(Way2Composer))]using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Controllers;
using Umbraco.Cms.Api.Management.Routing;
using Umbraco.Cms.Core.Composing;
namespace UmbracoDocs.Samples;
public interface IDoThing
{
string DoTheThing(string message);
}
public class FirstThing : IDoThing
{
public string DoTheThing(string message)
=> $"First: {message}";
}
public class SecondThing : IDoThing
{
public string DoTheThing(string message)
=> $"Second: {message}";
}
public class ThirdThing : IDoThing
{
public string DoTheThing(string message)
=> $"Third: {message}";
}
// OrderedCollection - use when order of items is important (You may want to execute them in order)
public class DoThingsCollectionBuilder : OrderedCollectionBuilderBase<DoThingsCollectionBuilder, DoThingsCollection, IDoThing>
{
protected override DoThingsCollectionBuilder This => this;
}
public class DoThingsCollection : BuilderCollectionBase<IDoThing>
{
public DoThingsCollection(Func<IEnumerable<IDoThing>> items)
: base(items)
{
}
}
public class DoThingsComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
// Explicitly add to the collection a Type in a specific order
builder
.WithCollectionBuilder<DoThingsCollectionBuilder>()
.Append<FirstThing>()
.Append<SecondThing>()
.Append<ThirdThing>();
}
}
// An Umbraco Management API Controller - used in a Dashboard or Property Editor, perhaps?
[ApiExplorerSettings(GroupName = "Do things")]
[VersionedApiBackOfficeRoute("do/things")]
public class DoThingsController : ManagementApiControllerBase
{
private readonly DoThingsCollection _doThings;
public DoThingsController(DoThingsCollection doThings)
=> _doThings = doThings;
[HttpGet]
[ProducesResponseType<string[]>(StatusCodes.Status200OK)]
public IActionResult DoAllThings(string message)
{
var allThingsDone = _doThings
.Select(doThing => doThing.DoTheThing(message))
.ToArray();
return Ok(allThingsDone);
}
}using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Controllers;
using Umbraco.Cms.Api.Management.Routing;
using Umbraco.Cms.Core.Composing;
namespace UmbracoDocs.Samples;
// Implement `IDiscoverable` to boost scanning performance
public interface IDoThing : IDiscoverable
{
string DoTheThing(string message);
}
public class FirstThing : IDoThing
{
public string DoTheThing(string message)
=> $"First: {message}";
}
public class SecondThing : IDoThing
{
public string DoTheThing(string message)
=> $"Second: {message}";
}
public class ThirdThing : IDoThing
{
public string DoTheThing(string message)
=> $"Third: {message}";
}
public class DoThingsCollectionBuilder : LazyCollectionBuilderBase<DoThingsCollectionBuilder, DoThingsCollection, IDoThing>
{
protected override DoThingsCollectionBuilder This => this;
}
public class DoThingsCollection : BuilderCollectionBase<IDoThing>
{
public DoThingsCollection(Func<IEnumerable<IDoThing>> items)
: base(items)
{
}
}
public class DoThingsComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
// Add types from assemblies. Be conscious of using type scanning, as this adds to the Umbraco boot time.
// If you need to use type scanning, ensure that your interface implements `IDiscoverable`.
builder
.WithCollectionBuilder<DoThingsCollectionBuilder>()
.Add(() => builder.TypeLoader.GetTypes<IDoThing>());
}
}
// An Umbraco Management API Controller - used in a Dashboard or Property Editor, perhaps?
[ApiExplorerSettings(GroupName = "Do things")]
[VersionedApiBackOfficeRoute("do/things")]
public class DoThingsController : ManagementApiControllerBase
{
private readonly DoThingsCollection _doThings;
public DoThingsController(DoThingsCollection doThings)
=> _doThings = doThings;
[HttpGet]
[ProducesResponseType<string[]>(StatusCodes.Status200OK)]
public IActionResult DoAllThings(string message)
{
var allThingsDone = _doThings
.Select(doThing => doThing.DoTheThing(message))
.ToArray();
return Ok(allThingsDone);
}
}Ordering of composers is important, the last one added can override a previously added composer! Make sure, when overriding, that your composer that is doing the overriding, is 'composing', after the composer has 'composed' the element you wish to override!
If you create a circular dependency then Umbraco will fail to boot and will report the conflicting/circular dependency.
Don't use type scanning if you can avoid it. Type scanning increases the Umbraco boot time.
If your use case requires type scanning, ensure your interface implements IDiscoverable. This marker interface ensures that types are scanned once and then cached by Umbraco. This way, we save time by not having to re-scan for types repeatedly.
BackOfficeAssets
Ordered
Explicit Registration - Empty by default
CacheRefreshers
Lazy
Type scanned for ICacheRefresher
Components
Ordered
Explicit Registration
ContentApps
Ordered
Package.manifest & Explicit Registration
ContentFinders
Ordered
Explicit Registration
ContentIndexHandlers
Lazy
Type scanned for IContentIndexHandler
Dashboards
Weighted
Package.manifest & Explicit Registration
DataEditors
Lazy
Type scanned for IDataEditor
DataValueReferenceFactories
Ordered
Explicit Registration - Empty by default
EditorValidators
Lazy
Type scanned for IEditorValidator
EmbedProviders
Ordered
Explicit Registration
FilterHandlers
Lazy
Type scanned for IFilterHandler
HealthChecks
Lazy
Type scanned for HealthCheck
HealthCheckNotificationMethods
Lazy
Type scanned for IHealthCheckNotificationMethod
ManifestFilters
Ordered
Explicit Registration - Empty by default
ManifestValueValidators
Set
Explicit Registration
MapDefinitions
Set
Explicit Registration
Mappers
Set
Explicit Registration
MediaUrlGenerators
Set
Explicit Registration
MediaUrlProviders
Ordered
Explicit Registration
NPocoMappers
Set
Explicit Registration
PackageMigrationPlans
Lazy
Type scanned for PackageMigrationPlan
PartialViewSnippets
Lazy
Explicit Registration. Reads .cshtml files from Umbraco.Cms.Core.EmbeddedResources.Snippets assembly
PropertyValueConverters
Ordered
Type scanned for IPropertyValueConverter
RuntimeModeValidators
Set
Explicit Registration
Sections
Ordered
Package.manifest & Explicit Registration
SelectorHandlers
Lazy
Type scanned for ISelectorHandler
SortHandlers
Lazy
Type scanned for ISortHandler
TourFilters
Base
Empty collection
Trees
Base
Type scanned. Must inherit TreeControllerBase & use [Tree]
UrlProviders
Ordered
Explicit Registration
UrlSegmentProviders
Ordered
Explicit Registration
Validators
Lazy
Explicit Registration
The base class for collection builders that order their items explicitly.
Weighted
WeightedCollectionBuilder
The base class for collection builders that order their items by the [Weight] attribute.
Lazy
LazyCollectionBuilderBase
The base class for collection builders that resolve the types at the last moment, only when the collection is required.
The runtime is booting.
Install
The runtime has detected that Umbraco is not installed at all, ie. there is no database, and is currently installing Umbraco.
Upgrade
The runtime has detected an Umbraco install that needed to be upgraded and is currently upgrading Umbraco.
Run
The runtime has detected an up-to-date Umbraco install and is running.


The Umbraco UI works in all modern browsers:
Chrome (Latest)
Edge (Chromium)
Firefox (Latest)
Safari (Latest)
Below you can find the minimum requirements to run Umbraco on your machine:
One of the
One of the following .NET Tools or Editors:
with the
Umbraco can be installed with a SQLite or SQL Server database and configured with a . For SQL Server, , indicating a minimum supported version of SQL Server 2016.
As Umbraco releases are aligned to the .NET release cadence, it's also aligned with Microsoft's Long-term support policy for the underlying framework. For the best experience, we would recommend that you ensure you are on the latest and supported Microsoft versions to run and host Umbraco CMS:
and other
For more information, see the article in the Microsoft documentation.
Ability to set file permissions to include create/read/write (or better) for the user that "owns" the Application Pool for your site. This would typically be NETWORK SERVICE.
Umbraco's backoffice features such as preview and server events uses SignalR, which works best over WebSockets but will negotiate to Server-Sent Events/Long Polling. Some hosting setups buffer streamed responses, which can break the SSE fallback and surface as a "Could not establish a connection to the server" warning ~30s after opening preview.
To ensure the preferred WebSocket transport is available on Windows Server/IIS, install the WebSocket Protocol feature via Server Manager → Add Roles and Features → Web Server (IIS) → Web Server → Application Development → WebSocket Protocol
The database account used in the connection string will need permission to read and write from tables. It will also require permission to create a schema during installs and upgrades:
The db_owner role has full permissions on the database.
To use an account with more restricted permissions, the db_datareader and db_datawriter roles will be needed for normal use to read from and write to the database. The db_ddladmin role, which can modify the database schema, is required for installs and upgrades of the CMS and/or any packages that create database tables.
For more information on the Database-level roles, see the .
Version-specific upgrade notes and breaking changes for Umbraco, covering migration paths between different versions.
Are you looking to upgrade an Umbraco Cloud project from 9 to 10? Follow the guide instead, as it requires a few steps specific to Umbraco Cloud.
Microsoft Visual Studio 2022 version 17.14 or higher.
Optional: JetBrains Rider version 2025.3.0.1 and higher
Node.js version 24.11.1 and higher
You can use Umbraco Cloud to manage the hosting infrastructure. All Umbraco Cloud plans are hosted on Microsoft Azure, which gives your site a proven and solid foundation.
Go to Tools > NuGet Package Manager > Manage NuGet Packages for Solution...
Go to the Installed tab in the NuGet Package manager.
Choose Umbraco.Cms.
Select 10.0.0 from the Version drop-down and click Install to upgrade your project to version 10.
Update Program.cs to the following:
/umbraco/UmbracoBackOffice/umbraco/UmbracoInstall
/umbraco/UmbracoWebsite
/umbraco/config/lang
/umbraco/config/appsettings-schema.json
If using Umbraco Forms, update your files and folders according to the Upgrading - version specific for version 10 article.
Restart your site in IIS, build and run your project to finish the installation of Umbraco 10.
/umbraco/PartialViewMacros
/umbraco/UmbracoBackOffice
/umbraco/UmbracoInstall
/umbraco/UmbracoWebsite
/umbraco/config/lang
/umbraco/config/appsettings-schema.json
If you are using Umbraco Forms, update your files and folders according to the Upgrading - version specific for version 10 article.
Deploy the site how you normally would to your public facing environment.
Start the site. At this point it will launch and upgrade the database, after which the site should become accessible and your upgrade is complete.
Check the logs for any errors which may have occurred during the upgrade process.
document.Name => document.Name()document.Children => document.Children()~/web.configMVC has been updated to MVC5
You need to update your web.config file to have the correct MVC version references - this should be done by doing a compare/merge of your ~/web.config file with the ~/web.config file in the release
The upgrader will take care of updating all other web.config’s (in all other folders, for example, the Views and App_Plugins folders) to have the correct settings
For general ASP.NET MVC 5 upgrade details see:
It is not required that you merge the changes for the Examine index paths in the ExamineIndex.config file. However, if you do, your indexes will be rebuilt on startup because Examine will detect that they don’t exist at the new location.
It's highly recommended to clear the browser cache - the ClientDependency version is automatically bumped during installation which should force the browser cache to refresh, however in some edge cases this might not be enough.
/config/AppSettings.config and /config/ConnectionString.config can be removed after the contents have been moved back to web.config.
Global.asaxFor people using uComponents 3.1.2 or below, 4.8.0 breaks support for it. Either upgrade to a newer version beforehand or follow the workaround posted here
Delete bin/Microsoft.Scripting.Debugging.dll
Delete bin/Microsoft.Dynamic.dll
@{
IPublishedContent contactPage;
var contactPageId = Model.Content.GetPropertyValue<int>("contactPagePicker");
if (contactPageId > 0)
{
contactPage = Umbraco.TypedContent(contactPageId);
}
}
<p>
<a href="@contactPage.Url">@contactPage.Name</a>
</p><p>
<a href="@Model.Content.ContactPagePicker.Url">@Model.ContactPagePicker.Name</a>
</p><section name="urlrewritingnet" restartOnExternalChanges="true" requirePermission="false" type="UrlRewritingNet.Configuration.UrlRewriteSection, UrlRewritingNet.UrlRewriter" /><urlrewritingnet configSource="config\UrlRewriting.config" /><system.web>
<httpModules>
<add name="UrlRewriteModule" type="UrlRewritingNet.Web.UrlRewriteModule, UrlRewritingNet.UrlRewriter"/>
...
</httpModules>
<system.web><system.webServer>
<modules>
<remove name="UrlRewriteModule"/>
<add name="UrlRewriteModule" type="UrlRewritingNet.Web.UrlRewriteModule, UrlRewritingNet.UrlRewriter"/>
...
</modules>
</system.webServer>
"$schema": "./umbraco/config/appsettings-schema.json","$schema": "./appsettings-schema.json",public class Program
{
public static void Main(string[] args)
=> CreateHostBuilder(args)
.Build()
.Run();
// The calls to `ConfigureUmbracoDefaults` and `webBuilder.UseStaticWebAssets()` are new.
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureUmbracoDefaults()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStaticWebAssets();
webBuilder.UseStartup<Startup>();
});
}Map the AngularJS concepts from Umbraco 13 backoffice extensions to Web Components, contexts, and the Umbraco HTTP Client in Umbraco 14 and later.
Umbraco 14 replaced the AngularJS backoffice with a new backoffice built on Web Components. AngularJS code does not run in the new backoffice, so you rebuild each extension. Most AngularJS concepts have a direct equivalent.
This article maps those concepts and ports a small dashboard as an example. For the server side of your extension, see the Porting old Umbraco API Controllers article.
The rest of this article ports a dashboard that lists, adds, and deletes items. It calls the API controller from the tutorial.
In Umbraco 13, the same API was an UmbracoAuthorizedApiController named MyItemApiController. Umbraco routed its actions to /umbraco/backoffice/api/MyItemApi/{action} by convention.
AngularJS extensions were often plain JavaScript files in App_Plugins, without a build step. You can still write plain JavaScript modules.
The sets up TypeScript, a Vite build, and the backoffice types for you. With the --include-example option, it also adds an example dashboard and API controller.
In Umbraco 13, a package.manifest file lists dashboards and the JavaScript files to load:
A language file next to it held the texts, including the label of the dashboard tab:
In Umbraco 14 and later, an umbraco-package.json file lists the extensions. Each extension has a type and points to the code it loads.
The manifest changes in these ways:
The sections array becomes a condition. Section aliases now have the Umb.Section. prefix, so member becomes Umb.Section.Members. To show a dashboard in one section, use match with a single alias instead of oneOf.
The dashboard loads a JavaScript module instead of an HTML view and a controller.
To show a dashboard first, give it a higher weight than the built-in dashboards of the section. The article lists their weights and the section aliases.
In Umbraco 13, an AngularJS controller holds the state and the logic:
An HTML view rendered the state:
In Umbraco 14 and later, one Web Component holds the state, the logic, and the markup. The following Lit element replaces both files:
Compile the element to App_Plugins/MyItems/my-items-dashboard.js, the file that the manifest points to. The Umbraco Extension Template compiles it for you. Without the template, see the article.
The element is the default export of the module, so the manifest needs no elementName.
Styles live in the element's static styles. The element renders into a Shadow DOM, so stylesheets on the page do not reach it.
To build a dashboard step by step, follow the tutorial.
Lit templates are JavaScript template literals. The following table maps the AngularJS directives to Lit:
The prefix on a binding decides what it sets. A . sets a property, a ? toggles a Boolean attribute, and an @ adds an event listener. Lit has no two-way binding, so you listen for input events and update the state yourself.
Import the directives from @umbraco-cms/backoffice/external/lit. For more about expressions, see the .
AngularJS injects services into a controller by parameter name. In the new backoffice, an element asks for a context with consumeContext(). The callback runs when the context is available.
A few of these work differently:
this.localize.term() returns the text right away. localizationService.localize() returned a promise.
umbConfirmModal() returns a promise. The promise resolves when the user confirms, and rejects when the user cancels.
Many contexts expose observables instead of promises. Use this.observe() to read the value when it arrives and each time it changes.
The following element replaces a call to userService.getCurrentUser():
Observers stop when the element leaves the page. You do not need to clean them up, as you did with $scope.$on('$destroy').
For more about contexts, see the article.
In Umbraco 13, you call an API controller with $http, and umbRequestHelper.resourcePromise unwraps the response:
In Umbraco 14 and later, use the Umbraco HTTP Client and wrap the call in tryExecute, as the dashboard example does:
The differences from $http are:
URLs: The route of the controller and the HTTP method replace the action name in the URL, and IDs move into the path. Write the full path, starting with /umbraco.
Property names: The Management API returns camelCase property names. UmbracoAuthorizedApiController returned the C# names, so data.Items becomes data.items.
Responses with status 401, 403, or 404 do not show a notification. Check the returned error and handle these responses in your code. For the full rules, see the article.
If your API has an OpenAPI document, you can generate a typed client instead. The Umbraco Extension Template sets up a generated client for you. For details, see the article.
In Umbraco 13, a ServerVariablesParsingNotification handler adds values to the global Umbraco.Sys.ServerVariables object. Umbraco 14 and later have no server variables.
Before you move a value over, check whether your extension needs it. Often the client can work without values from the server.
If your extension needs a value from the server, return it from a config endpoint on your API controller. The endpoint returns only the values your extension needs, instead of adding them to a global object on every backoffice page. Only signed-in backoffice users can call it by default, and you can restrict it further with the of the Management API.
The following controller returns how many items the dashboard shows. It reads the value from the MyItems:PageSize setting in appsettings.json:
The element reads the value with the Umbraco HTTP Client. The Management API returns camelCase property names, so PageSize becomes pageSize:
AngularJS wraps promises and timers in $q and $timeout, so that the view is updated afterward. The new backoffice uses the standard JavaScript APIs:
Lit has no digest cycle. An element renders again when a @state() or @property() value changes. Lit compares the old and the new value, so changing an item inside an array is not a change. Assign a new array or object to render again.
Property editors follow the same patterns, with a few additions:
$scope.model.value becomes the value property of the element. Dispatch an UmbChangeEvent when the value changes.
$scope.model.config becomes the config property. Read a setting with config.getValueByAlias().
Umbraco migrates your existing Data Types when you upgrade. The migration depends on how you registered the property editor. For details, see the article.
To build a property editor step by step, follow the tutorial.
The Lang/en-US.xml file becomes a localization extension. Each area becomes an object with a property for each key, so myItems_headline keeps working.
The tab label moves from the dashboardTabs_myItemsDashboard key to meta.label.
The weight sorts the other way. In Umbraco 13, the lowest weight came first. Now the highest weight comes first, so -10 moves the dashboard from the first tab to the last.
$http sent the backoffice cookie. The Management API uses access tokens instead. The security array tells the Umbraco HTTP Client to add the token of the current user.Sessions: The Umbraco HTTP Client refreshes an expired token. When the session has expired, it asks the user to log in again.
Errors: resourcePromise shows a notification only for server errors, and passes other failures to your rejection handler. tryExecute returns an object with data and error instead of a rejected promise. When the request fails, it shows a notification with the title and detail from the problem details in the response.
Types: The type argument maps the status code to the response type, so data has the right type.
Parameters: Pass query string parameters in query, and a request body in body.
The prevalues in package.manifest become settings in the meta of the propertyEditorUi extension.
package.manifest
umbraco-package.json
javascript array in the manifest
The element, js, or api property of each extension.
css array in the manifest
The static styles of each element.
Controller and HTML view
A Web Component, usually a Lit element.
$scope and vm properties
Class properties with the @state() decorator.
$scope.$watch
willUpdate() with its changed properties, or this.observe().
$scope.$on('$destroy')
disconnectedCallback()
Injected services
Contexts that you consume with consumeContext().
$http.get and $http.post
umbHttpClient.get and umbHttpClient.post.
umbRequestHelper.resourcePromise
tryExecute
Umbraco.Sys.ServerVariables
A config endpoint on your own API controller.
$q and $timeout
Promise, async and await, and setTimeout.
umb-box, umb-button, and other directives
uui-box, uui-button, and other Umbraco UI Library components.
<localize> and localizationService
<umb-localize> and this.localize.term()
Lang/*.xml files
localization extensions.
Content Apps
Workspace Views
Content App show rules
Workspace View conditions, such as Umb.Condition.WorkspaceContentTypeAlias.
Tree menu items from MenuRenderingNotification
entityAction extensions
UmbracoAuthorizedApiController
ManagementApiControllerBase
{
"dashboards": [
{
"alias": "myItemsDashboard",
"view": "/App_Plugins/MyItems/dashboard.html",
"sections": ["content", "member", "settings"],
"weight": -10
}
],
"javascript": ["/App_Plugins/MyItems/dashboard.controller.js"]
}<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<language alias="en_us" intName="English (US)" localName="English (US)" lcid="" culture="en-US">
<area alias="myItems">
<key alias="headline">My items</key>
<key alias="newItem">New item</key>
<key alias="itemAdded">Item added</key>
<key alias="deleteHeadline">Delete item</key>
<key alias="deleteConfirm">Are you sure you want to delete %0%?</key>
</area>
<area alias="dashboardTabs">
<key alias="myItemsDashboard">My Items</key>
</area>
</language>{
"name": "My Items",
"version": "1.0.0",
"extensions": [
{
"type": "dashboard",
"alias": "My.Dashboard.MyItems",
"name": "My Items Dashboard",
"element": "/App_Plugins/MyItems/my-items-dashboard.js",
"weight": -10,
"meta": {
"label": "My Items",
"pathname": "my-items"
},
"conditions": [
{
"alias": "Umb.Condition.SectionAlias",
"oneOf": ["Umb.Section.Content", "Umb.Section.Members", "Umb.Section.Settings"]
}
]
},
{
"type": "localization",
"alias": "My.Localization.En",
"name": "My Items English",
"meta": {
"culture": "en",
"localizations": {
"myItems": {
"headline": "My items",
"newItem": "New item",
"itemAdded": "Item added",
"deleteHeadline": "Delete item",
"deleteConfirm": "Are you sure you want to delete %0%?",
"greeting": "Hello %0%"
}
}
}
}
]
}angular.module("umbraco").controller("MyItemsDashboardController", function (
$http, $q, umbRequestHelper, notificationsService, overlayService, localizationService) {
var vm = this;
vm.loading = true;
vm.items = [];
vm.newValue = "";
function loadItems() {
vm.loading = true;
umbRequestHelper.resourcePromise(
$http.get("backoffice/api/MyItemApi/GetAllItems?take=20"),
"Failed to load the items")
.then(function (data) {
vm.items = data.Items;
vm.loading = false;
});
}
vm.addItem = function () {
var value = vm.newValue;
umbRequestHelper.resourcePromise(
$http.post("backoffice/api/MyItemApi/CreateItem?value=" + encodeURIComponent(value)),
"Failed to add the item")
.then(function (item) {
vm.items.push(item);
return localizationService.localize("myItems_itemAdded");
})
.then(function (headline) {
notificationsService.success(headline, value);
vm.newValue = "";
});
};
vm.deleteItem = function (item) {
$q.all([
localizationService.localize("myItems_deleteHeadline"),
localizationService.localize("myItems_deleteConfirm", [item.Value])
]).then(function (texts) {
overlayService.confirmDelete({
title: texts[0],
content: texts[1],
submit: function () {
umbRequestHelper.resourcePromise(
$http.delete("backoffice/api/MyItemApi/DeleteItem?id=" + item.Id),
"Failed to delete the item")
.then(function () {
vm.items.splice(vm.items.indexOf(item), 1);
});
overlayService.close();
}
});
});
};
loadItems();
});<div ng-controller="MyItemsDashboardController as vm">
<umb-box>
<umb-box-header title-key="myItems_headline"></umb-box-header>
<umb-box-content>
<umb-load-indicator ng-if="vm.loading"></umb-load-indicator>
<ul ng-if="!vm.loading">
<li ng-repeat="item in vm.items">
{{ item.Value }}
<umb-button type="button" button-style="danger" label-key="actions_delete"
action="vm.deleteItem(item)"></umb-button>
</li>
</ul>
<input type="text" ng-model="vm.newValue" />
<umb-button type="button" button-style="primary" label-key="general_add"
action="vm.addItem()" disabled="!vm.newValue"></umb-button>
</umb-box-content>
</umb-box>
</div>import { css, customElement, html, repeat, state } from "@umbraco-cms/backoffice/external/lit";
import type { UUIInputEvent } from "@umbraco-cms/backoffice/external/uui";
import { umbHttpClient } from "@umbraco-cms/backoffice/http-client";
import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element";
import { umbConfirmModal } from "@umbraco-cms/backoffice/modal";
import { UMB_NOTIFICATION_CONTEXT } from "@umbraco-cms/backoffice/notification";
import { tryExecute } from "@umbraco-cms/backoffice/resources";
interface MyItem {
id: string;
value: string;
}
interface MyItemPage {
items: Array<MyItem>;
total: number;
}
const ITEMS_URL = "/umbraco/management/api/v1/my/item";
@customElement("my-items-dashboard")
export class MyItemsDashboardElement extends UmbLitElement {
// @state() properties replace the vm properties. Changing one renders the element again.
@state()
private _items: Array<MyItem> = [];
@state()
private _loading = true;
@state()
private _newValue = "";
#notificationContext?: typeof UMB_NOTIFICATION_CONTEXT.TYPE;
constructor() {
super();
// Replaces injecting notificationsService into the controller
this.consumeContext(UMB_NOTIFICATION_CONTEXT, (context) => {
this.#notificationContext = context;
});
this.#loadItems();
}
async #loadItems() {
this._loading = true;
const { data, error } = await tryExecute(
this,
umbHttpClient.get<{ 200: MyItemPage }>({
url: ITEMS_URL,
query: { take: 20 },
security: [{ scheme: "bearer", type: "http" }],
}),
);
this._loading = false;
// Keep the current items if the request fails. tryExecute notifies for every error except 401, 403 and 404.
if (error || !data) return;
this._items = data.items;
}
async #addItem() {
const value = this._newValue;
const { data: id, error } = await tryExecute(
this,
umbHttpClient.post<{ 201: string }>({
url: ITEMS_URL,
query: { value },
security: [{ scheme: "bearer", type: "http" }],
}),
);
// tryExecute has already shown a notification for the failed request
if (error) return;
// For a created item, the Umbraco HTTP Client returns the ID from the Umb-Generated-Resource header as data.
// Assign a new array, so Lit renders the list again.
if (id) this._items = [...this._items, { id, value }];
this.#notificationContext?.peek("positive", {
data: {
headline: this.localize.term("myItems_itemAdded"),
message: value,
},
});
this._newValue = "";
}
async #deleteItem(item: MyItem) {
try {
await umbConfirmModal(this, {
headline: this.localize.term("myItems_deleteHeadline"),
content: this.localize.term("myItems_deleteConfirm", item.value),
color: "danger",
confirmLabel: this.localize.term("actions_delete"),
});
} catch {
// The user cancelled the dialog
return;
}
const { error } = await tryExecute(
this,
umbHttpClient.delete({
url: `${ITEMS_URL}/${item.id}`,
security: [{ scheme: "bearer", type: "http" }],
}),
);
if (!error) this._items = this._items.filter((existing) => existing.id !== item.id);
}
override render() {
return html`
<uui-box headline=${this.localize.term("myItems_headline")}>
${this._loading
? html`<uui-loader></uui-loader>`
: html`
<ul>
${repeat(
this._items,
(item) => item.id,
(item) => html`
<li>
${item.value}
<uui-button
look="secondary"
color="danger"
label=${this.localize.term("actions_delete")}
@click=${() => this.#deleteItem(item)}></uui-button>
</li>
`,
)}
</ul>
`}
<uui-input
label=${this.localize.term("myItems_newItem")}
.value=${this._newValue}
@input=${(event: UUIInputEvent) => (this._newValue = event.target.value.toString())}></uui-input>
<uui-button
look="primary"
label=${this.localize.term("general_add")}
?disabled=${!this._newValue}
@click=${this.#addItem}></uui-button>
</uui-box>
`;
}
static override styles = css`
:host {
display: block;
padding: var(--uui-size-layout-1);
}
`;
}
export default MyItemsDashboardElement;
declare global {
interface HTMLElementTagNameMap {
"my-items-dashboard": MyItemsDashboardElement;
}
}{{ vm.name }}
${this.name}
ng-if
A conditional expression, or the when() directive.
ng-repeat
notificationsService
UMB_NOTIFICATION_CONTEXT and its peek() method.
userService.getCurrentUser()
UMB_CURRENT_USER_CONTEXT and its currentUser observable.
localizationService.localize()
import { customElement, html, nothing, state } from "@umbraco-cms/backoffice/external/lit";
import { UMB_CURRENT_USER_CONTEXT } from "@umbraco-cms/backoffice/current-user";
import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element";
@customElement("my-current-user-greeting")
export class MyCurrentUserGreetingElement extends UmbLitElement {
@state()
private _userName?: string;
constructor() {
super();
this.consumeContext(UMB_CURRENT_USER_CONTEXT, (context) => {
this.observe(context?.currentUser, (currentUser) => {
this._userName = currentUser?.name;
});
});
}
override render() {
if (!this._userName) return nothing;
return html`<p>${this.localize.term("myItems_greeting", this._userName)}</p>`;
}
}
export default MyCurrentUserGreetingElement;umbRequestHelper.resourcePromise(
$http.get("backoffice/api/MyItemApi/GetAllItems?take=20"),
"Failed to load the items")
.then(function (data) {
vm.items = data.Items;
});const { data } = await tryExecute(
this,
umbHttpClient.get<{ 200: MyItemPage }>({
url: "/umbraco/management/api/v1/my/item",
query: { take: 20 },
security: [{ scheme: "bearer", type: "http" }],
}),
);using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Umbraco.Cms.Api.Management.Controllers;
using Umbraco.Cms.Api.Management.Routing;
namespace UmbracoDocs.Samples;
[VersionedApiBackOfficeRoute("my/config")]
[ApiExplorerSettings(GroupName = "My item API")]
public class MyItemsConfigApiController : ManagementApiControllerBase
{
private readonly IConfiguration _configuration;
public MyItemsConfigApiController(IConfiguration configuration)
=> _configuration = configuration;
[HttpGet]
public IActionResult GetConfig()
=> Ok(new MyItemsConfig(_configuration.GetValue("MyItems:PageSize", 20)));
}
public record MyItemsConfig(int PageSize);const { data: config } = await tryExecute(
this,
umbHttpClient.get<{ 200: { pageSize: number } }>({
url: "/umbraco/management/api/v1/my/config",
security: [{ scheme: "bearer", type: "http" }],
}),
);
const pageSize = config?.pageSize ?? 20;$q.defer()
new Promise()
$q.all()
Promise.all()
$q.when()
The repeat() directive, or Array.map().
ng-click="vm.save()"
@click=${this.save}
ng-model="vm.name"
.value=${this.name} and an @input event listener.
ng-class
The classMap() directive.
ng-show="vm.visible"
?hidden=${!this.visible}, or a conditional expression.
ng-hide="vm.hidden"
?hidden=${this.hidden}, or a conditional expression.
ng-disabled
?disabled=${...}
this.localize.term() on the element.
overlayService.confirmDelete()
umbConfirmModal()
editorService.open()
umbOpenModal() with a modal token.
editorService.contentPicker()
umbOpenModal() with UMB_DOCUMENT_PICKER_MODAL.
editorService.mediaPicker()
umbOpenModal() with UMB_MEDIA_PICKER_MODAL.
editorState.current
The workspace context, for example UMB_DOCUMENT_WORKSPACE_CONTEXT.
assetsService.loadJs()
An import statement.
Promise.resolve()
$timeout()
setTimeout()
.then() chains
async and await
Schema Alias: Umbraco.BlockGrid
UI Alias: Umb.PropertyEditorUi.BlockGrid
Returns: BlockGridModel
The Block Grid property editor enables editors to layout their content in the Umbraco backoffice. The content is made of Blocks that can contain different types of data.
The Block Grid property editor is configured via the Data Types backoffice interface.
To set up the Block Grid property editor, follow these steps:
Navigate to the Settings section in the Umbraco backoffice.
Click ... next to the Data Types folder.
Select Create -> Data Type.
Select Block Grid from the list of available property editors.
You will see the configuration options as shown below:
The Data Type editor allows you to configure the following properties:
Blocks - Defines the Block Types available for use in the property. For more information, see . Blocks can also be grouped. This is then visible to editors in the Block Catalogue when populating content, and can also be used to allow a group of Blocks in an Area.
Amount - Sets the minimum and/or the maximum number of Blocks that should be allowed at the root of the layout.
Live editing mode - Enabling this option will allow you to see the changes as you are editing them.
Block Types are based on . These can be created beforehand or while setting up your Block Types.
Once you have added an Element Type as a Block Type on your Block Grid Data Type you have the option to configure it.
Each Block has a set of properties that are optional to configure. These are described below.
Customize the user experience for your content editors when they work with the Blocks in the Content section.
Label - Defines a label for the appearance of the Block in the editor. The label can use to display values of properties. The label is also used for search in the Add Block dialog during content editing. If no label is defined, the block will not be searchable. The search does not fall back to the block’s name.
Content model - Presents the Element Type used as model for the Content section of this Block. This cannot be changed but you can open the Element Type to perform edits or view the properties available. Useful when writing your Label.
Settings model - Adds a Settings section to your Block based on a given Element Type. When selected you can open the Element Type or choose to remove the Settings section again.
Allow in root - Determines whether the Block can be created at the root of your layout. Turn this off if you only want a Block to appear within Block Areas.
Allow in areas - Determines whether the Block can be created inside Areas of other Blocks. If this is turned off it can still be allowed in Block Areas by defining specific allowed Blocks.
Customize the Blocks size in the Grid. If you define multiple options, the Block becomes scalable.
By default, a Block takes up the available width.
A Block can be resized in two ways:
When a Block is placed in an Area, it will fit to the Areas width. Learn more about .
A Block can have one or more Column Span options defined.
A Column Span option is used to define the width of a Block. With multiple Column Span options defined, the Content Editor can scale the Block to fit specific needs.
Additionally, Blocks can be configured to span rows, this enables one Block to be placed next to a few rows containing other Blocks.
Available column spans - Defines one or more columns, the Block spans across. For example: in a 12 columns grid, 6 columns is equivalent to half width. By enabling 6 columns and 12 columns, the Block can be scaled to either half width or full width.
Available row spans - Defines the amount of rows the Block spans across.
See the section of this article for an example of how scaling works.
Blocks can nest other Blocks to support specific compositions. These compositions can be used as a layout for other Blocks.
To achieve nesting, a Block must have one or more Areas defined. Each Area can contain one or more Blocks.
Each Area has a size, defined by column and rows spans. The grid for the Areas are based on the same amount of columns as your root grid, unless you choose to change it.
To scale an Area, click and drag the scale-button in the bottom-right corner of an Area.
Grid Columns for Areas - Overwrites the amount of columns used for the Area grid.
Areas - Determines whether the Block can be created inside Areas of other Blocks.
Alias - The alias is used to identify this Area. It is being printed by GetBlockGridHTML() and used as name for the Area slot in Custom Views. The alias is also available for CSS Selectors to target the HTML-Element representing an Area.
Create Button Label - Overwrites the Create Button Label of the Area.
Number of blocks - Determines the total number of Blocks in an Area.
When allowing a group of Blocks, you might want to require a specific amount for a certain Block of that group. This can be done by adding that Block Type to the list as well, and setting the requirements accordingly.
Advanced properties are also available for each Block, as shown below.
Overlay editor size - Sets the size for the Content editor overlay for editing this block.
Inline editing - Enabling this will change editing experience to inline, meaning that editing the data of blocks happens at sight as accordions.
Hide content editor - Hides the UI for editing the content in a Block Editor. This is only relevant if you made a custom view that provides the UI for editing of content.
Custom view - Overwrites the view for the block presentation in the Content editor. Building Custom Views for Block representations in Backoffice is the same for all Block Editors.
These properties refer to how the Block is presented in the Block catalogue, when editors choose which Blocks to use for their content.
Background color - Define a background color to be displayed beneath the icon or thumbnail. Eg. #424242.
Icon color - Change the color of the Element Type icon. Eg. #242424.
Thumbnail - Pick an image or SVG file to replace the icon of this Block in the catalogue.
The thumbnails for the catalogue are displayed at a maximum height of 150px and will scale proportionally to maintain their original aspect ratio. Any standard image format (PNG, JPG, SVG) will work effectively.
When viewing a Block Grid property editor in the Content section for the first time, you will be presented with the option to Add content.
Clicking the Add content button opens up the Block Catalogue.
The Block Catalogue looks different depending on the amount of available Blocks and their catalogue appearance.
Click the Block Type you wish to create and a new Block will appear in the layout.
More Blocks can be added to the layout by clicking the Add content button. Alternatively, use the Add content button that appears on hover to add new Blocks between, besides, or above the existing Blocks.
To delete a Block, click the trash icon which appears on the mouse hover.
Blocks can be rearranged using the click and drag feature. Move them up or down to place them in the desired order.
Moving a Block from one Area to another is done in the same way. If a Block is not allowed in the given position, the area will display a red color and not allow the new position.
If a Block has multiple size options it can be scaled via the UI. This appears in the bottom-right corner of the Block.
The Block is resized using a click-and-drag feature. Moving the mouse will change the size to the size options closest to the mouse pointer.
Rendering the stored value of your Block Grid property editor can be done in two ways:
You can choose to use the built-in rendering mechanism for rendering Blocks using a Partial View for each block.
The default rendering method is named GetBlockGridHtmlAsync() and comes with a few options - for example:
In the sample above "myGrid" is the alias of the Block Grid editor.
If you are using ModelsBuilder, the example will look like this:
To use the GetBlockGridHtmlAsync() method, you will need to create a Partial View for each Block Type. The Partial View must be named using the alias of the Element Type that is being used as Content Model for the Block Type.
These Partial View files need to go into the Views/Partials/blockgrid/Components/ folder.
Example: Views/Partials/blockgrid/Components/MyElementTypeAliasOfContent.cshtml.
The Partial Views will receive a model of type Umbraco.Cms.Core.Models.Blocks.BlockGridItem. This model contains Content and Settings from your block, as well as the configured RowSpan, ColumnSpan, and Areas of the Block.
The Partial View for the Block is responsible for rendering its own Block Areas. This is done using another built-in rendering mechanism:
Here you will need to create a Partial View for each Block Type within the Block Area. For the name, use the alias of the Element Type that is being used as Content Model for the Block Type.
These Partial Views must be placed in the same folder as before, (Views/Partials/blockgrid/Components/), and will receive a model of type Umbraco.Cms.Core.Models.Blocks.BlockGridItem.
The following is an example of a Partial View for a Block Type of type MyElementTypeAliasOfContent.
If you are using ModelsBuilder, you can make the property rendering strongly typed by letting your view accept a model of type BlockGridItem<T>. For example:
Using the default rendering together with your layout stylesheet will provide what you need for rendering the layout.
To use the Default Layout Stylesheet, copy the stylesheet to your frontend. You can download the default layout stylesheet from the link within the DataType, we recommend putting the file in the css folder, example: wwwroot/css/umbraco-blockgridlayout.css.
The built-in value converter for the Block Grid property editor lets you use the block data as you like. Call the Value<T> method with a type of BlockGridModel to have the stored value returned as a BlockGridModel instance.
BlockGridModel contains the Block Grid configuration (like the number of columns as GridColumns) whilst also being an implementation of IEnumerable<BlockGridItem> (see details for BlockGridItem above).
The following example mimics the built-in rendering mechanism for rendering Blocks using Partial Views:
If you do not want to use Partial Views, you can access the block item data directly within your rendering:
When using Block Grid in a headless scenario with the , the property outputs a structured JSON representation instead of rendered HTML.
The JSON structure includes:
gridColumns - The number of columns configured for the grid (typically 12)
items - An array of block items, each containing:
content - The block's content data
Your frontend application is responsible for:
Parsing the grid layout structure
Implementing CSS Grid or an equivalent layout system
Rendering blocks recursively to handle nested areas
Handling responsive behavior
For detailed information about the JSON structure and property expansion options, see .
The default layout stylesheet is using CSS Grid. This can be modified to fit your implementation and your project.
To make additions or overwrite parts of the default layout stylesheet, import the default stylesheet at the top of your own file.
You need to copy the Default Layout Stylesheet to your frontend. You can download the default layout stylesheet from the link within the DataType, we recommend putting the file in the css folder, example: wwwroot/css/umbraco-blockgridlayout.css.
In this case, you would have to write the layout from scratch.
You are free to pick any style, meaning there is no requirement to use CSS Grid. It is, however, recommended to use CSS Grid to ensure complete compatibility with the Umbraco backoffice.
When extending or writing your own layout, you need to know the structure and what data is available.
For example: You can use the below HTML structure:
Building Custom Views for Block representations in Backoffice is based on the same API for all Block Editors.
In this example, we will be creating content programmatically for a "spot" Blocks in a Block Grid.
Create an element type to represent block content called Spot Element with the following properties:
A property called title with the editor of Textstring
A property called text with the editor of Textstring
Create an element type to represent block content called Spot Settings with the following properties:
A property called featured with the editor of True/false.
Add a property called blockGrid in a Document Type.
Select Block Grid as the property editor.
Click Add in the Blocks Settings and select Spot Element.
Select Spot Settings
The raw input data for the spots looks like this:
The resulting JSON object stored for the Block Grid will look like this:
For each item in the raw data, we need to create:
One contentData entry with the title and text.
One settingsData entry with the featured value (the checkbox expects "0" or "1" as data value).
All contentData and layoutData entries need their own unique Udi as well as the ID (key) of their corresponding Element Types. In this sample, we only have one Element Type for content (spotElement) and one for settings (spotSettings). In a real life scenario, there could be any number of Element Type combinations.
Create a class called Model.cs containing the following to transform the raw data into Block Grid-compatible JSON:
By injecting and into an API controller, we can transform the raw data into Block Grid JSON. It can then be saved to the target content item. Create a class called BlockGridTestController.cs containing the following:
For the above code IContent? content = _contentService.GetById(Guid.Parse("efba7b97-91b6-4ddf-b2cc-eef89ff48c3b")); change the id with your content node that is using the Block Grid.
To test this implementation, run the project and send a POST request to /umbraco/api/blockgridtest/create after your domain name. If the result shows as Saved, then check your content node, and you will see the 2 spotElement contents.
This can also be tested via Postman as well if preferred.
Create Button Label - Overwrites the label on the Create button.
Create modal size - Controls the size of the overlay dialog that appears when an editor clicks to create or edit a block.
Grid Columns - Define the number of columns in your Block Grid. The default is 12 columns.
Layout Stylesheet - Replaces the built-in Layout Stylesheet. Additionally, you can retrieve the default layout stylesheet to use as a base for your own inspiration or for writing your own stylesheet.
settings - The block's settings data (if configured)
rowSpan and columnSpan - Layout dimensions for the block
areaGridColumns - Number of columns for nested areas
areas - Array of nested areas within the block, each containing their own items
layout entry with the desired column and row spans.













@await Html.GetBlockGridHtmlAsync(Model, "myGrid")@await Html.GetBlockGridHtmlAsync(Model.MyGrid)@await Html.GetBlockGridItemAreasHtmlAsync(Model)@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockGridItem>;
@* Render the value of field with alias 'heading' from the Element Type selected as Content section *@
<h1>@Model.Content.Value("heading")</h1>
@* Render the block areas *@
@await Html.GetBlockGridItemAreasHtmlAsync(Model)@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockGridItem<ContentModels.MyElementTypeAliasOfContent>>;
@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
@* Render the Heading property from the Element Type selected as Content section *@
<h1>@Model.Content.Heading</h1>
@* Render the block areas *@
@await Html.GetBlockGridItemAreasHtmlAsync(Model)<link rel="stylesheet" href="@Url.Content("~/css/blockgridlayout.css")" />@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
@using Umbraco.Cms.Core.Models.Blocks
@{
var grid = Model.Value<BlockGridModel>("myGrid");
// get the number of columns defined for the grid
var gridColumns = grid.GridColumns;
// iterate the block items
foreach (var item in grid)
{
var content = item.Content;
@await Html.PartialAsync("PathToMyFolderOfPartialViews/" + content.ContentType.Alias, item);
}
}@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
@using Umbraco.Cms.Core.Models.Blocks
@{
var grid = Model.Value<BlockGridModel>("myGrid");
// get the number of columns defined for the grid
var gridColumns = grid.GridColumns;
// iterate the block items
foreach (var item in grid)
{
// get the content and settings of the block
var content = item.Content;
var settings = item.Settings;
// get the areas of the block
var areas = item.Areas;
// get the dimensions of the block
var rowSpan = item.RowSpan;
var columnSpan = item.ColumnSpan;
// render the block data
<div style="background-color: #@(settings.Value<string>("color"))">
<h2>@(content.Value<string>("title"))</h2>
<span>This block is supposed to span <b>@rowSpan rows</b> and <b>@columnSpan columns</b></span>
</div>
}
}@import 'css/umbblockgridlayout.css';<div class="umb-block-grid"
style="--umb-block-grid--grid-columns: 12;"
>
<!-- Notice this is the same markup used every time we will be printing a list of blocks: -->
<div class="umb-block-grid__layout-container">
<!-- repeated for each layout entry -->
<div
class="umb-block-grid__layout-item"
data-content-element-type-alias="MyElementTypeAlias"
data-content-element-type-key="00000000-0000-0000-0000-000000000000"
data-element-udi="00000000-0000-0000-0000-000000000000"
data-col-span="6"
data-row-span="1"
style="
--umb-block-grid--item-column-span: 6;
--umb-block-grid--item-row-span: 1;
"
>
<!-- Here the Razor View or Custom View for this block will be rendered. -->
<!-- Each razor view must render the 'area-container' them self.
This can be done by the Razor helper method:
@await Html.GetBlockGridItemAreasHtmlAsync(Model)
The structure will be as printed below,
Do notice targeting the 'area-container' needs a double selector as markup will be different in Backoffice.
Here is an example of the CSS selector:
.umb-block-grid__area-container, umb-block-grid-areas-container::part(area-container) {
position: relative;
}
-->
<div
class="umb-block-grid__area-container"
style="--umb-block-grid--area-grid-columns: 9;"
>
<!-- repeated for each area for this block type. -->
<div
class="umb-block-grid__area"
data-area-col-span="3"
data-area-row-span="1"
data-area-alias="MyAreaAlias"
style="
--umb-block-grid--grid-columns: 3;
--umb-block-grid--area-column-span: 3;
--umb-block-grid--area-row-span: 1;
">
<!-- Notice here we print the same markup as when we print a list of blocks(same as the one in the root of this structure..):
<div class="umb-block-grid__layout-container">
...
</div>
End of notice. -->
</div>
<!-- end of repeat -->
</div>
</div>
<!-- end of repeat -->
</div>
</div>new[]
{
new { Title = "Item one", Text = "This is item one", Featured = false, ColumnSpan = 12, RowSpan = 1 },
new { Title = "Item two", Text = "This is item two", Featured = true, ColumnSpan = 6, RowSpan = 2 }
}{
"contentData":[
{
"contentTypeKey":"fd01539a-5bcf-48f7-aee5-8ad925c75902",
"udi":null,
"key":"019f2a7a-35b4-45b3-b867-910b3f340f25",
"values":[
{
"editorAlias":"Umbraco.TextBox",
"culture":null,
"segment":null,
"alias":"title",
"value":"Item one"
},
{
"editorAlias":"Umbraco.TextBox",
"culture":null,
"segment":null,
"alias":"text",
"value":"This is item one"
}
]
},
{
"contentTypeKey":"fd01539a-5bcf-48f7-aee5-8ad925c75902",
"udi":null,
"key":"063f8062-8610-441a-97f1-ea6d73fe2678",
"values":[
{
"editorAlias":"Umbraco.TextBox",
"culture":null,
"segment":null,
"alias":"title",
"value":"Item two"
},
{
"editorAlias":"Umbraco.TextBox",
"culture":null,
"segment":null,
"alias":"text",
"value":"This is item two"
}
]
}
],
"settingsData":[
{
"contentTypeKey":"03c43074-a4ba-4bd2-92b1-c3a35a0eed4d",
"udi":null,
"key":"5b2d74bc-3e85-4aa3-b684-4b1f11522d7c",
"values":[
{
"editorAlias":"Umbraco.TrueFalse",
"culture":null,
"segment":null,
"alias":"featured",
"value":0
}
]
},
{
"contentTypeKey":"03c43074-a4ba-4bd2-92b1-c3a35a0eed4d",
"udi":null,
"key":"1c6599fc-6558-4a0b-9da8-4f002925f59f",
"values":[
{
"editorAlias":"Umbraco.TrueFalse",
"culture":null,
"segment":null,
"alias":"featured",
"value":1
}
]
}
],
"expose":[
{
"contentKey":"019f2a7a-35b4-45b3-b867-910b3f340f25",
"culture":null,
"segment":null
},
{
"contentKey":"063f8062-8610-441a-97f1-ea6d73fe2678",
"culture":null,
"segment":null
}
],
"Layout":{
"Umbraco.BlockGrid":[
{
"columnSpan":12,
"rowSpan":1,
"areas":[
],
"contentUdi":null,
"settingsUdi":null,
"contentKey":"019f2a7a-35b4-45b3-b867-910b3f340f25",
"settingsKey":"5b2d74bc-3e85-4aa3-b684-4b1f11522d7c"
},
{
"columnSpan":12,
"rowSpan":1,
"areas":[
],
"contentUdi":null,
"settingsUdi":null,
"contentKey":"063f8062-8610-441a-97f1-ea6d73fe2678",
"settingsKey":"1c6599fc-6558-4a0b-9da8-4f002925f59f"
}
]
}
}using System.Text.Json.Serialization;
namespace My.Site.Models;
// this is the "root" of the block grid data
public class BlockGridData
{
public BlockGridData(BlockGridElementData[] contentData, BlockGridElementData[] settingsData, BlockGridExposeData[] expose, BlockGridLayout layout)
{
ContentData = contentData;
SettingsData = settingsData;
Expose = expose;
Layout = layout;
}
[JsonPropertyName("contentData")]
public BlockGridElementData[] ContentData { get; }
[JsonPropertyName("settingsData")]
public BlockGridElementData[] SettingsData { get; }
[JsonPropertyName("expose")]
public BlockGridExposeData[] Expose { get; }
[JsonPropertyName("Layout")]
public BlockGridLayout Layout { get; }
}
// this represents an item in the block grid content or settings data collection
public class BlockGridElementData
{
public BlockGridElementData(Guid contentTypeKey, Guid key, BlockGridValueData[] values)
{
ContentTypeKey = contentTypeKey;
Key = key;
Values = values;
}
[JsonPropertyName("contentTypeKey")]
public Guid ContentTypeKey { get; }
[JsonPropertyName("key")]
public Guid Key { get; }
[JsonPropertyName("values")]
public BlockGridValueData[] Values { get; }
}
public class BlockGridValueData
{
public BlockGridValueData(string alias, string editorAlias, object? value)
{
Alias = alias;
EditorAlias = editorAlias;
Value = value;
}
[JsonPropertyName("alias")]
public string Alias { get; }
[JsonPropertyName("editorAlias")]
public string EditorAlias { get; }
[JsonPropertyName("value")]
public object? Value { get; }
}
// this represents an item in the block grid expose data collection
public class BlockGridExposeData
{
public BlockGridExposeData(Guid contentKey) => ContentKey = contentKey;
[JsonPropertyName("contentKey")]
public Guid ContentKey { get; }
}
// this is a wrapper for the block grid layout, purely required for correct serialization
public class BlockGridLayout
{
public BlockGridLayout(BlockGridLayoutItem[] layoutItems) => LayoutItems = layoutItems;
[JsonPropertyName("Umbraco.BlockGrid")]
public BlockGridLayoutItem[] LayoutItems { get; }
}
// this represents an item in the block grid layout collection
public class BlockGridLayoutItem
{
public BlockGridLayoutItem(int columnSpan, int rowSpan, Guid contentKey, Guid settingsKey)
{
ColumnSpan = columnSpan;
RowSpan = rowSpan;
ContentKey = contentKey;
SettingsKey = settingsKey;
}
[JsonPropertyName("columnSpan")]
public int ColumnSpan { get; }
[JsonPropertyName("rowSpan")]
public int RowSpan { get; }
[JsonPropertyName("contentKey")]
public Guid ContentKey { get; }
[JsonPropertyName("settingsKey")]
public Guid SettingsKey { get; }
[JsonPropertyName("areas")]
// areas are omitted from this sample for abbreviation
public object[] Areas { get; } = [];
}using Microsoft.AspNetCore.Mvc;
using My.Site.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
namespace My.Site.Controllers;
[ApiController]
[Route("/umbraco/api/blockgridtest")]
public class BlockGridTestController : Controller
{
private readonly IContentService _contentService;
private readonly IContentTypeService _contentTypeService;
private readonly IJsonSerializer _serializer;
public BlockGridTestController(IContentService contentService, IContentTypeService contentTypeService, IJsonSerializer serializer)
{
_contentService = contentService;
_contentTypeService = contentTypeService;
_serializer = serializer;
}
// POST: /umbraco/api/blockgridtest/create
[HttpPost("create")]
public ActionResult Create()
{
// get the item content to modify
IContent? content = _contentService.GetById(Guid.Parse("7ed0bd1f-2a52-4b45-9811-2560b907fe48"));
if (content == null)
{
return NotFound("Could not find the content item to modify");
}
// get the element types for spot blocks (content and settings)
IContentType? spotContentType = _contentTypeService.Get("spotElement");
IContentType? spotSettingsType = _contentTypeService.Get("spotSettings");
if (spotContentType == null || spotSettingsType == null)
{
return NotFound("Could not find one or more content types for block data");
}
// this is the raw data to insert into the block grid
var rawData = new[]
{
new { Title = "Item one", Text = "This is item one", Featured = false, ColumnSpan = 12, RowSpan = 1 },
new { Title = "Item two", Text = "This is item two", Featured = true, ColumnSpan = 6, RowSpan = 2 }
};
// build the individual parts of the block grid data from the raw data
var contentData = new List<BlockGridElementData>();
var settingsData = new List<BlockGridElementData>();
var exposeData = new List<BlockGridExposeData>();
var layoutItems = new List<BlockGridLayoutItem>();
foreach (var data in rawData)
{
// generate new keys for block content and settings
var contentKey = Guid.NewGuid();
var settingsKey = Guid.NewGuid();
// create new content data
var contentValues = new BlockGridValueData[]
{
new("title", "Umbraco.TextBox", data.Title),
new("text", "Umbraco.TextBox", data.Text),
};
contentData.Add(new BlockGridElementData(spotContentType.Key, contentKey, contentValues));
// create new settings data
var settingValues = new BlockGridValueData[]
{
new("featured", "Umbraco.TrueFalse", data.Featured ? "1" : "0"),
};
settingsData.Add(new BlockGridElementData(spotSettingsType.Key, settingsKey, settingValues));
// create a new expose item
exposeData.Add(new BlockGridExposeData(contentKey));
// create a new layout item
layoutItems.Add(new BlockGridLayoutItem(data.ColumnSpan, data.RowSpan, contentKey, settingsKey));
}
// construct the block grid data from layout, content and settings
var blockGridData = new BlockGridData(
[.. contentData],
[.. settingsData],
[.. exposeData],
new BlockGridLayout([.. layoutItems]));
// serialize the block grid data as JSON and save it to the "blockGrid" property on the content item
var propertyValue = _serializer.Serialize(blockGridData);
content.SetValue("blockGrid", propertyValue);
_contentService.Save(content);
return Ok("Saved");
}
}Schema Alias: Umbraco.BlockList
UI Alias: Umb.PropertyEditorUi.BlockList
Returns: IEnumerable<BlockListItem>
Block List is a list editing property editor, using Element Types to define the list item schema.
The Block List property editor is configured in the same way as any standard property editor, via the Data Types admin interface.
To set up your Block List Editor property, create a new Data Type and select Block List from the list of available property editors.
Then you will see the configuration options for a Block List as shown below.
The Data Type editor allows you to configure the following properties:
Available Blocks - Here you will define the Block Types to be available for use in the property. For more information, see .
Amount - Sets the minimum and/or maximum number of blocks that should be allowed in the list.
Live editing mode - Enabling this will make editing of a block happening directly to the document model, making changes appear as you type.
Block Types are Element Types which need to be created before you can start configuring them as Block Types. This can be done directly from the property editor setup process. You can also set them up beforehand and add them to the block list after.
Once you have added an element type as a Block Type on your Data Type you will have the option to configure it further.
Each Block has a set of properties that are optional to configure. They are described below.
You can configure the properties in the group to customize the user experience for your content editors. This helps them to quickly identify and select the right blocks for their content.
Label - Define a label for the appearance of the Block in the editor. The label uses to display values of properties. The label is also used for search in the Add Block dialog during content editing. If no label is defined, the block will not be searchable. The search does not fall back to the block’s name.
Overlay editor size - Set the size for the Content editor overlay for editing this block.
It is possible to use two separate Element Types for your Block Types. Its required to have one for Content and optional to add one for Settings.
Content model - This presents the Element Type used as model for the content section of this Block. This cannot be changed, but you can open the Element Type to perform edits or view the properties available. Useful when writing your Label.
Settings model - Add a Settings section to your Block based on a given Element Type. When picked you can open the Element Type or choose to remove the settings section again.
These properties refer to how the Block is presented in the Block catalogue, when editors choose which Blocks to use for their content.
Background color - Define a background color to be displayed beneath the icon or thumbnail. For example, #424242.
Icon color - Change the color of the Element Type icon. For example, #242424.
Thumbnail - Pick an image or SVG file to replace the icon of this Block in the catalogue.
The thumbnails for the catalogue are displayed at a maximum height of 150px and will scale proportionally to maintain their original aspect ratio. Any standard image format (PNG, JPG, SVG) will work effectively.
These properties are relevant when you work with custom views.
Hide content editor - If you made a custom view for editing a block's content, you might want to hide the content-editor from the block editor overlay. This applies when using default editing mode (not inline).
When viewing a Block List editor in the Content section for the first time, you will be presented with the option to add content.
Clicking the Add content button brings up the Block Catalogue. If you only have a single block configured, this button will display "Add {block type name}".
The Block Catalogue looks different depending on the amount of available Blocks and their catalogue appearance.
Click the Block Type you wish to create and a new Block will appear in the list.
Depending on whether your Block List Editor is setup to use default or inline editing mode you will see one of the following things happening:
In default mode you will enter the editing overlay of that Block:
In inline editing mode, the new Blocks will expand to show its inline editor:
More Blocks can be added to the list by clicking the "Create new" button. You can also use the inline Add button that appears on hover between or above existing Blocks.
To reorder the Blocks, click and drag a Block up or down to place in the desired order.
To delete a Block click the trash-bin icon appearing on hover.
Rendering the stored value of your Block List property can be done in two ways.
You can choose to use the built-in rendering mechanism for rendering blocks via a Partial View for each block.
The default rendering method is named GetBlockListHtml() and comes with a few options to go with it. The typical use could be:
"MyBlocks" above is the alias for the Block List editor.
If using ModelsBuilder the example can be simplified:
Example:
To make this work you will need to create a Partial View for each block. The partial view should be named by the alias of the Element Type that is being used as Content Model.
These partial views must be placed in this folder: Views/Partials/BlockList/Components/. Example: Views/Partials/BlockList/Components/MyElementTypeAliasOfContent.cshtml.
A Partial View will receive the model of Umbraco.Core.Models.Blocks.BlockListItem. This gives you the option to access properties of the Content and Settings section of your Block.
In this example of a Partial view for a Block Type, the MyElementTypeAliasOfContent and MyElementTypeAliasOfSettings should correspond with the selected Element Type Alias for the given model.
Example:
ContentModels.MyElementTypeAliasOfContent must be replaced with the PascalCase version of your Element Type alias, as generated by ModelsBuilder. For example, an Element Type with alias exampleBlock becomes ContentModels.ExampleBlock.
With ModelsBuilder:
A built-in value converter is available to use the data as you like. Call the Value<T> method with a generic type of IEnumerable<BlockListItem> and the stored value will be returned as a list of BlockListItem entities.
Example:
Replace MyFolderOfBlocks/ with the path to your partial views folder. If using the default location, this should be ~/Views/Partials/BlockList/Components/.
Each item is a BlockListItem entity that contains two main properties Content and Settings. Each of these is a IPublishedElement which means you can use all the value converters you are used to using.
Example:
Sometimes, you might want to use the Block List Editor to hold some data and not necessarily render a view. This applies when the data should be presented in different areas on a page. An example could be a product page with variants stored in a Block List Editor.
In this case, you can extract the variant's data using the following, which returns IEnumerable<IPublishedElement>.
Example:
.Select(x => x.Content) strips away the BlockListItem wrapper and returns the IPublishedElement content data, discarding the settings.
If using ModelsBuilder the example can be simplified:
Example:
Replace the following:
Model.Variants with the ModelsBuilder-generated property name for your Block List property, for example Model.BlockListPropertyExample.
<ProductVariant> with the ModelsBuilder-generated class name for your element type, for example QuoteBlock.
If your Block List Editor only uses a single block, you can cast the collection to a specific type. Supply a type T using .OfType<T>(), otherwise the return value will be IEnumerable<IPublishedElement>.
Building Custom Views for Block representations in Backoffice is the same for all Block Editors.
Sometimes you need to create or update Block List content via code, for example, during content migrations, data imports, or automated workflows. This section explains how to achieve this using IContentService and IContentTypeService.
Block List data is stored as a JSON string. Understanding this structure is essential before writing any import code.
layout: Defines the order blocks appear in and links each block to its content through a contentKey (a GUID). If the block has a Settings model, the layout entry also holds a settingsKey.
contentData: Holds the property values for each block. Every entry must include a key matching a contentKey in the layout, a contentTypeKey
The following example shows how to build a Block List and save it to an existing content node. It assumes you have:
A Document Type with a Block List property aliased timelineItems.
An Element Type aliased timelineItem with two properties: eventName (Textstring Data Type) and period (Textstring Data Type).
Create a TimelineImportController.cs file in MyProject/Controllers.
Rebuild and run your project.
Make a POST request to:
With this body, substituting your actual GUID from the Info tab:
You can use Postman, Bruno, or the browser's fetch console to make the call. If you get a 401 back, the endpoint needs authentication. In that case, the quickest fix for local testing is to add [AllowAnonymous] to the controller temporarily.
Open your content node in the Backoffice.
Check the timelineItems Block List property. You should see the imported blocks populated with your data.
Create a Partial View for the timelineItem element type to render the imported blocks on the frontend at: Views/Partials/BlockList/Components/timelineItem.cshtml.
Example partial:
Render the Block List in your page template using:
Browse to your page on the frontend (for example, https://localhost:{port}) and you should see each imported block rendered.
By default, calling SetValue() with a new JSON structure overwrites all existing blocks. Use this approach instead if you need to preserve existing content.
To append new blocks to an existing list without losing current content, read and deserialize the existing value first. Then append to those collections before saving. Update the Import method in your controller:
If your Block Type has a Settings model configured, each block needs a settingsKey referenced in both layout and settingsData. A Settings model is the optional second Element Type you can attach to a block. It is commonly used to let editors control things like background color, padding, or visibility toggles separately from the block's content.
To use settings, fetch both Element Types and generate a separate key for each block's settings entry. Declare a settingsData list alongside the other collections and pass it when constructing the value: new BlockListValue(layout) { ContentData = contentData, SettingsData = settingsData, Expose = expose }.
If your site uses multiple languages and your Document Type is configured to vary by culture, pass the target culture string to SetValue() and GetValue().
Ensure Allow vary by culture is enabled on your Document Type in the Settings tab. The Block List property's Variation ("Shared across cultures") should be disabled. The Variation option on the Block List property editor only appears once the Document Type is set to vary by culture.
Property editor width - Overwrite the width of the property editor. This field takes any valid css value for "max-width".
Create modal size- Controls the size of the Block Catalogue dialog shown when an editor clicks "Create new" to choose a block type. It does not affect the block's content-editing overlay (for either creating or editing a block's content). The overlay's size is set per Block Type via Overlay editor size.
Single block mode - When enabled, the Block List is restricted to a single block and the property returns a BlockListItem<> instead of BlockListModel
values{ "alias", "value" }settingsData: Holds settings values if your Block Type has a Settings model configured. It follows the same shape as contentData.
expose: Lists which blocks are visible, per culture and segment. A block is only rendered if it has a matching expose entry. For invariant content, use null for both culture and segment.
@Html.GetBlockListHtml(Model, "MyBlocks")@Html.GetBlockListHtml(Model.MyBlocks)@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockListItem>;
@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
@{
var content = (ContentModels.MyElementTypeAliasOfContent)Model.Content;
var settings = Model.Settings as ContentModels.MyElementTypeAliasOfContent; // Cast Model.Settings safely using 'as' to avoid null reference exceptions
}
@* Output the value of field with alias 'heading' from the Element Type selected as Content section *@
<h1>@content.Value("heading")</h1>@* Output the value of field with alias 'heading' from the Element Type selected as Content section *@
<h1>@content.Heading</h1>@using Umbraco.Cms.Core.Models.Blocks
@using Umbraco.Cms.Web.Common.PublishedModels;
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ContentModels.TestBlockPage>
@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
@{
var blocks = Model.Value<IEnumerable<BlockListItem>>("myBlocksProperty");
foreach (var block in blocks)
{
var content = block.Content;
@Html.Partial("MyFolderOfBlocks/" + content.ContentType.Alias + ".cshtml", block)
}
}@using Umbraco.Cms.Core.Models.Blocks
@using Umbraco.Cms.Web.Common.PublishedModels;
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ContentModels.TestBlockPage>
@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
@{
var blocks = Model.Value<IEnumerable<BlockListItem>>("myBlocksProperty");
foreach (var block in blocks)
{
var content = (ContentModels.MyAliasOfContentElementType)block.Content;
var settings = (ContentModels.MyAliasOfSettingsElementType)block.Settings;
<h1>@content.MyExampleHeadlinePropertyAlias</h1>
}
}@using Umbraco.Cms.Core.Models.Blocks
@using Umbraco.Cms.Web.Common.PublishedModels;
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ContentModels.TestBlockPage>
@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
@{
var variants = Model.Value<IEnumerable<BlockListItem>>("variants").Select(x => x.Content);
foreach (var variant in variants)
{
<h4>@variant.Value("variantName")</h4>
<p>@variant.Value("description")</p>
}
}@using Umbraco.Cms.Core.Models.Blocks
@using Umbraco.Cms.Web.Common.PublishedModels;
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ContentModels.TestBlockPage>
@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
@{
var variants = Model.Variants.Select(x => x.Content).OfType<ProductVariant>();
foreach (var variant in variants)
{
<h4>@variant.VariantName</h4>
<p>@variant.Description</p>
}
}{
"layout": {
"Umbraco.BlockList": [
{ "contentKey": "abc123cd-0000-0000-0000-000000000000" }
]
},
"contentData": [
{
"key": "abc123cd-0000-0000-0000-000000000000",
"contentTypeKey": "faeccfe7-ebea-4461-9caa-cc9e3541c969",
"values": [
{ "alias": "myTextProperty", "value": "Hello world" }
]
}
],
"settingsData": [],
"expose": [
{ "contentKey": "abc123cd-0000-0000-0000-000000000000", "culture": null, "segment": null }
]
}using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models.Blocks;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
[ApiController]
[Route("/umbraco/api/timelineimport")]
public class TimelineImportController : ControllerBase
{
private readonly IContentService _contentService;
private readonly IContentTypeService _contentTypeService;
private readonly IJsonSerializer _jsonSerializer;
public TimelineImportController(
IContentService contentService,
IContentTypeService contentTypeService,
IJsonSerializer jsonSerializer)
{
_contentService = contentService;
_contentTypeService = contentTypeService;
_jsonSerializer = jsonSerializer;
}
[HttpPost("import")]
public IActionResult Import([FromBody] ImportModel importModel)
{
try
{
if (!Guid.TryParse(importModel.PageGuid, out var pageId))
return BadRequest("Invalid pageGuid value.");
var page = _contentService.GetById(pageId);
if (page == null)
return NotFound("Page not found.");
if (!page.Properties.Contains(importModel.BlockListAlias))
return BadRequest($"Property '{importModel.BlockListAlias}' does not exist.");
var elementType = _contentTypeService.Get(importModel.ElementTypeAlias);
if (elementType == null)
return NotFound($"Element Type '{importModel.ElementTypeAlias}' not found.");
var layout = new List<BlockListLayoutItem>();
var contentData = new List<BlockItemData>();
var expose = new List<BlockItemVariation>();
foreach (var item in importModel.Items)
{
// Generate a unique key (GUID) for each block. Never reuse or hardcode these.
var contentKey = Guid.NewGuid();
layout.Add(new BlockListLayoutItem(contentKey));
contentData.Add(new BlockItemData(contentKey, elementType.Key, elementType.Alias)
{
Values =
{
new BlockPropertyValue { Alias = "eventName", Value = item.Name },
new BlockPropertyValue { Alias = "period", Value = $"{item.StartDate} - {item.EndDate}" }
}
});
// A block is only rendered if it is exposed.
// Invariant content uses null for both culture and segment.
expose.Add(new BlockItemVariation(contentKey, culture: null, segment: null));
}
var blockListValue = new BlockListValue(layout)
{
ContentData = contentData,
Expose = expose
};
page.SetValue(importModel.BlockListAlias, _jsonSerializer.Serialize(blockListValue));
// Calling Publish() alone without Save() first will not persist changes.
_contentService.Save(page);
var publishResult = _contentService.Publish(page, ["*"]);
if (!publishResult.Success)
return BadRequest($"Failed to publish page: {publishResult.Result}");
return Ok("Items imported and published successfully.");
}
catch (Exception ex)
{
return StatusCode(500, $"Import failed: {ex.Message}");
}
}
}public class ImportModel
{
public string PageGuid { get; set; } = string.Empty;
public string BlockListAlias { get; set; } = string.Empty;
public string ElementTypeAlias { get; set; } = string.Empty;
public List<TimelineItemModel> Items { get; set; } = new();
}
public class TimelineItemModel
{
public string Name { get; set; } = string.Empty;
public string StartDate { get; set; } = string.Empty;
public string EndDate { get; set; } = string.Empty;
}POST https://localhost:{port}/umbraco/api/timelineimport/import
Content-Type: application/json{
"pageGuid": "YOUR-GUID-FROM-INFO-TAB",
"blockListAlias": "timelineItems",
"elementTypeAlias": "timelineItem",
"items": [
{ "name": "Project launched", "startDate": "2021", "endDate": "2022" },
{ "name": "First release", "startDate": "2022", "endDate": "2023" }
]
}@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockListItem>
@{
var eventName = Model.Content.Value("eventName")?.ToString();
var period = Model.Content.Value("period")?.ToString();
}
<div class="timeline-item">
<h3>@eventName</h3>
<p>@period</p>
</div>@Html.GetBlockListHtml(Model, "timelineItems")[HttpPost("import")]
public IActionResult Import([FromBody] ImportModel importModel)
{
try
{
if (!Guid.TryParse(importModel.PageGuid, out var pageId))
return BadRequest("Invalid pageGuid value.");
var page = _contentService.GetById(pageId);
if (page == null)
return NotFound("Page not found.");
if (!page.Properties.Contains(importModel.BlockListAlias))
return BadRequest($"Property '{importModel.BlockListAlias}' does not exist.");
var elementType = _contentTypeService.Get(importModel.ElementTypeAlias);
if (elementType == null)
return NotFound($"Element Type '{importModel.ElementTypeAlias}' not found.");
// Read the existing value and deserialise it, or start from an empty Block List.
var existingJson = page.GetValue<string>(importModel.BlockListAlias);
var blockListValue = string.IsNullOrWhiteSpace(existingJson)
? new BlockListValue()
: _jsonSerializer.Deserialize<BlockListValue>(existingJson) ?? new BlockListValue();
// Copy the existing layout so new items can be appended to it.
var layout = blockListValue.GetLayouts()?.ToList() ?? new List<BlockListLayoutItem>();
// Append new blocks to the existing collections
foreach (var item in importModel.Items)
{
var contentKey = Guid.NewGuid();
layout.Add(new BlockListLayoutItem(contentKey));
blockListValue.ContentData.Add(new BlockItemData(contentKey, elementType.Key, elementType.Alias)
{
Values =
{
new BlockPropertyValue { Alias = "eventName", Value = item.Name },
new BlockPropertyValue { Alias = "period", Value = $"{item.StartDate} - {item.EndDate}" }
}
});
blockListValue.Expose.Add(new BlockItemVariation(contentKey, culture: null, segment: null));
}
// Write the updated layout back to the Block List.
blockListValue.Layout[Constants.PropertyEditors.Aliases.BlockList] = layout;
page.SetValue(importModel.BlockListAlias, _jsonSerializer.Serialize(blockListValue));
_contentService.Save(page);
var publishResult = _contentService.Publish(page, ["*"]);
if (!publishResult.Success)
return BadRequest($"Failed to publish page: {publishResult.Result}");
return Ok("Items appended and published successfully.");
}
catch (Exception ex)
{
return StatusCode(500, $"Import failed: {ex.Message}");
}
}var contentElementType = _contentTypeService.Get("timelineItem");
var settingsElementType = _contentTypeService.Get("timelineItemSettings");
var contentKey = Guid.NewGuid();
var settingsKey = Guid.NewGuid();
// Layout entry references both keys
layout.Add(new BlockListLayoutItem(contentKey, settingsKey));
// Content entry uses the content key and content Element Type
contentData.Add(new BlockItemData(contentKey, contentElementType.Key, contentElementType.Alias)
{
Values =
{
new BlockPropertyValue { Alias = "eventName", Value = "Project launched" },
new BlockPropertyValue { Alias = "period", Value = "2021 - 2022" }
}
});
// Settings entry uses the settings key and settings Element Type
settingsData.Add(new BlockItemData(settingsKey, settingsElementType.Key, settingsElementType.Alias)
{
Values =
{
new BlockPropertyValue { Alias = "isHighlighted", Value = "1" }
}
});
// The block still needs an expose entry, which references the content key only
expose.Add(new BlockItemVariation(contentKey, culture: null, segment: null));string targetCulture = "da-DK";
// Read the existing value for the correct culture
var existingJson = page.GetValue<string>(importModel.BlockListAlias, culture: targetCulture);
var blockListValue = string.IsNullOrWhiteSpace(existingJson)
? new BlockListValue()
: _jsonSerializer.Deserialize<BlockListValue>(existingJson) ?? new BlockListValue();
// ... build or append blocks ...
// For culture-variant blocks, each expose entry must use the target culture instead of null:
// blockListValue.Expose.Add(new BlockItemVariation(contentKey, culture: targetCulture, segment: null));
page.SetValue(importModel.BlockListAlias, _jsonSerializer.Serialize(blockListValue), culture: targetCulture);
_contentService.Save(page);
_contentService.Publish(page, new[] { targetCulture });Single block mode is deprecated. Use the Single Block property editor instead.
Before Umbraco 14, Block List data used a different format. Blocks were referenced by UDI (umb://element/...), property values were stored as flat keys, and there was no expose array. That legacy format is no longer supported in Umbraco 18, so always write new content in the format shown below.
Always pass the same culture string to both GetValue() and SetValue(). Omitting the culture from GetValue() reads the invariant slot, which is empty on a culture-variant property, causing existing blocks to be overwritten instead of appended.









Breaking changes introduced in each major version of Umbraco CMS, with notes on what to update when upgrading.
Use the information below to learn about any potential breaking changes and common pitfalls when upgrading your Umbraco CMS project.
If any specific steps are involved with upgrading to a specific version they will be listed below.
Use the general upgrade guide to complete the upgrade of your project.
Before running the upgrade, consider the following:
Umbraco 18 can only upgrade from Umbraco 16.4 or later, because it no longer includes the migrations from Umbraco 13 to 17. Upgrade your project to Umbraco 17, the latest Long-term Support (LTS) version, before you upgrade to Umbraco 18.
In Umbraco 18, the EnableMediaRecycleBinProtection setting defaults to true. With this enabled, media files moved to the recycle bin are renamed with a .deleted suffix (and renamed back on restore). Emptying the media recycle bin before upgrading avoids any uncertainty around the state of files already in the bin from prior versions.
For details, see the entry on EnableMediaRecycleBinProtection further down.
The single-mode block list migration was added in Umbraco 17 but disabled by default. It now runs automatically during the upgrade to Umbraco 18.
If your site has custom property editors that nest block list values, you must implement and register an ITypedSingleBlockListProcessor before upgrading. Without this, nested data in those property values will not be migrated and will remain in the old format.
For details, see the article.
You can find a list of all the released Umbraco versions on website. When you visit Our Umbraco website, click on the version number to view the changes made in that specific version.
To look up a specific node by its key or ID, use IPublishedContentQuery.Content(id) (or UmbracoHelper.Content(id)) directly.
Scripts
IScriptService
MemberConfigurationResponseModelIMemberGroupService (#22632)
IMemberService.GetMembersByPropertyValue (#22678)
You rely on Razor runtime compilation to edit templates via the backoffice.
You use the RoslynCompiler class (you'll also need to update your namespace usings).
ChildrenAsTableChildrenAsTableDataTableRetryUntilSuccessOrTimeout
RetryUntilSuccessOrMaxAttempts
HasFlagAny
Deconstruct
AsEnumerable, ContainsKey and GetValue extending NameValueCollection
DisposeIfDisposable
SafeCast
ToDictionary on object
SanitizeThreadCulture
UMB_CURRENT_USER_CONFIG_STORE_CONTEXTtryExecuteAndNotifytryExecuteUmbraco.Cms.Infrastructure.Migrations.MigrationPlan.get_PostMigrationTypes removed.
Umbraco.Cms.Infrastructure.Migrations.Upgrade.Upgrader.Execute(Umbraco.Cms.Core.Migrations.IMigrationPlanExecutor,Umbraco.Cms.Core.Scoping.IScopeProvider,Umbraco.Cms.Core.Services.IKeyValueService) was obsolete and is replaced by method taking a ICoreScopeProvider instead of a IScopeProvider
Umbraco.Cms.Core.Models.PublishedContent.IPublishedPropertyType.ConvertInterToDeliveryApiObject(Umbraco.Cms.Core.Models.PublishedContent.IPublishedElement,Umbraco.Cms.Core.PropertyEditors.PropertyCacheLevel,System.Object,System.Boolean,System.Boolean)
Umbraco.Cms.Core.Models.PublishedContent.IPublishedPropertyType.ConvertInterToDeliveryApiObject(Umbraco.Cms.Core.Models.PublishedContent.IPublishedElement,Umbraco.Cms.Core.PropertyEditors.PropertyCacheLevel,System.Object,System.Boolean)
Umbraco.Cms.Core.Models.PublishedContent.IPublishedPropertyType.DeliveryApiCacheLevel
Umbraco.Cms.Core.Scoping.ICoreScope.Locks
Umbraco.Cms.Core.Migrations.IMigrationPlanExecutor.ExecutePlan(Umbraco.Cms.Infrastructure.Migrations.MigrationPlan,System.String)
Umbraco.Cms.Infrastructure.Search.IUmbracoIndexingHandler.RemoveProtectedContent
Umbraco.Cms.Infrastructure.Examine.IUmbracoIndex.SupportProtectedContent
Core.Constants.DatabaseProviders and Core.Constants.-DbProviderNames to Umbraco.Cms.Persistence.SqlServer.ConstantsSome SQL Server related services moved from the Umbraco.Infrastructure project to the new Umbraco.Cms.Persistence.
SqlServer project with altered namespaces e.g. SqlServerSyntaxProvider, SqlServerBulkSqlInsertProvider, SqlServerDatabaseCreator.
ISqlSyntaxProvider.InsertForUpdateHint(Sql)
ISqlSyntaxProvider.AppendForUpdateHint(Sql)
ISqlSyntaxProvider.LeftJoinWithNestedJoin(Sql,Func<Sql,Sql>,String)
umbracoMemberLastLockoutDateumbracoMemberLastLogin
umbracoMemberLastPasswordChangeDate
/umbraco/swagger
/umbraco/openapi
/umbraco/swagger/{documentName}/swagger.json
/umbraco/openapi/{documentName}.json
Old (IFileService)
New
Templates
ITemplateService
Partial views
IPartialViewService
Stylesheets
Important! These modes do not rely on Razor runtime compilation. However, ensure the following settings are removed from your .csproj file.
Community Insight: Watch this video walkthrough for a deep dive into the major changes from Umbraco 13 through 17.
IStylesheetService
public class ProductsController : UmbracoApiController
{
public IActionResult GetAll() => Ok(new[] { "Table", "Chair" });
}using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("/api/shop/products")]
public class ProductsController : Controller
{
[HttpGet]
public IActionResult GetAll() => Ok(new[] { "Table", "Chair" });
}var parent = Model.Parent;
foreach (var child in Model.Children)
{
// ...
}var parent = Model.Parent();
foreach (var child in Model.Children())
{
// ...
}IEnumerable<IPublishedContent> roots = Umbraco.ContentAtRoot();public class MyComponent
{
private readonly ILocalizationService _localizationService;
public MyComponent(ILocalizationService localizationService)
=> _localizationService = localizationService;
public IEnumerable<ILanguage> GetLanguages()
=> _localizationService.GetAllLanguages();
}public class MyComponent
{
private readonly ILanguageService _languageService;
public MyComponent(ILanguageService languageService)
=> _languageService = languageService;
public async Task<IEnumerable<ILanguage>> GetLanguagesAsync()
=> await _languageService.GetAllAsync();
}public class AddCommentsTable : MigrationBase
{
public AddCommentsTable(IMigrationContext context) : base(context)
{
}
protected override void Migrate()
{
if (TableExists("BlogComments") == false)
{
Create.Table<BlogCommentSchema>().Do();
}
}
}public class AddCommentsTable : AsyncMigrationBase
{
public AddCommentsTable(IMigrationContext context) : base(context)
{
}
protected override Task MigrateAsync()
{
if (TableExists("BlogComments") == false)
{
Create.Table<BlogCommentSchema>().Do();
}
return Task.CompletedTask;
}
} "Umbraco": {
"CMS": {
"SystemDateMigration": {
"Enabled": false
}
}
} "Umbraco": {
"CMS": {
"SystemDateMigration": {
"LocalServerTimeZone": "Eastern Standard Time"
}
}
}import { Editor } from '@umbraco-cms/backoffice/external/tiptap';import { Editor } from '@umbraco-cms/backoffice/tiptap';<PropertyGroup>
<RazorCompileOnBuild>false</RazorCompileOnBuild>
<RazorCompileOnPublish>false</RazorCompileOnPublish>
</PropertyGroup>:root {
--umb-header-logo-display: none;
} {
"type": "mfaLoginProvider",
"alias": "my.2fa.provider",
"name": "My 2fa Provider",
"forProviderName": "UmbracoUserAppAuthenticator",
"meta": {
"label": "Authenticate with a 2FA code"
}
} {
"type": "authProvider",
"alias": "My.AuthProvider.Google",
"name": "Google Auth Provider",
"forProviderName": "Umbraco.Google",
"meta": {
"label": "Google",
"defaultView": {
"icon": "icon-google"
},
"linking": {
"allowManualLinking": true
}
}
}
{
...
"ConnectionStrings": {
"umbracoDbDSN": "Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True",
"umbracoDbDSN_ProviderName": "Microsoft.Data.Sqlite",
"umbracoCommerceDbDSN": "Data Source=|DataDirectory|/Umbraco.Commerce.sqlite.db;Mode=ReadWrite;Foreign Keys=True;Pooling=True;Cache=Shared",
"umbracoCommerceDbDSN_ProviderName": "Microsoft.Data.Sqlite"
},
...
}
Umbraco.Extensions.ServiceCollectionExtensions.AddUnique<TImplementing>(Microsoft.Extensions.DependencyInjection.IServiceCollection)
Umbraco.Extensions.EnumExtensions.HasFlagAll<T>(T, T)
Umbraco.Extensions.FriendlyImageCropperTemplateExtensions.GetLocalCropUrl(Umbraco.Cms.Core.Models.MediaWithCrops, string, string?)Umbraco.Cms.Core.Constants.Conventions.Member.IsApproved
Umbraco.Cms.Core.Constants.Conventions.Member.IsApprovedLabel
Umbraco.Cms.Core.Constants.Conventions.Member.IsLockedOut
Umbraco.Cms.Core.Constants.Conventions.Member.IsLockedOutLabel
Umbraco.Cms.Core.Constants.Conventions.Member.LastLoginDate
Umbraco.Cms.Core.Constants.Conventions.Member.LastLoginDateLabel
Umbraco.Cms.Core.Constants.Conventions.Member.LastPasswordChangeDate
Umbraco.Cms.Core.Constants.Conventions.Member.LastPasswordChangeDateLabel
Umbraco.Cms.Core.Constants.Conventions.Member.LastLockoutDate
Umbraco.Cms.Core.Constants.Conventions.Member.LastLockoutDateLabel
Umbraco.Cms.Core.Constants.Conventions.Member.FailedPasswordAttempts
Umbraco.Cms.Core.Constants.Conventions.Member.FailedPasswordAttemptsLabel
Umbraco.Cms.Core.WebAssets.IRuntimeMinifier.Reset()
Umbraco.Cms.Core.Services.IExternalLoginService
Umbraco.Cms.Core.Services.ExternalLoginService.ExternalLoginService(
Umbraco.Cms.Core.Scoping.ICoreScopeProvider,
Microsoft.Extensions.Logging.ILoggerFactory,
Umbraco.Cms.Core.Events.IEventMessagesFactory,
Umbraco.Cms.Core.Persistence.Repositories.IExternalLoginRepository)
Umbraco.Cms.Core.Services.ExternalLoginService.GetExternalLogins(int)
Umbraco.Cms.Core.Services.ExternalLoginService.GetExternalLoginTokens(int)
Umbraco.Cms.Core.Services.ExternalLoginService.Save(int,
System.Collections.Generic.IEnumerable<Umbraco.Cms.Core.Security.IExternalLogin>)
Umbraco.Cms.Core.Services.ExternalLoginService.Save(int,
System.Collections.Generic.IEnumerable<Umbraco.Cms.Core.Security.IExternalLoginToken>)
Umbraco.Cms.Core.Services.ExternalLoginService.DeleteUserLogins(int)
Umbraco.Cms.Core.Services.IMacroWithAliasService
Umbraco.Cms.Core.Services.ITwoFactorLoginService2
Umbraco.Cms.Core.Services.LocalizedTextService.LocalizedTextService(
System.Collections.Generic.IDictionary<System.Globalization.CultureInfo, System.Collections.Generic.IDictionary<string, System.Collections.Generic.IDictionary<string, string>>>,
Microsoft.Extensions.Logging.ILogger<Umbraco.Cms.Core.Services.LocalizedTextService>)
Umbraco.Cms.Core.Services.ServiceContext.ServiceContext(
System.Lazy<Umbraco.Cms.Core.Services.IPublicAccessService>?,
System.Lazy<Umbraco.Cms.Core.Services.IDomainService>?,
System.Lazy<Umbraco.Cms.Core.Services.IAuditService>?,
System.Lazy<Umbraco.Cms.Core.Services.ILocalizedTextService>?,
System.Lazy<Umbraco.Cms.Core.Services.ITagService>?,
System.Lazy<Umbraco.Cms.Core.Services.IContentService>?,
System.Lazy<Umbraco.Cms.Core.Services.IUserService>?,
System.Lazy<Umbraco.Cms.Core.Services.IMemberService>?,
System.Lazy<Umbraco.Cms.Core.Services.IMediaService>?,
System.Lazy<Umbraco.Cms.Core.Services.IContentTypeService>?,
System.Lazy<Umbraco.Cms.Core.Services.IMediaTypeService>?,
System.Lazy<Umbraco.Cms.Core.Services.IDataTypeService>?,
System.Lazy<Umbraco.Cms.Core.Services.IFileService>?,
System.Lazy<Umbraco.Cms.Core.Services.ILocalizationService>?,
System.Lazy<Umbraco.Cms.Core.Services.IPackagingService>?,
System.Lazy<Umbraco.Cms.Core.Services.IServerRegistrationService>?,
System.Lazy<Umbraco.Cms.Core.Services.IEntityService>?,
System.Lazy<Umbraco.Cms.Core.Services.IRelationService>?,
System.Lazy<Umbraco.Cms.Core.Services.IMacroService>?,
System.Lazy<Umbraco.Cms.Core.Services.IMemberTypeService>?,
System.Lazy<Umbraco.Cms.Core.Services.IMemberGroupService>?,
System.Lazy<Umbraco.Cms.Core.Services.INotificationService>?,
System.Lazy<Umbraco.Cms.Core.Services.IExternalLoginService>?,
System.Lazy<Umbraco.Cms.Core.Services.IRedirectUrlService>?,
System.Lazy<Umbraco.Cms.Core.Services.IConsentService>?,
System.Lazy<Umbraco.Cms.Core.Services.IKeyValueService>?,
System.Lazy<Umbraco.Cms.Core.Services.IContentTypeBaseServiceProvider>?)
Umbraco.Cms.Core.Services.ServiceContext.CreatePartial(
Umbraco.Cms.Core.Services.IContentService?,
Umbraco.Cms.Core.Services.IMediaService?,
Umbraco.Cms.Core.Services.IContentTypeService?,
Umbraco.Cms.Core.Services.IMediaTypeService?,
Umbraco.Cms.Core.Services.IDataTypeService?,
Umbraco.Cms.Core.Services.IFileService?,
Umbraco.Cms.Core.Services.ILocalizationService?,
Umbraco.Cms.Core.Services.IPackagingService?,
Umbraco.Cms.Core.Services.IEntityService?,
Umbraco.Cms.Core.Services.IRelationService?,
Umbraco.Cms.Core.Services.IMemberGroupService?,
Umbraco.Cms.Core.Services.IMemberTypeService?,
Umbraco.Cms.Core.Services.IMemberService?,
Umbraco.Cms.Core.Services.IUserService?,
Umbraco.Cms.Core.Services.ITagService?,
Umbraco.Cms.Core.Services.INotificationService?,
Umbraco.Cms.Core.Services.ILocalizedTextService?,
Umbraco.Cms.Core.Services.IAuditService?,
Umbraco.Cms.Core.Services.IDomainService?,
Umbraco.Cms.Core.Services.IMacroService?,
Umbraco.Cms.Core.Services.IPublicAccessService?,
Umbraco.Cms.Core.Services.IExternalLoginService?,
Umbraco.Cms.Core.Services.IServerRegistrationService?,
Umbraco.Cms.Core.Services.IRedirectUrlService?,
Umbraco.Cms.Core.Services.IConsentService?,
Umbraco.Cms.Core.Services.IKeyValueService?,
Umbraco.Cms.Core.Services.IContentTypeBaseServiceProvider?)
Umbraco.Cms.Core.Services.TwoFactorLoginService.TwoFactorLoginService(
Umbraco.Cms.Core.Persistence.Repositories.ITwoFactorLoginRepository,
Umbraco.Cms.Core.Scoping.ICoreScopeProvider,
System.Collections.Generic.IEnumerable<Umbraco.Cms.Core.Security.ITwoFactorProvider>,
Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Identity.IdentityOptions>,
Microsoft.Extensions.Options.IOptions<Umbraco.Cms.Core.Security.BackOfficeIdentityOptions>)
Umbraco.Cms.Core.Routing.DefaultUrlProvider.DefaultUrlProvider(
Microsoft.Extensions.Options.IOptionsMonitor<Umbraco.Cms.Core.Configuration.Models.RequestHandlerSettings>,
Microsoft.Extensions.Logging.ILogger<Umbraco.Cms.Core.Routing.DefaultUrlProvider>,
Umbraco.Cms.Core.Routing.ISiteDomainMapper,
Umbraco.Cms.Core.Web.IUmbracoContextAccessor,
Umbraco.Cms.Core.Routing.UriUtility)
Umbraco.Cms.Core.Persistence.Repositories.IExternalLoginRepository
Umbraco.Cms.Core.Persistence.Repositories.IMacroWithAliasRepository
Umbraco.Cms.Core.Persistence.Repositories.IMemberRepository.SetLastLogin(string, System.DateTime)
Umbraco.Cms.Core.Notifications.UmbracoApplicationComponentsInstallingNotification
Umbraco.Cms.Core.Notifications.UmbracoApplicationMainDomAcquiredNotification
Umbraco.Cms.Core.Notifications.UmbracoApplicationStartingNotification.UmbracoApplicationStartingNotification(Umbraco.Cms.Core.RuntimeLevel)
Umbraco.Cms.Core.Notifications.UmbracoApplicationStoppingNotification.UmbracoApplicationStoppingNotification()
Umbraco.Cms.Core.Models.IContentTypeWithHistoryCleanup
Umbraco.Cms.Core.Models.Language.Language(Umbraco.Cms.Core.Configuration.Models.GlobalSettings, string)
Umbraco.Cms.Core.Models.RelationType.RelationType(string, string, bool, System.Nullable<System.Guid>, System.Nullable<System.Guid>)
Umbraco.Cms.Core.Models.PublishedContent.PublishedContentType.PublishedContentType(int, string,
Umbraco.Cms.Core.Models.PublishedContent.PublishedItemType,
System.Collections.Generic.IEnumerable<string>,
System.Collections.Generic.IEnumerable<Umbraco.Cms.Core.Models.PublishedContent.PublishedPropertyType>,
Umbraco.Cms.Core.Models.ContentVariation,
bool)
Umbraco.Cms.Core.Models.PublishedContent.PublishedContentType.PublishedContentType(int, string,
Umbraco.Cms.Core.Models.PublishedContent.PublishedItemType, System.Collections.Generic.IEnumerable<string>,
System.Func<Umbraco.Cms.Core.Models.PublishedContent.IPublishedContentType,
System.Collections.Generic.IEnumerable<Umbraco.Cms.Core.Models.PublishedContent.IPublishedPropertyType>>,
Umbraco.Cms.Core.Models.ContentVariation,
bool)
Umbraco.Cms.Core.Models.Mapping.ContentTypeMapDefinition.ContentTypeMapDefinition(
Umbraco.Cms.Core.Models.Mapping.CommonMapper,
Umbraco.Cms.Core.PropertyEditors.PropertyEditorCollection,
Umbraco.Cms.Core.Services.IDataTypeService,
Umbraco.Cms.Core.Services.IFileService,
Umbraco.Cms.Core.Services.IContentTypeService,
Umbraco.Cms.Core.Services.IMediaTypeService,
Umbraco.Cms.Core.Services.IMemberTypeService,
Microsoft.Extensions.Logging.ILoggerFactory,
Umbraco.Cms.Core.Strings.IShortStringHelper,
Microsoft.Extensions.Options.IOptions<Umbraco.Cms.Core.Configuration.Models.GlobalSettings>,
Umbraco.Cms.Core.Hosting.IHostingEnvironment)
Umbraco.Cms.Core.Models.ContentEditing.UserGroupPermissionsSave.Validate(System.ComponentModel.DataAnnotations.ValidationContext)
Umbraco.Cms.Core.Install.InstallSteps.TelemetryIdentifierStep.TelemetryIdentifierStep(
Microsoft.Extensions.Logging.ILogger<Umbraco.Cms.Core.Install.InstallSteps.TelemetryIdentifierStep>,
Microsoft.Extensions.Options.IOptions<Umbraco.Cms.Core.Configuration.Models.GlobalSettings>,
Umbraco.Cms.Core.Configuration.IConfigManipulator)
Umbraco.Cms.Core.IO.ViewHelper.ViewHelper(Umbraco.Cms.Core.IO.IFileSystem)
Umbraco.Cms.Core.HealthChecks.Checks.Security.BaseHttpHeaderCheck.BaseHttpHeaderCheck(
Umbraco.Cms.Core.Hosting.IHostingEnvironment,
Umbraco.Cms.Core.Services.ILocalizedTextService,
string,
string,
string,
bool)
Umbraco.Cms.Core.DependencyInjection.UmbracoBuilderExtensions.AddOEmbedProvider<T>(Umbraco.Cms.Core.DependencyInjection.IUmbracoBuilder)
Umbraco.Cms.Core.DependencyInjection.UmbracoBuilderExtensions.OEmbedProviders(Umbraco.Cms.Core.DependencyInjection.IUmbracoBuilder)
Umbraco.Cms.Core.Configuration.Models.RequestHandlerSettings.CharCollection.get
Umbraco.Cms.Core.Configuration.Models.RequestHandlerSettings.CharCollection.set
Umbraco.Cms.Core.Composing.IUserComposer
Umbraco.Cms.Core.Security.BackOfficeUserStore.BackOfficeUserStore(
Umbraco.Cms.Core.Scoping.ICoreScopeProvider,
Umbraco.Cms.Core.Services.IUserService,
Umbraco.Cms.Core.Services.IEntityService,
Umbraco.Cms.Core.Services.IExternalLoginService,
Microsoft.Extensions.Options.IOptions<Umbraco.Cms.Core.Configuration.Models.GlobalSettings>,
Umbraco.Cms.Core.Mapping.IUmbracoMapper,
Umbraco.Cms.Core.Security.BackOfficeErrorDescriber,
Umbraco.Cms.Core.Cache.AppCaches)
Umbraco.Cms.Core.Security.MemberUserStore.MemberUserStore(
Umbraco.Cms.Core.Services.IMemberService,
Umbraco.Cms.Core.Mapping.IUmbracoMapper,
Umbraco.Cms.Core.Scoping.ICoreScopeProvider,
Microsoft.AspNetCore.Identity.IdentityErrorDescriber,
Umbraco.Cms.Core.PublishedCache.IPublishedSnapshotAccessor,
Umbraco.Cms.Core.Services.IExternalLoginService)
Umbraco.Cms.Core.Logging.Viewer.ILogViewer.GetLogLevel()
Umbraco.Cms.Core.Logging.Viewer.SerilogLogViewerSourceBase.SerilogLogViewerSourceBase(
Umbraco.Cms.Core.Logging.Viewer.ILogViewerConfig,
Serilog.ILogger)
Umbraco.Cms.Core.Logging.Viewer.SerilogLogViewerSourceBase.GetLogLevel()
Umbraco.Cms.Core.Configuration.JsonConfigManipulator.JsonConfigManipulator(Microsoft.Extensions.Configuration.IConfiguration)Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement.MemberRepository.SetLastLogin(string, System.DateTime)
Umbraco.Cms.Infrastructure.Packaging.PackageMigrationBase.PackageMigrationBase(
Umbraco.Cms.Core.Services.IPackagingService,
Umbraco.Cms.Core.Services.IMediaService,
Umbraco.Cms.Core.IO.MediaFileManager,
Umbraco.Cms.Core.PropertyEditors.MediaUrlGeneratorCollection,
Umbraco.Cms.Core.Strings.IShortStringHelper,
Umbraco.Cms.Core.Services.IContentTypeBaseServiceProvider,
Umbraco.Cms.Infrastructure.Migrations.IMigrationContext)
Umbraco.Cms.Infrastructure.Migrations.Install.DatabaseSchemaCreator.DatabaseSchemaCreator(
Umbraco.Cms.Infrastructure.Persistence.IUmbracoDatabase?,
Microsoft.Extensions.Logging.ILogger<Umbraco.Cms.Infrastructure.Migrations.Install.DatabaseSchemaCreator>,
Microsoft.Extensions.Logging.ILoggerFactory,
Umbraco.Cms.Core.Configuration.IUmbracoVersion,
Umbraco.Cms.Core.Events.IEventAggregator)
Umbraco.Cms.Infrastructure.Migrations.Install.DatabaseSchemaCreatorFactory.DatabaseSchemaCreatorFactory(
Microsoft.Extensions.Logging.ILogger<Umbraco.Cms.Infrastructure.Migrations.Install.DatabaseSchemaCreator>,
Microsoft.Extensions.Logging.ILoggerFactory,
Umbraco.Cms.Core.Configuration.IUmbracoVersion,
Umbraco.Cms.Core.Events.IEventAggregator)
Umbraco.Cms.Infrastructure.HostedServices.RecurringHostedServiceBase.RecurringHostedServiceBase(
System.TimeSpan,
System.TimeSpan)
Umbraco.Cms.Infrastructure.HostedServices.ReportSiteTask.ReportSiteTask(
Microsoft.Extensions.Logging.ILogger<Umbraco.Cms.Infrastructure.HostedServices.ReportSiteTask>,
Umbraco.Cms.Core.Configuration.IUmbracoVersion,
Microsoft.Extensions.Options.IOptions<Umbraco.Cms.Core.Configuration.Models.GlobalSettings>)Umbraco.Cms.Web.Common.Security.ConfigureIISServerOptions
Umbraco.Cms.Web.Common.RuntimeMinification.SmidgeRuntimeMinifier.Reset()
Umbraco.Cms.Web.Common.Middleware.UmbracoRequestMiddleware.UmbracoRequestMiddleware(
Microsoft.Extensions.Logging.ILogger<Umbraco.Cms.Web.Common.Middleware.UmbracoRequestMiddleware>,
Umbraco.Cms.Core.Web.IUmbracoContextFactory,
Umbraco.Cms.Core.Cache.IRequestCache,
Umbraco.Cms.Core.Events.IEventAggregator,
Umbraco.Cms.Core.Logging.IProfiler,
Umbraco.Cms.Core.Hosting.IHostingEnvironment,
Umbraco.Cms.Core.Routing.UmbracoRequestPaths,
Umbraco.Cms.Infrastructure.WebAssets.BackOfficeWebAssets,
Microsoft.Extensions.Options.IOptionsMonitor<Smidge.Options.SmidgeOptions>,
Umbraco.Cms.Core.Services.IRuntimeState,
Umbraco.Cms.Core.Models.PublishedContent.IVariationContextAccessor,
Umbraco.Cms.Core.PublishedCache.IDefaultCultureAccessor)
Umbraco.Cms.Web.Website.Controllers.UmbLoginController.UmbLoginController(
Umbraco.Cms.Core.Web.IUmbracoContextAccessor,
Umbraco.Cms.Infrastructure.Persistence.IUmbracoDatabaseFactory,
Umbraco.Cms.Core.Services.ServiceContext,
Umbraco.Cms.Core.Cache.AppCaches,
Umbraco.Cms.Core.Logging.IProfilingLogger,
Umbraco.Cms.Core.Routing.IPublishedUrlProvider,
Umbraco.Cms.Web.Common.Security.IMemberSignInManager)
Umbraco.Cms.Web.BackOffice.Trees.MemberTypeAndGroupTreeControllerBase.MemberTypeAndGroupTreeControllerBase(
Umbraco.Cms.Core.Services.ILocalizedTextService,
Umbraco.Cms.Core.UmbracoApiControllerTypeCollection,
Umbraco.Cms.Core.Trees.IMenuItemCollectionFactory,
Umbraco.Cms.Core.Events.IEventAggregator)
Umbraco.Cms.Web.BackOffice.Controllers.CurrentUserController.CurrentUserController(
Umbraco.Cms.Core.IO.MediaFileManager,
Microsoft.Extensions.Options.IOptions<Umbraco.Cms.Core.Configuration.Models.ContentSettings>,
Umbraco.Cms.Core.Hosting.IHostingEnvironment,
Umbraco.Cms.Core.Media.IImageUrlGenerator,
Umbraco.Cms.Core.Security.IBackOfficeSecurityAccessor,
Umbraco.Cms.Core.Services.IUserService,
Umbraco.Cms.Core.Mapping.IUmbracoMapper,
Umbraco.Cms.Core.Security.IBackOfficeUserManager,
Microsoft.Extensions.Logging.ILoggerFactory,
Umbraco.Cms.Core.Services.ILocalizedTextService,
Umbraco.Cms.Core.Cache.AppCaches,
Umbraco.Cms.Core.Strings.IShortStringHelper,
Umbraco.Cms.Web.Common.Security.IPasswordChanger<Umbraco.Cms.Core.Security.BackOfficeIdentityUser>)
Umbraco.Cms.Web.BackOffice.Controllers.EntityController.GetUrlsByUdis(Umbraco.Cms.Core.Udi[], string?)
Umbraco.Cms.Web.BackOffice.Controllers.HelpController.HelpController(Microsoft.Extensions.Logging.ILogger<Umbraco.Cms.Web.BackOffice.Controllers.HelpController>)
Umbraco.Cms.Web.BackOffice.Controllers.LanguageController.LanguageController(
Umbraco.Cms.Core.Services.ILocalizationService,
Umbraco.Cms.Core.Mapping.IUmbracoMapper,
Microsoft.Extensions.Options.IOptionsSnapshot<Umbraco.Cms.Core.Configuration.Models.GlobalSettings>)
Umbraco.Cms.Web.BackOffice.Controllers.LogViewerController.LogViewerController(Umbraco.Cms.Core.Logging.Viewer.ILogViewer)
Umbraco.Cms.Web.BackOffice.Controllers.LogViewerController.GetLogLevel()
Umbraco.Cms.Web.BackOffice.Controllers.MediaController.GetPagedReferences(int, string, int, int)
Umbraco.Cms.Web.BackOffice.Controllers.MemberTypeController.GetAllTypes()
Umbraco.Cms.Web.BackOffice.Controllers.TemplateController.TemplateController(
Umbraco.Cms.Core.Services.IFileService,
Umbraco.Cms.Core.Mapping.IUmbracoMapper,
Umbraco.Cms.Core.Strings.IShortStringHelper)Umbraco.Cms.Tests.Common.Testing.TestOptionAttributeBase.ScanAssembliesUmbraco.Extensions.NPocoDatabaseExtensions.ConfigureNPocoBulkExtensions()
Umbraco.Extensions.UmbracoBuilderExtensions.AddUmbracoImageSharp(Umbraco.Cms.Core.DependencyInjection.IUmbracoBuilder)Umbraco.Cms.Web.Common.Media.ImageSharpImageUrlGenerator
Umbraco.Cms.Web.Common.ImageProcessors.CropWebProcessor
Umbraco.Cms.Web.Common.DependencyInjection.ConfigureImageSharpMiddlewareOptions
Umbraco.Cms.Web.Common.DependencyInjection.ConfigurePhysicalFileSystemCacheOptionsUmbraco.Cms.Infrastructure.Persistence.LocalDb
Umbraco.Cms.Infrastructure.Persistence.FaultHandling.RetryPolicyFactory
Umbraco.Cms.Infrastructure.Persistence.FaultHandling.ThrottlingMode
Umbraco.Cms.Infrastructure.Persistence.FaultHandling.ThrottlingType
Umbraco.Cms.Infrastructure.Persistence.FaultHandling.ThrottledResourceType
Umbraco.Cms.Infrastructure.Persistence.FaultHandling.ThrottlingCondition
Umbraco.Cms.Infrastructure.Persistence.FaultHandling.Strategies.NetworkConnectivityErrorDetectionStrategy
Umbraco.Cms.Infrastructure.Persistence.FaultHandling.Strategies.SqlAzureTransientErrorDetectionStrategyUmbraco.Cms.Core.Services.IMacroService.GetAll(params string[])
Umbraco.Cms.Core.Persistence.Repositories.IMacroRepository.GetByAlias(string)
Umbraco.Cms.Core.Persistence.Repositories.IMacroRepository.GetAllByAlias(string[])
Umbraco.Cms.Core.Services.ITwoFactorLoginService.DisableWithCodeAsync(string, System.Guid, string)
Umbraco.Cms.Core.Services.ITwoFactorLoginService.ValidateAndSaveAsync(string, System.Guid, string, string)
Umbraco.Cms.Core.Models.IContentType.HistoryCleanup
Umbraco.Cms.Core.Media.IImageDimensionExtractor.SupportedImageFileTypesUmbraco.Cms.Core.Services.IMembershipMemberService<T>.SetLastLogin(string, System.DateTime)Umbraco.Cms.Infrastructure.PublishedCache.DataSource.ContentData.ContentData()
Umbraco.Cms.Infrastructure.PublishedCache.DataSource.ContentData.Name.set
Umbraco.Cms.Infrastructure.PublishedCache.DataSource.ContentData.UrlSegment.set
Umbraco.Cms.Infrastructure.PublishedCache.DataSource.ContentData.VersionId.set
Umbraco.Cms.Infrastructure.PublishedCache.DataSource.ContentData.VersionDate.set
Umbraco.Cms.Infrastructure.PublishedCache.DataSource.ContentData.WriterId.set
Umbraco.Cms.Infrastructure.PublishedCache.DataSource.ContentData.TemplateId.set
Umbraco.Cms.Infrastructure.PublishedCache.DataSource.ContentData.Published.set
Umbraco.Cms.Infrastructure.PublishedCache.DataSource.ContentData.Properties.set
Umbraco.Cms.Infrastructure.PublishedCache.DataSource.ContentData.CultureInfos.setUmbraco.Cms.Core.Media.EmbedProviders.DailyMotion
Umbraco.Cms.Core.Media.EmbedProviders.Flickr
Umbraco.Cms.Core.Media.EmbedProviders.GettyImages
Umbraco.Cms.Core.Media.EmbedProviders.Giphy
Umbraco.Cms.Core.Media.EmbedProviders.Hulu
Umbraco.Cms.Core.Media.EmbedProviders.Issuu
Umbraco.Cms.Core.Media.EmbedProviders.Kickstarter
Umbraco.Cms.Core.Media.EmbedProviders.Slideshare
Umbraco.Cms.Core.Media.EmbedProviders.Soundcloud
Umbraco.Cms.Core.Media.EmbedProviders.Ted
Umbraco.Cms.Core.Media.EmbedProviders.Twitter
Umbraco.Cms.Core.Media.EmbedProviders.Vimeo
Umbraco.Cms.Core.Media.EmbedProviders.YouTubebool TryFindContent(IPublishedRequestBuilder request);Task<bool> TryFindContent(IPublishedRequestBuilder request);IEnumerable<SearchResultEntity?> Search(string query, int pageSize, long pageIndex, out long totalFound, string? searchFrom
= null)Task<EntitySearchResults> SearchAsync(string query, int pageSize, long pageIndex, string? searchFrom = null);<RazorCompileOnBuild>false</RazorCompileOnBuild>
<RazorCompileOnPublish>false</RazorCompileOnPublish>Schema Alias: Umbraco.ContentPicker
UI Alias: Umb.PropertyEditorUi.DocumentPicker
Returns: IEnumerable<IPublishedContent>
The Content Picker enables choosing the type of content tree to display and which specific part to render. It also allows you to set a dynamic root node for the content based on the current document using the Content Picker.
Define a limit on the number of items allowed to be selected.
Checking this field allows users to choose nodes they normally cannot access.
This option allows for configuring what type of content is available when using the Data Type. The available types of content are Content, Members, or Media items.
When selecting Content from the dropdown, the option to specify a root node, also called the origin, becomes available.
When picking the origin there are several different options available:
The following options are available when picking the origin:
Content Root: The root of the content tree.
Root: The root is the first level item of the sub-tree of the current node.
Parent: The parent is the nearest ancestor of the current node.
Current: The current node.
When an origin has been specified, it becomes possible to continue to build a Dynamic Root by adding additional query steps.
Navigate the content tree relative to the specified origin to execute multiple query steps and find the root node needed.
The following options are available:
Nearest Ancestor or Self: Find the nearest ancestor or current item that fits with one of the configured Document Types.
Furthest Ancestor or Self: Find the furthest ancestor or current item that fits with one of the configured Document Types.
Nearest Descendant or Self: Find the nearest descendant or current item that fits with one of the configured Document Types.
The options above are all based on navigating the document hierarchy by locating ancestors and descendants. It is possible to execute custom steps to build even more complex queries. Once a custom query is available it will be added to the bottom of the Append steps to query dialog. Learn more about .
Each query step takes the output from the origin or the previous step as input. It is only ever the result of the last query step that is passed to the next step.
Custom query steps can be used to solve specific use cases, such as traversing sibling documents or matching property values. Before the custom query steps can be selected in the Data Type settings, they must be defined via code.
When implementing a query step it requires a collection of origins and information about the query step. The collection is taken from where the name specified in the UI can be found.
You can inject dependencies into the constructor. These dependencies could be custom repositories or the IVariationContextAccessor, if you want to use the current culture.
The ExecuteAsync method receives a set of content keys from the last executed query step or the origin. It has to return a new set of content keys.
To register the custom query step, append it to the existing query steps, DynamicRootSteps(). This is done from a composer as shown below.
Finally, register the custom query step on the client side and provide a brief description.
You can do this in an umbraco-package.json file, as shown below:
Choose which types of content should be available to pick using the Content Picker.
This is done by selecting one or more Document Types.
Consider the following tree structure where the Document Type alias is presented in square brackets.
Codegarden
2023 [year]
Talks [talks]
Consider configuring a Content Picker on the talk Document Type to select a stage for the talk. Here, you want to display only the stages for the actual year. To do this, you need to set the parent as the origin.
For instance, if you are on the Umbraco anno MMXXIII node, the collection of content keys passed into the first query step will only contain the Talks content node.
First, query for the nearest ancestors of the type year. This will return 2023.
Second, query for the nearest descendants of the type stages.
When opening the picker on the Umbraco anno MMXXIII node, it will now show the children of the node on the path Codegarden > 2023 > Stages.
See the example below to see how a value can be added or changed programmatically. To update the value of a property editor you need the .
Although the use of a GUID is preferable, you can also use the numeric ID to get the page:
If Models Builder is enabled you can get the alias of the desired property without using a magic string:
A picker that uses the current node, cannot pick anything when the current node is created, as it will not have any children.
Site: The nearest ancestor of the current node with a domain assigned.
Specific node: A specific node selected from the existing content.
...
Umbraco anno MMXXIII [talk]
Stages [stages]
Social Space [stage]
No 10 [stage]
No 16 [stage]
The Theatre [stage]
2022 [year]
Talks [talks]
...
Stages [stages]
Main Stage [stage]
The Barn [stage]
The Theatre [stage]
Specifying the origin is required for the custom query step to become available.
Read the Node Type section above to learn more about this.





public class MyCustomDynamicRootQueryStep : IDynamicRootQueryStep
{
private readonly IMyCustomRepository _myCustomRepository;
public MyCustomDynamicRootQueryStep(IMyCustomRepository myCustomRepository)
{
_myCustomRepository = myCustomRepository;
}
// The string below is what you specify in the UI to execute this custom query step.
public virtual string SupportedDirectionAlias { get; set; } = "MyCustomStep";
public async Task<Attempt<ICollection<Guid>>> ExecuteAsync(ICollection<Guid> origins, DynamicRootQueryStep filter)
{
if (filter.Alias != SupportedDirectionAlias)
{
return Attempt<ICollection<Guid>>.Fail();
}
if (origins.Any() is false)
{
return Attempt<ICollection<Guid>>.Succeed(Array.Empty<Guid>());
}
// Replace the following with your custom logic
var result = await _myCustomRepository.GetWhateverIWantAsync(origins);
return Attempt<ICollection<Guid>>.Succeed(result);
}
}public class CustomQueryStepComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
builder.DynamicRootSteps().Append<MyCustomDynamicRootQueryStep>();
}
}{
"$schema": "../../umbraco-package-schema.json",
"name": "My.Test.Extension",
"version": "0.1.0",
"extensions": [
{
"type": "dynamicRootQueryStep",
"alias": "Umb.DynamicRootQueryStep.MyCustomStep",
"name": "Dynamic Root Query Step: My Custom Step",
"meta": {
"queryStepAlias": "MyCustomStep",
"label": "My Custom Step",
"description": "My custom step description.",
"icon": "icon-coffee"
},
"weight": 0
}
]
}@{
var typedContentPicker = Model.Value<IEnumerable<IPublishedContent>>("featuredArticles");
if (typedContentPicker != null) {
foreach (var item in typedContentPicker)
{
<p>@item.Name</p>
}
}@{
var typedContentPicker = Model.FeaturedArticles;
foreach (var item in typedContentPicker)
{
<p>@item.Name</p>
}
}@using Umbraco.Cms.Core
@using Umbraco.Cms.Core.Services
@inject IContentService ContentService
@{
// Create a variable for the GUID of the page you want to update
var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef");
// Get the page using the GUID you've defined
var content = ContentService.GetById(guid); // ID of your page
// Get the pages you want to assign to the Content Picker
var page = Umbraco.Content("665d7368-e43e-4a83-b1d4-43853860dc45");
var anotherPage = Umbraco.Content("1f8cabd5-2b06-4ca1-9ed5-fbf14d300d59");
// Create Udi's of the pages
var pageUdi = Udi.Create(Constants.UdiEntityType.Document, page.Key);
var anotherPageUdi = Udi.Create(Constants.UdiEntityType.Document, anotherPage.Key);
// Create a list of the page udi's
var udis = new List<string>{pageUdi.ToString(), anotherPageUdi.ToString()};
// Set the value of the property with alias 'featuredArticles'.
content.SetValue("featuredArticles", string.Join(",", udis));
// Save the change
ContentService.Save(content);
}@{
// Get the page using it's id
var content = ContentService.GetById(1234);
}@using Umbraco.Cms.Core.PublishedCache
@inject IPublishedContentTypeCache PublishedContentTypeCache
@{
// Set the value of the property with alias 'featuredArticles'
content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.FeaturedArticles).Alias, string.Join(",", udis));
}Learn about the Document Type options available when you create a new Document Type in Umbraco, and when to use each one.
When you create a Document Type in the Settings section, you choose between four options. This article describes each option and when to use it.
A Document Type defines the content structure and fields that can be used across different content items. When creating a Document Type without a template, you focus solely on structured content without tying it to a specific design or layout. This is ideal for content that doesn’t require direct front-end rendering, such as blocks or items managed within a headless CMS setup.
Use a Document Type without a template for structured, reusable content like metadata schemas, settings, or components such as product details and author profiles.
A Document Type with a Template combines the content structure with a predefined visual presentation. This approach links your structured content with a specific page design, ensuring a consistent and cohesive look and feel across your site. It allows you to manage content and its appearance separately, which makes updates more efficient.
Use a Document Type with a template for pages like blog posts, landing pages, or services that appear directly on the website.
An Element Type is a Document Type without a template designed for reusable and repeatable set of properties. These are used for Elements and in editors like the Block List Editor or Block Grid Editor to create structured, nested content.
Element Types cannot render directly on the front end. When Allow in Library is enabled, Element Types can be used to create from the Library section.
Use an Element Type when defining building blocks for complex page layouts, such as grid blocks or reusable sections. They are an essential part of modular content design.
The Folder in the Document Types section is used to organize and structure your Document Types within the Settings section. It serves purely as an organizational container, with no impact on the Content section or site functionality.
Use a Folder to create logical groupings, like a folder named Compositions to hold all your Composition Document Types. This makes it easier to navigate and manage your Document Types, especially in larger projects.
Folders are a powerful tool to keep your Document Types organized and your backoffice tidy.


This article describes how to run an Umbraco 9 site on a local IIS server.
This is a quick guide on getting your Umbraco website running locally on IIS.
The guide will assume you already have IIS configured and know your way around it, as well as having a local website you wish to host.
First, you need to ensure you have "Development time IIS support installed". To check this, go to the Visual Studio installer, click modify and check on the right side under "ASP.NET and web development":
Once that is installed you should set up a new IIS site - and make sure to add the hostname to your hosts file as well. Here is my setup for an example:
You might need to change permissions for the NuGet cache folder - C:\users\<username>\.nuget\packages. The user or group (IIS_IUSRS) that the IIS site is running on requires Read permissions on this folder because this is where some of the files for Umbraco and Umbraco packages are being served from during development. If the IIS user or group does not have permission to read from the NuGet cache folder, you could run into a DirectoryNotFoundException while running the site.
When the site is published these files are copied from the NuGet cache folder to wwwroot/umbraco and wwwroot/App_Plugins and these folders will typically have the correct permissions. For more information on setting permissions, see the article.
At this point you can go to your Visual Studio solution of the site and in the Properties folder there is a launchSettings.json file, that looks like this:
You can add a new profile called IIS, and point it at your local domain. Here it is with my example domain:
At this point IIS will be added to the launch profiles, and you can run the site from Visual Studio by choosing IIS in the dropdown:
And finally the site is running from your local IIS:
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:40264",
"sslPort": 44360
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Umbraco.Web.UI.NetCore": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:44360;http://localhost:40264"
}
}
}{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iis": {
"applicationUrl": "https://testsite.local",
"sslPort": 0
},
"iisExpress": {
"applicationUrl": "http://localhost:40264",
"sslPort": 44360
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS": {
"commandName": "IIS",
"launchBrowser": true,
"launchUrl": "https://testsite.local",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Umbraco.Web.UI.NetCore": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:44360;http://localhost:40264"
}
}
}