|
|
Want to know more about Packt's Article Network? Interested in contributing your article ideas? Please visit our FAQ for more information. See More BROWSE
All Titles WordPress Web Services SOA BPEL Web Graphics & Video Web Development RAW Portugues, Espanol, Italiano, French PHP/MySQL Oracle Open Source Networking & Telephony Moodle Microsoft & .NET Linux Servers jQuery Joomla! JBoss Java e-Learning e-Commerce Dynamics Drupal CRM Cookbook Content Management Beginner Guides Architecture and Analysis AJAX Future Titles Recently Published Titles The Philosophy Quotes module that we will create in this article will use Drupal's theme system and a simple database query to theme the content of a custom content type. Here are some of the items we will cover in this article by Matt Butcher while working on this module:
See More |
Creating Our First Module using Drupal 6 (Part1)
Starting OutOur first module is going to fetch XML data from Goodreads, a free social networking site for avid readers. There, users track the books they are reading and have read, rate books and write reviews, and share their reading lists with friends. Reading lists at Goodreads are stored in bookshelves. These bookshelves are accessible over a web-based XML/RSS API. We will use that API to display a reading list on the Philosopher Bios website(example website) To integrate the Goodreads information in Drupal, we will create a small module. Since this is our first module, we will get into greater details. A Place for the ModuleIn Drupal, every module is contained in its own directory. This simplifies organization; all of the module's files are located in one place. To keep naming consistent throughout the module (a standard in Drupal), we will name our directory with the module name. Later, we will install this module in Drupal, but for development, the module directory can be wherever it is most convenient. Once we have created a directory named goodreads, we can start creating files for our module. The first file we need to create is the .info (dot-info) file. Creating a .info FileBefore we start coding our new module, we need to create a simple text file that will hold some basic information about our module. Various 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. If you are interested in the details of INI file processing, you can visit http://php.net/manual/en/function.parse-ini-file.php for a description of this format and how it can be parsed in PHP. Our .info file will only be five lines long, which is probably about average. The .info file must follow the standard naming conventions for modules. It must be named <modulename>.info, where <modulename> is the same as the directory name. Our file, then, will be called goodreads.info. Following are the contents of goodreads.info: ;$Id$ This file isn't particularly daunting. The first line of the file is, at first glance, the most cryptic. However, its function is mundane: it is a placeholder for Drupal's CVS server. Drupal, along with its modules, is maintained on a central CVS (Concurrent Version System) server. CVS is a version control system. It tracks revisions to code over time. One of its features is its ability to dynamically insert version information into a file. However, it needs to know where to insert the information. The placeholder for this is the special string $Id$. But since this string isn't actually a directive in the .info file, it is commented out with the PHP INI comment character, ; (semi-colon). You can insert comments anywhere in your .info file by beginning a line with the ; character. The next four directives each provide module information to Drupal. The name directive provides a human-readable display name for the module. Here's an example:
In this above screenshot, the names Aggregator and Blog are taken from the values of the name directives in these modules' .info files. While making the module's proper name short and concise is good (as we did when naming the module directory goodreads above), the display name should be helpful to the user. That usually means that it should be a little longer, and a little more descriptive. However, there is no need to jam all of the module information into the name directive. The description directive is a good place for providing a sentence or two describing the module's function and capabilities. The third directive is the core directive. The core and php directives are new in Drupal 6. This directive specifies what version of Drupal is required for this module to function properly. Our value, 6.x, indicates that this module will run on Drupal 6 (including its minor revisions). In many cases, the Drupal packager will be able to automatically set this (correctly). But Drupal developers are suggesting that this directive be set manually for those who work from CVS. Finally, the php directive makes it possible to specify a minimum version number requirement for PHP. PHP 5, for example, has many features that are missing in PHP 4 (and the modules in this book make use of such features). For that reason, we explicitly note that our modules require at least PHP version 5.1. That's all there is to our first module .info file. What we have here is sufficient for our Goodreads module. Now, we are ready to write some PHP code. A Basic .module FileThere 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. This file typically implements a handful of hook functions that Drupal will call at pre-determined times during a request. Here, we will create a .module file that will display a small formatted section of information. Later in this article, we will configure Drupal to display this information to site visitors. Our Goal: A Block HookFor our very first module, we will implement the hook_block() function. In Drupal parlance, a block is a chunk of auxiliary information that is displayed on a page alongside the main page content. Sounds confusing? An example might help. Think of your favorite news website. On a typical article page, the text of the article is displayed in the middle of the page. But on the left and right sides of the page and perhaps at the top and bottom as well, there are other bits of information: a site menu, a list of links to related articles, links to comments or forums about this article, etc. In Drupal, these extra pieces are treated as blocks. 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. Don't worry... we'll start out simply and build up from there. Starting the .moduleDrupal follows rigorous coding and documentation standards (http://drupal.org/coding-standards). In this article, we will do our best to follow these standards. So as we start out our module, the first thing we are going to do is provide some API documentation. Just as with the .info file, the .module file should be named after the module. Following is the beginning of our goodreads.module file: <?php The .module file is just a standard PHP file. So the first line is the opening of the PHP processing instruction: <?php. Throughout this article you may notice something. While all of our PHP libraries begin with the <?php opening, none of them end with the closing ?> characters. This is intentional, in fact, it is not just intentional, but conventional for Drupal. As much as it might offend your well-formed markup language sensibilities, it is good coding practice to omit the closing characters for a library. Why? Because it avoids printing whitespace characters in the script's output, and that can be very important in some cases. For example, if whitespace characters are output before HTTP headers are sent, the client will see ugly error messages at the top of the page. After the PHP tag is the keyword for the version control system: // $Id$ When the module is checked into the Drupal CVS, information about the current revision is placed here. The third part of this example is the API documentation. API documentation is contained in a special comment block, which begins /** and ends with a */. Everything between these is treated as documentation. Special extraction programs like Doxygen can pull out this information and create user-friendly programming information. The Drupal API reference is generated from the API comments located in Drupal's source code. The program, Doxygen, (http://www.stack.nl/~dimitri/doxygen/) is used to generate the API documents from the comments in the code. The majority of the content in these documentation blocks (docblocks, for short) is simply text. But there are a few additions to the text. First, there are special identifiers that provide the documentation generating program with additional information. These are typically prefixed with an @ sign. /** In the above example, there are two such identifiers. The @file identifier tells the documentation processor that this comment describes the entire file, not a particular function or variable inside the file. The first comment in every Drupal PHP file should, by convention, be a file-level comment. The other identifier in the above example is the @see keyword. This instructs the documentation processor to attempt to link this file to some other piece of information. In this case, that piece of information is a URL. Functions, constants, and variables can also be referents of a @see identifier. In these cases, the documentation processor will link this docblock to the API information for that function, constant, or variable. With these formalities out of the way, we're ready to start coding our module. Learning Drupal 6 Module Development
The hook_block() ImplementationOur module will display information inside a Drupal block. To do this, we need to implement the hook_block() function. Remember, what we are doing here is providing a function that Drupal will call. When Drupal calls a hook_block() function, Drupal passes it as many as three parameters:
The $op parameter will contain information about the type of operation Drupal expects the module to perform. This single hook implementation is expected to be able to perform a variety of different operations. Is the module to output basic information about itself? Or display the block? Or provide some administration information? The value of $op will determine this. $op can have the following four possible values:
The $delta parameter is set during a particular operation. When $op is set to the string view, which is the operation for displaying the block, then the $delta will also be set. $delta contains extra information about what content should be displayed. Using deltas, you can define a single hook_block() function that can display several different blocks. For example, we might define two deltas—one that displays our Goodreads bookshelf, and the other that displays information about our Goodreads account. Which one is displayed will depend on which $delta value is passed into the goodreads_block() function. Finally, the $edit parameter is used during configuration (when the save operation is called). Since we are not implementing that operation in our first module, we will not use this parameter. Drupal is meticulously documented, and the API documents are available online at http://api.drupal.org. More information about hook_block() parameters is available at this URL: http://api.drupal.org/api/function/hook_block/6. All hook methods should follow the module naming convention: <module name>_<hook name>. So our goodreads block hook will be named goodreads_block(). /** Following Drupal conventions, we precede the function with a documentation block. For hooks, it is customary for the documentation therein to indicate which hook it is implementing. Next is our function signature: function goodreads_block($op='list', $delta=0, $edit=array()). The $op, $delta, and $edit parameters are all explained above. Each parameter is initialized to a default value. Here, we follow the customary defaults, but you can define them otherwise if you prefer. As I mentioned earlier the $op parameter might be set to one of several different values. What we do in this function is largely determined by which of those four values is set in the $op flag. For that reason, the first thing we do in this function is use a switch statement to find out which operation to execute. Each case in the switch statement handles one of the different operations. For now, we don't have any administration configuration to perform, so there are no cases to handle either configure or save operations. We just need to handle the list and view operations. Let's look at each. case 'list': When Drupal calls this hook with $op set to 'list', then this module will return a two‑dimensional array that looks as follows: array( Each element in this array is a block descriptor, which provides information about what this block implementation does. There should be one entry here for every $delta value that this function recognizes. Our block will only return one value (we don't make use of deltas), so there is only one entry in the block descriptor array. A block descriptor can contain several different fields in the associative array. One is required: the 'info' field that we have set above. But we could also provide information on caching, default weighting and placement, and so on. For detailed information on this and other aspects of the hook_block() hook, see the API documentation: http://api.drupal.org/api/function/hook_block/6 Drupal uses the 'info' field to display an item in the module management list, which we will see in the Installing a Module section of this article. The t() FunctionIn this example, there is one more thing worthy of mention. We use the function t(). This is the translation function. It is used to provide multi-language support and also provide a standard method of string substitution. When t() is called, Drupal will check to see if the user's preferred language is other than the default (US English). If the user prefers another language, and that language is supported, then Drupal will attempt to translate the string into the user's preferred language. For multi-language support, you will need to enable the Content translation module. Whenever we present hard-coded text to a user, we will use the t() function to make sure that multi-language support is maintained. In simple cases, the t() function takes just a string containing a message. In this case, the entire string will be translated. But sometimes, extra data needs to be passed into the string function. For example, we may want to add a URL into a string dynamically: 'Trying to access !url.' In this case, we want t() to translate the string, but to substitute a URL in place of the !url placeholder. To do this, we would call t() with the following parameters: t('Trying to access !url.', array('!url'=>'http://example.com'));In this example, t() has two arguments: the string to translate, and an associative array where the key is the placeholder name and the value is the value to be substituted. Running the above when the locale is set to English will result in a string as follows: Trying to access http://example.com There are three different kinds of placeholder. We have seen one above.
Sometimes it is desirable to do some escaping of the variables before substituting them into the string. The other two placeholder markers indicate that extra escaping is necessary.
Don't trust user-entered data We will use the t() function throughout this article. For now, though, let's continue looking at the hook_block() function we have created. A view OperationNow let's turn to the view case. This second case in our switch statement looks as follows: case 'view': The view operation should return one block of content for displaying to the end user. This block of content must have two parts stored as name/value pairs in an associative array: a subject and a content item. The subject is the title of the block, and the content is main content of the block. The value of the subject entry will be used as a title for the block, while the content will be placed into the block's content. Again, we used the translation function, t(), to translate the title and content of this block. While it is not terribly exciting yet, our module is ready to test. The next thing to do is install it. Learning Drupal 6 Module Development
Installing a ModuleWe have a working module. Now we need to install it. This is typically done in three steps:
Some of the contributed modules for Drupal require additional setup steps. Such steps are documented by the module's authors. We will walk through each of these three steps. Step 1: Copying the ModuleModules in Drupal are stored in one of the three places under Drupal's root directory:
In this article, we will be storing our modules under the sites/all/modules/ directory. However, this directory is not created by default, so we will need to create it by hand. On my Linux server, Drupal is installed in /var/www/drupal/. (Yours may be somewhere else.) All of the file system paths will be relative to this directory. We will add the appropriate subdirectory inside the sites/all/ directory:
In this example, we change into the appropriate directory and create the new modules/ directory. By default, the permissions on the directory should be set to allow the web-server user (such as www-data) access to the files in the module. However, on some systems you may have to set these yourselves. On Windows, the same can be done through Windows explorer, and the same goes for Mac and Finder. Simply locate your Drupal installation directory, navigate down to sitesall, and create a new folder named modules. Next, we need to copy our module into this directory.
UNIX and Linux users: Don't move it; link it! Now we have our module in a location where Drupal expects to find modules. Copying the module to the correct location is all we need to do for Drupal to recognize the module, but new modules are disabled by default. We will need to log in to the web interface and enable the module. Step 2: Enabling the ModuleA module is enabled through the Drupal Administration interface. Once logged into Drupal, navigate to Administer | Site Building | Modules in the left-hand navigation.
This page lists all the modules, beginning with the core modules (those installed by default). At the very bottom of this page is the list of third-party modules. Our module will appear in that list.
To activate the module, simply check the box under the Enabled heading, and then click the Save configuration button. Where did Drupal get the information about our module? For most of this part, this information came from our goodreads.info file. Next, we need to configure the module to display on our site. Step 3: Displaying the Module's ContentThe module we have created is a block module. Typically, blocks are displayed in specifically defined locations on the screen. What we want to do now is tell Drupal where to display our block content. Just as with enabling the module, this is done through the administration interface. Go to Administer | Site Building | Blocks to configure block placement.
This tools allows us to configure the details of how blocks appear on the site. In fact, the site uses the templates that a site visitor would see. You can see how the site looks as you configure it. At the bottom of this page is the block configuration tool—lists of modules along with page placement parameters. We will configure our goodreads module to appear in the right sidebar. If all goes well, then our goodreads module should display in the right sidebar. Make sure to press the Save Blocks button at the bottom. Otherwise the block's new location will not be saved. To generate the preceding screen, the block placement screen calls the hook_block() functions for each of the block modules, setting $op to list. When the block's new location is saved, it will be displayed in the right-hand column on all of our pages.
What is the content in this module? What we see in the above screenshot are the fields returned when Drupal's module manager calls the hook_block() function of our module with something equivalent to this: goodreads_block('view');This will return the $blocks array, whose contents look like this: array( The subject value is used as the block's title, and the content item is used as the block's content. Our module is installed. But it is doing very little. Next, we will add some sophistication to our module. SummarySo far, we have created a basic module that uses hook_block() to add block content and installed this basic module. As it stands, however, this module does no more than simply displaying a few lines of static text. In the next part, we are going to extend the module's functionality. We will add a few new functions that retrieve and format data from Goodreads. If you have read this article you may be interested to view : Learning Drupal 6 Module Development
About the AuthorMatt Butcher is the principal consultant for Aleph-Null, Inc. (http://aleph-null.tv), where he specializes in content management systems, Linux system integration, and Open Source technologies. He has been an active participant in Open Source technologies for over a decade. Along with Learning Drupal 6, Matt has also written Mastering OpenLDAP, Managing and Customizing OpenCms 6, and Building Websites with OpenCms, all of which are published by Packt. Matt writes his technical blog at technosophos.com. When not pushing bits, Matt likes to explore Chicago with his wife and three daughters. Books from Packt |
TOP TITLES ![]()
In the first part of this 2-part article series we had created a basic module that uses hook_block() to add block content and installed this basic module. In this article by Matt Butcher, we are going to extend the module's functionality. We will add a few new functions that retrieve and format data from Goodreads. See More |
| ||||||||