Friday, 6 February 2015

Creating Your First Module in Drupal 7 Module Development

Our goal: a module with a block

In this article we are going to build a simple module. The module will use the Block Subsystem to add a new custom block. The block that we add will simply display a list of all of the currently enabled modules on our Drupal installation.
We are going to divide this task of building a new module into the three parts:
  • Create a new module folder and module files
  • Work with the Block Subsystem
  • Write automated tests using the SimpleTest framework included in Drupal
We are going to proceed in that order for the sake of simplicity. One might object that, following agile development processes, we ought to begin by writing our tests. This approach is called Test-driven Development (TDD), and is a justly popular methodology.
Agile software development is a particular methodology designed to help teams of developers effectively and efficiently build software. While Drupal itself has not been developed using an agile process, it does facilitate many of the agile practices. To learn more about agile, visit http://agilemanifesto.org/
However, our goal here is not to exemplify a particular methodology, but to discover how to write modules. It is easier to learn module development by first writing the module, and then learn how to write unit tests. It is easier for two reasons:
  • SimpleTest (in spite of its name) is the least simple part of this article. It will have double the code-weight of our actual module.
  • We will need to become acquainted with the APIs we are going to use in development before we attempt to write tests that assume knowledge of those APIs.
In regular module development, though, you may certainly choose to follow the TDD approach of writing tests first, and then writing the module.
Let's now move on to the first step of creating a new module.

Creating a new module

Creating Drupal modules is easy. How easy? Easy enough that over 5,000 modules have been developed, and many Drupal developers are even PHP novices! In fact, the code in this article is an illustration of how easy module coding can be. We are going to create our first module with only one directory and two small files.

Module names

It goes without saying that building a new module requires naming the module. However, there is one minor ambiguity that ought to be cleared up at the outset, a Drupal module has two names:
  • A human-readable name: This name is designed to be read by humans, and should be one or a couple of words long. The words should be capitalized and separated by spaces. For example, one of the most popular Drupal modules has the human-readable name Views. A less-popular (but perhaps more creatively named) Drupal 6 module has the human-readable name Eldorado Superfly.
  • A machine-readable name: This name is used internally by Drupal. It can be composed of lower-case and upper-case letters, digits, and the underscore character (using upper-case letters in machine names is frowned upon, though). No other characters are allowed. The machine names of the above two modules are views and eldorado_superfly, respectively.
By convention, the two names ought to be as similar as possible. Spaces should be replaced by underscores. Upper-case letters should generally be changed to lower-case.
Because of the convention of similar naming, the two names can usually be used interchangeably, and most of the time it is not necessary to specifically declare which of the two names we are referring to. In cases where the difference needs to be made (as in the next section), the authors will be careful to make it.

Where does our module go?

One of the less intuitive aspects of Drupal development is the filesystem layout. Where do we put a new module? The obvious answer would be to put it in the /modules directory alongside all of the core modules.
As obvious as this may seem, the /modules folder is not the right place for your modules. In fact, you should never change anything in that directory. It is reserved for core Drupal modules only, and will be overwritten during upgrades.
The second, far less obvious place to put modules is in /sites/all/modules. This is the location where all unmodified add-on modules ought to go, and tools like Drush ( a Drupal command line tool) will download modules to this directory.
In some sense, it is okay to put modules here. They will not be automatically overwritten during core upgrades.
However, as of this writing, /sites/all/modules is not the recommended place to put custom modules unless you are running a multi-site configuration and the custom module needs to be accessible on all sites.
The current recommendation is to put custom modules in the /sites/default/modules directory, which does not exist by default. This has a few advantages. One is that standard add-on modules are stored elsewhere, and this separation makes it easier for us to find our own code without sorting through clutter. There are other benefits (such as the loading order of module directories), but none will have a direct impact on us.
We will always be putting our custom modules in /sites/default/modules. This follows Drupal best practices, and also makes it easy to find our modules as opposed to all of the other add-on modules.
The one disadvantage of storing all custom modules in /sites/default/modules appears only under a specific set of circumstances. If you have Drupal configured to serve multiple sites off of one single instance, then the /sites/default folder is only used for the default site. What this means, in practice, is that modules stored there will not be loaded at all for other sites.
In such cases, it is generally advised to move your custom modules into /sites/all/modules/custom.
Other module directories
Drupal does look in a few other places for modules. However, those places are reserved for special purposes.

Creating the module directory

Now that we know that our modules should go in /sites/default/modules, we can create a new module there.
Modules can be organized in a variety of ways, but the best practice is to create a module directory in /sites/default/modules, and then place at least two files inside the directory: a .info (pronounced "dot-info") file and a .module ("dot-module") file.
The directory should be named with the machine-readable name of the module. Similarly, both the .info and .module files should use the machine-readable name.
We are going to name our first module with the machine-readable name first, since it is our first module. Thus, we will create a new directory, /sites/default/modules/first, and then create a first.info file and a first.module file:
Creating Your First Module in Drupal 7 Module Development
Those are the only files we will need for our module.
For permissions, make sure that your webserver can read both the .info and .module files. It should not be able to write to either file, though.
In some sense, the only file absolutely necessary for a module is the .info file located at a proper place in the system. However, since the .info file simply provides information about the module, no interesting module can be built with just this file.
Next, we will write the contents of the .info file.

Writing the .info file

The purpose of the .info file is to provide Drupal with information about a module—information such as the human-readable name, what other modules this module requires, and what code files this module provides.
A .info file is a plain text file in a format similar to the standard INI configuration file. A directive in the .info file is composed of a name, and equal sign, and a value:
name = value
By Drupal's coding conventions, there should always be one space on each side of the equals sign.
Some directives use an array-like syntax to declare that one name has multiple values. The array-like format looks like this:
name[] = value1
name[] = value2
Note that there is no blank space between the opening square bracket and the closing square bracket.
If a value spans more than one line, it should be enclosed in quotation marks.
Any line that begins with a ; (semi-colon) is treated as a comment, and is ignored by the Drupal INI parser.
Drupal does not support INI-style section headers such as those found in the php.ini file.
To begin, let's take a look at a complete first.info file for our first module:
;$Id$

name = First
description = A first module.
package = Drupal 7 Development
core = 7.x
files[] = first.module

