Skip To Content

Improve Content Authoring with Kentico Xperience’s Robust API

Introduction  

At BlueModus, we use a code generator to create lightweight DTO classes for Kentico Xperience page types. These lightweight classes improve caching, support JSON serialization, and allow modeling page type inheritance.  Mirroring page type inheritance in the object model enables rendering many types of content with one MVC partial view. For example, a partial view created to render a card can render a product, promotion, or article teaser without knowing the difference as long as they share inherited fields. We create a base type called ListableBase that provides common fields like title, summary, thumbnail, and URL. Using this base type, a website can render lists of content, from simple links to rich card layouts, without knowing the specific content types. This cuts down type-specific boilerplate code. Additionally, using inherited types to share common fields improves SQL performance. When querying Xperience for the content of multiple types, most of the fields will align to reduce the effect of union “hell”. SQL union queries become narrower because page types have common field names.  

Problem 

A user experience challenge arises from using inherited page types because most field properties can only be set in the base page type. For example, if a field’s caption is “title” in the base type, its caption cannot be changed to “product name” in an inherited type. This prevents customizing the following field settings in derived types, settings we use to enhance the author experience: 

  • Caption 
  • Description 
  • Explanation 
  • Form control 
  • Drop-down list 

We often need to customize advanced settings in our custom field controls. For example, we also have a custom field control for selecting related content. With this control, authors can compose pages using reusable content components. In the control’s advanced settings, we need to change the allowed child page types, but these settings are also disabled in an inherited type.  

Solution 

The good news is Xperience allows you to configure most field properties in alternative forms. This allows changing a field’s caption, description, or advanced properties for an inherited type. Therefore, a product, call-to-action, promotion, and article can all inherit the same title field but have unique captions and explanations to improve the author’s user experience.  Alternative forms allow you to control the fit and polish of each page type’s form and provides significant improvement to the author’s experience.  

Unfortunately, when using alternative forms to override the settings of inherited fields, you can't make only one alternative form. You must create an alternative form for each edit mode – that is an alternative form for both “update” and “insert”.  Creating two alternative forms for a page type was a burden, but an author's user experience is one of the most important factors in the success of an Xperience project. This made the extra effort worth it. However, we realized a third alternative form was needed for sites supporting multiple cultures. In that case, we had the overhead of creating three alternative forms for each page type that required you to override the inherited field settings. Suddenly, this great idea became too much overhead. 

Xperience’s best-kept secret 

I've often said that Xperience’s best-kept secret is its robust API and extensibility. The API allows so much customization that there is almost always a solution for unique customer requirements.  This time, the API allowed us to create a custom AlternativeFormInfoProvider. By creating a custom provider, we added code that would cause Xperience to use an alternative form named “upsert” whenever it couldn't find one named “insert”, “update”, or “newculture”. Here’s a rudimentary example that shows how to create a custom AlternativeFormInfoProvider. Keep reading to find our version in the DevNet Marketplace. 

using CMS; 

using CMS.FormEngine; 

using Acme.UpsertAlternativeForms; 

using System; 

using System.Linq; 

 

[assembly: RegisterCustomProvider(typeof(UpsertAlternativeFormInfoProvider))] 

 

namespace Acme.UpsertAlternativeForms 

{ 

    /// <inheritdoc /> 

    /// <summary> 

    /// Kentico custom provider for alternative forms to enable using  

    /// alternative forms named "upsert" for all three form modes supported  

    /// for pages: "insert", "update", and "newculture". 

    /// </summary> 

    public class UpsertAlternativeFormInfoProvider : AlternativeFormInfoProvider 

    { 

        // These three alternative form names are the built-in names used for Page Types. 

        private static readonly string[] BuiltInPageTypeAlternativeFormNames = 

            { "update", "insert", "newculture" }; 

 

        /// <inheritdoc /> 

        /// <summary> 

        /// Overrides default Kentico behavior by allowing an alternative  

        /// form named "upsert" to be used if forms named "insert", "update", 

        /// or "newculture" do not exist. 

        /// </summary> 

        /// <param name="alternativeFormFullName">The name of the alternative form</param> 

        /// <param name="useHashtable">Optional flag to use a hash table</param> 

        /// <returns>An AlternativeFormInfo object</returns> 

        protected override AlternativeFormInfo GetInfoByFullName( 

            string alternativeFormFullName,  

            bool useHashtable = true) 

        { 

            var providedForm = base.GetInfoByFullName( 

                alternativeFormFullName, 

                useHashtable); 

 

            if (providedForm != null) 

            { 

                return providedForm; 

            } 

 

            var delimiterPosition = alternativeFormFullName.LastIndexOf('.'); 

            var className = alternativeFormFullName.Substring(0, delimiterPosition); 

            var formName = alternativeFormFullName.Substring(delimiterPosition + 1); 

 

            if (!BuiltInPageTypeAlternativeFormNames.Contains( 

                formName,  

                StringComparer.OrdinalIgnoreCase)) 

            { 

                return null; 

            } 

            var upsertFormName = className + "." + formName; 

            return base.GetInfoByFullName(upsertFormName); 

        } 

    } 

} 

Result 

After adding a small amount of code, we were able to create one alternative form for each derived page type. This greatly reduced the overhead of using alternative forms and increased the efficiency of tailoring the author user experience.  

Upsert Alternative Forms in the Marketplace 

We now use this custom AlternativeFormInfoProvider in every new project and want to share it with the Xperience community. The “Kentico Xperience Upsert Alternative Forms Provider” is available in the Xperience DevNet Marketplace and on GitHub. It is also compatible with projects built in Xperience version 11, 12, or 13.  I hope, with the help of this provider, you are inspired to create great author user experiences. 

Have questions on how to get the most out of your Kentico implementation? Drop me a line on Twitter (@HeyMikeWills), or view my other articles here.