Custom module configuration form for Drupal
Tags: drupal, forms, php
Published: 2019-08-16 22:13:38

Recently I found my self in the need to add a configuration page to a custom module in Drupal 7.

This module was used to send daily email notification to the users, but settings like the recipient list email address were hardcoded in the code.

To update this list I was forced to update the code repository and make a deploy on production. So this was not ideal.

![Oh C'mon!](https://i.imgur.com/p1MJTSh.png)

So I put my self to the task to learn how to _improve_ the custom module by adding its own configuration page. 

Finally it only took a couple of hours to read the relevant documentation, implement the code, and perform the relevant tests.

# TL;DR

You can skip directly to the documentation on this links:

- Drupal 7 HowTos - Creating custom modules: https://www.drupal.org/docs/7/creating-custom-modules
    - Preparing for a module configuration form: https://www.drupal.org/docs/7/creating-custom-modules/preparing-for-a-module-configuration-form
    - Creating the configuration form: https://www.drupal.org/docs/7/creating-custom-modules/creating-the-configuration-form
    - Validating the data: https://www.drupal.org/docs/7/creating-custom-modules/validating-the-data
- Drupal 7 form API: https://api.drupal.org/api/drupal/developer%21topics%21forms_api_reference.html/7.x


# Prerequisites

You will need a Drupal instance with a custom module already created for witch you also have access to the source code.

# How to

All steps are to be applied on the `.module` file of your module, except for the step #2 that is to be applied on the `.info` file of the module.


## 1. Adding a new menu item

```php
/**
 * Implements hook_menu().
 */
function my_custom_module_menu()
{
    $items = array();

    $items['admin/modules/my_custom_module'] = array(
        'title' => 'My Custom Module configuration',
        'description' => 'Configuration for My Custom Module',
        'page callback' => 'drupal_get_form',
        'page arguments' => array('my_custom_module_admin'),
        'access arguments' => array('administer site configuration'),
        'type' => MENU_NORMAL_ITEM,
    );

    return $items;
}
```

For this example the custom module name is `my_custom_module`, so the hook_menu function name must be `my_custom_module_menu`.

- We add a new $items to the menu. The key value is the path to the main menu we want for this new page (in this example `admin/modules/my_custom_module`).
- The `page arguments` value points to the function that will be used to populate the form (in this example `my_custom_module_admi`). We will build this function in the next step.
- The `access arguments` value is used to determine who has access to this menu item.


## 2. Adding a configuration link in the module description

![Configuration link](https://i.imgur.com/aGWRIUz.png)

Adding a configuration link on the custom module description page is simple as adding this line to the .info module file:

```php
configure = admin/modules/my_custom_module
```
> This is the same menu path we already used on step #1.


## 3. Adding items to the form


```php
function my_custom_module_admin($form, &$form_state)
{

    // EMAILS Fieldset
    $form['my_custom_module_settings__emails'] = array(
        '#type' => 'fieldset',
        '#title' => t('Email account settings'),
    );

    // From
    $form['my_custom_module_settings__emails']['my_custom_module_settings__emails__from'] = array(
        '#type' => 'textfield',
        '#title' => t('From address'),
        '#default_value' => variable_get('my_custom_module_settings__emails__from', false),
        '#description' => t('Email address to be used as FROM and Reply-To.'),
        '#required' => true,
    );
    // To
    $form['my_custom_module_settings__emails']['my_custom_module_settings__emails__to'] = array(
        '#type' => 'textarea',
        '#title' => t('To address'),
        '#default_value' => variable_get('my_custom_module_settings__emails__to', false),
        '#description' => t('Recipient email address. You can add multiple email addresses by separating them by a colon (,) character.'),
        '#required' => true,
    );

    return system_settings_form($form);
}

```

Adding items to the form is simple enough using the Drupal form API documentation.

- In this example we can find a fieldset and insde two email fields. The first an input text field for the FORM address, and the second a textarea for multiple recipients email addresses.
- In all the `#default_value` parameters we make use of the Drupal function `variable_get` to retrieve the last saved value of the field.
- The name of the field is the one you specified on the $form array. So, for `$form['my_custom_module_settings__emails']['my_custom_module_settings__emails__to']` the variable name will be `my_custom_module_settings__emails__to`.
- The last line `return system_settings_form($form);` will take care to save the form values on submit.


## 4. Adding custom validating

```php
function my_custom_module_admin_validate($form, &$form_state)
{

    $from = $form_state['values']['my_custom_module_settings__emails__from'];
    if (!filter_var($from, FILTER_VALIDATE_EMAIL)) {
        form_set_error('my_custom_module_settings__emails__from', t('You must enter a valid FROM email address.'));
    }

    $to = $form_state['values']['my_custom_module_settings__emails__to'];
    echo $to;
    $to = explode(',', $to);
    for ($i = 0; $i < count($to); $i++) {
        $address = trim($to[$i]);
        if (!filter_var($address, FILTER_VALIDATE_EMAIL)) {
            form_set_error('my_custom_module_settings__emails__to', t('You must enter a valid TO email address.'));
            break; //Exit the For/Loop on first error
        }
    }
}
```

While field parameters like '#required' will take care of basic validation like making a field requiered, some fields may require a more complex check up.

You can add a validation hook with the function name `my_custom_module_admin_validate` and add your own validations.

- All form field values will be available inside the `$form_state['values']`.
- You can validate multiple fields, and return errors individually by using the Drupal function `form_set_error`.

---


Thats all. Happy coding!