;dependencies[] = autoload
;php = 5.2
This ten-line file is about as complex as a module's .info file ever gets.
The first line is a standard. Every .info file should begin with ;$Id$. What is this? It is the placeholder for the version control system to store information about the file. When the file is checked into Drupal's CVS repository, the line will be automatically expanded to something like this:
;$Id: first.info,v 1.1 2009/03/18 20:27:12 mbutcher Exp $
This information indicates when the file was last checked into CVS, and who checked it in.
CVS is going away, and so is $Id$. While Drupal has been developed in CVS from the early days through Drupal 7, it is now being migrated to a Git repository. Git does not use $Id$, so it is likely that between the release of Drupal 7 and the release of Drupal 8, $Id$ tags will be removed.
You will see all PHP and .info files beginning with the $Id$ marker. Once Drupal uses Git, those tags may go away.
The next couple of lines of interest in first.info are these:
name = First
description = A first module.
package = Drupal 7 Development
The first two are required in every .info file. The name directive is used to declare what the module's human-readable name is. The description provides a one or two-sentence description of what this module provides or is used for. Among other places, this information is displayed on the module configuration section of the administration interface in Modules.
In the screenshot, the values of the name and description fields are displayed in their respective columns.
The third item, package, identifies which family (package) of modules this module is related to. Core modules, for example, all have the package Core. In the screenshot above, you can see the grouping package Core in the upper-left corner. Our module will be grouped under the package Drupal 7 Development to represent its relationship. As you may notice, package names are written as human-readable values.
When choosing a human-readable module name, remember to adhere to the specifications mentioned earlier in this section.
The next directive is the core directive: core = 7.x. This simply declares which main-line version of Drupal is required by the module. All Drupal 7 modules will have the line core = 7.x.
Along with the core version, a .info file can also specify what version of PHP it requires. By default, Drupal 7 requires Drupal 5.1 or newer. However, if one were to use, say, closures (a feature introduced in PHP 5.3), then the following line would need to be added:
php = 5.3
Next, every .info file must declare which files in the module contain PHP functions, classes, or interfaces. This is done using the files[] directive. Our small initial module will only have one file, first.module. So we need only one files[] directive.
files[] = first.module
More complex files will often have several files[] directives, each declaring a separate PHP source code file.
JavaScript, CSS, image files, and PHP files (like templates) that do not contain functions that the module needs to know about needn't be included in files[] directives. The point of the directive is simply to indicate to Drupal that these files should be examined by Drupal.
One directive that we will not use for this module, but which plays a very important role is the dependencies[] directive. This is used to list the other modules that must be installed and active for this module to function correctly. Drupal will not allow a module to be enabled unless its dependencies have been satisfied.
Drupal does not contain a directive to indicate that another module is recommended or is optional. It is the task of the developer to appropriately document this fact and make it known. There is currently no recommended best practice to provide such information.
Now we have created our first.info file. As soon as Drupal reads this file, the module will appear on our Modules page.
In the screenshot, notice that the module appears in the DRUPAL 7 DEVELOPMENT package, and has the NAME and DESCRIPTION as assigned in the .info file.
With our .info file completed, we can now move on and code our .module file.
Modules checked into Drupal's version control system will automatically have a version directive added to the .info file. This should typically not be altered.

Creating a module file

The .module file is a PHP file that conventionally contains all of the major hook implementations for a module. We will gain some practical knowledge of them.
A hook implementation is a function that follows a certain naming pattern in order to indicate to Drupal that it should be used as a callback for a particular event in the Drupal system. For Object-oriented programmers, it may be helpful to think of a hook as similar to the Observer design pattern.
When Drupal encounters an event for which there is a hook (and there are hundreds of such events), Drupal will look through all of the modules for matching hook implementations. It will then execute each hook implementation, one after another. Once all hook implementations have been executed, Drupal will continue its processing.
In the past, all Drupal hook implementations had to reside in the .module file. Drupal 7's requirements are more lenient, but in most moderately sized modules, it is still preferable to store most hook implementations in the .module file.
There are cases where hook implementations belong in other files. In such cases, the reasons for organizing the module in such a way will be explained.
To begin, we will create a simple .module file that contains a single hook implementation – one that provides help information.
<?php
// $Id$

/**
 * @file
 * A module exemplifying Drupal coding practices and APIs.
 *
 * This module provides a block that lists all of the
 * installed modules. It illustrates coding standards,
 * practices, and API use for Drupal 7.
 */

/**
 * Implements hook_help().
 */
function first_help($path, $arg) {
  if ($path == 'admin/help#first') {
    return t('A demonstration module.');
  }
}
Before we get to the code itself, we will talk about a few stylistic items.
To begin, notice that this file, like the .info file, contains an $Id$ marker that CVS will replace when the file is checked in. All PHP files should have this marker following a double-slash-style comment: // $Id$.
Next, the preceding code illustrates a few of the important coding standards for Drupal.

Source code standards

