Telling Drupal about your module
- Drupal version: Drupal 7.x
- Audience: Developers and coders
- Last modified: May 9, 2011
Main topic described: .info files
All modules must have a 'modulename.info' file, which contains meta information about the module.
The general format is:
description = A description of what your module does.
core = 7.x
For our module, we will replace 'modulename' in the example above with the name of our module, 'current_posts'. Without this file, the module will not show up in the module listing. Here are the contents:
description = A block module that lists links to recent posts.
core = 7.x
Add the source above to a file named current_posts.info and save it into the module's directory at sites/all/modules/current_posts.
Note: If you copy and paste this code block, ensure that the description data does not contain a line break (turn off word-wrap on your text-editor to be sure). Otherwise, the .info file will not parse correctly.
.Info File Details
- name (Required)
- The displayed name of your module. It should follow the Drupal capitalization standard: only the first letter of the first word is capitalized ("Example module", not "example module" or "Example Module").
name = Current posts
- description (Required)
- A short, preferably one line description that will tell the administrator what this module does on the module administration page. Overly long descriptions can make this page difficult to work with, so please try to be concise. This field is limited to 255 characters.
description = A block module that lists links to recent posts.
Descriptions can contain links to documentation and sources. The following example shows a link to the author. It could be a link to a documentation node on Drupal.org. This is useful when the online documentation is better than the readme file and when you want to read about a module before switching it on.
description = Domain manager by <a href="http://petermoulding.com">Peter Moulding .com</a>.
- core (Required)
- The version of Drupal that your module is for. For Drupal 7 this would be 7.x, etc. Note that modules cannot specify the minor version of a branch of Drupal. 6.x is correct; 6.2 is not.
core = 7.x
- files (Optional)
- Drupal now supports a dynamic-loading code registry. To support it, all modules must now declare any code files containing class or interface declarations in the .info file, like so:
name = Example module
description = "Gives an example of a module."
...
files[] = example.testWhen a module is enabled, Drupal will rescan all declared files and index all the classes and interfaces that it finds. Classes will be loaded automatically by PHP when they are first accessed.
- dependencies (Optional)
- There are a couple of extra options that may appear in the .info file, one of which are module dependencies. If a module requires another module to be enabled, list each module (filename) required in the following syntax:
dependencies[] = taxonomy
dependencies[] = commentFor the example module, these don't apply and we will simply omit them. If dependencies are assigned for a module, Drupal will not allow it to be activated until the required dependencies are met.
- package (Optional)
- If a module has a package string, on the admin/build/modules page it will be listed with other modules with the same category. If a package string is not assigned, it will simply be listed in the 'Other' category. Not assigning a package for your module is perfectly ok; in general packages are best used for modules that are distributed together or are meant to be used together. If in doubt, leave this field blank.
package = "Your arbitrary grouping string"
Suggested examples of appropriate items for the package field:
- Administration
- Commerce
- Development
- Fields
- Media
- User interface
- Views
- Voting (if it uses/requires VotingAPI)
.info files have several other optional categories that are rarely used or discouraged and are not relevant to this tutorial. See Writing .info files (Drupal 7.x), if you want all the details.
Check
Your module should now appear in the module list in your site. Go to Modules and scroll down to the bottom of the list in the 'Other' category. You should see the module 'Current posts'.
Writing comments and implementing your first hook
- Drupal version: Drupal 7.x
- Audience: Developers and coders
- Last modified: November 11, 2011
Drupal hook described: hook_help()
Comments in Drupal modules
It's always a good idea to document how your module works in comments. Drupal uses Doxygen to draw documentation from source code, so contrib modules on drupal.org follow strict comment guidelines. See Doxygen and comment formatting conventions for more details. Following these guidelines is beneficial to anyone looking at your code even if it's not strictly necessary for your situation.
Your first comment:
/**
* @file
* A block module that displays recent blog and forum posts.
*/
?>
@file signifies that this comment pertains to the entire file. The doc block begins with a slash and two asterisks (/**) and ends with one asterisk and a slash (*/). Following Drupal guidelines, we will introduce each function in the module with such a comment.
Implementing your first hook
Hooks are fundamental to Drupal modules. They allow you to integrate your module into the actions of Drupal core. If you missed it, go back and read about hooks in Introduction to Drupal modules.
Your first hook is hook_help. This hook is recommended for inclusion in all contrib modules. hook_help provides help and additional information about the module to the user. To implement any hook in Drupal, replace "hook" in the hook name with your module's short name, and create a function in the .module file with that name. So, to implement hook_help() in our example module, we create a function called current_posts_help() in the current_posts.module file:
function current_posts_help($path, $arg) {
}
?>
The $path parameter provides context for the help: where in Drupal or the module the user is when they are accessing help. The recommended way to process this variable is with a switch statement. This code pattern is common in Drupal modules. Here is an abbreviated implementation of this function for your module, along with its doc block comment:
/**
* Implements hook_help.
*
* Displays help and module information.
*
* @param path
* Which path of the site we're using to display help
* @param arg
* Array that holds the current path as returned from arg() function
*/
function current_posts_help($path, $arg) {
switch ($path) {
case "admin/help#current_posts":
return '<p>'. t("Displays links to nodes created on this date") .'</p>';
break;
}
}
?>
(Note the closing ?> should not appear in your code.)
The admin/help#modulename case is used by Drupal core to link from the main help page (/admin/help or ?q=admin/help). You will eventually want to add more text to provide a better help message to the user; see Help text standard for the complete recommendation. The t() function that wraps the text marks it for translation. This function not only allows for translation, it can give your code an added layer of security. See Localization API for more information.
Check
Look again at the module list by clicking Modules on the Toolbar in your Drupal installation. Enable the module and click 'Save configuration'. Close and reopen the Modules page, find your module in the list, and you should see a link to 'Help' on the right. Click it to see the help text returned by current_posts_help. You can also follow the Help link in the toolbar (http://example.com/admin/help) and find your help link listed with the others on that page.
Disable your module and save ('Save configuration' button). Important: Be sure you follow that last step and disable your module and save, or new partial code in your module could break your site.
Declaring the block
- Drupal version: Drupal 7.x
- Audience: Developers and coders
- Last modified: December 20, 2011
Drupal hook described: hook_block_info()
Modules are created to do all sorts of things: create blocks (abbreviated content that often appears on the right or left side of multiple pages), create special content types (for full page content - such as the content you are reading right now), track back-end information, and more. You may hear the term 'block modules' used to describe modules that primarily create block content (such as the menu module), or 'node modules' used to describe modules that primarily generate full page content (such as the blog and forum modules). At this stage, this module is a 'block module', because it generates a block.
In Drupal 7, there are at least eight block hooks. For the purposes of this module, we will use two of them. The first is hook_block_info(). As you might suspect, this hook tells Drupal what block(s) your module creates. We will use this hook to define a block that will eventually display the most recent posts. You can use a given hook exactly once in any module, so this hook must declare all blocks the module needs. For this module, a single block is all we need.
To use this hook to define our block, go to your current_posts.module file and create the function current_posts_block_info() as follows:
/**
* Implements hook_block_info().
*/
function current_posts_block_info() {
$blocks['current_posts'] = array(
'info' => t('Current posts'), //The name that will appear in the block list.
'cache' => DRUPAL_CACHE_PER_ROLE, //Default
);
return $blocks;
}
?>
(Remember not to include the closing ?> in your code.)
The doc block simply identifies the hook. For such a straightforward implementation, that is sufficient. Anyone reading the code can easily go to the API and call up the hook for further information.
The return value takes the form of an associative array. Pay special attention to this array structure, as it is Drupal's preferred programming structure. Arrays in PHP are well supported and very fast, and Drupal makes extensive use of them.
The only required value is 'info'. hook_block_info can also specify configuration settings. Here we set the cache to the default. See hook_block_info for a complete list of settings available.
Don't forget the final return statement.
Check
At this point, go to Modules, click the checkbox to enable Current posts, and save your configuration. Next, navigate to Structure > Blocks. Scroll down to the bottom of the list. Among the disabled blocks, you should find the name, 'Current posts'. Return to Modules, disable your module and save. Important: Be sure you disable your module and save, or new partial code in your module could break your site.
See Also hook_block_info
Retrieving data
- Drupal version: Drupal 7.x
- Audience: Developers and coders
- Last modified: November 11, 2011
Main topic described: Database API
Main function described: db_select()
Next we will create a custom function to retrieve the most recent posts. When a node is first created, the time of creation is stored in the database. We'll use this database field to find our data. We could include this code in the hook we will implement in the next tutorial page. Putting this section into a separate function keeps the code cleaner, easier to read and to maintain.
We will call the function current_posts_contents. We continue to follow the naming convention by beginning with the module short name. Then we use a descriptive word that is not a Drupal hook. The function begins with getting the time numbers. Here's the first part:
/**
* Custom content function.
*
* Set beginning and end dates, retrieve posts from database
* saved in that time period.
*
* @return
* A result set of the targeted posts.
*/
function current_posts_contents(){
//Get today's date.
$today = getdate();
//Calculate the date a week ago.
$start_time = mktime(0, 0, 0,$today['mon'],($today['mday'] - 7), $today['year']);
//Get all posts from one week ago to the present.
$end_time = time();
?>
This code gets the current time, then calculates the time (in seconds since epoch start, see mktime for more information on time format) for midnight a week ago. These functions are straight PHP; you can look them up on the PHP website (php.net) for more details.
Next we use Drupal's Database API to retrieve our list of current nodes. This is the second part of the custom function:
//Use Database API to retrieve current posts.
$query = db_select('node', 'n')
->fields('n', array('nid', 'title', 'created'))
->condition('status', 1) //Published.
->condition('created', array($start_time, $end_time), 'BETWEEN')
->orderBy('created', 'DESC') //Most recent first.
->execute();
return $query;
}
?>
Built into Drupal is a very robust query builder, using a special object-oriented API. INSERT, UPDATE, and DELETE queries need this special care in order to behave consistently across all different databases. Although our SELECT query doesn't require this structure, this is a good opportunity to become familiar with it. You will see this structure used throughout Drupal.
- We build the query using the db_select method, which takes a table name ('node') and alias ('n') as arguments.
- The fields method uses the table assigned the alias 'n' to select the fields listed in the array in the second argument.
- The condition method takes three arguments. The first is the field, the second the value, the third the operator. If no operator is specified, as in 'status' above, = is assumed.
- The orderBy method sorts according to the field in the first argument, in the order specified by the second argument.
- The execute method compiles and runs the query and returns a result set/statement object.
Here's the complete function:
/**
* Custom content function.
*
* Set beginning and end dates, retrieve posts from database
* saved in that time period.
*
* @return
* A result set of the targeted posts.
*/
function current_posts_contents(){
//Get today's date.
$today = getdate();
//Calculate the date a week ago.
$start_time = mktime(0, 0, 0,$today['mon'],($today['mday'] - 7), $today['year']);
//Get all posts from one week ago to the present.
$end_time = time();
//Use Database API to retrieve current posts.
$query = db_select('node', 'n')
->fields('n', array('nid', 'title', 'created'))
->condition('status', 1) //Published.
->condition('created', array($start_time, $end_time), 'BETWEEN')
->orderBy('created', 'DESC') //Most recent first.
->execute();
return $query;
}
?>
(Remember not to include the closing ?> in your code.)
Generating block content
- Drupal version: Drupal 7.x
- Audience: Developers and coders
- Last modified: September 29, 2011
Drupal hook described: hook_block_view()
Main functions described: user_access(), l(), theme()
The next step in this tutorial is to take the data we generated in our custom function and turn it into content for the block. We will do this using hook_block_view. This function returns two values, 'subject', which is the title of the block, and 'content', which is self-documenting. Once again, we will use a switch structure. This structure allows for additional blocks to be added in the future if needed. The $delta parameter tells the function which block is being requested.
Access check
Here's the first part of the code:
function current_posts_block_view($delta = '') {
switch($delta){
case 'current_posts':
$block['subject'] = t('Current posts');
if(user_access('access content')){
//Retrieve and process data here.
}
?>
Best practice dictates that information displayed to the user be assessed against that user's permissions. Here we implement the most basic of checks, 'access content'. You can use any permission here that Drupal supplies, or even create your own. For a list of permission names, go to People > List (tab) (or http://example.com/admin/people). In the permission dropdown there, you will find a list of the machine readable names that you can use in your code. This list will include all permissions active on your site, including those created by contrib modules. The names in the Permissions tab (http://example.com/admin/people/permissions) are not the machine readable names.
Another way to find permissions set in core modules is through the API reference. Enter the module name followed by _permission, for example, node_permission. You'll get a list of all the permissions that node defines. Knowing which one to use might be a bit tricky. For example, the access content permission we use here is actually defined in the node module, not the block module.
Coding the data as links
Here's the next bit of code:
//Use our custom function to retrieve data.
$result = current_posts_contents();
//Array to contain items for the block to render.
$items = array();
//Iterate over the resultset and format as links.
foreach ($result as $node){
$items[] = array(
'data' => l($node->title, 'node/' . $node->nid),
);
}
?>
First we use our custom function to save the data into the $result variable. The $items variable gives us a place to store the processed data. We then iterate over the resultset, processing each item and formatting it as a link.
Notice the actual link is created by the l() function. (That's a small case 'L'.) The first parameter sets the link text, in this case the node's title. The second parameter is the actual link path. The path to any node is always "node/#", where # is the ID number of the node. l() uses this path to generate appropriate links, adjusting the URL to the installation's URL configuration.
Theming the data
Drupal's presentation layer is a pluggable system known as the theme layer. Each theme can take control of most of Drupal's output, and has complete control over the CSS. Theming in Drupal is a vast subject with entire books devoted to the subject. Here we will merely touch the surface with a theme function.
Here's the last section of code for current_posts_block_view:
if (empty($items)) { //No content in the last week.
$block['content'] = t('No posts available.');
} else {
//Pass data through theme function.
$block['content'] = theme('item_list', array(
'items' => $items));
}
}
}
return $block;
}
?>
First, we allow for the possibility of no content that fits our criteria. Your module's block should appear whether or not new content from the last week exists on your site.
If the $items variable contains data, it goes to the theme() function. The first argument of this function is the theme hook. Drupal includes many default theme hooks you can use with this function; see Default theme implementations for the complete list. We have chosen to theme our data as an unordered list, the theme_item_list theme hook. The second argument passes the content to be themed.
You may wonder why the code takes this form if the function is theme_item_list. theme() looks for a theme function called theme_hookname, where 'hookname' is the first argument, in this case, item_list. In other words, the second part of the hook name becomes the first argument when the function is called, telling the theme function which of its default versions to use.
The whole function
/**
* Implements hook_block_view().
*
* Prepares the contents of the block.
*/
function current_posts_block_view($delta = '') {
switch($delta){
case 'current_posts':
$block['subject'] = t('Current posts');
if(user_access('access content')){
//Use our custom function to retrieve data.
$result = current_posts_contents();
//Array to contain items for the block to render.
$items = array();
//Iterate over the resultset and format as links.
foreach ($result as $node){
$items[] = array(
'data' => l($node->title, 'node/' . $node->nid),
);
}
if (empty($items)) { //No content in the last week.
$block['content'] = t('No posts available.');
}
else {
//Pass data through theme function.
$block['content'] = theme('item_list', array(
'items' => $items));
}
}
}
return $block;
}
?>
(Remember not to include the opening or closing PHP tags when you add this section.)
Testing and troubleshooting the module
- Drupal version: Drupal 7.x
- Audience: Developers and coders
- Last modified: May 9, 2011
It's time to enable and fully test your module!
Enable the module
Go to Modules, or http://example.com/admin/modules, and scroll down to the bottom of the list in the 'Other' category. You should see the module 'Current posts.' Click the checkbox to enable Current posts, and save your configuration. Now you should see a link to Help beside the module name. Click it to see the help text you entered in current_posts_help.
Enable the block
Next, navigate to Structure > Blocks, or http://example.com/admin/structure/block. Scroll down to the bottom of the list. Among the disabled blocks, you should find the name, 'Current posts'. Set its location for one of the page regions and save. Navigate to another page like your homepage to see your block. Congratulations! You have written a working module.
Troubleshooting
If you get a "white screen" or a PHP error when you enable this module, it probably means you have a syntax error in your .module file. Be sure all your punctuation is correct, semi-colons, commas, etc. all in the right places, and that you have all the hook names and module short names spelled correctly. (In the case of a white screen, you may be able to find out what the PHP error was by looking in your Apache error log. Or you can try changing PHP's error reporting level.)
If you cannot find and fix the syntax error, nothing on your site will display, because Drupal will try to load your module on every page request. The easiest way to get your site working again is to delete the module's folder or move it out of the site, in which case Drupal will figure out that it shouldn't load this module after all, and your site should work again.
Clear caches
Drupal caches a lot of data, and if you are not seeing changes appear, that could be why. In this phase of the module, the caches shouldn't be an issue, but they will be as we proceed. To get all the troubleshooting instructions in one place, we'll give you the instructions here that you'll need later.
To clear the caches, go to Configuration > Performance or http://example.com/admin/config/development/performance, and click the Clear all caches button.
Preparing for a module configuration form
- Drupal version: Drupal 7.x
- Audience: Developers and coders
- Page status: Needs technical review
- Last modified: April 4, 2011
Drupal hook described: hook_menu()
Main function described: drupal_get_form()
Now that we have a working module, we'd like to make it more flexible. With a busy site, we might not want to display all the links to content created last week. So we'll create a configuration form where the administrator can adjust how many links to display.
Registering the URL
We will define our form using hook_menu(). The name of this hook is a bit misleading, as it does far more than simply assign menu items. Using this hook, modules register paths to define how URL requests are handled. Paths may be registered for URL handling only, or as a link to be placed in a menu (usually the Navigation menu). In this case, we will set a path that will make the form available from the Configuration page (http://example.com/admin/config).
hook_menu() implementations return an associative array whose keys define paths and whose values are an associative array of properties for each path. The definition for each path may include a page callback function, which is invoked when the registered path is requested. After we have set up our form in hook_menu, we will create the actual form by writing the page callback function we define here.
Access check
hook_menu() also provides an important part of Drupal's security, as it performs user access checks. We would like only administrators to be able to access this form, and we'll check that permission here in hook_menu(). To minimize the number of permissions an administrator has to deal with, we'll use the core administration permission instead of creating a new custom permission.
In Drupal's menu system, 'title' and 'description' attributes are automatically translated. Throughout Drupal, you are encouraged to use the t() function on all string literals. This is one place where you must remember not to do that.
Here's the code:
/**
* Implements hook_menu().
*/
function current_posts_menu() {
$items = array();
$items['admin/config/content/current_posts'] = array(
'title' => 'Current posts',
'description' => 'Configuration for Current posts module',
'page callback' => 'drupal_get_form',
'page arguments' => array('current_posts_form'),
'access arguments' => array('access administration pages'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
?>
(Remember not to include the opening or closing PHP tags when you add this section.)
Setting properties
The path set as the array key for $items becomes the path to our form. It must take the form of an internal Drupal path with no leading or trailing slashes. We begin the path with admin/config to tell Drupal to include a link to this form on the site administration page (Configuration or http://example.com/admin/config). content tells Drupal which section of this page the link belongs to, in this case, Content authoring. You can choose any one of the default sections for your form by including its path name here.
Next comes the value, the associative array that lists properties of the item. title and description, as noted previously, are without the t() function. We include the administrator permission under access arguments, and the value of type is the default. This listing will not appear in any menu, only on the Configuration page.
Declaring the form
page callback tells Drupal what to call when the link is requested, in this case, drupal_get_form, the "key" function in the Form API. (Note that the trailing parentheses are not included in the call to drupal_get_form.) page arguments values are passed to that function. By assigning current_posts_form, we define that as both the form ID and the name of the function that will create our settings form. As the name of a function, it must follow PHP variable naming conventions, with no spaces or hyphens. To prevent name collision, always start the function name with the name of your module, followed by an underscore.
We'll begin to explore the Form API as we build that function in the next part of the tutorial.
See also
Creating the configuration form
- Drupal version: Drupal 7.x
- Audience: Developers and coders
- Page status: Needs technical review
- Last modified: June 29, 2011
Main topic described: Form API
Main functions described: variable_get(), system_settings_form()
Next, we will build the current_posts_form() function. We build the form by adding elements to the $form array. In a pattern similar to the menu $items variable, the name of each element is its key in the array, with that key's value being a specially formatted associative array. In this value array, we list the attributes of the element, this time preceding each key with a hash mark (#).
Add the following to your current_posts.module file:
/**
* Form function, called by drupal_get_form()
* in current_posts_menu().
*/
function current_posts_form($form, &$form_state) {
$form['current_posts_max'] = array(
'#type' => 'textfield',
'#title' => t('Maximum number of posts'),
'#default_value' => variable_get('current_posts_max', 3),
'#size' => 2,
'#maxlength' => 2,
'#description' => t('The maximum number of links to display in the block.'),
'#required' => TRUE,
);
return system_settings_form($form);
}
?>
(Remember not to include the opening or closing PHP tags when you add this section.)
The element attributes
Here we create a text field, with a title of 'Maximum number of posts', and a description, which will appear below the field. Note that both of these strings are passed through the t() function for translation. Size is 2, maximum length is 2. The Form API will automatically validate the maxlength attribute when the form is submitted and throw an error if the length exceeds 2. We have also designated the field as required. The form API will mark it with an asterisk and will throw an error if the form is submitted with no value in the field. See the forms_api_reference for the complete list of available elements and properties.
Persistent variables
Certain data, like system settings and user-configurable information, needs to be saved and retrievable for a website to function properly. Drupal accomplishes this through the use of persistent variables. These variables are stored in a database table with keys provided by the implementing module.
The function variable_get() retrieves a persistent variable, and variable_set(), as you might expect, sets one. We use variable_get() above to retrieve the value of our field if it has been set. If not, we specify a default value of 3. variable_get() uses the name of the element, current_posts_max, to find the relevant data.
System settings
Drupal makes it easy for us to save the form's data with the function system_settings_form(). By using the function in our code, we tell Drupal to provide a submit button and to save data into persistent variables using variable_set(). It will also provide a green confirmation message when data is successfully saved, and a red error message if something went wrong. If you prefer, you can create a submit function yourself, (see Form API Quickstart Guide) but for now, we will use this handy shortcut.
Editing the query
We must add two lines of code to our query function, current_posts_contents, one using variable_get() to retrieve the data from our settings form, and the other adding the range function to include this limit in the query. Here's the revised function, with the new lines noted in comments:
function current_posts_contents() {
//Get today's date.
$today = getdate();
//Calculate midnight a week ago.
$start_time = mktime(0, 0, 0,$today['mon'],($today['mday'] - 7), $today['year']);
//Get all posts from one week ago to the present.
$end_time = time();
//NEW LINE
$max_num = variable_get('current_posts_max', 3);
//Use Database API to retrieve current posts.
$query = db_select('node', 'n')
->fields('n', array('nid', 'title', 'created'))
->condition('status', 1) //Published.
->condition('created', array($start_time, $end_time), 'BETWEEN')
->orderBy('created', 'DESC') //Most recent first.
->range(0, $max_num) //NEW LINE
->execute();
return $query;
}
?>
Using variable_get(), we save the configuration setting into the $max_num variable or assign a default of 3. Then we add the range method to our select query. That method's first argument is set to zero to specify starting at the beginning of the set. The second argument, $max_num, determines how many records to return.
Check
Go ahead and again enable your module. Then 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 Configuration > Performance or http://example.com/admin/config/development/performance, and click the Clear all caches button.
Now you can test the settings form. Navigate to it: Configuration > Content authoring > Current posts or http://example.com/admin/config/content/current_posts. Adjust the number of links and save the configuration. The maximum number of links in the block should adjust accordingly. See how system_settings_form() has added a submit button and gives you a confirmation message when you have successfully saved.
Please note: be sure to disable your module before continuing.
See also
Validating the data
- Drupal version: Drupal 7.x
- Audience: Developers and coders
- Page status: Needs technical review
- Last modified: June 15, 2011
Main topic described: Form API
Main functions described: _validate(), form_set_error()
The Form API supplies excellent default validation, but it also allows us to create our own validation function. We want to be sure that the value the user enters is a number greater than 0. The validation function works much like a hook, with the form ID taking the place of the module name. Our validate function will be named current_posts_form_validate($form, &$form_state). Don't confuse this with hook_validate(), which is part of the main hook system.
Notice the $form_state array variable, an argument here and also for our form function. $form_state is passed by reference along through each stage of form processing to capture information about the form's workflow and its current state. Incoming $_POST data is first sanitized and checked against the structure of the form before being handed off to validate and submit handlers. The array's values key is the default key for storing this data. See drupal_build_form() for a list of $form_state keys.
Add this function to your current_posts.module file:
/**
* Implements validation from the Form API.
*
* @param $form
* A structured array containing the elements and properties of the form.
* @param $form_state
* An array that stores information about the form's current state
* during processing.
*/
function current_posts_form_validate($form, &$form_state){
$max_num = $form_state['values']['current_posts_max'];
if (!is_numeric($max_num)){
form_set_error('current_posts_max', t('You must enter an integer for the maximum number of posts to display.'));
}
else if ($max_num <= 0){
form_set_error('current_posts_max', t('Maximum number of posts to display must be positive.'));
}
}
?>
(Remember not to include the closing ?> in your code.)
Testing the data
First we retrieve the configuration setting from $form_state and save it into a variable. We then check to be sure it's a number. If not, form_set_error() goes into action, setting the element in the first argument with an error CSS class (red by default). It also displays a red box with the error message given in the second argument.
If the data passes the first check, we make sure it's a positive number. If not, we again call form_set_error() Notice that both our string literals for error messages are wrapped in t().
Check
Enable your module again and visit the configuration page. Experiment with entering values to see how the validation works on errors. Be sure to disable your module before you add more code.
I love your blog a lot
Thank you