Creating a module configuration (settings) page
Main topic described: Module settings
Drupal hook used: hook_menu
Now that we have a working module, we'd like to make it more flexible. If we have a site that has been around for a while, content from a week ago might not be as interesting as content from a year ago. Similarly, if we have a busy site, we might not want to display all the links to content created last week. So, let's create a configuration page for the administrator to adjust how many links to display, and leave it at that for this tutorial.
Create the configuration function
We'd like to configure how many links display in the block, so we'll create a form for the administrator to set the number of links. The first step in doing that is to define a "system settings" form page, using the Drupal Forms API. Since this is our "administer" page, we'll call the function that generates the function onthisdate_admin() (or we could choose another name, but it should start with onthisdate_ ) and put it into our onthisdate.module file:
<?php
function onthisdate_admin() {
$form = array();
$form['onthisdate_maxdisp'] = array(
'#type' => 'textfield',
'#title' => t('Maximum number of links'),
'#default_value' => variable_get('onthisdate_maxdisp', 3),
'#size' => 2,
'#maxlength' => 2,
'#description' => t("The maximum number of links to display in the block."),
'#required' => TRUE,
);
return system_settings_form($form);
}
?>There are several things to notice about this function:
- $form is an array defining form elements in the Drupal Forms API. Each element of the array corresponds to a form element; in this case, we have one required two-character text field whose label is "Maximum number of links", with help text "The maximum number of links to display in the block".
- We only have to define form elements for the actual settings elements -- the
system_settings_form()function will take care of creating the form page, adding a submit button, and saving the settings. - Drupal maintains a database of "variables", or settings; each setting must have a unique name, so customarily the module name is used as a prefix -- our setting is called 'onthisdate_maxdisp'.
- The Drupal function variable_get() is used to retrieve the previously-stored value of the setting, and we've given it a default value of 3 if there was no previously-stored value.
- The setting name, 'onthisdate_maxdisp', is used in the call to
variable_get()and is also the array key for the form element in the $form array. This is important, because the Drupalsystem_settings_form()function will use the array key as the name of the setting to save when the form is submitted. - All of the text our form will display is passed through the translate function of t(), so that sites in other languages can use our module.
- Refer to Drupal Forms API Reference and Drupal Forms API Quickstart Guide for more detailed information on what more you can do with the Drupal Forms API.
We'll also need to modify our hook_block() implementation to use this setting. The best way to do that in Drupal is to use the db_query_range function:
<?php
$limitnum = variable_get("onthisdate_maxdisp", 3);
$query = "SELECT nid, title, created FROM " .
"{node} WHERE created >= %d " .
"AND created <= %d";
$query_result = db_query_range($query, $start_time, $end_time, 0, $limitnum);
?>You'll need to replace the corresponding $query and $query_result lines in your existing
onthisdate_block() function with these three lines.
Add the page to hook_menu
Once you have created the function with your settings form, you need to define a URL within Drupal for your settings page. This is done by implementing Drupal's hook_menu. In our hook_menu implementation, we will return an array which describes to Drupal which URL path to use, the title to display, the function to call to generate the page, and the permissions required.
We would like only administrators to be able to access this page, so we'll place the permissions check for the module here in hook_menu so that Drupal can itself check the appropriate permission. To minimize the number of permissions an administrator has to deal with, we're going to use the global administration permission for administrating our module instead of creating a new custom permission.
To implement hook_menu(), create a function called onthisdate_menu() and put it in your onthisdate.module file:
<?php
function onthisdate_menu() {
$items = array();
$items['admin/settings/onthisdate'] = array(
'title' => 'On this date module settings',
'description' => 'Description of your On this date settings page',
'page callback' => 'drupal_get_form',
'page arguments' => array('onthisdate_admin'),
'access arguments' => array('access administration pages'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
?>Note that the array key 'admin/settings/onthisdate' is the URL that we are defining, and the array elements give the menu link title ("On this date module settings" -- it should always start with a capital letter and otherwise be lower-case), a longer description, the name of the function to call that will return the settings form ('onthisdate_admin'), and the access permission. You can check out the hook_menu documentation for more details.
After adding this to the module, you will need to clear the menu cache, so that Drupal will recognize the new URL (Drupal caches a lot of data, including a list of all the URLs it recognizes). To clear the cache, go to Administer >> Settings >> Performance, scroll to the foot of the page, and click the "Clear cached data" button.
Now you can test the settings page by editing the number of links displayed and noticing that the block content adjusts accordingly. Navigate to the settings page: admin/settings/onthisdate or Administer » Site configuration » On this date. Adjust the number of links and save the configuration. The maximum number of links in the block should adjust accordingly.
Validate the user input
Although we aren't required to validate the user input, it is nice to do so. We can do this by writing a onthisdate_admin_validate function (in onthisdate.module) that checks whether the value the user entered is a number greater than 0. Because the validation function has the same name as the form generation function, with a "_validate" suffix, Drupal will use our validation function automatically when the form is submitted.
<?php
function onthisdate_admin_validate($form, &$form_state) {
$maxdisp = $form_state['values']['onthisdate_maxdisp'];
if (!is_numeric($maxdisp)) {
form_set_error('onthisdate_maxdisp', t('You must enter an integer for the maximum number of links.'));
}
else if ($maxdisp <= 0) {
form_set_error('onthisdate_maxdisp', t('Maximum number of links must be positive.'));
}
}
?>Now if you try to enter something that it doesn't like (a word, or a negative number), it will tell you to enter a correct value.

Validate
Changing
if (!is_int($maxdisp))to
if (!is_numeric($maxdisp))makes the module validation function behave as intended.
Check out the 'Note:' section at http://us.php.net/is_int
Correction to the tutorial
Hi,
I am a new user of Drupal and I hope I am not wrong saying this, but I believe that where it says:
It should say:
Since I have a new installation of Drupal (6.13) and it appears as "Administer >> Site configuration" instead of "Administer >> Settings".
Thank you,
Javier.