Drupal has a thorough and strictly enforced set of coding standards. All core code adheres to these standards. Most add-on modules do, too. (Those that don't generally receive bug reports for not conforming.) Before you begin coding, it is a good idea to familiarize yourself with the standards as documented here: http://drupal.org/coding-standards. The Coder module can evaluate your code and alert you to any infringement upon the coding standards.
We will adhere to the Drupal coding standards. In many cases, we will explain the standards as we go along. Still, the definitive source for standards is the URL listed above, not our code here.
We will not re-iterate the coding standards. The details can be found online. However, several prominent standards deserve immediate mention. I will just mention them here, and we will see examples in action as we work through the code.
  • Indenting: All PHP and JavaScript files use two spaces to indent. Tabs are never used for code formatting.
  • The <?php ?> processor instruction: Files that are completely PHP should begin with <?php, but should omit the closing ?>. This is done for several reasons, most notably to prevent the inclusion of whitespace from breaking HTTP headers.
  • Comments: Drupal uses Doxygen-style (/** */) doc-blocks to comment functions, classes, interfaces, constants, files, and globals. All other comments should use the double-slash (//) comment. The pound sign (#) should not be used for commenting.
  • Spaces around operators: Most operators should have a whitespace character on each side.
  • Spacing in control structures: Control structures should have spaces after the name and before the curly brace. The bodies of all control structures should be surrounded by curly braces, and even that of if statements with one-line bodies.
  • Functions: Functions should be named in lowercase letters using underscores to separate words. Later we will see how class method names differ from this.
  • Variables: Variable names should be in all lowercase letters using underscores to separate words. Member variables in objects are named differently. As we work through examples, we will see these and other standards in action.
As we work through examples, we will see these and other standards in action.
        Read more about this book      
(For more resources on this subject, see here.)

Doxygen-style doc blocks

Drupal uses Doxygen to extract API documentation from source code. Experienced PHP coders may recognize this concept, as it is similar to PhpDocumentor comments (or Java's JavaDoc). However, Drupal does have its idiosyncrasies, and does not follow the same conventions as these systems.
We will only look at the documentation blocks as they apply to our preceding specific example.
Let's take a closer look at the first dozen lines of our module:
<?php
// $Id$

/**
 * @file
 * A module exemplifying Drupal coding practices and APIs.
 *
 * This module provides a block that lists all of the
 * installed modules. It illustrates coding standards,
 * practices, and API use for Drupal 7.
*/
After the PHP processor instruction and the $Id$ line, the part of the code is a large comment. The comment begins with a slash and two asterisks (/**) and ends with a single asterisk and a slash (*/). Every line between begins with an asterisk. This style of comment is called a doc block or documentation block.
A doc block is a comment that contains API information. It can be extracted automatically by external tools, which can then format the information for use by developers.
Doc blocks in action: api.drupal.org
Drupal's doc blocks are used to generate the definitive source of Drupal API documentation at http://api.drupal.org. This site is a fantastic searchable interface to each and every one of Drupal's functions, classes, interfaces, and constants. It also contains some useful how-to documentation.
All of Drupal is documented using doc blocks, and you should always use them to document your code.
The initial doc block in the code fragment above begins with the @file decorator. This indicates that the doc block describes the file as a whole, not a part of it. Every file should begin with a file-level doc block.
From there, the format of this doc block is simple: It begins with a single-sentence description of the file (which should always be on one line), followed by a blank line, followed by one or more paragraph descriptions of what this file does.
The Drupal coding standards stipulate that doc blocks should always be written using full, grammatically correct, punctuated sentences.
If we look a little further down in our module file, we can see our first function declaration:
/**
 * Implements hook_help().
 */
function first_help($path, $arg) {
  if ($path == 'admin/help#first') {
    return t('A demonstration module.');
  }
}
Before moving onto the function, let's take a look at the doc block here. It is a single sentence: Implements hook_help(). This single-sentence description follows a Drupal doc block coding standard, too. When a function is a hook implementation, it should state so in exactly the format used above: Implements NAME OF HOOK. Why the formula? So that developers can very quickly identify the general purpose of the function, and also so that automated tools can find hook implementations.
Note that we don't add any more of a description, nor do we document the parameters. This is okay when two things are true:
  • The function implements a hook
  • The function is simple
In such cases, the single-line description will do, since coders can simply refer to the API documentation for the hook to learn more.
Later we will see how non-hook functions and more complex hook implementations have an extended form of doc block comment. For now, though, we have addressed the basics of doc blocks. We will move on and look at the help function.

The help hook

Drupal defines a hook called hook_help(). The help hook is invoked (called) when a user browses the help system. Each module can have one implementation of hook_help(). Our module provides brief help text by implementing the help hook.
function first_help($path, $arg) {
  if ($path == 'admin/help#first') {
    return t('A demonstration module.');
  }
}
How does this function become a hook implementation? Strictly by virtue of its name: first_help(). The name follows the hook pattern. If the hook is named hook_help(), then to implement it, we replace the word hook with the name of the module. Thus, to implement hook_help(), we simply declare a function in our first module named first_help().
Each hook has its own parameters, and all core Drupal hooks are documented at http://api.drupal.org.
A hook_help() implementation takes two arguments:
  • $path: The help system URI path
  • $arg: The arguments used when accessing this URL
In our case, we are only concerned with the first of these two. Basically, the help system works by matching URI paths to help text. Our module needs to declare what help text should be returned for specific URIs.
Specifically, the module-wide help text should be made available at the URI admin/help#MODULE_NAME, where MODULE_NAME is the machine-readable name of the module.
Our function works by checking the $path. If the $path is set to admin/help#first, the default help screen for a module, then it will return some simple help text.
If we were to enable our new module and then look at Drupal's help text page with our new module enabled, we would see this:
Notice that Help now shows up under OPERATIONS. If we were to click on the Help link, we would see our help text:
The key to make this system work is in the use of the $path checking, which displays the help information only when the context-sensitive help for this module is enabled via hook_help().
if ($path == 'admin/help#first') {
  return t('A demonstration module.');
}
First, the previous code conforms to Drupal's coding standards, which we briefly covered earlier. Whitespace separates the if and the opening parenthesis (, and there is also a space between the closing parenthesis ) and the opening curly brace ({). There are also spaces on both sides of the equality operator ==. Code is indented with two spaces per level, and we never use tabs. In general, Drupal coders tend to use single quotes (') to surround strings because of the (admittedly slight) speed improvement gained by skipping interpolation.
Also important from the perspective of coding standards is the fact that we enclose the body of the if statement in curly braces even though the body is only one line long. And we split it over three lines, though we might have been able to fit it on one. Drupal standards require that we always do this.
Finally, in the example above we see one new Drupal function: t().

The t() function and translations

Every natural language string that may be displayed to a user should be wrapped in the t() function. Why? Because the t() function is responsible for translating strings from one language into other.
Drupal supports dozens of languages. This is one of the strongest features of Drupal's internationalization and localization effort. The method by which Drupal supports translation is largely through the t() function.
There are three features of this function that every developer should understand:
  • What happens when t() is called
  • How Drupal builds the translation table
  • Additional features you get by using the t() function
First, let's look at what the t() function does when it is called. If no language support is enabled and no second argument is passed to t(), it simply returns the string unaltered. If more languages are enabled and the user's language is something other than English, Drupal will attempt to replace the English language string with a string in the appropriate language.
The second thing to look at is how Drupal builds the translation information. There are two aspects to this: The human aspect and the technical one. The translations themselves are done by dozens and dozens of volunteers who translate not only Drupal's core, but also many of the add-on modules. Their translations are then made into downloadable language bundles (.po files) that you can install on your site.
On the more technical side, this dedicated group of translators does not simply search the source code looking for calls to the t() function. Instead, an automated tool culls the code and identifies all of the translatable strings. This automated tool, though, can only extract string literals. In other words, it looks for calls like this:
t('This is my string');
It cannot do anything with lines like this, though:
$variable = 'This is a string';
t($variable);
Why won't the translation system work in the case above? Because when the automated translation system runs through the code, it does not execute the code. It simply reads it. For that reason, it would become cumbersome (and many times impossible) to determine what the correct value of a variable is.
The locale module can, under certain circumstances, identify other strings that were not correctly passed into the t() function and make them available to translators. This, however, should not be relied upon.
So the t() function should always be given a literal string for its first argument.
The third thing to note about the t() function is that it does more than translate strings. It offers a method of variable interpolation that is more secure than the usual method.
In many PHP applications, you will see code like this:
print "Welcome, $username.";
The code above will replace $username with the value of the $username variable. This code leaves open the possibility that the value of $username contains data that will break the HTML in the output – or worse, that it will open an avenue for a malicious user to inject JavaScript or other code into the output.
The t() function provides an alternate, and more secure, method for replacing placeholders in text with a value. The function takes an optional second argument, which is an associative array of items that can be substituted. Here's an example that replaces the the previous code:
$values = array('@user' => $username);
print t('Welcome, @user', $values);
In the previous case, we declare a placeholder named @user, the value of which is the value of the $username variable. When the t() function is executed, the mappings in $values are used to substitute placeholders with the correct data.
But there is an additional benefit: these substitutions are done in a secure way.
If the placeholder begins with @, then before it inserts the value, Drupal sanitizes the value using its internal check_plain() function.
If you are sure that the string doesn't contain any dangerous information, you can use a different symbol to begin your placeholder: the exclamation mark (!). When that is used, Drupal will simply insert the value as is. This can be very useful when you need to insert data that should not be translated:
$values = array('!url' => 'http://example.com');
print t('The website can be found at !url', $values);
In this case, the URL will be entered with no escaping. We can do this safely only because we already know the value of URL. It does not come from a distrusted user.
Finally, there is a third placeholder decorator: the percent sign (%) tells Drupal to escape the code and to mark it as emphasized.
$values = array('%color' => 'blue');
print t('My favorite color is %color.', $values);
Not only will this remove any dangerous characters from the value, but it will also insert markup to treat that text as emphasized text. By default, the preceding code would result in the printing of the string My favorite color is &ltem&gtblue</em>. The emphasis tags were added by a theme function (theme_placeholder()) called by the t() function.
There are more things that can be done with t(), format_plural(), translation contexts, and other translation system features. To learn more, you may want to start with the API documentation for t() at http://api.drupal.org/api/function/t/7.
We have taken a sizable detour to talk about the translation system, but with good reason. It is a tremendously powerful feature of Drupal, and should be used in all of your code. Not only does it make modules translatable, but it adds a layer of security. It can even be put to some interesting (if unorthodox) uses, as is exemplified by the String Overrides module at http://drupal.org/project/stringoverrides.
At this point, we have created a working module, though the only thing that it does is display help text. It's time to make this module a little more interesting. In the next section we will use the Block API to write code that generates a block listing all of the currently enabled modules.
        Read more about this book      
(For more resources on this subject, see here.)

Working with the Block API

In this section, we are going to learn how to create blocks in code. The Block API provides the tools for hooking custom code into the block subsystem.
The Block API has changed substantially since Drupal 6. In Drupal 6, there was only one function used for all block operations. Now there is a family of related functions.
We are going to create a block that displays a bulleted list of all of the modules currently enabled on our site.
There are half a dozen hooks in the Block API, providing opportunities to do everything from declaring new blocks to altering the content and behavior of existing blocks. For our simple module, we are going to use two different hooks:
  • hook_block_info(): This is used to tell Drupal about the new block or blocks that we will declare
  • hook_block_view(): This tells Drupal what to do when a block is requested for viewing
One thing to keep in mind, in the context of the Block API as well as other APIs is that each module can only implement a given hook once. There can be only one first_block_info() function.
Since modules should be able to create multiple blocks, that means that the Block API must make it possible for one block implementation to manage multiple blocks. Thus, first_block_info() can declare any number of blocks, and first_block_view() can return any number of blocks.
The entire Block API is documented in the official Drupal 7 API documentation, and even includes an example module: http://api.drupal.org/api/drupal/developer--examples--block_example.module/7.
To keep our example simple, we will be creating only one block. However, it is good to keep in mind that the API was designed in a way that would allow us to create as many blocks as we want.
Let's start with an implementation of hook_block_info().

The block info hook

All of the functions in our module will go inside of the first.module file—the default location for hook implementations in Drupal. Before, we created first_help(), an implementation of hook_help(). Now, we are going to implement the hook_block_info() hook.
The purpose of this hook is to tell Drupal about all of the blocks that the module provides. Note that, as with any hook, you only need to implement it in cases where your module needs to provide this functionality. In other words, if the hook is not implemented, Drupal will simply assume that this module has no associated blocks.
Here's our 'block info' hook implementation declaring a single block:
/**
 * Implements hook_block_info().
 */
function first_block_info() {
  $blocks = array();

  $blocks['list_modules'] = array(
    'info' => t('A listing of all of the enabled modules.'),
    'cache' => DRUPAL_NO_CACHE,
  );

  return $blocks;
}
Once again, this function is preceded by a doc block. And since we are writing a trivial implementation of hook_block_info(), we needn't add anything other than the standard documentation.
An implementation of hook_block_info() takes no arguments and is expected to return an associative array.
Associative arrays: Drupal's data structure of choice
Arrays in PHP are very fast. They are well supported, and because they serve double duty as both indexed arrays and dictionary-style associative arrays, they are flexible. For those reasons Drupal makes heavy use of arrays—often in places where one would expect objects, linked lists, maps, or trees.
The returned array should contain one entry for every block that this module declares, and the entry should be of the form $name => array($property => $value).
Thus, the important part of our function above is this piece:
$blocks['list_modules'] = array(
  'info' => t('A listing of all of the enabled modules.'),
  'cache' => DRUPAL_NO_CACHE,
);
This defines a block named list_modules that has two properties:
  • info: This provides a one-sentence description of what this block does. The text is used on the block administration screens.
  • cache: This tells Drupal how to cache the data from this block. Here in the code I have set this to DRUPAL_NO_CACHE, which will simply forgo caching altogether. There are several other settings providing global caching, per-user caching, and so on.
There are a handful of other possible properties that Drupal recognizes. You can read about these in the Drupal API documentation at http://api.drupal.org/api/function/hook_block_info/7.
We have now created a function that tells Drupal about a block named list_modules. With this information, Drupal will assume that when it requests that block for viewing, some function will provide the block's contents. The next function we implement will handle displaying the block.

The block view hook

In the section above we implemented the hook that tells Drupal about our module's new block. Now we need to implement a second hook—a hook responsible for building the contents of the block. This hook will be called whenever Drupal tries to display the block.
An implementation of hook_block_view() is expected to take one argument—the name of the block to retrieve—and return an array of data for the given name.
Our implementation will provide content for the block named list_modules.
Here is the code:
/**
 * Implements hook_block_view().
 */
function first_block_view($block_name = '') {
  if ($block_name == 'list_modules') {
    $list = module_list();

    $theme_args = array('items' => $list, 'type' => 'ol');
    $content = theme('item_list', $theme_args);

    $block = array(
      'subject' => t('Enabled Modules'),
      'content' => $content,
    );

    return $block;
  }
}
By now, the doc block should be familiar. The Drupal coding style should also look familiar. Again, we have implemented hook_block_view() simply by following the naming convention.
The argument that our first_block_view() function takes, is the name of the block. As you look through Drupal documentation you may see this argument called $which_block or $delta—terms intended to identify the fact that the value passed in is the identifier for which block should be returned.
The term $delta is used for historical reasons. It is not a particularly apt description for the role of the variable, and more recently it has been replaced by more descriptive terms.
The only block name that our function should handle is the one we declared in first_block_info(). If the $block_name is list_modules, we need to return content.
Let's take a close look at what happens when a request comes in for the list_modules block. This is the content of the if statement above:
$list = module_list();

$theme_args = array('items' => $list, 'type' => 'ol');
$content = theme('item_list', $theme_args);

$block = array(
  'subject' => t('Enabled Modules'),
  'content' => $content,
);

return $block;
On the first line, we call the Drupal function module_list(). This function simply returns an array of module names. (In fact, it is actually an associative array of module names to module names. This duplicate mapping is done to speed up lookups.)
Now we have a raw array of data. The next thing we need to do is format that for display. In Drupal formatting is almost always done by the theming layer. Here, we want to pass off the data to the theme layer and have it turn our module list into an HTML ordered list.
The main function for working with the theming system is theme(). In Drupal 7, theme() takes one or two arguments:
  • The name of the theme operation
  • An associative array of variables to pass onto the theme operation
Previous versions of Drupal took any number of arguments, depending on the theme operation being performed. That is no longer the case in Drupal 7.
To format an array of strings into an HTML list, we use the item_list theme, and we pass in an associative array containing two variables:
  • the items we want listed
  • the type of listing we want
From theme() we get a string of HTML.
Now all we need to do is assemble the data that our block view must return. An implementation of hook_block_view() is expected to return an array with two items in it:
  • subject: The name or title of the block.
  • content: The content of the block, as formatted text or HTML.
So in the first place we set a hard-coded, translatable string. In the second, we set content to the value built by theme().
One thing you may notice about the $block array in the code above is its formatting:
$block = array(
  'subject' => t('Enabled Modules'),
  'content' => $content,
);
This is how larger arrays should be formatted according to the Drupal coding standards. And that trailing comma is not a error. Drupal standards require that multi-line arrays terminate each line—including the last item—with a comma. This is perfectly legal in PHP syntax, and it eliminates simple coding syntax problems that occur when items are added to or removed from the array code.
Not in JavaScript!
Drupal programmers make the mistake of using a similar syntax in Drupal JavaScript. Object literal definitions (the JavaScript equivalent of associative arrays) do not allow the last item to terminate with a comma. Doing so causes bugs in IE and other browsers.
Now we have walked through our first module's code. For all practical purposes, we have written an entire module (though we still have some automated testing code to write). Let's see what this looks like in the browser.

The first module in action

Our module is written and ready to run. To test this out, we need to first enable the module, and then go to the block administration page.
The module can be enabled through the Modules menu. Once it is enabled, go to Structure | Blocks. You should be able to find a block described as A listing of all of the enabled modules. (This text came from our first_block_info() declaration.)
Once you have placed this module in one of the block regions, you should be able to see something like this:
The output from our module is a simple ordered list of modules. Like any other block, it can be positioned in any of the block regions on the site, and responds in all the ways that a block is expected to respond.

Now that we have a working module, we are going to write a couple of automated tests for it.

Creating Drupal 7.x modules

This section includes tutorials and other information that you need to create modules for Drupal version 7.x.

Other general resources

For a collection of useful materials for module developers, see Module Development with Drupal.

Creating Drupal 8.x modules

This section includes tutorials and other information that you need to create modules for Drupal version 8.x.
An excellent overview: Understanding Drupal 8

Other general resources

Several introductory screencasts walking you through setting up a basic D8 module have been published:
An excellent presentation on working with the Drupal 8 API Amsterdam 2014: Drupal 8: The Crash Course
Alex Bronstein wrote an introductory article titled "Drupal 8: Hello OOP, Hello world!"
There is also a Sitepoint series on developing Drupal 8 modules that you can check out.
Note that core Drupal has moved on since both these tutorials were written, and the code no longer works without error. You can find some explanation of the changes needed, as well as links to the updated code here.

Drupal 7 - How to Make a Simple Module with a Form and Menu Link

This guide will show you how to add a form to your website that is accessed through its own URL. This guide will go over module creation, form creation, and the menu hook function.
Creating the module structure
The first step in creating the module is to create a folder for the module. You should put this in "sites/all/modules/{name of your module}." Keep in mind that whenever I say "{name of your module}," you should insert the name of your module. For example, we will use the module directory "sites/all/modules/form_example."
Now, create two empty text files called "{name of your module}.module" and "{name of your module}.info."
These two files are required by your module. The .info file contains information about what your module does, while the .module file contains the actual code including hooks. Hooks are functions with special names that will be called by Drupal when actions occur. For example "form_example_menu()" is called when menu information is gathered. In many examples, you will see names such as "hook_menu()" or "my_theme_menu()" and in these cases "my_theme" and "hook" should be replaced by the name of your module or theme.
Build the basic module files
Here is what we will put into the form_example.info file. This tells Drupal and users about your module.
core = "7.x"
description = "An example module used to learn module development and forms creation."
name = "Form Example Module"
There are more options that you can put in the .info file, but the ones above should be added.
Here is the start of our form_example.module file. This will create a very basic form that only has one field, a submit button.
<?phpfunction form_example_form($form, &$form_state) {
 
 
$form['submit_button'] = array(
   
'#type' => 'submit',
   
'#value' => t('Click Here!'),
  );
 
  return
$form;
}
?>
Note: Do not include the last "?>" part of the PHP code and leave a trailing blank line at the end of the file. This is the Drupal standard.
The module right now contains one function that will create a form. It is important to note that the function takes the inputs $form, and a reference &$form_state. This function will be called when Drupal tries to build the form "form_example_form."
The process for creating a form is mainly two steps. The first is to build an associative array $form that contains all the fields. The second step is to return that $form variable.
To add a field, you set the variable $form[{name of your field}] = array(); Each field can then have a number of attributes, such as "#type" and "#value." Most of these attributes are named with a proceeding "#" sign.
The field we added above is a submit button with the text "Click Here!" on the button. Note that t() will output text and is a Drupal function that plays nice with translation.
Now that we have a form, we need to add two more function: form_example_form_validate, and form_example_form_submit. These two functions are hook functions that will be called when Drupal validates the form and when it submits the form (assuming it validated).
form_example.module:
<?phpfunction form_example_form($form, &$form_state) {
 
 
$form['submit_button'] = array(
   
'#type' => 'submit',
   
'#value' => t('Click Here!'),
  );
 
  return
$form;
} function
form_example_form_validate($form, &$form_state) {
} function
form_example_form_submit($form, &$form_state) {
}
?>
You will note that these three functions take the same variables. $form is the original form information and can be seen as the original structure of the form. $form_state holds all of the submitted values as well as other information, some of which you can add yourself. These two functions need to named similar to the other form, but with "validate" and "submit" at the end.
We want to see the form!!! We will add a menu link to this form.
form.example.module
<?php function form_example_menu() {
 
$items = array();   $items['examples/form-example'] = array( //this creates a URL that will call this form at "examples/form-example"
   
'title' => 'Example Form', //page title
   
'description' => 'A form to mess around with.',
   
'page callback' => 'drupal_get_form', //this is the function that will be called when the page is accessed.  for a form, use drupal_get_form
   
'page arguments' => array('form_example_form'), //put the name of the form here
   
'access callback' => TRUE
 
);   return $items;
} function
form_example_form($form, &$form_state) {
 
 
$form['submit_button'] = array(
   
'#type' => 'submit',
   
'#value' => t('Click Here!'),
  );
 
  return
$form;
} function
form_example_form_validate($form, &$form_state) {
} function
form_example_form_submit($form, &$form_state) {
}
?>
Now enable your module and try to access the link. You will probably need to clear the cache.
Add more functionality to the form.
Now we will add one more field to the form.
form_example.module
<?php function form_example_menu() {
 
$items = array();   $items['examples/form-example'] = array( //this creates a URL that will call this form at "examples/form-example"
   
'title' => 'Example Form', //page title
   
'description' => 'A form to mess around with.',
   
'page callback' => 'drupal_get_form', //this is the function that will be called when the page is accessed.  for a form, use drupal_get_form
   
'page arguments' => array('form_example_form'), //put the name of the form here
   
'access callback' => TRUE
 
);   return $items;
} function
form_example_form($form, &$form_state) {
 
 
$form['price'] = array(
   
'#type' => 'textfield', //you can find a list of available types in the form api
   
'#title' => 'What is Your Price?',
   
'#size' => 10,
   
'#maxlength' => 10,
   
'#required' => TRUE, //make this field required
 
);   $form['submit_button'] = array(
   
'#type' => 'submit',
   
'#value' => t('Click Here!'),
    ),
  );
 
  return
$form;
} function
form_example_form_validate($form, &$form_state) {
} function
form_example_form_submit($form, &$form_state) {
}
?>
Here we have added a new textfield and made it required. We have also set the maximum length. You'll see if you try to submit the form, that Drupal will automatically produce an error for the user if they don't fill in the required fields. We will add some more validation in the next step.
Add validation
form_example.module
<?php function form_example_menu() {
 
$items = array();   $items['examples/form-example'] = array( //this creates a URL that will call this form at "examples/form-example"
   
'title' => 'Example Form', //page title
   
'description' => 'A form to mess around with.',
   
'page callback' => 'drupal_get_form', //this is the function that will be called when the page is accessed.  for a form, use drupal_get_form
   
'page arguments' => array('form_example_form'), //put the name of the form here
   
'access callback' => TRUE
 
);   return $items;
} function
form_example_form($form, &$form_state) {
 
 
$form['price'] = array(
   
'#type' => 'textfield', //you can find a list of available types in the form api
   
'#title' => 'What is Your Price?',
   
'#size' => 10,
   
'#maxlength' => 10,
   
'#required' => TRUE, //make this field required
 
);   $form['submit_button'] = array(
   
'#type' => 'submit',
   
'#value' => t('Click Here!'),
    ),
  );
 
  return
$form;
} function
form_example_form_validate($form, &$form_state) {
  if (!(
$form_state['values']['price'] > 0)){
   
form_set_error('price', t('Price must be a positive number.'));
  }
} function
form_example_form_submit($form, &$form_state) {
}
?>
You will now see that the form will not submit unless price is a positive number. We do this by checking the value of price, in $form_state['values'][{name of your field}]. There are similar variables for all of your fields.
We then set an error with form_set_error. Adding this error will alert Drupal that the form did not pass validation.
What to do when your form is submitted?
From this point, you will want to either save the form data, send an email, or display some information. That is beyond the scope of this How To at this point.
I have built some module "tools" or "calculators" using the above method and included the calculation steps in the submit function. You can set the variable "$form_state['rebuild'] = TRUE;" in the submit function so that Drupal does not clear the form. You can therefore edit the $form_state to change a "markup" field type to have your output.
This can also be done with AJAX so that the form displays the calculated values without a page load. That gets a little more complicated and may be added as a separate How To.
Conclusions
Hopefully this is helpful for people interested in writing a module, or adding a form to a module.

