When working with forms, sometimes you need to make special requirements to validate the data that customers enter. In this topic, I will show you how to create custom rules in Magento 2.

Magento form validation rules

  • Magento has created a lot of useful rules and you can find them in vendor/magento/module-ui/view/base/web/js/lib/validation/rules.js
    vendor/magento/module-review/view/frontend/web/js/validate-review.js
    vendor/magento/module-payment/view/base/web/js/model/credit-card-validation/validator.js
  • Below are a few commonly used rules:

How to add a custom validation rule 

In this example, I will create the module Magenest_CustomRule, and apply custom rules for the customer address edit form in the frontend and configuration field in the admin panel.

Step 1: To create new custom rules, you can create a js file app/code/Magenest/CustomRule/view/base/web/js/validation.js and calling the $.validator.addMethod function with the custom validation rule parameters like below. 

define([
   'jquery',
   'jquery/validate',
   'mage/translate'
], function($) {
   'use strict';

   return function() {
      // Add a validation method that checks if the name is less than 5 characters.
       $.validator.addMethod(
           'custom-validate-length',
           function(name) {
               return name.length <= 5;
           },
           $.mage.__('Length must not be greater than 5 character length!')
       );
      // Add a validation method that checks if the zip code is five-digit or 
      // nine-digit(ZIP+4format).
       $.validator.addMethod(
           'custom-validate-zip',
           function(zip) {
               return /^[0-9]{5}(?:-[0-9]{4})?$/g.test(zip);
           },
           $.mage.__('Please enter a valid zip code!')
       );
   }
});

Here I use $.validator.addMethod( name, method, [ message ] )

  • name: the name of the method used to identify.
  • method: the actual method implementation, returning true if an element is valid.
  • message: if the method returns false, the message is displayed.

Step 2: After creating your rules, add the new validation rule to the mixin in app/code/Magenest/CustomRule/view/base/requirejs-config.js

var config = {
  config: {
    mixins: {
      'mage/validation': {
        'Magenest_CustomRule/js/validation': true
      }
    }
  }
}

    Now, your rules will be available everywhere.

In Frontend

Step 3: Create a template file app/code/Magenest/CustomRule/view/frontend/templates/address/edit.phtml 

Step 4:  open the file edit.phtml in vendor/magento/module-customer/view/frontend/templates and copy the content to app/code/Magenest/CustomRule/view/frontend/templates/address/edit.phtml.

Step 5:  You need to change the file customer_address_form.xml in module Magento_Customer. So, you must create a file with the same name in app/code/Magenest/CustomRule/view/frontend/layout and add the following content to it:

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
       <referenceBlock name="customer_address_edit" >
          <action method="setTemplate">
            <argument name="template" xsi:type="string">Magenest_CustomRule::address/edit.phtml</argument>
          </action>
       </referenceBlock>
    </body>
</page>

Step 6: Add new rules custom-validate-length to validate street length and custom-validate-zip to validate zip code in edit.phtml like this

<input type="text"
       name="street[]"
       value="<?= $block->escapeHtmlAttr($block->getStreetLine(1)) ?>"
       title="<?= /* @noEscape */ $block->getAttributeData()->getFrontendLabel('street') ?>"
       id="street_1"
       class="input-text <?= $block->escapeHtmlAttr($_streetValidationClass) ?>"
      data-validate="{'custom-validate-length':true}"/>
<input type="text"
       name="postcode"
       value="<?= $block->escapeHtmlAttr($block->getAddress()->getPostcode()) ?>"
       title="<?= /* @noEscape */ $block->getAttributeData()->getFrontendLabel('postcode') ?>"
       id="zip"
       class="input-text custom-validate-zip validate-zip-international <?= $block->escapeHtmlAttr($this->helper('Magento\Customer\Helper\Address')->getAttributeValidationClass('postcode')) ?>">

You can add new rules to forms in these ways:

  • As a data-validate attribute
<input id="field-1" ... data-validate='{"validate-custom":true}'/>
  • As an attribute
<input id="field-1" ... validate-custom="true"/>
  • As a class name
<input id="field-1" ... class="input-text validate-custom"/>
  • Using data-mage-init
<form 
 data-mage-init='{"validation": {"rules": {"field-1": {"validate-custom":true}}}}'>
 ...
</form>

In the Admin Panel

I will add custom validation for the Store Name field in Stores > Configuration >  GENERAL > General > Store Information

Step 3: Create app/code/Magenest/CustomRule/etc/adminhtml/system.xml and add the following content:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <section id="general">
            <group id="store_information">
                <field id="name">
                    <frontend_class>custom-validate-length</frontend_class>
                </field>
            </group>
        </section>
    </system>
</config>

This is the folder structure of the module

When you have done, you have to run bin\magento cache:clean to clear cache and apply the changes. Below is the result, the form gets validated before sending data to the server for processing.

Hope this article is helpful to you. If you have a comment, please comment below so we can better complement this article and the following articles.

Thank you all and good luck.