This is the fourth blog post in a series of posts relating to building plugins for Umbraco v5 (Jupiter). This post will show you how to get started with building an editor. An Editor is the term used to express the editing pane on the right hand side of the back-office. Examples include: the content editor, media editor, document type editor, script editor, etc..

Related Posts:

  1. Umbraco Jupiter Plugins – Part 1
  2. Umbraco Jupiter Plugins – Part 2 – Routing
  3. Umbraco Jupiter Pluings – Part 3 – Trees

Disclaimer

This post is about developing for Umbraco v5 (Jupiter) which at the time of this post is still under development. The technical details described below may change by the time Umbraco Jupiter is released. If you have feedback on the technical implementation details, please comment below.

Defining an Editor

An Editor in Umbraco v5 is the combination of: An MVC Controller, View(s), JavaScript and CSS. The first step to creating an Editor is to create a class that inherits from the Umbraco base editor class: Umbraco.Cms.Web.Editors.StandardEditorController. 

The next step is to register this editor as an editor plugin. To do this you just need to add an attribute to your class such as:

[Editor("ADD307B3-A5F9-4A89-ADAC-72289A5943FF")]

The mandatory parameter passed to this attribute is the editor plugin ID (this MUST be unique so ensure you generated a new GUID for every single one of your plugins).

The next thing you’ll need to do to ensure your editor plugin is found and loaded is to ‘advertise’ that your assembly contains a plugin. To do this, just edit your assembly’s AssemblyInfo.cs file and add the following attribute:

[assembly: AssemblyContainsPlugins]

Creating an Editor

Important convention: All Editor controller names MUST be suffixed with ‘EditorController’. For example, if you are creating an editor to display system information, you might call your Editor: SystemInfoEditorController. If you don’t follow this convention, you’re editor controller wont be routed.

When creating an Editor there are a few base classes to choose from. Generally however, you should inherit from: Umbraco.Cms.Web.Editors.StandardEditorController. The other base classes and their hierarchy are as follows:

  • Umbraco.Cms.Web.Mvc.Controllers.BackOffice.SecuredBackOfficeController
    • Umbraco.Cms.Web.Editors.BaseEditorController
      • Umbraco.Cms.Web.Editors.DashboardEditorController
        • Umbraco.Cms.Web.Editors.StandardEditorController

When inheriting from any of the base classes above, you will be required to create a constructor accepting an parameter of type: IBackOfficeRequestContext :

[Editor("ADD307B3-A5F9-4A89-ADAC-72289A5943FF")]
public class MyEditorController : StandardEditorController
{
    public MyEditorController(IBackOfficeRequestContext requestContext)
        : base(requestContext)
    {
    }        
}

The StandardEditorController has an abstract method: Edit(HiveId id) that needs to be implemented (the abstract Edit Action is marked as [HttpGet])

[Editor("ADD307B3-A5F9-4A89-ADAC-72289A5943FF")]
public class MyEditorController : StandardEditorController
{
    public MyEditorController(IBackOfficeRequestContext requestContext)
        : base(requestContext)
    {
    }
        
    public override ActionResult Edit(HiveId id)
    {
        return View();
    }
}

Most Editors will be displaying a view to edit data based on a HiveId which is the unique identifier type for pretty much all data in Umbraco 5. If you are writing an editor to edit data in a custom Hive provider, then this will work seamlessly for you. Even if you are creating an editor for data that you aren’t writing a custom Hive provider for, you can still use HiveId as a unique identifier since it has support for wrapping Guid, Int and String Id types. If however you decide that HiveId isn’t for you, then you can inherit from one of the other editor base classes that doesn’t have the abstract Edit method attached to it and create your own Actions with your own parameters.

The above Edit Action simply returns a view without a model to be rendered. At this point, you’ll need to know where your view should be stored which has everything to do with MVC Areas or embedding views.

MVC Areas & Jupiter Packages

In a previous post we talk about how packages in v5 are actually registered as their own MVC Area. All packages get installed to the following location: ~/App_Plugins/Packages/{YourPackageName} . If you aren’t embedding your views, then they should be stored inside of your package folder. Each plugin type has a specific view folder name that your views should be stored in:

  • Editor views & partial views:
    • ~/App_Plugins/Packages/{YourPackageName}/Editors/Views/ {EditorControllerName}/{ViewName}.cshtml
    • ~/App_Plugins/Packages/{YourPackageName}/Editors/Views/Shared/ {ViewName}.cshtml
  • Property Editor partial views:
    • ~/App_Plugins/Packages/{YourPackageName}/PropertyEditors/Views/Shared/ {ViewName}.cshtml
  • Dashboard partial views:
    • ~/App_Plugins/Packages/{YourPackageName}/Dashboards/Views/ {ViewName}.cshtml
  • Rendering (front-end) partial views:
    • ~/App_Plugins/Packages/{YourPackageName}/Views/Partial/ {ViewName}.cshtml

So with the controller created above, I would have a view in the following location:

~/App_Plugins/{MyPackageName}/Editors/Views/MyEditor/Edit.cshtml

NOTE: The package name folder will be created when installing your NuGet package and will be based on your NuGet package name and version assigned.

Embedding views

Many of the views shipped with v5 are embedded which helps to reduce the number of actual files that are shipped. This is also handy if you don’t want to give the ability for people to change what’s in your markup.

Embedding a view is really easy:

  • Create a Razor (.cshtml) view in your Package’s project
  • View the Properties for this file and choose ‘Embedded Resource’ as the ‘Build Action’

Now to use the embedded view we use the following syntax:

[Editor("ADD307B3-A5F9-4A89-ADAC-72289A5943FF")]
public class MyEditorController : StandardEditorController
{
    public MyEditorController(IBackOfficeRequestContext requestContext)
        : base(requestContext)
    {
    }
        
    public override ActionResult Edit(HiveId id)
    {
        return View(EmbeddedViewPath.Create("MyProject.Editors.Views.Edit.cshtml"));
    }
}

Its important to get the correct path to your view file. In this instance, my view’s path in my project is: MyProject.Editors.Views.Edit.cshtml

Displaying your Editor

Most of the time an editor is displayed by clicking on a node in the tree or by accessing a context menu item. In a previous post about creating trees there was a method to create a tree node:

protected override UmbracoTreeResult GetTreeData(HiveEntityUri id, FormCollection queryStrings)
{
    NodeCollection.Add(
        CreateTreeNode(id, null, "My only node", string.Empty, false));
    return UmbracoTree();
}

This simply created a tree node that had no editor URL but now that we have an editor, I’ll update the code to click through to my Edit Action:

protected override UmbracoTreeResult GetTreeData(HiveId id, FormCollection queryStrings)
{
    NodeCollection.Add(
        CreateTreeNode(id, null, "My only node",
        Url.GetEditorUrl("MyEditor", id, new Guid("ADD307B3-A5F9-4A89-ADAC-72289A5943FF")),
        false));
    return UmbracoTree();
}
GetEditorUrl is an extension method of UrlHelper which has a few overloads for generating an Editor’s Url. In this case we are passing in the Editor’s name and Id with the Id of the current node being rendered in the tree.

When the node is clicked it will now link to the Edit Action of the MyEditor Controller.