Creating modules - a tutorial: Drupal 7.x

This tutorial describes how to create a module for Drupal 7. If your goal is to convert a module from Drupal 6 or earlier to Drupal 7, see: Updating your modules.
A module is a collection of functions that link into Drupal, providing additional functionality for your Drupal installation. After reading this tutorial, you will be able to create a basic block module and use it as a template for more advanced modules.

Requirements

This tutorial assumes you have:
  • Basic PHP knowledge, including syntax and the concept of PHP objects
  • Basic understanding of database tables, fields, records and SQL statements
  • A working Drupal 7 installation
  • Drupal administration access
  • Webserver access
This tutorial does not assume you have any knowledge about the inner workings of a Drupal module.
For more information on module development, see Module Development with Drupal.

When finished

This tutorial will not necessarily prepare you to write modules for public release. It does not cover important topics such as: caching, permissions, or security issues. Use this tutorial as a starting point and then extend your skills with other resources, including:
When you are finished developing a useful module, you may want to contribute it back to the community. If so follow the instructions for: creating a new full project.

Building a Drupal 7 Module: Show Latest Nodes

Drupal is one of the most popular open source content management systems. It has a lot of functionality built in and thousands of free and paid modules to choose from for your site. It has a very extensible and flexible architecture which lets you build on top of the Drupal core and extend its functionality as needed. Drupal lets you plug into its system using Drupal hooks. We are going to use some of the hooks in the module which we are going to build in this article – a Drupal 7 module to show the different types of nodes (all content on a Drupal website is stored and treated as nodes) on your Drupal site by creating a Drupal block. The types of nodes which will be shown can be selected in the configuration menu of the module.
Before we begin, if you don't have an active Drupal installation on your machine, please set one up by following the instructions in their installation guide.

