Add an additional validation function to an existing Drupal form

There are many reasons why you might want to add extra validation rules to a Drupal form. This is a simple tutorial on how to add a validation function to an existing form that is generated from a module that you have not created yourself. It could be in a core or contributed module.

The problem

A form has been created by another module, but we need to add additional validation.

The solution

1) Use hook_form_alter to alter the form and add an additional validation function

  1. <?php
  2. /**
  3.  * Implementation of hook_form_alter().
  4.  */
  5. function my_module_form_alter(&$form, $form_state, $form_id) {
  6. if ($form_id == 'example_form_id') {
  7. array_unshift($form['#validate'], 'example_validate');
  8. }
  9. }
  10. ?>

array_unshift will add the validation function to the beginning of the $form['#validate'] array. This is helpful if you require other validation function to process after your new one. For example, if the form is the user login form (form ID is user_login), then the user_login_final_validate function should happen last. Therefore, we wouldn't want to add a validation function to the end of the $form['#validate'] array.

If it doesn't matter if the validation function goes at the end of the $form['#validate'] array, then the standard way to add a validation function is as follows:

  1. $form['#validate'][] = 'example_validate';

2) Add the custom validation function

  1. /**
  2.  * Validate profile form
  3.  *
  4.  */
  5. function example_validate ($form, &$form_state) {
  6. //perform some validation logic
  7. }

Working example

As an example, I want to add extra validation when a user changes his/her email address. If the new email address is the same as their existing email address, I want the form to not validation and display a validation error (since the user should add a different email address).

  1. /**
  2.  * Implementation of hook_form_alter().
  3.  */function my_module_form_alter(&$form, $form_state, $form_id) {
  4. if ($form_id == 'user_profile_form') {
  5. array_unshift($form['#validate'], 'email_check_validate');
  6. }
  7. }
  8.  
  9. /**
  10.  * Validate profile form
  11.  * Force form error if new email address matches current email address
  12.  *
  13.  */
  14. function email_check_validate ($form, &$form_state) {
  15. global $user;
  16. $old_email = $user->mail;
  17. $new_email = $form_state['values']['mail'];
  18.  
  19. if ($old_email == $new_email) {
  20. form_set_error('mail', t('Your email could not be changed'));
  21. }
  22. }

In the above validation function, I am comparing the user's current email address, as defined by the user object of the current logged in user($user->mail), with the new email address from the form itself ($form_state['values']['mail']). If they match, the user has entered the same email address as their current email address, therefore the form does not validate and the user receives an error message.

If you liked this, you'll love my book, Master Drupal Module Development.

"..the must have drupal developers book"


Feeling stuck with Drupal 8 module dev?

Get the free 7 lesson course that will help you get started today without feeling overwhelmed.

  • Create Drupal modules with just a few commands using the Drupal Console
  • Create custom pages
  • Create custom blocks
  • Create admin forms
  • Demystify routers and controllers
  • Bonus material

Find out more


Comments

Hi, just to make sure; shouldn't: function email_check_validate ($form, $form_state)
be function email_check_validate ($form, &amp;$form_state) ??
great article!, thanks!
nico.

Blair Wadman's picture

Yes, you are correct, thanks for pointing that out. I've updated the article accordingly.

I have created additional fields for registration form. I created a module to validate just the email and phone field. The error message is displaying correctly but only after all default validation. I want it to appear in the order of the fields not after default validation. Can you suggest any solutions.

Blair Wadman's picture

I'm not actually sure if it is possible to change the order of validation. You can change the order of the validation handlers in the validation array ($form['#validate']), but I'll need to test if that changes the order in which the validation errors appear.

I'll do some testing and get back to you.

Where it shows how to add additional validation If it doesn't matter if the validation function goes at the end of the $form['#validate'] array, it says:

$form['#validate'][] = example_validate;

But it should be:

$form['#validate'][] = 'example_validate';

i.e. the name of the function between quotes, because it is a string.

Greetings

Blair Wadman's picture

Thanks so much for pointing that out! Corrected now.

Add new comment