15 min read

 

Drupal 7 Module Development

Drupal 7 Module Development

Create your own Drupal 7 modules from scratch

  • Specifically written for Drupal 7 development
  • Write your own Drupal modules, themes, and libraries
  • Discover the powerful new tools introduced in Drupal 7
  • Learn the programming secrets of six experienced Drupal developers
  • Get practical with this book’s project-based format
        Read more about this book      

The focus of this article by Matt Butcher, author of Drupal 7 Module Development, is module creation. We are going to begin coding in this article.

Here are some of the important topics that we will cover in this article:

  • Starting a new module
  • Creating .info files to provide Drupal with module information
  • Creating .module files to store Drupal code
  • Adding new blocks using the Block Subsystem
  • Using common Drupal functions
  • Formatting code according to the Drupal coding standards

(For more resources on this subject, see here.)

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.


Subscribe to the weekly Packt Hub newsletter

* indicates required

LEAVE A REPLY

Please enter your comment!
Please enter your name here