Creating modules - a tutorial: Drupal 6.x

Last modified: June 18, 2009 - 23:01

This tutorial describes how to create a module for Drupal 6. It is an update to the tutorial for Drupal 5. Please see comments there, also. Much of this tutorial is valid for Drupal 5 as well, but you should check the API documentation, as well as the documentation on how to update your modules from one version of Drupal to another.

A module is a collection of functions that link into Drupal, providing additional functionality to 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 and node modules.

This tutorial will not necessarily prepare you to write modules for release into the wild. It does not cover caching, nor does it elaborate on permissions or security issues. Use this tutorial as a starting point, and review other modules and the Drupal handbook, the documentation on writing secure code and the Coding standards for more information.

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 installation
  • Drupal administration access
  • Webserver access

This tutorial does not assume you have any knowledge about the inner workings of a Drupal module. This tutorial will not help you write modules for versions of Drupal earlier than 5.

For caching, see Cache API and caching tutorials

Outline

This tutorial goes through all of the steps necessary to create a module that deploys a block listing recent blog posts and forum discussions. Here is an outline of what is covered in each of the tutorial pages:

  • Getting Started: Creating a directory for your module and the initial .module file
  • Telling Drupal about your module: Creating a .info file for your module, and implementing hook_help() to provide a brief description of your module in Drupal's help system
  • Telling Drupal who can use your module: Implementing hook_perm(), which defines permission types for your module
  • Declaring block content: Start of implementation of hook_block() -- the part that tells Drupal our module deploys a block
  • Generating the block content: Finish implementing hook_block() -- the part that actually displays the block content. This involves running a database query to retrieve recent blog and forum posts, and then displaying them.
  • Installing, enabling and testing the module: Getting the initial module working
  • Creating a module configuration (settings) page: Modifying the module so that the user can define what "recent" means, by implementing hook_menu() and using the Drupal Form API to define a settings page
  • Generating page content: Adding a full page view to the module, in case there are more recent posts than will fit easily in the block - part 1: write a function that generates the page
  • Letting Drupal know about the new function: Part 2 of adding the full page view to the module -- using hook_menu() to give the page a URL
  • Adding a 'more' link and showing all entries: Part 3 of adding the full page view to the module -- linking the new URL as a "more" link in the block

A Test Module

chadhester - June 23, 2009 - 16:17

I am new to module development, and have spent the past month studying this guide and the various Drupal module development books. I have found each very helpfully, but have had some difficulty with the database abstraction layer and the Forms API. To test some of the things that I've learned, I curbed my module development to create a rather simple "Test Module". This module makes a simple table to log messages. Those messages can also execute PHP code if they are prefixed by the string "eval:" (so I can test code).

I have attached my code below for each of the three files in hope that someone can benefit from my research (albeit not perfect). The three files are rather standard: test_module.info, test_module.install, and test_module.module. Remember to remove the "?>" from the code to comply with Drupal coding standards:

test_module.info

; $Id$
name = Test Module
description = A Test Module.
core = 6.x

package = "Test"

version = "6.x-0.1-dev"

test_module.install

<?php
// $Id$

/**
* Install the test_module module, including it's content (node)
* type.
* @file
*/

/**
* Implementation of hook_install()
*/
function test_module_install() {
   
drupal_install_schema('test_module');
   
db_query("DELETE FROM {cache}");
}

/**
* Implementation of hook_uninstall()
*/
function test_module_uninstall() {
   
drupal_uninstall_schema('test_module');
}

/**
* Implementation of hook_schema()
* @return array of Schema API table definitions.
*/
function test_module_schema() {
   
$schema['test_module_log'] = array(
       
'fields' => array(
           
'id' => array('type' => 'serial', 'size' => 'big', 'unsigned' => TRUE, 'not null' => TRUE,
               
'description'=> "Log ID"),
           
           
'timestamp' => array('type' => 'int', 'not null' => TRUE, 'default' => 0,
               
'description'=> "Timestamp (Unix Timestamp, which is limited to values above Jan 1, 1970)"),
           
'message' => array('type' => 'text', 'not null' => FALSE,
               
'description'=> "Log messages."),  //NOTE:  On MySQL, text fields cannot have default values.
       
),
       
'primary key' => array('id') //Don't put a comma after primary key definition, since doing so will cause database errors.
   
);
   
    return
$schema;
}
?>

test_module.module

<?php
// $Id$
/**
* @file
* A Test Module.
*/

/*******************************************************************************
* Hook Functions (Drupal)
******************************************************************************/

