Conditional content properties in Optimizely

How to transform metadata to hide properties based on the context in the Optimizely Content Cloud

In a recent Optimizely project we were building multiple sites that could share content types between them. One problem we encountered was that some of the blocks and pages required slightly different content, and therefore separate content fields (known as properties). The simplest solution is to have 2 properties and if one is empty then the other one is used. The page or block can then display the content accordingly depending on what the content editor has provided.

The problem with that approach is that it becomes increasingly complex for the content editor and can result in content inconsistencies on the website. To solve this problem we developed a solution that could show or hide properties depending on the site that the shared content type is used. The use case in this article is for the properties to be conditional based on the site, however the same techniques can be applied to other similar use cases.

Transform metadata with custom attributes

Metadata is very important and useful in the Optimizely CMS because it controls how content is rendered in the editing view. The metadata of a property contains a bunch of setting values for things such as if the property is required, disabled or even hidden entirely. There are multiple ways to influence the metadata of a property — one option is to create a custom attribute that implements the IDisplayMetadataProvider interface.

Hide a property based on the current site

What we're trying to achieve here is to show the property only when it is rendered for a specific site. The code sample below contains a custom attribute that accepts a parameter containing names of the sites that the property should be available for. The CreateDisplayMetadata method from the IDisplayMetadataProvider interface is then used to dynamically update the metadata to only display the property if the current site matches those sites.

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class)]
public class AvailableOnSitesAttribute : Attribute, IDisplayMetadataProvider
{
    public IEnumerable<string> SiteNames{ get; }

    public AvailableOnSitesAttribute(params string[] siteNames)
    {
        SiteNames = siteNames;
    }

    private bool IsCurrentSite()
    {
        return SiteNames.Any() && SiteNames.Contains(SiteDefinition.Current.Name, StringComparer.InvariantCultureIgnoreCase);
    }

    public void CreateDisplayMetadata(DisplayMetadataProviderContext context)
    {
        if(context.DisplayMetadata.AdditionalValues[ExtendedMetadata.ExtendedMetadataDisplayKey] is ExtendedMetadata extendedMetadata)
        {
            extendedMetadata.ShowForEdit = IsCurrentSite();
        }
    }
}

There are many use cases where this type of attribute can be useful. It doesn't necessarily have to be based on the current site, it can be completely conditional based on any requirements. One thing to note is that it requires a page reload for the metadata to update, meaning that it's not an ideal method when the condition is related to another property on the same content type.

The custom attribute can be applied to any content type property. Below is a simple example of how a different introduction property can be displayed for the sites called Site1, Site2 and Site3. The names of the sites are configured in the 'manage sites' section of the admin UI.

[AvailableOnSites("Site1")]
public virtual string Intro { get; set; }

[AvailableOnSites("Site2", "Site3")]
public virtual XhtmlString DetailedIntro { get; set; }

Closing thoughts

The use case and examples in this article were somewhat simplified to make it less complex and confusing. To make things more robust you can adjust the metadata based on the site ID, or a site setting of sorts, instead of the name of the site.

As a final note I suggest customising the functionality to meet your requirements and firstly considering all your options — before you end up overcomplicating the properties on your content types. Handling properties this way can be very powerful and this article is meant to help developers meet specific requirements.