Building your module's basic structure

Let's start by creating the basic folder structure and files for our module. A Drupal module needs to be placed in a specific directory in your Drupal installation and it needs to have some basic files so that it can be identified as a module by the Drupal system. The first thing we need to do is create a folder for our module called shownodes. That folder should be kept in the sites\all\modules\ folder of your Drupal installation. In this folder create two blank files called shownodes.info and shownodes.module.
The file shownodes.info provides the general information about your module to Drupal and the file shownodes.module will contain the implementation for various hooks used by our module. The following is how the file structure should look for our module.
image01
Now open the shownodes.info file and add the following content:
name = shownodes
description = This module displays various nodes in a block on your Drupal site.
core = 7.x
This basically describes your module's basic properties like its name, description and on which Drupal core level it can be deployed. Once you have added these details to the shownodes.info file you should be able to see your module in the module list as shown below. You can enable your module now.

Understanding Drupal Hooks

The system to extend Drupal is built completely on the concept of hooks. Hooks are based on naming. For a module to implement a hook in Drupal, it has to create a function called modulename_hookname depending on which hook it needs to implement in the .module file. Once there is an event to call the hooks, the Drupal system will call the hook implementation of all the enabled modules. To read more about the available hooks visit the hooks documentation page.
The first hook we will implement in our module is the hook_help which lets you provide help text on your module to describe what your module does.
Add the following code to your shownodes.module file
<?php
/**
 * @file
 * This is the main module file.
 */