/**
* Display help and module information
* @param path which path of the site we're displaying help
* @param arg array that holds the current path as would be returned from arg() function
* @return help text for the path
*/
function test_module_help($path, $arg) {
   
//$output = '<p>'.  t("test_module is a simple module to test functions and pages in Drupal");
    //    The line above outputs in ALL admin/module pages
   
switch ($path) {
        case
"admin/help/test_module":
       
$output = '<p>'t("test_module is a simple module to test functions and pages in Drupal") .'</p>';
            break;
    }
    return
$output;
}
// function test_module_help

/**
* Valid permissions for this module
* @return array An array of valid permissions for the test_module module
*/
function test_module_perm() {
    return array(
'administer test_module', 'access test_module content');
}
// function test_module_perm()

/**
* Menu for this module
* @return array An array with this module's settings.
*/
function test_module_menu() {
   
$items = array();
   
   
//Link to the test_module admin page:
   
$items['admin/settings/test_module'] = array(
       
'title' => 'Test Module',
       
'description' => 'Administer Test Module Messages',
       
'page callback' => 'test_module_message',
       
'access arguments' => array('administer test_module'),
       
'type' => MENU_NORMAL_ITEM,
    );
   
    return
$items;
}

/**
* Test Module Messages
* @return array An array of form data.
*/
function test_module_message() {
   
$page_content = '';
   
   
$page_content .= drupal_get_form('test_module_message_form');
   
   
$get_messages = db_query("SELECT * FROM {test_module_log} ORDER BY timestamp DESC");
    if (
$get_messages !== false) {
       
$page_content .= "<h2>Test Message Log</h2>";
       
$row_count = 1;
       
$id = 0;
        while(
$row = db_fetch_array($get_messages)) {
           
$page_content .= "<p>";
            foreach (
$row as $key=>$value) {
                if (
$key == 'id') $id = $value;
                if (
$key == 'timestamp') $value = date('F j, Y G:i:s A', $value);
                if (
$key == 'message') {
                    if (
strpos($value, 'eval:') !== false && $row_count === 1) {
                       
$value = trim(preg_replace('/eval:/', '', $value, 1));
                        eval(
$value);
                       
drupal_set_message(t("Executed code:\n").strval($value));
                       
//Once the "eval:" code is evaluated, remove the "eval:" text to avoid executing the code again.
                       
db_query("UPDATE {test_module_log} SET message = '%s' WHERE id = %d", $value, $id);
                    }
                   
$page_content .= "<br />\n";
                }
               
$page_content .= "<b>".$key."</b> = ".htmlspecialchars(strval($value))."&nbsp;&nbsp;";
            }
           
$page_contents .= "</p>\n";
           
$row_count += 1;
        }
    }
   
    return
$page_content;
}

/**
* The callback function (form constructor) that creates the HTML form for test_module_message().
* @return form an array of form data.
*/
function test_module_message_form() {
   
$form['test_module_message'] = array(
       
'#type' => 'textarea',
       
'#title' => t('Message'),
       
'#default_value' => variable_get('test_module_message', 'Test Message'),
       
'#cols' => 50,
       
'#rows' => 5,
       
'#description' => t("Enter a test message.  Begin the message with \"eval:\" to execute PHPcode."),
    );
   
   
//Submit button:
   
$form['submit'] = array(
       
'#type' => 'submit',
       
'#value' => t('Save Message'),
    );
   
    return
$form;
}

/**
* Form validation for this module's settings
* @param form an array that contains this module's settings
* @param form_state an array that contains this module's settings
*/
function test_module_message_form_validate($form, &$form_state) {
   
$test_module_message = $form_state['values']['test_module_message'];
    if (isset(
$test_module_message)) {
        if (!
is_string($test_module_message) || $test_module_message == '') {
           
form_set_error('test_module_message', t('Please enter a test message.'));
        }
    }
}

/**
* Form submission for user data.
* @param form an array that contains user data
* @param form_state an array that contains user data
*/
function test_module_message_form_submit($form, &$form_state) {
   
$test_message = $form_state['values']['test_module_message'];
   
$exe_query = db_query("INSERT INTO {test_module_log} (timestamp, message) VALUES(%d, '%s')", time(), $test_message);
   
   
$last_id = db_last_insert_id('{test_module_log}','id');
    if (
$exe_query !== false) {
       
$msg = 'Added message to log: %id';
       
$vars = array('%id'=>$last_id);
       
watchdog('test_module', $msg, $vars, WATCHDOG_INFO);
       
drupal_set_message(t('Added message to log: ').strval($last_id));
    } else {
       
$msg = 'Could not add message to log: ';
       
$vars = array();
       
watchdog('test_module', $msg, $vars, WATCHDOG_ERROR);
       
drupal_set_message(t('Could not add message to log.'));
    }
   
   
$form_state['redirect'] = 'admin/settings/test_module';
}
?>

could you change your text size please

prabirchoudhury - July 4, 2009 - 22:53

could you change your text size please.

 
 

Drupal is a registered trademark of Dries Buytaert.