This article covers how to implement custom fields for Piranha. If you want to read more about the standard field included, please refer to Fields in the section Content.
Fields are the lowest level of content in Piranha CMS and are used to build up Regions and Blocks. In many cases the fields included in Piranha are sufficient, but you might also want to create custom fields for you application. One use case is for example if you would like to reference a custom entity in your application from a Page or Post, much like the included PageField
does.
When naming your components, whether it's fields, blocks or block groups you should stay clear of the names already used by the internal components of the Piranha manager.
block-group-horizontal
block-group-vertical
block-group
folder-item
generic-block
page-item
pagecopy-item
post-archive
region
sitemap-item
In order to create a custom field your class has to implement the IField
interface from the Piranha.Extend
namespace. The interface contains the following methods that needs to be implemented:
public interface IField
{
/// <summary>
/// Gets the list item title if this field is used in
/// a collection regions.
/// </summary>
string GetTitle();
}
string GetTitle();
Gets the list item title if this field is used in a collection region. Please note that it's only supported to reference Field
Properties as title.
// Synchronous Init method
void Init(...);
// Asyncronous Init method
Task Init(...);
Initializes the field for client use. This is called when the field is loaded and is used for loading additional resources. As an example, the ImageField
loads the referenced image from the database when Init()
is called.
The method supports Dependency Injection which means that any service registered in the DI Container can be added as an parameter. This is useful when loading custom data from your application.
// Synchronous Init method
void InitManager(...);
// Asyncronous Init method
Task InitManager(...);
Initializes the field when it's loaded from within the manager. This can for example be useful if you want to load meta-data for the field that you only need when editing it. Just like the regular Init
method it supports Dependency Injection so that you can use any service registered in the DI Container.
Let's take a look at how a simple string field could be implemented.
using Piranha;
using Piranha.Extend;
[FieldType(Name = "Simple String", Component = "simple-field")]
public class SimpleStringField : IField
{
public string Value { get; set; }
public string GetTitle() {
return Value;
}
public void Init() {
// Nothing special for this field
}
}
When registering a field with the FieldTypeAttribute
you can set the following properties.
public string Name { get; set; }
The display name of the field type in the manager interface.
public string Component { get; set; }
The name of the global Vue
component that should be used for rendering the field in the manager interface.
All available fields has to be registered in the singleton Piranha.App
after the app has been initialized.
Piranha.App.Init(api);
// Register custom fields
Piranha.App.Fields.Register<SimpleStringField>();
The manager interface is based on Vue.js
and assumes that all fields are registered as global components. As these components are written in Javascript
you need to register your custom resources in the manager. For more information about this, please refer to Resources in the section Manager Extensions.
Let's take a look at how the component for our SimpleStringField could look like.
Vue.component("simple-field", {
props: ["uid", "toolbar", "model", "meta"],
template:
"<textarea class='form-control' " +
" :placeholder='meta.placeholder' " +
" v-model='model.value'>" +
"</textarea>"
});
All field components get the following properties from the main edit views in the manager interface.
A globally unique id that can be used in the component when rendering more complex views. This field is generated at runtime and will be different each time for every field.
The id of the container that toolbars should be positioned inside, for example when using the Tiny MCE
editor.
This is your custom field, i.e the SimpleStringField serialized as JSON
.
Meta information about the field collected from both the FieldTypeAttribute
and the FieldAttribute
on the model. The meta object has the following properties.
{
uid: "Runtime generated unique string",
name: "The field name",
title: "The title if this component is used in a list",
description: "Optional description",
placeholder: "Optional placeholder",
component: "The name of the vue component",
id: "The field id",
isHalfWidth: "How the field is rendered",
notifyChange: "If this field should notify changes to title"
}
As default, all fields are serialized as JSON
in the database, however you can choose to serialize your data in a different way, or maybe even store it in a separate table in the database. The easiest way to do this is the register a custom serializer for your field. You can read more about this in Serializers.