📋 Content Models
Property Editors Settings
📖 Docs

Property Editors and Settings - Optimizely CMS 12

Exam Area: Content Area 5 – Content Models (25%)
Reference: https://docs.developers.optimizely.com/content-management-system/docs/property-editors


1. UIHint Attribute

// Suggests the editor type in CMS UI
public class ArticlePage : PageData
{
    // Built-in UIHint values
    [UIHint(UIHint.Image)]        // Image selector
    public virtual ContentReference HeroImage { get; set; }

    [UIHint(UIHint.Video)]        // Video selector
    public virtual ContentReference Video { get; set; }

    [UIHint(UIHint.MediaFile)]    // Any media selector
    public virtual ContentReference Attachment { get; set; }

    [UIHint(UIHint.Textarea)]     // Multi-line text
    public virtual string Description { get; set; }

    [UIHint(UIHint.HtmlEditor)]   // Full TinyMCE editor
    public virtual string Content { get; set; }

    [UIHint(UIHint.FloatNumber)]  // Float input
    public virtual double Price { get; set; }

    [UIHint(UIHint.LongString)]   // Long text (equivalent to textarea)
    public virtual string Notes { get; set; }
}

2. EditorDescriptor - Custom Editor

// EditorDescriptor maps UIHint → Editor widget

[EditorDescriptorRegistration(
    TargetType = typeof(string),
    UIHint = "ColorPicker",
    EditorDescriptorBehavior = EditorDescriptorBehavior.ExtendBase)]
public class ColorPickerEditorDescriptor : EditorDescriptor
{
    public ColorPickerEditorDescriptor()
    {
        ClientEditingClass = "myApp.ColorPickerEditor";  // Dojo widget
    }

    public override void ModifyMetadata(
        ExtendedMetadata metadata,
        IEnumerable<Attribute> attributes)
    {
        base.ModifyMetadata(metadata, attributes);
        
        // Add configuration for the editor
        metadata.EditorConfiguration["defaultColor"] = "#ffffff";
    }
}

// Usage
[UIHint("ColorPicker")]
public virtual string TextColor { get; set; }

3. Property Settings

// Settings interface
public interface IPropertySettings<T> where T : PropertyDataType
{
    bool IsModified { get; }
    void Reset();
}

// TinyMCE Settings Example
public class CustomTinyMceSettings : TinyMcePropertySettings
{
    public override bool IsDefault => false;
    public override string GetConfiguration()
    {
        return new TinyMceConfiguration()
            .AddToolbarRow("bold italic underline | bullist numlist | link image")
            .AddPlugin("paste")
            .AddPlugin("image")
            .Build();
    }
}

// Usage
[Display(Name = "Restricted editor")]
[BackingType(typeof(PropertyXhtmlString))]
[Settings(typeof(CustomTinyMceSettings))]
public virtual XhtmlString SimplifiedEditor { get; set; }

4. SelectOne / SelectMany

// Single select dropdown
[SelectOne(SelectionFactoryType = typeof(ThemeSelectionFactory))]
[Display(Name = "Theme")]
public virtual string Theme { get; set; }

// Multi select checkboxes
[SelectMany(SelectionFactoryType = typeof(CategorySelectionFactory))]
[Display(Name = "Categories")]
public virtual string[] Categories { get; set; }

// Selection factory
public class ThemeSelectionFactory : ISelectionFactory
{
    public IEnumerable<ISelectItem> GetSelections(ExtendedMetadata metadata)
    {
        return new[]
        {
            new SelectItem { Text = "Light", Value = "light" },
            new SelectItem { Text = "Dark", Value = "dark" },
            new SelectItem { Text = "Blue", Value = "blue" }
        };
    }
}

5. AutoSuggest

[AutoSuggestSelection(typeof(CountrySelectionFactory))]
public virtual string Country { get; set; }

public class CountrySelectionFactory : IAutoSuggestSelectionFactory
{
    public IEnumerable<ISelectItem> GetSuggestions(string query, int count, ExtendedMetadata metadata)
    {
        return Countries.All
            .Where(c => c.Name.StartsWith(query, StringComparison.OrdinalIgnoreCase))
            .Take(count)
            .Select(c => new SelectItem { Text = c.Name, Value = c.Code });
    }
}

6. Property Grouping (Tabs)

// Create custom tab
public static class CustomTabs
{
    [GroupDefinition]
    public const string Metadata = "Metadata";
    
    [GroupDefinition]
    public const string SEO = "SEO";
}

// Usage
[Display(GroupName = CustomTabs.SEO, Order = 100)]
public virtual string MetaDescription { get; set; }

[Display(GroupName = SystemTabNames.Content, Order = 10)]  // Built-in tab
public virtual string Heading { get; set; }

[Display(GroupName = SystemTabNames.Settings, Order = 10)]  // Settings tab
public virtual bool ShowInMenu { get; set; }

7. Property Visibility in Tabs

// Available tabs:
SystemTabNames.Content        // Main content tab
SystemTabNames.Settings       // Settings tab
SystemTabNames.Shortcut       // Shortcut tab

8. BackingType Attribute

// Map .NET type → CMS property type
[BackingType(typeof(PropertyXhtmlString))]
public virtual XhtmlString Body { get; set; }

[BackingType(typeof(PropertyLongString))]
public virtual string LongText { get; set; }

[BackingType(typeof(PropertyContentReference))]
public virtual ContentReference Link { get; set; }

[BackingType(typeof(PropertyContentArea))]
public virtual ContentArea MainArea { get; set; }

Review Questions

  1. What does UIHint(UIHint.Image) do? (Specifies the image selector editor for a property)
  2. What is EditorDescriptor used for? (Maps a UIHint string to a client-side editor widget)
  3. Which editor type is [Settings(typeof(...))] used with? (TinyMCE and other editors that have settings)
  4. How does [SelectOne] differ from [SelectMany]? (Single dropdown vs multi-select checkboxes)
  5. What does the [BackingType] attribute do? (Maps a .NET type to a CMS property type for correct serialization/storage)