/**
 * Implements hook_help().
 */
function shownodes_help($path, $arg) {

  if ($path == 'admin/help#shownodes') {
    $output = '<h3>' . t('About') . '</h3>';
    $output .= '<p>' . t('The shownodes module allows the Administrator to display various types of nodes as a block on your Drupal site.') . '</p>';
    return $output;
  }
}
We are implementing the hook_help hook through a function called shownodes_help which returns the help text for our module whenever the help request is fired. Once you have implemented this hook the help option will be shown on the module and clicking it will show the help as follows.

Adding configuration options to your Module

Now let's add some configuration options for the administrator of our site. We will create an options page for the Administrator so that he can select which node types he wants to display in the block. This can be done using the Drupal menu hooks. We will implement the hook_menu hook in our shownodes.module like so:

/**
* Implementation of hook_menu().
*/
function shownodes_menu() {

  $items['admin/config/shownodes'] = array(
  'title' => t('Choose the nodes to show'),
  'description' => t('You can select which node types you want to show'),
  'page callback' => 'system_admin_menu_block_page',
  'access arguments' => array('administer site configuration'),
  'file' => 'system.admin.inc',
  'file path' => drupal_get_path('module', 'system'),
  );
  
  $items['admin/config/shownodes/settings'] = array(
  'title' => t('Choose the nodes to show'),
  'description' => t('You can select which node types you want to show'),
  'page callback' => 'drupal_get_form',
  'page arguments' => array('shownodes_admin_settings'),
  'access arguments' => array('administer site configuration'),
  'type' => MENU_NORMAL_ITEM,
  );
  
  return $items;
}

