Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
A guide to creating a custom property value converter in Umbraco
A Property Value Converter converts a property editor's database-stored value to another type. The converted value can be accessed from MVC Razor or any other Published Content API.
For example the standard Umbraco Core "Content Picker" stores a nodeId as String
type. However if you implement a converter it could return an IPublishedContent
object.
Published property values have four "Values":
Source - The raw data stored in the database, this is generally a String
Intermediate - An object of a type that is appropriate to the property, for example a nodeId should be an Int
or a collection of nodeIds would be an integer array, Int[]
Object - The object to be used when accessing the property using a Published Content API, for example UmbracoHelper's GetPropertyValue<T>
method
XPath - The object to be used when the property is accessed by XPath; This should generally be a String
or an XPathNodeIterator
The current implementation of XPath is suboptimal, marked as obsolete, and scheduled for removal in Umbraco 14. The replacement for ContentXPath is IContentLastChanceFinder.
PropertyValueConverters are automatically registered when implementing the interface. Any given PropertyEditor can only utilize a single PropertyValueConverter.
If you are implementing a PropertyValueConverter for a PropertyEditor that doesn't already have one, creating the PropertyValueConverter will automatically enable it. No further actions are needed.
If you aim to override an existing PropertyValueConverter, possibly from Umbraco or a package, additional steps are necessary. Deregister the existing one to prevent conflicts in this scenario.
The built-in PropertyValueConverters included with Umbraco, are currently marked as internal. This means you will not be able to remove them by type since the type isn't accessible outside of the namespace. In order to remove such PropertyValueConverters, you will need to look up the instance by name and then deregister it by the instance. This could be the case for other PropertyValueConverters included by packages as well, depending on the implementation details.
Implement IPropertyValueConverter
from the Umbraco.Cms.Core.PropertyEditors
namespace on your class
This method is called for each PublishedPropertyType (Document Type Property) at application startup. By returning True
your value converter will be registered for that property type and your conversion methods will be executed whenever that value is requested.
Example: Checking if the IPublishedPropertyType EditorAlias property is equal to the alias of the core content editor. This check is a string comparison but we recommend creating a constant for it to avoid spelling errors:
This method is called to determine if the passed-in value is a value, and is of the level specified. There's a basic implementation of this in PropertyValueConverterBase
.
This is where you can specify the type returned by this Converter. This type will be used by ModelsBuilder to return data from properties using this Converter in the proper type.
Example: Content Picker data is being converted to IPublishedContent
.
Here you specify which level the property value is cached at.
A property value can be cached at the following levels:
PropertyCacheLevel.Unknown
Do not use this cache level unless you know exactly what you're doing. We recommend using the PropertyCacheLevel.Element
level.
PropertyCacheLevel.Element
The property value will be cached until its element is modified. The element is what holds (or owns) the property. For example:
For properties used at the page level, the element is the entire page.
For properties contained within Block List items, the element is the individual Block List item.
This is the most commonly used cache level and should be your default, unless you have specific reasons to do otherwise.
PropertyCacheLevel.Elements
The property value will be cached until any element (see above) is changed. This means that any change to any page will clear the property value cache.
This is particularly useful for property values that contain references to other content or elements. For example, this cache level is utilized by the Content Picker to clear its property values from the cache upon content updates.
PropertyCacheLevel.Snapshot
The property value will only be cached for the duration of the current snapshot.
A snapshot represents a point in time. For example, a snapshot is created for every content request from the frontend. When accessing a property in a snapshot using this cache level, it gets converted, cached throughout the snapshot, and later cleared.
For all intents and purposes, think of this cache level as "per request". If your property value should only be cached per request, this is the cache level you should use. Use it with caution, as the added property conversions incur a performance penalty.
PropertyCacheLevel.None
The property value will never be cached. Every time a property value is accessed (even within the same snapshot) property conversion is performed explicitly.
Use this cache level with extreme caution, as it incurs a massive performance penalty.
There are a few different levels of conversion which can occur.
This method should convert the raw data value into an appropriate type. For example, a node identifier stored as a String
should be converted to an Int
or Udi
.
Include a using Umbraco.Extensions;
to be able to use the TryConvertTo
extension method.
This method converts the Intermediate to an Object. The returned value is used by the GetPropertyValue<T>
method of IPublishedContent
.
The below example converts the nodeId (converted to Int
or Udi
by ConvertSourceToIntermediate) into an 'IPublishedContent' object.
This method converts the Intermediate to XPath. The return value should generally be of type String
or XPathNodeIterator
.
In the example below, we convert the nodeId (converted by ConvertSourceToIntermediate) back into a String
.
The current implementation of XPath is suboptimal, marked as obsolete, and scheduled for removal in Umbraco 14. The replacement for ContentXPath is IContentLastChanceFinder.
Content Picker to IPublishedContent
using IPropertyValueConverter
interface
Guide on how to work with and create Property Editors in Umbraco
This section describes how to work with and create Property Editors. A property editor is the editor used to insert content into Umbraco. See here for definition
Reference for the package.manifest JSON file format to register one or more property editors for Umbraco.
Convert the stored property data value to a useful object returned by the Published Content APIs.
Use Property Actions to add additional functionaility to your custom property editors.
Learn how to build your own Block Editors.
Learn how to extend Property editors to track entity references inside the property editor.
Guide on how to implement Property Actions for Property Editors in Umbraco
Property Actions are a built-in feature that provide a generic place for secondary functionality for property editors.
Property Actions appear as a small button next to the label of the property, which expands to show the available actions. They are defined and implemented in the Property Editor, making it open as to what a Property Action is.
Property Actions are an array of objects defining each action. An action is defined by the following properties:
We use labelKey
and labelTokens
to retrieve a localized string that is displayed as the Actions label. See localization for more info.
isDisabled
is used to disable an Action, which change the visual appearance and prevents interaction. Use this option when an action wouldn't provide any change. In the example above, the action remove all entries
would not have any impact if there is no entries.
The implementation of Property Actions varies depending on whether your Property Editor is implemented with a Controller or as a Component.
When your Property Editor is implemented with a Controller, use the following approach for the Property Action:
Follow this guide if your Property Editor is implemented as a Component. The Component must be configured to retrieve an optional reference to umbProperty
. The requirement must be optional because property-editors are implemented in scenarios where it's not presented.
See the following example:
See the following example for implementation of Property Actions in a Component, notice the difference is that we are parsing actions to this.umbProperty.setPropertyActions(...)
.
This guide is currently being re-evaluated, as it might not work as intended.
Before reading this document we highly recommend that you familiarise yourself with the basics of developing a custom Property Editor for Umbraco.
In order for your editor to become a Block Editor you must setup your property editor through C#. The constructor of the class can be auto generated by your Integrated Development Environment (IDE).
Notice how the PropertyEditorAsset
attribute is used to load the UnicornBlocks.controller.js
JavaScript file.
Your Property Editor will need a PropertyValueConverter
. Read more about Property Value Converters.
The Block Editor data structure consists of three main parts:
Layout: The Layout defines Blocks that each will reference (by UDI) a content item in the list of data. The Layout object pairs keys with Property Editor aliases and their value type varies based on setup.
ContentData: A list of content items based on ElementTypes (IPublishedElement).
SettingsData: A list of content items based on ElementTypes (IPublishedElement).
In the following example the layout object "MyOwn.UnicornBlocksEditor" is of type Array.
We created the BlockEditorModelObject to aid in managing the presented Data Structure in the Block Editor.
To get a better understanding of what the Model Object does for you, we need to look at some usages of the Model Object.
The layout
of a Block Editor can be any structure. Therefore the Model Object (BlockEditorModelObject) cannot maintain this data. Our usage of the Model Object becomes complex. We give it a reference to a layout
entry and perform an action that may need to reflect changes back to the layout
.
Since the origin of blocks is in the layout
the Model Object only can serve as a helper to maintain and create data. Therefore the Property Editor code will be using the layout
as origin, using the Model Object to help manage specific parts.
This is explained in more detail below.
Instantiate a Model Object and load dependencies. Provide the basic structure for the layout
property when receiving the reference to it:
Use the Model Object to create a Block and append the returned layout-entry to the layout
.
In the following example we will create a new block and append it at the appropriate location in the 'layout' object:
The layout-entries alone do not provide much value when displaying or editing Blocks.
Our Model Object allows obtaining a Block Object by parsing a block's layout-entry for a specific Block.
The Block Object provides data of interest. The most important of these properties are: Block configuration, a label and the Block content in the Element Type Data Model format. This Content-model is useful for building the UI for editing the Content of a Block.
This example uses the Model Object to retrive a Block Object for outputting its label in the console.
This similar example uses the Block Object for setting a value on the first property in the Blocks Content.
See blockEditorModelObject for the getBlockObject method for more information on the properties avaiable on a Block Object.
Removing a Block and destroying its data is done by calling the removeDataAndDestroyModel
method of the Model Object, which allows us to maintain the 'layout' object.
Your code will be based on working with Block Objects and therefore removal of a Block is be done by referring to a Block Object.
This example shows how to remove the first Block of our imaginary Block Editor and remove the block from our layout.
Block Objects are used extensively and should be available throughout your Block Editor's runtime, rather than created for each action.
You probably want to use BlockObjects for your property-editor view. We append them to layout entries, so you can access them as properties from the layout object.
The following example loops through a layout array to display the contentUdi of each block:
Guide on how to implement tracking entity references for Property Editors in Umbraco
Property editors can be extended further to track entity references that may be selected or referenced inside the property editor. For example in the core of the CMS we have added this to numerous property editors.
A good example of this is the Media Picker. The CMS stores a reference to the selected media item, enabling the identification of content nodes that use that particular media item. This avoids it being accidentally deleted if it is being used.
When a content node is saved it will save the entity references as relations.
Go to the Media section.
Select a media item and click the Info tab.
Go to the Settings section.
Under the Relation Types folder, select Related Document relations and click Relations.
Go to the Settings section.
Expand the Data Types folder.
Select the Data Type you wish to view the references
Navigate to the Info tab.
The following example shows how to implement tracking for the inbuilt CMS property editor Content Picker. It will always add a specific media reference, regardless of what value is picked in the content picker. In your own implementations, you will need to parse the value stored from the property editor you are implementing. You will also need to find any references to picked items in order to track their references.
Generally Umbraco supports two different ways to declare a property editor. Most commonly one would create a package.manifest
file, and then use it for declaring one or more property editors. But as an alternative, property editors can also be declared using C#.
A property editor consists of a number of mandatory properties, and some optional ones as well. As such, the outer JSON object for the property editor has the following properties:
Name | Type | Required | Description |
---|---|---|---|
The editor
object then has the following properties:
Name | Type | Required | Description |
---|---|---|---|
A package manifest is a file specific to your package or custom code. This file is always stored in a folder in /App_Plugins/{YourPackageName}
, and with the name package.manifest
:
This example manifest specifies a Sir Trevor property editor via the propertyEditors
collection, and also adds a single JavaScript file via the javascript
property.
The actual Sir Trevor property editor has some additional configuration. It's a block based editor, so for instance it has a prevalue for setting the maximum amount of blocks allowed. In full, the package.manifest
file for the Sir Trevor package looks like:
The same property editor can be declared using C# instead using the DataEditor
class and decorating the class with the DataEditor
attribute:
Also notice how the PropertyEditorAsset
attribute is used to load the SirTrevor.controller.js
JavaScript file.
The DataEditor attribute shown in the example above is the primary component to declaring the property editor in C#. Notice that the first four properties must be set through the constructor.
As shown in the C# example, the PropertyEditorAsset attribute was used to make Umbraco load the specified JavaScript file.
The constructor of the attribute takes the type of the assets as the first parameter. Possible values are either AssetType.Javascript
or AssetType.Css
. The second parameter is the URL of the asset.
In the example above, the SirTrevorEditor
class doesn't really do much. For more basic property editors, the C# approach may require a bit more work compared to that of package.manifest
files. But as property editors grow in complexity, using C# becomes a bit more useful - and also lets you do things not possible with package.manifest
files.
The DataEditor class defines a virtual CreateConfigurationEditor
method. It returns a model which is used for the Angular view when editing the prevalues of a Data Type.
Virtual methods are methods declared in a parent class. These methods have a default implementation that can be overridden in classes that inherit from the parent class. For instance in the example below, we can override the method and provide our own SirTrevorConfigurationEditor
instead of what Umbraco returns by default.
In this case, the SirTrevorConfigurationEditor
class doesn't do much either - but notice that it inherits from ConfigurationEditor<SirTrevorConfiguration>
, meaning the configuration will be of type SirTrevorConfiguration
:
The referenced SirTrevorConfiguration
class is then what declares the configuration fields of when editing a Data Type using the Sir Trevor property editor:
A benefit of this approach (opposed to package.manifest
files) is that we can now refer to the configuration using a strongly typed model - eg. as in this example Razor view:
Both instances of IDataType
and PublishedDataType
have a Configuration
property. When looking across all data types and property editors, there is no common type for the configuration, so the return value is object
. To get the strongly typed model, you can either cast the configuration value on your own, or use the generic ConfigurationAs
extension method as shown above.
Like mentioned before, the SirTrevorConfigurationEditor
class doesn't really do much in this example with the Sir Trevor property editor. But the Multi Node Tree Picker and others of Umbraco's build in property editors also override the ToValueEditor
method.
This method is used when the strongly typed configuration value is converted to the model used by the Angular logic in the backoffice. So with the implementation of the MultiNodePickerConfigurationEditor class, some additional configuration fields are sent along. For instance that it's a multi picker and that the ID type should be URI's. These are configuration values that the user should not be able to edit, but the property editor may still rely on them.
Name | Type | Required | Description |
---|---|---|---|
alias
string
Yes
A unique alias that identifies the property editor.
name
string
Yes
The friendly name of the property editor, shown in the Umbraco backoffice.
editor
object
Yes
This describes details about the editor. See the table below for further information.
icon
string
No
A CSS class for the icon to be used in the Select Editor dialog - eg: icon-autofill
.
group
string
No
The group to place this editor in within the Select Editor dialog. Use a new group name or alternatively use an existing one such as Pickers.
isParameterEditor
boolean
No
Enables the property editor as a macro parameter editor. Can be either true
or false
(default).
defaultConfig
object
No
Provides a collection of default configuration values, in cases the property editor is not configured or is used a parameter editor (which doesn't allow configuration). The object is a key/value collection and must match the prevalue fields keys.
view
string
Yes
This is the full path to the HTML view for your property editor.
hideLabel
bool
Yes
If set to true
, this hides the label for the property editor when used in Umbraco on a Document Type.
valueType
object
No
This is the type of data you want your property editor to save to Umbraco. Possible values are STRING
, JSON
, DATETIME
, TEXT
and INT
. Default is STRING
.
validation
object
No
Object describing required validators on the editor.
isReadOnly
boolean
No
If set to true this makes the property editor read only.
Alias
string
Yes
Gets the unique alias of the editor.
EditorType
Yes
Gets the type of the editor. Possible values are EditorType.PropertyValue
, EditorType.MacroParameter
or EditorType.Nothing
.
Name
string
Yes
Gets the friendly name of the editor.
View
string
Yes
Gets the view to use to render the editor.
ValueType
string
No
Gets or sets the type of the edited value.
HideLabel
boolean
No
Gets or sets a value indicating whether the editor should be displayed without its label.
Icon
string
No
Gets or sets an optional icon.
Group
string
No
Gets or sets an optional group.
IsDeprecated
boolean
No
Gets or sets a value indicating whether the value editor is deprecated.