Using Hooks to Modify Forms

Objectives
  • Learn how to use hooks to modify existing forms.
Prerequisites
  • Know how to find and implement hooks.
  • Know how to build forms with the Form API.

Which hooks can I use?

Two of the most commonly implemented hooks are hook_form_alter() and hook_form_FORM_ID_alter().

These hooks let you modify a form's definition before it gets turned into a render array for output.

Things you can do to a form include:

  • Removing fields
  • Adding fields
  • Making fields read-only
  • Changing field labels
  • Adding html markup before/after the form
  • Adding html markup before/after individual fields
  • Adding a css or js snippet/file
  • Adding your own validation or submit handler
  • Replacing a form's validation or submit handler
  • Reorder fields
  • Group fields into fieldsets
  • ...

What's the difference between hook_form_alter() and hook_form_FORM_ID_alter()?

hook_form_alter() is invoked every time a form is built; hook_form_FORM_ID_alter() is invoked only for the form whose id is FORM_ID.

hook_form_alter()

If you use hook_form_alter() your code will executed for every form. This may or may not be your intention. If you only want to modify certain forms, you'll need to add some logic that compares the form id with your predefined list of ids.

You can, of course, add any logic you want, such as:

  • Only if $form_id equals a certain id, modify it.
  • Only if $form_id contains a certain word, modify it (such as: all form_ids that start with user_).
  • Only modify the form if the current user has the 'administrator' role.
  • ...

Example 1

The following hook will be invoked every time any form gets built:

  • Each form will be wrapped in a div with class = 'form-wrapper'.
  • Two specific forms are singled out for modification, and their modification is followed by a message being displayed.
Code
<?php
use Drupal\Core\Form\FormStateInterface;

// [...]

/**
 * Implements hook_form_alter().
 */
function my_module_form_alter(&$form, $form_state, $form_id) {
  $form['#prefix'] = '<div class="form-wrapper">';
  $form['#suffix'] = '</div>';

  if ($form_id == 'node_article_form' || $form_id == 'page_article_form') {
    // Code to modify the form goes here.

    $message = t('Modified form with id: @id', ['@id' => $form_id]);
    \Drupal::messenger()->addMessage($message);
  }

}

The above example illustrates that the generic hook_form_alter() is interesting when you want to modify all forms, or a set of forms based on (part of) their name.

You could also use this hook to modify one specific form, by checking if ($form_id == 'some_form_id', but in that case it's better practice to use the more specific hook_form_FORM_ID_alter().

hook_form_FORM_ID_alter()

If you only want to modify one specific form, it's cleaner and more performant to use hook_form_FORM_ID_alter(), where FORM_ID is replaced with the id of the form you want to modify.

Example

The following example modifies the form with FORM_ID 'example_form' by adding a description to the 'phone_number field'.

Note the name of the function:

  • 'Hook' is replaced with 'my_module', the name of the module that implements the hook.
  • 'FORM_ID' is replaced with 'example_form', the id of the form that's being modified.
Code
<?php
use Drupal\Core\Form\FormStateInterface;

// [...]

/**
 * Implements hook_form_FORM_ID_alter().
 */
function my_module_form_example_form_alter(&$form, $form_state) {
  $form['phone_number']['#description'] = t('Start with + and your country code.');
}

Where can I find a form's ID?

You can look through the core and contrib source code, find the class that builds the form you want to alter, and then get the ID from the getFormId() method.

However, the easier method is to load the page that shows the form in your browser, view its source (or use your browser's inspector tools), and then look for the <form ...> ... </form> definition.

Every Drupal form has a hidden input field named "form_id" that contains the form id.

Example

If you navigate to /node/add/page and view source, you will find the following:

Code
[...]

<input data-drupal-selector="edit-node-page-form" type="hidden" name="form_id" value="node_page_form" />

[...]

→ from this snippet you learn that the form_id for the Article creation form is node_page_form.

Activity

Implement hook_form_alter() in your my_hooks_demo module:

  • Make it show the message 'Altered form with id: ID', replacing ID with the actual form id.
  • The result should be that this message is shown on every page that contains a form (such as the content creation forms, many configuration pages, etc).
Hide hints
show hints

Activity

Implement hook_form_FORM_ID_alter():

  • Alter the forms used to create content of the type 'article'.
  • Show the message 'Altered the Article form'.
  • The form id for the Page creation form was mentioned in this unit.
Hide hints
show hints

Summary

  • You can modify forms through hooks.
  • The most often used hooks for this purpose are hook_form_alter() and hook_form_FORM_ID_alter()