function shownodes_admin_settings() {

  $types = node_type_get_types();
  foreach($types as $node_type) {
    $nodetypes[$node_type->type] = $node_type->name;
  }

  $form['shownodes_nodes_toshow'] = array(
  '#type' => 'checkboxes',
  '#title' => t('Select the nodes to show'),
  '#options' => $nodetypes,
  '#default_value' => variable_get('shownodes_nodes_toshow', array('')),
  '#description' => t('All the node types selected below will be shown'),
  );
  
  return system_settings_form($form);
}
You can read more about hook_menu at the aforementioned hooks docs page.
In this case, we create two menu items at the path admin/config/shownodes and admin/config/shownodes/settings and then we build a form with the help of drupal_get_form which creates check boxes for all the installed node types which we get from the Drupal function node_type_get_types. Saving the form, Drupal will automatically store the selected values in a variable using variable_set with the name taken from the form element which in our case is shownodes_nodes_toshow. We can fetch the value of this using the function variable_get('shownodes_nodes_toshow', array('')).
We will use this to set the default values in the form and then later in the block implementation below to show the selected node types. Once we have added the above functions we should be able to see our configuration option as shown below in the Administration->configuration option.

Selecting this option will show us our form with all the node types in the Drupal system and we will be able to select and save the node types which we want to show on our block as shown below.

