Insights

How To Setup A Custom Field Validator In Sitecore

The Need for Custom Field Validators in Sitecore

In a recent project, one of the components we were building was utilizing a Single-line Text field to capture time in the format h:mm and another dropdown to select am vs pm. We could’ve used the time zone feature, but because of Daylight Savings confusions in the past, this was a better approach to ensure the date and time shown was always accurate to their needs.

The Problem

There are two primary issues that can come about with storing time within a string field. The first being that OOTB there’s no validation to ensure that people are entering in time in the correct format and because of the extra computed fields that occur, it needs to be correct. The second, is that if it was incorrect and not fixed, and then the user published the item it would cause publishing to fail, again, due to the nature of a couple pipelines at play. And if the user is publishing many, many items it would be near impossible for them to determine where the problem is. And silently logging the issue does not help anyone. Great for debugging of sorts, but

Creating a Custom Field Validator in Sitecore

It’s actually a two part solution. The first being building a custom field validator. The second revolves some smart Exception handling.

The Validator

Creating a custom validator is remarkably easy and to be honest, should really be utilized to a greater degree in my opinion. Here’s the primary code to get this to work:

using Sitecore.Data.Validators;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;
using Sitecore.Data.Fields;

namespace ABCCompany.Foundation.Extensions.Validators
{
    public class CustomTimeValidator : StandardValidator
    {
        public CustomTimeValidator() : base()
        {
        }

        public CustomTimeValidator(SerializationInfo info, StreamingContext context)
           : base(info, context)
        {
        }

        protected override ValidatorResult Evaluate()
        {
            // Get the field value from the Parameters property
            Field field = this.GetField();
            string fieldValue = field?.Value;
            if (String.IsNullOrEmpty(fieldValue)) return GetFailedResult(ValidatorResult.CriticalError);

            // Perform the validation logic
            if (!string.IsNullOrEmpty(fieldValue))
            {
                // Implement your validation logic here
                // You can use regular expressions or other parsing methods to check the format
                // Example: Regular expression pattern to match the h:mm format
                string pattern = @"^\d{1,2}:\d{2}$";
                if (!System.Text.RegularExpressions.Regex.IsMatch(fieldValue, pattern))
                {
                    // Set the error message if the validation fails
                    this.Text = "The time format should be in h:mm.";
                    return GetFailedResult(ValidatorResult.CriticalError);
                }
            }

            // Return successful result if the validation passes
            return ValidatorResult.Valid;
        }
        public override string Name
        {
            get { return "Custom Time Validator"; }
        }

        protected override ValidatorResult GetMaxValidatorResult()
        {
            // Return the maximum validator result
            return ValidatorResult.CriticalError;
        }

    }
}

Essentially everything within the Evaluate() function is where you will determine if the field value meets the necessary criteria or not. This can be as complicated or as simple as you wish.

Next we have the configuration file patch.

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:localenv="http://www.sitecore.net/xmlconfig/localenv">
    <sitecore  role:require="Standalone or ContentDelivery or ContentManagement">
        <pipelines>
            <saveUI>
                <processor type="ABCCompany.Foundation.Extensions.Validators.CustomTimeValidator, ABCCompany.Foundation.Extensions" />
            </saveUI>
        </pipelines>
    </sitecore>
</configuration>

And finally, we have creating the corresponding Sitecore item that we can then assign to the field as part of validation.

This is located in /sitecore/system/settings/Validation Rules/Field Rules.

Custom field validator in Sitecore to ensure that time is entered in the correct format.

Exception Handling

Normally if we have a pipeline and an invalid time was entered and then subsequently published you would likely see an error in the Publishing modal talking about some kind of DateTime parse issue but in no way indicate on which item or which field the error occurred. So to show you how this works I’ve now entered an invalid time.

How to handle exceptions when an invalid time is entered and published

And then we published it. On purpose.

Exception Handling for A Custom Field Validator in Sitecore

So what we’ve done here is we’ve wrapped the DateTime.ParseExact function in a try / catch. And then within the catch statement, we’ve thrown a new Exception with a custom message detailing the cause of the error, the item ID it happened on, and even the path to the item. Using some simple /n within the string we’ve added some simple formatting to ensure it’s more readable.

Simple things like this just ensure your authors' experiences are less stressful.


Related Links

Meet David Austin

Development Team Lead | Sitecore Technology MVP x 3

📷🕹️👪

David is a decorated Development Team Lead with Sitecore Technology MVP and Coveo MVP awards, as well as Sitecore CDP & Personalize Certified. He's worked in IT for 25 years; everything ranging from Developer to Business Analyst to Group Lead helping manage everything from Intranet and Internet sites to facility management and application support. David is a dedicated family man who loves to spend time with his girls. He's also an avid photographer and loves to explore new places.

Connect with David