Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
A package extends the functionality of Umbraco to provide additional functionality to editors, developers, site visitors, and all other types of users of Umbraco.
A package extends Umbraco to provide additional functionality to editors, developers, site visitors, and all other types of users of Umbraco. It can impact one or more of these groups of people depending on the type of package.
An Umbraco Package can be many things, but is generally characterized by:
Adding or extending functionality in the Umbraco CMS
Empowering people to do more and/or do things more efficiently
Engaging community members in collaboration and sharing
Solving real life problems
Inspiring people on what Umbraco can be made capable of
Packages provide a wide variety of functionality, and can often span multiple categories. In general, though, the functionality they provide fall into these main groups:
A package that can be categorized as a Schema Extension will extend the default Umbraco Schema. Schema in this sense refers to things like Data Types, Property Editors, Document Types and Media Types. By extending Umbraco with packages such as Our.Umbraco.GMaps editors are given greater capabilities when they are populating their content pages.
A Management Extension package helps you manage your site, and provides information to the users. Management extensions typically contain custom sections or dashboards to facilitate site management. Diplo God Mode is an example of a comprehensive management extension package with additional tools and information.
Starter kits are, as the name suggests, a package that helps you set up a starter version of whatever you want to build. Most starter kit packages are for starting a website, and include schema like Document Types and Templates as well as content nodes and media. There are also some specialized starter kits, for example for creating a blog. Umbraco HQ has released their own starter kit, that creates a small site with the most commonly used features.
Content apps are almost like dashboards for content nodes that are intended to display node specific information. A good example of this is the Preflight content app. It shows you readability scores for your written content, directly on each content node.
This type of package can be a lot of things, and can include a number of the other package types. They are generally integrating a larger system into Umbraco. A good example could be an e-commerce package such as UCommerce, that includes an entire webshop module for Umbraco.
Packages for Umbraco 10 and above are installed as NuGet packages.
This short tutorial will teach you how to create a package in the Umbraco backoffice. It will also give a quick overview of what a generated package will contain.
Package authors who would like their UI to be multi-lingual can include their own set of language files as part of their package distribution.
Once you've created a package make it available on the Umbraco Marketplace to share it with the community.
Things you should know if you are developing for Umbraco Cloud.
Some guidance on how to maintain your package after release.
There are many ways to build and deploy your package to NuGet. You will likely have your own approach for organizing a solution and preferred tools for build and deployment.
If you are looking for inspiration to follow form some tried and tested packages, read more here.
Depending on which version of Umbraco CMS you are using, we distinguish between two package types, NuGet packages, and Package ZIP files.
There are two main ways to install packages in Umbraco CMS: Package zip files and NuGet packages.
The zip file package type is only available for Umbraco version 8 and earlier versions. Learn more about it in the Package zip Files section of this article.
When developing a package you need to consider the Umbraco CMS version you're using before determining the package type.
Modern Umbraco (Umbraco 10+): Providing a NuGet package is the only option.
Legacy Umbraco (Umbraco 8 and earlier versions): It is recommended to provide both a zip file and a NuGet package.
A NuGet package is a standard way of delivering compiled code and configuration to a .NET project. NuGet packages contain dll-files and other files required for the solution. For more information on NuGet packages see Microsoft's An introduction to NuGet documentation.
NuGet packages can be installed using via the command line or through Visual Studio using either the Package Manager Console or the NuGet Package Manager.
See below, for an example of installing a package using the Package Manager Console in Visual Studio:
NuGet packages can include any solution files and can be configured to run PowerShell scripts after installation.
As NuGet packages are installed outside of the Umbraco website they cannot directly manipulate any of the Umbraco settings or content during their installation.
When adding or changing configuration of Umbraco as part of a NuGet package you need to develop code to run as part of a Migration. The Migration will run the first time the Umbraco site starts after the package is installed, applying the correct configuration.
Zip file packages are only available for Umbraco CMS 8 and earlier versions.
Refer to the NuGet Packages section above, if your website is using Umbraco 10 or a later version.
A package zip file can be installed directly through the Umbraco backoffice.
Packages zip files can contain:
Content
Solutions files (dll
s, App_Plugins
files, etc)
Document Types
Templates
Stylesheets
Macros
Languages
Dictionary Items
Data Types
Media
To include media in your package, select it in the "Media" section. Additionally, choose it in the "Package Files" section under "Path to file."
Information on how to list your package on the Umbraco Marketplace.
It lists all commercial and open-source packages that the community has made available on NuGet.
Tutorial to create a package in Umbraco
To create a package, you first need to create a package schema through the Umbraco backoffice:
Go to the Packages
section.
Select Created
in the top-right corner of the screen.
Select the Create package
button.
On the Create package
page, there are fields that you can use to construct the contents of your package that are based on items from the backoffice.
We will now take a look at the different information that can be filled in:
These values are used to determine which backoffice items the package should contain. We will fill in the following things:
After filling out all the information, we can select Create to create the package schema. We will download it and take a closer look at what it contains.
If your package doesn't include backoffice specific items, the result from downloading it will be just a package.xml
file. Otherwise, if you select media files you will download a ZIP package that looks like this:
Additionally to the package.xml
, there is a folder containing the media items for your package. The rest of the information is recorded in the XML schema document.
You will notice that the values for each of the fields we provided can be found inside this XML file. But since our example doesn't require any backoffice items, just the package name is contained. In a different case, the other values will be kept under the respective XML tags.
This is the next step of preparing your package before install. Umbraco 9 only supports packages using NuGet installation, which enforces better practices for both source control and deployment. Here, you will find how to create a NuGet Package for the custom dashboard that will extend Umbraco's functionality.
Assuming you have already installed the Umbraco templates, you can execute the following command in the .NET CLI to create a package project, that will include the necessary configuration for packing and installing your client-side assets:
The outcome is the files generated below:
This file contains an msbuild
target that is executed when a project has a dependency on this package. It copies the App_Plugins
folder into the project on build. This is required for having Umbraco packages in a NuGet package format.
If you are planning to overwrite the contents of the App_Plugins folder, make sure that the subfolder containing your package contents has the same name as the one you specified after the --name
flag and that the package.manifest
has the correct path references to your files.
You can also add your custom C# files in the root of the package folder which will be part of the DLL of the package, but for our example, this won't be necessary.
As mentioned previously, let's navigate to the App_Plugins folder and replace its contents with the custom files we created for our new dashboard.
In this section, we will demonstrate how you can add metadata about the package and its creator(s).
Now that Umbraco 9 is built on ASP.NET Core, you can add values directly to the package csproj
file and it will pick them up. If you don't want to manually edit the csproj
file, you can right-click your project, go to Properties and then to Package. There you can insert your specific information:
Here is an example of some basic properties that you can specify in your project file:
The Title
, Description
, PackageTags
came with the template and we added some further information like Version
, Authors
, PackageProjectUrl
and PackageLicenseExpression
that we elaborate on below:
It is time to create the actual NuGet package (that is, a .nupkg file). Executing the dotnet pack
command in the package directory will take care of building the project and outputing the generated NuGet package in the bin
folder (the output on the CLI shows the full path to the .nupkg
file).
If you want to specify the output location, just execute the following command instead:
It will pack the project in the current directory and place the resulting package into the MyNugetPackages
folder.
You can install your newly created NuGet package using Visual Studio, Rider, Command Line or editing the project file directly.
We will continue using the CLI and first create a Umbraco project, and then add the package reference to it:
You can check that the NuGet package was referenced in your solution and that the App_Plugins assets were restored successfully. Our simple package is now installed and you can see the custom dashboard in the backoffice. No further actions are required for our example. However, we will go ahead and mention a few more steps necessary for the more complex packages.
A different approach when you want to test it locally without publishing it anywhere is to create a test site of the package. You can use our dotnet new umbraco
template, this time with a special flag -p
which will add a project dependency to our package and import the target file from that project. So when you build the new project, it will also copy the App_Plugins folder from the package project into the test project. In the same way, as if it was a NuGet reference.
This is the full command:
Afterwards, you can enter the CustomWelcomeDashboardProject
directory, build your Umbraco website using the dotnet build
command and then run the application.
We can run a migration plan for each package that contains Umbraco content (referenced in the package schema).
If you just want to ship a package that only installs the schema and the content you chose, then you can inherit from the AutomaticPackageMigrationPlan
as seen below, and specify the package name that will be displayed under the packages Installed tab in the backoffice. You will also need to embed the schema file in the same namespace.
Whenever the embedded package.xml file changes, the automatic package migration plan is executed again. This is due to the fact that the migration state is based on the file hash. Existing schema or content will not be overwritten in this process.
Instead of creating an automatic package migration plan, we will inherit from the PackageMigrationPlan
and again specify the name of the package in the base constructor. Further on, we will define the plan using a unique GUID - in the example below we have a single migration called MyCustomMigration
.
The custom migrations can inherit from PackageMigrationBase
where we can use helper methods to pick up the schema. But we can also use the regular MigrationBase
class.
Here we also added the ZIP file as an embedded resource to the package project.
Whichever migration plan you choose to create, you will be able to see that your package has been installed after the migration is completed.
When using a custom package migration plan, the current state is ignored by default. This causes it to execute all migrations again whenever this isn't the same as the final state of the plan (e.g. if you added a new migration). This is due to the IgnoreCurrentState
being set to true
in the PackageMigrationPlan
base class. You can override this property and set it to false
again to make it behave like regular migration plans and only run the migrations that have not yet been executed on the current environment.
After creating a migration plan, the content and schema will automatically be imported either during unattended package migration or from the Packages section in the backoffice.
By default, all these package migrations are executed unattended during startup but the solution owners can disable this in the configuration. IntelliSense can help, as well as provide further information about the PackageMigrationsUnattended
setting. Then in the Packages section, there will be an option to run the package migration for each package individually when the PackageMigrationsUnattended
is set to false
.
The configuration of package migrations can be different for each environment and makes it possible to have the migration executed unattended on the development environment, but leave them out or manually execute them on other environments. This is useful when you use a tool like Umbraco Deploy or USync as these will migrate the content.
The is a website built and maintained by Umbraco HQ to support searching and reviewing packages.
More information, including details of the steps for listing, are available at the dedicated .
The goal of this tutorial is to extend Umbraco and create a package. The tutorial's starting point is to create a package out of the dashboard from the . The process is the same for most packages so feel free to follow along with something else.
Enter the package name at the top - we will call our dashboard the same as in the mentioned : Custom Welcome Dashboard
.
Property | Value | Note |
---|
The files that we created from the will be discussed at a later point. Now, let's take a look at the package.xml
file:
NuGet is the standard package manager for .NET projects. More information about NuGet and how it works can be found on the .
For a guide on how to install the project templates, follow the 2 steps listed in the .
Apart from the project file, you can find an empty package.manifest
inside the App_Plugins folder, which we will replace with the one created from the . But more importantly, it also contains a build/CustomWelcomeDashboard.targets
file.
Property | Value | Note |
---|
To allow other people to use your package you will need to publish it to a public NuGet repository. The most common repository is at .
There is comprehensive documentation on how to in the official NuGet documentation, as well as how to while developing.
Content | Empty | Here, you can include content - e.g. if you want to create a starter kit. Not relevant for this package though. |
Media | Empty | Here, you can include media - e.g. if you want to add media to the starter kit. Not relevant for this package though. |
Document Types | Empty | Similar to the Content picker above. It is important to note that if you include content, you will need to also pick all its dependencies in this and the next steps for them to be packaged together! |
Media Types | Empty | Similar to the Media picker above. It is important to note that if you include media, you will need to also pick all its dependencies in this and the next steps for them to be packaged together! |
Macros | Empty | See |
Languages | Empty | See |
Dictionary | Empty | See |
Data Types | Empty | See |
Templates | Empty | See |
Stylesheets | Empty | These will come from the wwwroot/css folder. If you have stylesheets you want to include from other locations (like App_Plugins folder) you can do so at a later step. |
Scripts | Empty | These will come from the wwwroot/scripts folder. If you have scripts you want to include from other locations (like App_Plugins folder) you can do so at a later step. |
Partial Views | Empty | See |
Information on how to use language files to make your Umbraco package UI support multiple languages
Umbraco Core includes language files, but package authors must provide their own for multi-lingual UI.
For each language your package supports, you include an .xml file in the same format as the core language files, named with its language code. The language files must be located in a Lang
folder inside your package folder in App_Plugins
. If your package assets are in /App_Plugins/mypackage
all language files must be placed in the following locations:
English keys: /App_Plugins/mypackage/Lang/en-US.xml
Danish keys: /App_Plugins/mypackage/Lang/da-DK.xml
The App_Plugins
version of the Lang
directory is case sensitive on Linux systems, so make sure that it start with a capital L
.
Each language file can include one or more area. Each area contains a collection of language keys with the translation.
For reference on the language file format see the core language files on GitHub
Version | 1.0.0 | This is automatically set to 1.0.0 but can be changed as appropriate. |
Authors | Your name | Here you get to take credit for your awesome work! |
PackageProjectUrl | https://umbraco.com | This URL will be shown as the package's URL when others install it. It will likely be a Github repository, or similar. |
PackageLicenseExpression | MIT |
The process of installing and, in turn, uninstalling packages in your Umbraco CMS website depends on the version and package type.
This article will cover the process of installing as well as uninstalling packages from your Umbraco CMS website.
As the article will cover both NuGet packages and zip file packages, it is important to know the distinction:
NuGet packages: Modern Umbraco (Umbraco 10+) and Legacy Umbraco (Umbraco 8 and earlier versions).
Package zip files: Legacy Umbraco (Umbraco 8 and earlier versions) only.
Learn more about the different types of packages in the Types of packages article.
In the Umbraco Backoffice, you will find a Packages section that displays the Umbraco Marketplace. From here you can browse all community-made as well as official Umbraco packages for the Umbraco CMS.
For Umbraco CMS version 8 and earlier versions, the Packages section displays the Packages site on Our.
Navigating to a specific package in the section will present you with an overview of the package, as well as an install snippet for NuGet CLI.
The packages can be installed by using:
NuGet Package Manager in Visual Studio
Package Manager Console in Visual Studio
.NET CLI (usually accessible from the terminal/command prompt of your system)
For example, to install the StarterKit package for the Umbraco CMS the command would be:
dotnet add package Umbraco.TheStarterKit
Navigating to the NuGet Package Manager in Visual Studio is more visual, and gives you an overview of already installed packages.
The Package Manager has an integrated search function that allows you to find any public NuGet package and install it on the project.
Once the package has been installed, it will show up under the Packages section in the backoffice, under Installed tab.
Package zip files are only available for Umbraco 8 or earlier versions.
Once you have downloaded an Umbraco package zip file, you can install it in the Umbraco backoffice by following the steps below:
Navigate to the Packages section.
Select Install local on the top-right side of the page.
Drag'n drop the package onto the page or use the file explorer to select the package zip file.
Accept terms of use to confirm the package installation.
The package will be installed and any necessary reboots of the site will be initiated.
You can also install packages directly when browsing the packages in the Umbraco backoffice. This is usually preferred in order to ensure that the package is compatible with the Umbraco CMS version used.
Navigate to the specific package you want to install.
Click Install package in the right-hand side of the page.
Confirm the installation.
The package will be install and the site will be rebooted.
Uninstalling packages is not always as straightforward as installing them.
In this section, we will provide two examples of uninstalling a package - the StarterKit package and the SEOChecker package.
Keep in mind that this particular guide targets a specific package. There are many packages out there, and each one is different. The exact steps presented here might not work the exact same way for all the packages, though the general approach should still apply.
The Starter Kit provides you with a boilerplate website solution to build upon. The package installs Document Types, Templates, media, content, and everything else needed to set up a small website. There is little custom code/functionality involved which is usually the case for such starter kit or sample-site packages.
To uninstall a package, either run a command or use the NuGet Package Manager in Visual Studio.
dotnet remove package Umbraco.TheStarterKit
If you are using Umbraco 8 or an earlier version you uninstall the packages directly from the Packages section of the Umbraco backoffice.
Navigate to the Installed tab in the Packages section.
Click Uninstall package next to the package you want to uninstall.
Confirm that action by checking Confirm package uninstall.
It is recommended to clean the solution after removing any package. This can be done by right-clicking the project in Visual Studio and choosing the Clean option, or using the dotnet clean
command.
With packages like the StarterKit, the process does not end there. While the package is gone, content - and everything else needed for the website - is still available in the backoffice. To fully remove this kind of package, additional steps are needed.
Keep in mind that this particular guide targets a specific package. There are many packages out there, and each one is different. The exact steps presented here might not work the exact same way for all the packages, though the general approach should still apply.
More advanced packages that add functionality on top of Umbraco, usually rely on providing custom, compiled code. That being said, many of such packages also implement custom Sections, Dashboards, editors, and views.
In this example, we will be using the SEOChecker package. This package allows developers of the site to add custom properties to Document Types used to track search engine optimization practices.
An example use case of the SEOChecker property on a Document Type, as presented in the Content section:
To uninstall the SEOChecker from a website, the first step is to remove the package via a dotnet
command or use the NuGet Package Manager.
The following command can be used for uninstalling the package:
dotnet remove package SEOChecker
After that, cleaning the solution is recommended.
If content on the website relies on having a custom Property Editor or a data source installed, those properties will default to a label
Data Type. All previously saved content in the property will in turn be converted to a string.
In the case of the SEOChecker, the custom property added from the package would look like this after all the package files have been removed:
Depending on the packages and the implementation, rendering of content from custom editors, or any frontend functionality dependent on external code, might not work correctly. It is always recommended to inspect the frontend of the site after removing any packages.
Information on good practices and common defaults for Umbraco package development.
This document provides guides and notes on package development. It includes good practice guidelines that will help you maintain and support your package through multiple releases and versions of Umbraco. These good practices are not prescriptive, but offer a guide as to what often works well, and not-so-well, when developing packages for Umbraco.
To extend the Umbraco backoffice, a package can provide files such as a package.manifest
and AngularJS views/controllers that should be stored within the App_Plugins
folder. It's recommended to put all files in a subfolder with a unique name, preferably using the package name, like App_Plugins\MyPackage
.
Files in the App_Plugins
folder will be publicly available on the website even though they are not in the wwwroot
folder. You should not store sensitive information in the App_Plugins
folder.
Files in the App_Plugins
folder should be considered immutable. This means that they are not something a user of your package is expected to change on their site.
The default delivery method for files to the App_Plugins
folder is via a .targets
file within a package. This means when a website is built, the files in this folder are copied over from the NuGet cache. When this happens, any changes a user might have made to these files will be lost. Equally, if the user performs a dotnet clean
on a solution, all files in the App_Plugins
folder will be deleted.
If you have files that you expect users of your package to alter you should not place them in the App_Plugins
folder.
Views are used to render content on the front end of a website. If your package provides a way for the user to present the content publicly, you should copy these files to the views folder.
As the files will still be copied during build you should ensure your target file does not overwrite newer or altered files. You should also ensure that it doesn't delete files on clean.
When you have a package that contains many views you might consider building a dotnet template or Razor Class Library (RCL) instead. By doing this, the files will not pollute your user's solutions.
Umbraco products store their licenses in /umbraco/Licences
. It is recommended for third-party packages that require license files to also store their license files in this location.
The default .gitignore
for Umbraco templates will include any files in the /Licenses
folder while ignoring most of the rest of the Umbraco folder.
The /umbraco/Licenses
folder does not exist on a fresh installation of Umbraco. You need to create it manually before you save your license file to this folder.
Umbraco (version 9 and up) is an ASP.NET Core application and can be run on multiple operating systems (Windows, Linux and macOS). When developing packages there are a few things you should be aware of for your package to run on all possible operating systems.
The Linux and macOS file systems are case-sensitive by default. This means that App_Plugins/myPackage
is a different location from app_plugins/MyPACKAGE
. When building your package you should ensure that you always refer to folders and paths in a consistent way.
A good way to ensure consistency is to use constants in your code to define file or folder locations.
You can adjust the case sensitivity of a Windows folder by running a command against a newly created/empty folder:
Some folders within Umbraco will already exist for all installations. If you access these folders, you need to be aware of the case used to ensure you end up in the correct place:
If you create a custom section/tree, Umbraco will build paths based on the name of that section or tree. These folder paths will be case-sensitive.
For example: if you have a custom tree with the treeAlias
of MyCustomTree
Umbraco will look for files in App_Plugins\MyPackage\backoffice\MyCustomTree\
.
You should never hardwire a file or folder location into code. Instead, it is recommended to follow either of the options below:
Access files using the ASP.NET Core file providers from IHostingEnvironment
.
Use the built-in methods to access well-known locations (see below).
The location of the Umbraco temp folder can be controlled via configuration and cannot be assumed. Use the IHostingEnvironment.LocalTempPath
variable to locate the temp folder.
If you require the path of a folder relative to the site root, you can use the IHostingEnvironment
method to map a path:
It is not recommended to assume things about the folder structure of a site or use direct I/O commands to access the file system. Access to the disk within an ASP.NET Core site is usually managed with File Providers. You can access the file providers from the IWebHostEnvironment
class.
Example: If you want to read robots.txt
from the wwwroot
folder, use WebRootFileProvider
in a controller to get to the root of the site and read the file:
This is the preferred method for file I/O. Not all files served up by a site are placed in the wwwroot
folder when you expect them to be. This is especially true if the site is using Razor Class Library projects to insert static files.
Building folder path strings manually can cause problems when swapping between file systems. Windows uses the backslash character ('\') to separate folders and files while Linux uses the forward slash ('/').
On Windows, a file might be located at d:\website\robots.txt
while on Linux this might look like /home/website/robots.txt
instead.
You should use the .NET Path
methods wherever possible when building paths to ensure that the correct path is built:
If you need to build a path manually, use Path.DirectorySeparatorChar
instead to get the correct separator for the file system.
Most packages will require some settings to be stored for the users to control in order to change the behavior of the package. Where you store these settings will depend a lot on the nature of the package.
Property Editors should store their settings as part of their Data Type in Umbraco. This is the standard way property editor behavior is controlled while it is familiar to users and supported by deployment tools.
You should not alter appsettings.json
via code.
Settings in ASP.NET Core are merged from a number of different locations at runtime. You cannot guarantee that appsettings.json
is the location that a setting is read from and your users may not want certain settings in that file. You can read settings from the configuration, but you cannot assume they have come from appsettings.json
.
There are many options for where you might save your settings and a lot will depend on the nature of your package.
Below you can find pros and cons for different places where you might save the settings for your package.
Settings can be saved to the database. Settings can be stored in the database using the Umbraco IKeyValueService
, and for more complex settings you can use a custom database table.
Pros:
Settings will be accessible directly from the database, and not dependent on deployed files on disk.
Cons:
Setup is required to create the database tables for the settings to live in.
The settings will only be available to the specific instance of the site, and any settings will not be deployed between a local, development, or staging site.
You can choose to save the settings to disk. As an example, the settings can be saved in the /config
folder at the root of the site.
Pros:
Settings will be accessible to the site and can be included in deployments between sites.
Cons:
You cannot guarantee that the folder or files will be present on a site or that they will be writable.
Using your own config means your users cannot harness the power of the .NET Core configuration system and move settings to environment variables or other key/value stores. This means that sensitive information may end up on disk.
You could choose to provide your users with a snippet they can copy into their appsettings.json
file. This will ensure that the settings are stored in the correct location.
Pro: Allows your users to fully control how and where the settings are stored (eg. secure key/value stores).
Con: Requires the user to edit files on disk to get the settings in place.
Things to consider for package development and usage in Umbraco Cloud
If you want to use or develop packages for Umbraco Cloud there are a few things to consider and be aware of. The two most important things to know about are
When developing a package you will sometimes store data, this can be data in many forms - Umbraco schema / content, package settings, etc.
When you develop a package for Umbraco Cloud there are a few things to be aware of when storing data, mainly whether you want that data to be specific to 1 environment or more.
Let's take a look at the most common ways of storing data in packages - and what to watch out for on Cloud.
A migration is some code that you run as part of a migration plan. That migration plan has an ID that is stored in the database (in the KeyValue table). This means that when you add new migrations Umbraco will only execute the ones that came after the one with the stored ID. The most important difference between a migration and a package action is when they are initialized. A package action runs on package install and uninstall, whereas a migration will run whenever you want it to run, see below for common examples.
As migration runs are stored in the database of the site it also means that they will run on each environment you trigger them on. The most common way to trigger a migration is to include them in a composer, which will ensure they run on site startup. This means any commands you have in your migration will automatically run when the site starts up. When your package code is pushed to a new environment it will run them from the beginning on that environment as no ID is saved in the database.
This is normally a good thing. However if you generate any Umbraco schema then Umbraco Deploy will automatically create UDA files based on that schema, and commit them to source control. This means that when you deploy all your files to the next environment the migration will run again, create duplicates and generate duplicate UDA files, which could end up causing a lot of issues.
You could consider creating Umbraco schema only during a package action, and then running things like creating database tables in migrations. Another good workaround could be to not run the migrations in a composer, but rather create a dashboard for the package where the user can choose which migrations to run themselves. The Articulate package has an example of this.
You may sometimes choose to save data in a file. Could be a separate config file for your package or a config transform file to add an app setting to the web.config. If you do this be aware of two things:
If these files are generated on a Cloud environment they will not be stored in source control, and will be overwritten on next deployment. They need to be installed locally, committed to source control and then pushed up to the Cloud environments. We have an existing feature request on allowing package creators to commit their files directly on Cloud, and it is possible to do so currently but not in a supported way, and it may change suddenly.
If you need the content of the files to be different on the different environments you will need to use environment specific config transforms.
A ValueConnector is an extension to Deploy that allows you to transform data when you deploy content of any kind between environments. It is mostly used to transfer ID based content between environments. Other than transforming values they also manage dependencies for property data. That means that if you save for example an id of an image in your property editor, then you can make sure that not only the id but the actual image is transferred as well!
An example of creating one for your package would be if you had a custom property editor that allowed you to write in the ID of a media node. Not a very usable property editor but it will work for this example.
So you have a property editor with a textarea input, that saves an ID as a string. It could look like this:
Then in the template you have something like this:
Renders the image perfectly!
However now you do a content transfer to your Cloud environment, and one of three things will happen:
You got lucky and the ID you had on local happened to be the same as what the media node was assigned on your Cloud environment.
Your page will now show a different image as the ID you had corresponds to something else on this environment.
You will get an error on the frontend as it can't find any media nodes with that ID.
To prevent this from happening we will need to use a ValueConnector.
Before we start working on making a ValueConnector a few notes on how to test and work with them. You probably will need to test the values that are being converted, but you probably also doesn't want to build, git push, content transfer to see that the value may not have changed.
First thing we will do is create the ValueConnector using the interface. If you implement it you will get something like this:
In this case I cloned the Cloud project down using the uaas.cmd tool, which means that I have a class library that I can add the ValueConnector to. This will automatically have some references included and will build a DLL, eg. projectalias.core.dll
, and put it in the websites bin folder when building.
This has no impact on the way you work, but it may help you understand why some things are named the way they are.
At this point I have one clone of the site locally. However, to test this I will push the changes to the Cloud site and then clone it down again. The second clone doesn't need to be cloned with the uaas.cmd
tool as we aren't developing on it, all we need is to run it locally.
At this point I have two local sites:
Site 1: Full Visual Studio solution Running on http://localhost:6240/ (Randomly generated) Has the ValueConnector in a class library that is built to a dll and copied to the websites bin on build
Site 2: A website served through VS Code (Could be IIS or anything else, doesn't matter) Running on http://localhost:17025/ (Randomly generated) Has the ValueConnector dll in the bin from the clone
Now we will set up these two identical sites to transfer content between each other.
To do so go to site1/Config/UmbracoDeploy.config
and edit the live environment url to be Site 2's url (http://localhost:17025/ in my case). Then do the same for Site 2 but put in the domain for Site 1 as the "live" one.
At this point you should be able to go to the backoffice of either environment and do a Content transfer to live, and it should end up on the other (Assuming no errors from your custom connector).
At this point we haven't done anything to the ValueConverter yet, other than return the original value. Now we will attach Visual Studio to the IIS processes and try a transfer to see what it sends along.
Go to Visual Studio
Hit "Attach to Process" (default ALT + CTRL + P)
Choose your two IIS processes
Add breakpoints in the ToArtifact
and FromArtifact
methods
Go to the backoffice in Site 1
Try to do a content transfer to live (Site 2).
It will hit your breakpoint, and if you continue you will then get an error. On the breakpoint you can see why the error occurs. It should look like this:
Here you can see that value is null, and if you try to return value.ToString()
you will get a null exception.
We will change the ToArtifact
method a little:
At this point you can't reattach the process as the code has changed. So, build the project, go to site1/bin
and copy projectalias.Core.dll
and projectalias.Core.pdb
. Paste these files into site2/bin
, attach to the two IIS processes and try another transfer.
The workflow here is not optimal, but a lot quicker than trying to deploy to Cloud everytime, and with this you can attach the debugger as well to help you out.
After copying the dll and pdb files over we are synced up, now attach the debugger and attempt another transfer. Now you will see that value
is null a few times, then your hardcoded ID a few times, but nothing breaks here. Eventually you will hit the FromArtifact
method instead:
Here you will notice that the value is what you had returned in ToArtifact
.
You may have realized at this point that the flow is something like this:
Site 1 content transfer initiated
Property data is fetched on Site 1
Hit the ToArtifact
method on Site 1
Send to Site 2
Hit the FromArtifact
method on Site 2
Property data is saved on Site 2
So in our case, what we want to do is to ensure the ID from Site 1 is changed during the transfer to match what the new ID in Site 2 is. We do this by converting the ID to a GUID in the ToArtifact
method on Site 1, which will then get transferred to Site 2. On site 2 we will convert it back to an ID in the FromArtifact
method. This way the user will still see an ID on the content node, but the ID they see will be updated to the correct one.
In this example, there would be no way for Deploy to know to also transfer the image. We assume that you would transfer all content and images to ensure it is on the target environment under a different ID.
That is not a good assumption, and you may have noticed that there is a parameter on the ToArtifact
method that you could update by finding the image and adding it to ICollection<ArtifactDependency> dependencies
.
In order to add the image as a dependency for the item being transferred, we will update the code in the ToArtifact
method:
You can find references on the methods used here in our API documentation:
When stepping through the code we can see that everything seems to work fine:
Note: Showing the variable values is a feature of ReSharper.
By the time we hit FromArtifact
value of "umb://media/00c9eff861654f52be7a33367c3561a4"
all that is left to do is convert back to an int
.
Here is a gif showing the ValueConnector in action. A new image is uploaded, the ID on the node is updated and transferred. Finally the image is on the new environment and the ID is updated:
The final ValueConnector code will look like this:
In addition, any fixes and updates to the UI components will be pushed through to the packages when you rebuild them with the updates.
Accessibility testing is more a specialist skillset than it is automated testing. The purpose of this document is to outline what can be done to help build accessible packages. It is not a complete list of accessibility tests that can be performed.
Use the keyboard to tab through the elements on the page checking:
Does the element tabbed to have a focus state?
Does the tab order make sense?
Check the UI with a screen reader.
Install an accessibility testing tool as a plugin into your browser to run automated tests:
Suggestions for organizing and Umbraco package source code repository.
There are many ways to build and deploy your package to NuGet. You will likely have your own approach for organizing a solution and preferred tools for build and deployment.
It may be useful though to review some practices we share here, of how we build packages at Umbraco.
The solution consists of three projects.
Here we provide an upper bound on the package. This ensures that developers can only install it into projects that are using versions of Umbraco that we have tested the package with.
When the next major version of Umbraco is released, we'll test and either extend the range or release a new version, as appropriate.
As well as the projects, the following files are added to the solution:
We use AzureDevOps pipelines for continuous integration and releasing new versions of the package. The definition of how the project is built is defined in a .yaml
file that's part of the source code repository.
Even if using another tool it may be worth reviewing how we have setup our pipeline. It may be you can setup something similar with your own provider.
The build consists of two stages: building the solution and running unit tests. Only if both succeed is the build as a whole considered successful.
We release the package manually in AzureDevOps, with a two stage process. Firstly we release to a "pre-releases" feed, and then after manual approval, to NuGet.
Once you've created and published your package, here is what's involved in it's ongoing maintenance
Once you've created and published your package, what's involved in its ongoing maintenance?
When a new version of Umbraco is released you should test your package on this latest version to confirm it still works.
On the 'Package Details' section of the form update the 'Current Version'. You should also add some details about which versions of your package are for which version of Umbraco in the 'Package Description'. For example:
On the 'Package Files' section of the form you can upload a new file and then make it the 'current' one. You don't have to archive the previous version as you are allowed multiple active ones that will all appear in the Package Files list, for example:
You can only have one 'current' file - this is the version that will be downloaded from the main button on the package's public page:
To add a new forum you will need to specify a name and a description, such as:
Any forum you create will appear under the Package Files list on the package's public page:
If you are the sole maintainer of a package then it's a good idea to find someone to help you. If you have accepted pull requests from people then why not ask them if they would like to collaborate?
If someone requests a feature that you think is a good fit but you don't have the time, then ask that person if they would like to work with you to get it added.
At the bottom of the 'Package Details' form, tick to say 'Retired' and specify the reason for the retirement.
Moving 'Next' will save your changes, and the retired status and reason will be displayed prominently on the package's public page:
The license is set to MIT. Please consider how you want your package licensed. If in doubt when deciding an open-source license there are .
Folder | Note |
---|---|
Creating accessible packages extends on accessibility in an .
The Umbraco UI components have been built to be accessible and have accessibility tests built within them. Building the user interface (UI) using these ensures that the package is as accessible as the Umbraco backoffice.
Build the components using the as these have accessibility tests built within them.
More on focus, tab orders, other common interactions and techniques for keyboard testing can be found at
and some guidelines on screen reader testing are available from
Tools like are built to reduce the number of false positives in a test.
If the UI does not follow the Umbraco Style, then check the contrast with a tool like the . This will help ensure contrast.
Some add-ons to the CMS created by Umbraco are closed-source, but we have some we make freely available with open-source repositories. An example is , that has a source code repository .
The lives in src/<ProjectName>
. It contains in the project file a dependency on Umbraco CMS:
We have a in tests/<ProjectName>.Tests
. It contains references to Umbraco.Cms.Tets
and a project reference to the package:
Finally there's an that we use for manual testing of the package. It also has a project reference to the package project, allowing us to test updates as they are compiled.
- used by AzureDevOps services to . This helps to reduce pipeline execution time.
- used to for multiple developers working on the same project across editors and IDEs.
- controls which files are added to source control.
- provides .
- used to provide common setting across all projects in the solution.
global.json - ensures that the solution is always . We add this when we have a solution that targets a single Umbraco major version.
- indicates the license through which the code is available.
- a top-level documentation page for the source code repository.
- an icon used for the package on NuGet and the Umbraco Marketplace.
- provides .
- provides package versioning information for use by . We use this tool for generating version numbers.
The file can be found .
The current package repository on does not allow you to edit your list of supported versions. The only way to do this, at present, is to upload the package file again and set the full range of supported versions at the same time. You can edit your packages, including uploading new files, from . As this is a replacement file you should archive the previous one and then mark the new one as 'current'.
It would also be helpful to ensure that the 'Package Compatibility' details are correct on the package's public page on .
Make the changes required so that your code works on the latest version of Umbraco. Next you need to create a new version of your package. Read the article for guidelines on creating the package zip file using the backoffice.
To publish your new version on Our, visit and select the package that you are updating.
If you want to encourage feedback, feature requests, and issue reports then you should add a forum to your package. You can manage your forums from :
If you'd like to find a collaborator you are welcome to raise a 'Request for Collaborators' via the .
You can assign other Our members to the 'team' for your package. Team members will see the package in their list to maintain, and will be able to edit its details. You can manage your team of collaborators from :
If your package should no longer be used (perhaps it is now too old, or it has been superseded by another one that you recommend instead), then you should update your package accordingly via :
/App_Plugins
Uppercase A
and P
/App_Plugins/[Ll]ang
Uppercase L
(in Umbraco 9.3 and higher can be either uppercase L
or lowercase l
/Views
Uppercase V
/umbraco/Licenses
Lowercase u
and uppercase L
/config
Lowercase c