Attribute to set TinyMCE settings per property in Episerver

After the introduction of TinyMCE editor v2, creating an initialization module is the recommended way of configuring TinyMCE in Episerver CMS 11. This works well when you want the same configuration for all your XhtmlString properties, but that is not always the case.

In the previous version, before TinyMCE was moved to a separate NuGet package, it was possible to create custom settings that could be added to selected properties using an attribute. I liked that approach better!

With some inspiration from @athraen (blog post) and @lucgosso (blog post), I found a solution I'm happy with.

I would like some of my XhtmlString properties to have just a few options available. This attribute will add five buttons to the toolbar, include the necessary plugins, clear the menu bar and adjust the height.

using System;
using System.Collections.Generic;
using System.Web.Mvc;
using EPiServer.Shell.ObjectEditing;

namespace Alloy.Business.Attributes
{
    [AttributeUsage(AttributeTargets.Property)]
    public class SimpleTinyMceEditorAttribute : Attribute, IMetadataAware
    {
        public void OnMetadataCreated(ModelMetadata metadata)
        {
            ExtendedMetadata extendedMetadata = metadata as ExtendedMetadata;
            if (extendedMetadata == null) return;

            if (extendedMetadata.EditorConfiguration["settings"] is Dictionary<string, object> settings)
            {                
                settings["toolbar"] = "epi-link unlink | bold italic | code";
                settings["plugins"] = "epi-link link code";
                settings["menubar"] = "";
                settings["height"] = 175;
            }
        }
    }
}

Make sure you use IMetadataAware from System.Web.Mvc, not System.Web.ModelBinding. If you reference the wrong namespace, the code will compile but your OnMetadataCreated-method will not be hit.

Then, I can add the attribute to my selected properties like this:

public class StandardPage : SitePageData
{
    [SimpleTinyMceEditor]
    public virtual XhtmlString MainIntro { get; set; }

    public virtual XhtmlString MainBody { get; set; }
}

And it would look like this:

The default configuration, used for most properties, can be kept in the initialization module. The few exceptions can be handled using one or more attributes.