Creating latest node Block

Once our configuration is saved we will build our block to display the node types which were selected in the configuration. To create a block we will implement the hooks hook_block_info and hook_block_view as shown below.
/**
 * Implements hook_block_info().
 */
function shownodes_block_info() {
  $blocks = array();

  $blocks['shownodeblock'] = array(
    'info' => t('A block to show selected nodes'),
  );

  return $blocks;
}

/**
 * Implements hook_block_view().
 */
function shownodes_block_view($block_name = '') {
  if ($block_name == 'shownodeblock') {

    //Get the selected node types and create a list of them
    $show_nodes_list = array();
    $show_nodes_array = variable_get('shownodes_nodes_toshow', array(''));
    foreach ($show_nodes_array as $key => $value) {
      if($value) {
          array_push($show_nodes_list,$value);
      }
    }
    
    //Based on the node types create a query and then load the node types
    $query = new EntityFieldQuery();
    $query
    ->entityCondition('entity_type', 'node')
    ->entityCondition('bundle', $show_nodes_list)
    ->propertyCondition('status', 1)
    ->propertyOrderBy('created', 'DESC');
    
    $result = $query->execute();
    $nodes = array();
    if (isset($result['node'])) {
      $nids = array_keys($result['node']);
      $nodes = node_load_multiple($nids);
    }
    
    //Loop through the loded nodes to create a list
    //Which we will pass to the theme
    $list = array();
    foreach ($nodes as $node) {
      $options = array('absolute' => TRUE);
      $url = url('node/' . $node->nid, $options);
      $list[] = ''.$node->title.'';
    }
    
    //Return the content of the block
    $theme_args = array('items' => $list, 'type' => 'ol');
    $content = theme('item_list', $theme_args);

    $block = array(
      'subject' => t('Show Nodes Block'),
      'content' => $content,
    );
    return $block;
  }
}
In the above code we define a new block called shownodeblock in the function shownodes_block_info. Then, in the function shownodes_block_view we provide the view for that block by first reading the values which were saved in the configuration using the function variable_get('shownodes_nodes_toshow', array(''));. Next we query Drupal to get the node IDs based on the node types using the EntityFieldQuery class. Finally, we load those nodes and then loop through them to show them on our block.

Once we have added the above code we should see our block in the block list. You can place the block in one of the regions (regions are actual parts of your layout, essentially, locations for blocks)

Drupal Module: Creating First Simple Module

Drupal Module Creating First Simple Module Tutorial. Now we will dive in and create our first module. Our first module will show simple text, format it, and display it as a block in the site's layout. We will cover the following steps:
  • Creating the .info and .module files
  • Creating a new module
  • Using basic hooks
  • Installing and configuring the module
There are two files that every module must have (though many modules have more). The first, the .info file, we examined above. The second file is the .module (dot-module) file, which is a PHP script file.

A Place for the Module

In Drupal, every module is contained in its own directory. To keep naming consistent throughout the module (a standard in Drupal), we will name our directory with the module name.
In this practice, we will create a module named "helloword". So we have to create a directory named "helloword". Place it within \sites\all\modules.
Drupal Module Creating Module Folder Tutorial

Creating a .info File

Drupal components use the information in this file for module management. The .info file is written as a PHP INI file, which is a simple configuration file format.
The .info file must follow the standard naming conventions for modules. It must be named .info. is the same as the directory name. Example helloword.info.
Drupal Module Create info file tutorial
1;$Id$
2name = "Hello Word!"
3description = "Our first module in drupal module development"
4core = 6.x
5php = 5.2

A Basic .module File

Drupal Module Creating .module file tutorial

A Block Hook

The hook_block() function isn't just for displaying block contents, though. In fact, this function is responsible for displaying the block and providing all the administration and auxiliary functions related to this block
Write these code at helloword.module file:
01<?php
02// $Id$
03/**
04* @file
05* Module for showing hello word
07*/
08 
09/**
10* Implementation of hook_block()
11*/
12function helloword_block($op='list' , $delta=0, $edit=array()) {
13    switch ($op) {
14        case 'list':
15            $blocks[0]['info'] = t('Hello Word!');
16            return $blocks;
17        case 'view':
18            $blocks['subject'] = t('Hello Word!');
19            $blocks['content'] = t('This is our first module!');
20        return $blocks;
21    }
22}
23 
24?>
Our module will display information inside a Drupal block. To do this, we need to implement the hook_block() function. When Drupal calls a hook_block() function, Drupal passes it as many as three parameters: $op, $delta, $edit
$op can have the following four possible values:
  • list: This is passed when the module should provide information about itself.
  • view: to provide content for displaying to the user.
  • configure: an administration form used to configure the block.
  • save: configuration information from the form data generated by configure needs to be saved.
The $delta parameter is set during a particular operation. The $edit parameter is used during configuration (when the save operation is called). We dont need in this example.

Installing a Module

Step #1: Enabling The Module

A module is enabled through the Drupal Administration interface. Once logged into Drupal, navigate to Administer | Site Building | Modules in the left-hand navigation
Drupal Module Administration Menu Tutorial
To activate the module, simply check the box under the Enabled heading, and then click the Save configuration button.
Drupal Module Activate the module tutorial

Displaying the Module's Content

Just as with enabling the module, this is done through the administration interface. Go to Administer | Site Building | Blocks to configure block placement. We will configure our module to appear in the right sidebar.
Drupal module block placement tutorial
Make sure to press the Save Blocks button at the bottom.
Drupal Module Showing Block Tutorial