Skip to main content

Using open source software to design, develop, and deploy a collaborative Web site, Part 14: The announcement module source code

Alister Lewis-Bowen (alister.lewisbowen@gmail.com), Senior Software Engineer, IBM
Alister's photo
Alister Lewis-Bowen is a senior software engineer in IBM's Internet Technology Group. He has worked on Internet and Web technologies as an IBM UK employee since 1993. Alister was brought to the U.S. to work on the Web sites for the IBM-sponsored sports events, then as senior Webmaster for ibm.com. He is currently helping create semantic Web prototypes.
Louis Weitzman (louis.weitzman@gmail.com ), Senior Software Engineer, IBM
Louie's photo
Louis Weitzman is a senior software engineer in IBM's Internet Technology Group. For 30 years he has worked at the intersection of design and computation. He helped develop an XML, fragment-based content management system in use by ibm.com, and currently is involved with bringing the design process to emerging projects.
Stephen Evanchik (evanchsa@gmail.com), Software Engineer, IBM
Stephen's photo
Stephen Evanchik is a software engineer in IBM's Internet Technology Group. He has been a contributor to many open source software projects, the most notable being his IBM TrackPoint driver in the Linux kernel. Stephen is currently working with emerging semantic Web technologies.

Summary:  Follow along in this series of articles as the IBM Internet Technology Group designs, develops, and deploys an extranet Web site for a fictitious company, International Business Council (IBC), using a suite of freely available software. In this article, you get the announcement module, which is used as an example throughout this series. All the functions from this module are presented here and can be downloaded in a single file. In the final installment, Part 15, you get a brief review of the entire series.

View more content in this series

Date:  13 Mar 2007
Level:  Intermediate
Activity:  2115 views

Introduction

This article presents the source code for the announcement module we use as our example throughout this series. Each function in the module is described here; most of the functions are implementations of the hook interface for developing modules as described in Part 6, "Building a Custom Module in Drupal." This module is written in Drupal 4.7. The upcoming summary article (Part 15) provides a migration for this module from Drupal version 4.7 to 5.0.

Code listings for the announcement.module

announcement_help

This is the implementation of hook_help. This function allows the announcement module to make documentation available to the Drupal interface. (See http://api.drupal.org/api/HEAD/function/hook_help for more details.)

Input parameter: $section
This determines which part of the interface is requesting help content. Here we return content for the module description under the administration interface admin/modules#description and at the top of the form to add a new announcement node/add#announcement.
Return value
A string containing the help content

Listing 1. Implementation of hook_help
                
function announcement_help($section) {
 switch ($section) {
  case 'admin/modules#description':
    return t('Enables the creation of announcement pages ' .
    'that are presented on the home page.');
  case 'node/add#announcement':
    return t('An Announcement. Use this page to add an announcement page.');
  }
}
	

announcement_perm

This is the implementation of hook_perm. This function supplies the permissions that the announcement module defines. These can then be selected on the Drupal user permissions administration page and used to restrict access to actions the announcement module performs. (See http://api.drupal.org/api/HEAD/function/hook_perm for more details.)

Return value
An array of strings used to identify permissible actions

Listing 2. Implementation of hook_perm
                
function announcement_perm() {
  return array('create announcement', 'edit announcement');
}
	

announcement_node_info

This function is required for modules to define one or more node types. It allows Drupal to determine the names and the attributes of the announcement module node type. (For more details see http://api.drupal.org/api/HEAD/function/hook_node_info.)

Return value
An array of information on the module's node types. The minimum required information that needs to be returned is the module's human readable name, the Drupal module name used to build hook function names, and short description of the node type.

Listing 3. Implementation of hook_node_info
                
function announcement_node_info() {
  return array('announcement' => array(
      'name'        => 'Announcement', 
      'description' => 'An Announcement. Use this page to add an announcement page.',
      'module'      => 'announcement'));
}
	

announcement_access

This is the implementation of hook_access. This function allows the announcement module to limit access to the node type it defines depending on the operation currently being performed and the permissions defined in the Drupal user permissions administration page. (See http://api.drupal.org/api/HEAD/function/hook_access for more details.)

Input parameter: $op
The Drupal operation currently being performed. Here we want to control access for the 'create', 'view', 'update', and 'delete' operations.
Input parameter: $node
The node object on which this operation is being performed
Return value
A boolean value depending on whether the operation can be performed or not

Listing 4. Implementation of hook_access
                
function announcement_access($op, $node) {
	global $user;
	
	if ($op == 'create') {
	    return user_access('create announcement');
	}
	else if ($op == 'view') {
	  	return user_access('access content');
	}
	else if ($op == 'update' ||  $op == 'delete') {
	  	if($user->uid == $node->uid || user_access('edit announcement')) {
	    	return true;
		}
		else {
			return false;
		}
	}
  	else {
  		return false;
  	}
}
	

announcement_menu

This is the implementation of hook_menu. This function allows the announcement module to register URL paths and determine how these requests are to be handled. Depending on the registration, a link may be placed in a menu or as a tab at the top of the page. (See http://api.drupal.org/api/HEAD/function/hook_menu for more details.)

Note: For version 5.X, instead of using the hook_settings function to generate a forum under the admin UI, you need register the URL path, admin/settings/announcement, to map to a callback function that creates this a form.

Input parameter: $may_cache
This is a boolean value used to determine whether or not a registered URL path should be cached. Usually, those URL paths that include some dynamic value should not be cached.
Return value
An array of registered URL path objects. These contain at least the registered URL path, a string of text used as a title for these paths, an access flag built by testing the access list, a type to determine how this registration should be used, and the name of the callback function that should be called when this URL path is requested.

Listing 5. Implementation of hook_menu
                
function announcement_menu($may_cache) {
 $items = array();
    if ($may_cache) {
 $items[] = array('path'     => 'announcements/add',
   'title'    => t('Add a new Announcement'), 
   'access'   => node_access('create', 'announcement'),
   'type'     => MENU_CALLBACK,
   'callback arguments' => array('announcement'),
   'callback' => 'node_add');	
						 
   $items[] = array('path'     => 'announcements',
     'title'    => t('Announcements'),
     'access'   => user_access('access content'),
	 'type'     => MENU_CALLBACK,
	 'callback' => 'announcement_all'); 
  	}
	else {
		
   $items[] = array('path'     => 'announcements/pager',
     'title'    => t('Announcements Pager Example'),
      'access'   => user_access('administer site'),
      'type'     => MENU_CALLBACK,
      'callback' => 'announcement_pager');	
		
      if(is_numeric(arg(1))) {			
		$node = node_load(arg(1));
			
   $items[] = array('path'     => 'announcements/' . arg(1),
	  'title'    => t('View an Announcement'),
	  'access'   => node_access('view', $node),
	   'type'     => MENU_CALLBACK,
	   'callback' => 'node_page');                      
							 
	$items[] = array('path'     => 'announcements/' . arg(1) . '/view',
		'title'    => t('View an Announcement'),
	    'access'   => node_access('view', $node),
	    'type'     => MENU_CALLBACK,
		'callback' => 'node_page');                      
							 
	 $items[] = array('path'     => 'announcements/' . arg(1) . '/edit',
		 'title'    => t('Edit an Announcement'),
		  'access'   => node_access('edit', $node),
		  'type'     => MENU_CALLBACK,
		  'callback' => 'node_page');          
							 
	  $items[] = array('path'     => 'announcements/' . arg(1) . '/delete',
	       'access'   => node_access('delete', $node),
	       'type'     => MENU_CALLBACK,
	       'callback' => 'node_delete_confirm');			
		}						 
	}
	
  	return $items;
}
	

announcement_pager

This function builds a themed set of links, known as the pager, to each page of a paginated list of announcements. This is usually placed at the bottom of each of these paginated pages.

Return value
A string of XHTML used to render the pager

Listing 6. Implementation of announcement_pager
                
function announcement_pager() {
	$result = pager_query(db_rewrite_sql("SELECT n.nid, n.created FROM {node} n " .
	             "WHERE type = 'announcement' ORDER BY n.created DESC"), 
	             variable_get('default_nodes_main', 10));
	while ($announcement = db_fetch_object($result)) {
		$output .= node_view(node_load($announcement->nid), 1);
    }
    
    $output .= theme('pager', NULL, variable_get('default_nodes_main', 10));
    
    return $output;
}
	

announcement_cron

This is the implementation of hook_cron. This function allows the announcement module to insert its own actions when the cron.php script is run, usually by the system cron system. This is useful when performing periodic asynchronous tasks (as in this case) such as checking to see if any announcements have expired. We use this hook to mark expired announcements as unpublished so that nonadministrative users cannot see them on the site through standard node mechanisms. (See http://api.drupal.org/api/HEAD/function/hook_cron for more details.)


Listing 7. Implementation of hook_cron
                
function announcement_cron() {
   $queryResult = db_query("UPDATE {node} AS n INNER JOIN {announcement} AS a " .
                           "ON n.nid = a.nid SET n.status = 0 " .
                           "WHERE n.type='announcement' AND n.status = 1 AND " .
                           "a.expiration_date < %d", time());

}
	

announcement_link

This is the implementation of hook_link. This function allows the announcement module to insert its own links into certain parts of Drupal-generated content. In this case Add, Edit, and Delete links are added to Drupal-rendered announcements, depending on the access permissions of the current user. (See http://api.drupal.org/api/HEAD/function/hook_link for more details.)

Input parameter: $type
A string identifying the type of link being requested. In this case, the links placed below an announcement node.
Input parameter: $node
The node object currently being requested.
Input parameter: $teaser
A boolean indicating whether the full announcement is being displayed or just its teaser.
Return value
An array of link objects as created by the l() function.

Listing 8. Implementation of hook_link
                
function announcement_link($type, $node = NULL, $teaser = FALSE) {
global $user;
	
$links = array();

	if($type == 'node' && $node->type == 'announcement') {
	
	if(node_access('create', 'announcement')) {			
$links[] = l(t('Add'), "node/add/announcement",
	  array('title' => t('Add a new announcement')));
		}
		
	if(node_access('update', $node)) {
$links[] = l(t('Edit'), "announcements/$node->nid/edit",
		array('title' => t('Edit Announcement ') . $node->title)); 

$links[] = l(t('Delete'), "announcements/$node->nid/delete",
		array('title' => t('Delete Announcement ') . $node->title)); 
		}
	}

	return $links;
}
	

announcement_settings

This is the implementation of hook_settings. This function provides an administrative interface for controlling various settings for the announcement module. (See http://api.drupal.org/api/4.7/function/hook_settings for more details.)

Note: This hook is not used in Drupal V5. (http://drupal.org/node/64279#hook-settings)

Return value
An array description, in the Drupal Forms API format, of the elements to render the settings interface.

Listing 9. Implementation of hook_settings
                
function announcement_settings() {
$form = array();
$form['announcement_block_max_list_count'] = array('#type' => 'textfield',
'#title'         => t('Maximum number of block announcements'),
'#default_value' => variable_get('announcement_block_max_list_count', 3),
'#description'   => t('The maximum number of items listed in the announcement block'),
'#required'      => FALSE, 
'#weight'        => 0
	);
 $form['announcement_display_classification'] = array('#type' => 'checkbox',
 '#title'         => t('Display additional announcement classification'),
 '#default_value' => variable_get('announcement_display_classification', 1),
 '#description'  => t('Insert the additional classification in the announcement modules'),
 '#required'      => FALSE, 
 '#weight'        => 0
	);
	return $form; 
}
	

announcement_form

This is the implementation of hook_form. This function is called to create the form that is displayed when one creates or edits an announcement. (See http://api.drupal.org/api/HEAD/function/hook_form for more details.)

Input parameter: $node
The node that is being created or edited
Return value
An array description, in the Drupal Forms API format, of the elements to render announcement form

Listing 10. Implementation of hook_form
                
function announcement_form(&$node) {
	
    if ($node->expiration_date == NULL) {
        $node->expiration_date = time() + (365 * 86400);
    }

    if ($node->publish_date == NULL) {
        $node->publish_date = time();
    }
	
    $form['title'] = array('#type' => 'textfield',
        '#title'         => t('Title'),
        '#default_value' => $node->title,
        '#description'   => t('Title of the announcement'),
        '#required'      => TRUE, 
        '#weight'        => 1
    );
	
    $form['publication'] = array('#type'=> 'fieldset',
        '#collapsible'   => FALSE,
        '#title'         => t('Publication dates'),
        '#weight'        => 5 
    );
	 
    $form['publication']['publish_date'] = array(
        '#prefix'        => '<div class="date_widget">',
        '#suffix'        => '</div>',
        '#type'          => 'date',
        '#title'         => t('Publication date'),
        '#default_value' => _announcement_unixtime2drupaldate($node->publish_date)
    );

    $form['publication']['expiration_date'] = array(
        '#prefix'        => '<div class="date_widget">',
        '#suffix'        => '</div>',	
        '#type'          => 'date',
        '#title'         => t('Expiration date'),
        '#default_value' => _announcement_unixtime2drupaldate($node->expiration_date)
    );
	
    $form['abstract'] = array('#type' => 'textarea',
		'#title'         => t('Abstract'),
		'#default_value' => $node->abstract,
		'#rows'          => 3,
		'#description'   => t('Short summary of the full announcement'),
		'#required'      => TRUE,
		'#weight'        => 9 
    );
	
    $form['body'] = array('#type' => 'textarea',
        '#title'         => t('Body'),
        '#default_value' => $node->body,
        '#description'   => t('Full content for the announcement which is shown ' .
                                 'with the abstract on the details page'),
        '#required'      => TRUE, 
        '#weight' => 10 
    );
	
    return $form;
}
	

announcement_all

This function creates the themed list of announcements. For the average user, only those announcements that have not expired are shown. If the user has access to edit announcements, then all are shown.

Return value
Formatted content showing all announcements

Listing 11. Function to show all announcements
                
function announcement_all() {
	
    if (user_access('edit announcement')) {
       $queryResult = db_query(
            "SELECT n.nid FROM node n INNER JOIN announcement a ON n.nid = a.nid " .
            "WHERE n.type='announcement' ORDER BY n.sticky DESC, A.publish_date DESC");
    }
    else {
        $queryResult = db_query(
            "SELECT n.nid FROM node n INNER JOIN announcement a ON n.nid = a.nid " .
            "WHERE n.type='announcement' AND a.expiration_date > %d " .
            "ORDER BY n.sticky DESC, a.publish_date DESC", date("U"));
	}
	
    $page_content = array();
    $page_content[] = "<h2 class='category'>Announcements</h2>";
    while ($announcement = db_fetch_object($queryResult)) {
        $announcement = node_load($announcement->nid);
        $announcement->url = url('announcements/' . $announcement->nid);
        $page_content[] = theme('announcement_compact', $announcement);
    }
	
    return implode('', $page_content);
}
	

announcement_view

This is the implementation of hook_view. This function allows the announcement module to add extra variables to any announcement nodes before they are rendered by the Drupal system. Here we insert the URL to the announcement detail into the announcement node object. (See http://api.drupal.org/api/HEAD/function/hook_view for more information.

Input parameter: $node
The node to be displayed.
Input parameter: $teaser
Whether a summary is being generated for display or the whole node.
Input parameter: $page
Whether the node is being displayed as a standalone page, i.e., the page title should not be displayed.
Return value
The modified node object.

Listing 12. Implementation hook_view
                
function announcement_view(&$node, $teaser = FALSE, $page = FALSE) {
    if ($page) {
        $node->url = url('announcements/' . $node->nid);
    }
}
	

announcement_validate

This is the implementation of hook_validate. This function is called after a user has submitted an creation or edit form. Here we check to ensure that the expiration date is after the publish date. (See http://api.drupal.org/api/HEAD/function/hook_validate for more details.)

Input parameter: $node
The node being validated

Listing 13. Implementation of hook_validate
                
function announcement_validate($node) {
   if ($node) {
      $publish_date    = _announcement_drupaldate2unixtime($node->publish_date);
      $expiration_date = _announcement_drupaldate2unixtime($node->expiration_date);
      if ($publish_date >= $expiration_date) {
         form_set_error('publish_date',    
           t('The publish date of an announcement must be before its expiration date.'));
      }
   }
} 
	

announcement_submit

This is the implementation of hook_submit. This function allows the announcement module to change the node object information prior to saving this data to the database. Here we convert the date values to integers and ensure the announcement is properly classified in the taxonomy. (See http://api.drupal.org/api/HEAD/function/hook_submit for more details.)

Input parameter: $node
The node being submitted to the database

Listing 14. Implementation of the hook_submit
                
function announcement_submit(&$node) {
    $node->publish_date    = _announcement_drupaldate2unixtime($node->publish_date);
    $node->expiration_date = _announcement_drupaldate2unixtime($node->expiration_date);
	
    $now = time();
    if($now > $node->publish_date && $now < $node->expiration_date) {
        $node->status = 1;
    }
    else {
        $node->status = 0;
    }
	
    $vocab = announcement_get_vocabulary_by_name('IBC');
    $term  = taxonomy_get_term_by_name('announcements');
    $node->taxonomy = _announcement_merge_tid($vocab->vid, 
                                              $term[0]->tid, 
                                              $node->taxonomy);
}
	

announcement_get_vocabulary_by_name

This helper function returns the vocabulary object given the vocabulary name.

Input parameter: $name
Name of the vocabulary to retrieve
Return value
Vocabulary object

Listing 15. Find a vocabulary by its name
                
function announcement_get_vocabulary_by_name ($name) {
	$results = db_query('SELECT * FROM {vocabulary} WHERE name = "%s"', $name);
	if (db_num_rows($results) > 0) {
	 	return db_fetch_object($results);
	}
	else {
		return null;
	}
}
	

_announcement_merge_tid

This local function, identified as such by the leading underscore in the function name, merges terms in a vocabulary

Input parameter: $vid
Vocabulary id
Input parameter: $tid
Term id
Input parameter: $taxonomy
Taxonomy in which the vocabulary exists
Return value
The updated taxonomy

Listing 16. Merge vocabulary terms
                
function _announcement_merge_tid($vid, $tid, $taxonomy) {
    $values = array_values($taxonomy[$vid]);     // get all tid values for vocabulary
    if (!in_array($tid, $values)) {              // if the tid is not there
        $taxonomy[] = $tid;                      // add it 
    }
    return $taxonomy;
}
	

announcement_load

This is the implementation of hook_load. This function allows the announcement module to add extra data to the announcement node object. Here we merging the associated date from the announcement table. (See http://api.drupal.org/api/HEAD/function/hook_load for more information.)

Input parameter: $node
The node being loaded from the database
Return value
Return any additional values from the database that will be merged into the node

Listing 17. Implementation of hook_load
                
function announcement_load(&$node) {
	$additions = db_fetch_object(db_query('SELECT * FROM {announcement} ' .
	                                      'WHERE nid = %d', $node->nid));
  	return $additions;
}
	

announcement_insert

This is the implementation of hook_insert. This function allows the announcement module to take action when a new node is being inserted in the database. Here we are inserting a new record into the announcement table using data found in the node object. (See http://api.drupal.org/api/HEAD/function/hook_insert for more details.)

Input parameter: $node
Node being inserted into the database

Listing 18. Implementation of hook_insert
                
function announcement_insert($node) {
	db_query("INSERT INTO {announcement} (nid, abstract, publish_date, expiration_date) " .
	         "VALUES (%d, '%s', '%d', '%d')", $node->nid, $node->abstract, 
	         $node->publish_date, $node->expiration_date);
	
} 
	

announcement_update

This is the implementation of hook_update. This function allows the announcement module to take action when an existing announcement node is being updated in the database. Here we perform our own database updates, such as putting information into the announcement table. (See http://api.drupal.org/api/HEAD/function/hook_update for more information.)

Input parameter: $node
The node being updated in the database

Listing 19. Implementation of hook_update
                
function announcement_update($node) {
	db_query("UPDATE {announcement} SET abstract='%s', publish_date = '%s', " .
	         "expiration_date = '%s' WHERE nid = %d", $node->abstract, 
	         $node->publish_date, $node->expiration_date, $node->nid);
} 
	

announcement_delete

This is the implementation of hook_delete. This function allows the announcement module to take action when an announcement node is being deleted from the database. (See http://api.drupal.org/api/HEAD/function/hook_delete for more information.)

Input parameter: $node
The node being deleted from the database

Listing 20. Implementation of hook_delete
                
function announcement_delete($node) {
  	db_query('DELETE FROM {announcement} WHERE nid = %d', $node->nid);
}
	

announcement_block

This is the implementation of hook_block. This function defines two blocks that are provided to the Drupal system. The site administrator can then use the Drupal interface to chose where to put these on the page if needed. The first block lists the recently updated announcements and the second uses the IBC vocabulary, described in Part 11, "Using taxonomies in Drupal," to list announcements by categories. (See http://api.drupal.org/api/HEAD/function/hook_block for more details.)

Input parameter: $op
The kind of information to retrieve about the announcement block.
Input parameter: $delta
Number of the block to return.
Input parameter: $edit
If $op is 'save', this variable contains the submitted block configuration form data.
Return value
If $op is 'list', it returns an array of arrays, each of which must define an info element describing the block. If $op is 'view', it returns an array which defines 'subject' and 'content' elements defining the block indexed by $delta.

Listing 21. Implementation of hook_block
                
function announcement_block($op = 'list', $delta = 0, $edit = array()) {
    global $user;
    if ($op == 'list') {
        $blocks[0]['info'] = t('Recently updated announcements');	
        $blocks[1]["info"] = t('List nodes in the IBC vocabulary');
        return $blocks;
    }
    else if ($op == 'view')	{
        $block	= array();
        switch ($delta) {
            case 0:
                $announcement_items	= array();
                if (user_access('access content')) {
                    $q = 'SELECT N.uid,N.nid,N.title,A.publish_date,N.status '.
                         'FROM {node} N JOIN {announcement} A USING(nid) '.
                         "WHERE N.type='announcement' ".
                         'AND N.status = 1 '.
                         'AND A.publish_date < %d ' .
                         'AND A.expiration_date > %d ' .
                         'ORDER BY A.publish_date DESC ';

                    $now = time();
                    $items = variable_get('announcement_block_max_list_count', 3);
                    $announcements = db_query_range($q, $now, $now, 0, $items);
                    while (db_num_rows($announcements) > 0 and 
                           $announcement = db_fetch_object($announcements)) {	
                        $announcement_items[] = $announcement;			
                    }
                }
                $block['subject'] = t('Announcements');
                $block['content'] = theme('announcement_block_list', 
                                          $announcement_items);
                break;
            case 1:
                if (user_access("access content")) {
                    $vocabulary = announcement_get_vocabulary_by_name('IBC');
                    $block["subject"]= t('IBC');
                    $block["content"]= announcement_vocab_vert($vocabulary->vid);
                }
        }
        return $block;
    }
}
	

announcement_vocab_vert

This function was adapted from the taxonomy_dhtml module to build the content to be displayed in a block of nodes classified in the vocabulary. It builds an array which holds all children of current term. It is necessary to build a proper or value in the HREF.

Input parameter: $vocabulary_id
ID of the vocabulary
Input parameter: $op
An operation that can be added to the URL of a node listed
Return value
Output for the display of the block

Listing 22. Displaying nodes classified by vocabulary terms
                
function announcement_vocab_vert($vocabulary_id, $op = NULL) {
    $tree = taxonomy_get_tree($vocabulary_id);
    foreach ($tree as $term) {
        $url = "taxonomy/term/$term->tid";
        if ($op) {
            $url .= "/$op";
        }
        $link = l(t($term->name), $url, array("title" => t($term->description)));
        $out .= _taxonomy_depth($term->depth, "&nbsp;")."- $link";
        $count = taxonomy_term_count_nodes($term->tid);
        if ($count) {
            $out .= " ($count)";
            $out .= _announcement_by_terms($term->tid);
        }
        else {
            $out .= " (0)";
        }
        $out .= "<br/>";
    }
    return $out;
}
	

_announcement_by_terms

This local function returns a themed list of link to announcements for a given vocabulary term.

Input parameter: $tid
The ID of the term to be rendered
Return value
The rendered term for output

Listing 23. Output the display of a term
                
function _announcement_by_terms($tid) {
	$result = '';
	$tids   = array( $tid );
	$nodes  = taxonomy_select_nodes($tids, 'or', 0, FALSE);
	while ($r = db_fetch_object($nodes)) {
		$url = "announcements/". $r->nid;
		$result .= "
&nbsp; - &nbsp;" . l($r->title, $url, array("title" => t($r->title))); } return $result; }

announcement_nodeapi

This is the implementation of hook_nodeapi. This function allows the announcement module to take action when Drupal recognizes a particular action is being performed. Here, if the current Drupal operation is "update index", we add the abstract of this announcement to the search index. (See http://api.drupal.org/api/HEAD/function/hook_nodeapi for more information.)

Input parameter: $node
The node being processed
Input parameter: $op
The action on the node, such as "delete", "update index"
Return value
This is dependent on the operation, but in our case we return the text that needs to be indexed for this node.

Listing 24. Implementation of hook_nodeapi
                
function announcement_nodeapi(&$node, $op) {
    switch ($op) {
        case 'update index':
            if ($node->type == 'announcement') {
                $text = ''; 
                $q = db_query(
                    'SELECT a.abstract FROM node n LEFT JOIN announcement a ON '.
                    'n.nid = a.nid WHERE n.nid = %d', $node->nid);
                if ($r = db_fetch_object($q)) {
                    $text = $r->abstract;
                }
                return $text;
            }
    }
}
	

Theming functions

The following functions provide a method by which a theme designer can override how data generated by this module is presented. There are two classes of theme functions:

theme_announcement
Generic theme function that will work for all themes and theme engines
phptemplate_announcement
Theme function that will be used by the phptemplate engine

For the sake of these articles we did not insert any code to structure data into the default theme functions. Instead we concentrated on showing how the overriding phptemplate theme functions structure the data. Usually, these phptemplate functions are placed within your theme directory's phptemplate.php file.


Listing 25. Theme functions
                
function theme_announcement($announcement) {
	return '';
}

function theme_announcement_compact($announcement) {
	return '';
}

function theme_announcement_block_list($announcement_list) {
	return '';
}

function phptemplate_announcement($announcement) {
 return _theme_phptemplate_announcement($announcement, 'announcement');
}

function phptemplate_announcement_compact($announcement) {
 return _theme_phptemplate_announcement
 ($announcement, 'announcement_compact');
}

function phptemplate_announcement_block_list($announcement_list) {
 global $user;
	return _phptemplate_callback('announcement_block_list', 
	  array('announcements' => $announcement_list, 
	          'user'=> $user));	
}

function _theme_phptemplate_announcement
($announcement, $announcement_template) {
	$expired = FALSE;
	if ($announcement->expiration_date < time()) {
	$expired = TRUE;		
	}
	$variables = array(
'title'      => $announcement->title,
'body'    => $announcement->body,
'links'     => $announcement->links ? theme('links', $announcement->links) : '',
'abstract'  => $announcement->abstract,
'published' => format_date($announcement->publish_date,'custom','j M, Y'),
'expires'   => format_date($announcement->expiration_date,'custom','j M, Y'), 
'expired'  => $expired,
'node'      => $announcement
	);
return _phptemplate_callback($announcement_template, $variables);	
}
	

_announcement_drupaldate2unixtime

This is a local utility function for converting a structured data array containing a date into an integer representation.

Input parameter: $drupal_date
A representation of a date in an array indexed by day, month, and year
Return value
An integer representation of the date

Listing 26. Converting dates from Drupal internal representation to an integer
                
function _announcement_drupaldate2unixtime($drupal_date) {

	$year  = $drupal_date["year"];
	$month = $drupal_date["month"];
	$day   = $drupal_date["day"];
	
	return mktime(0,0,0, (int)$month, (int)$day, (int)$year);
}
	

_announcement_unixtime2drupaldate

This is a local utility function for converting a integer representation of the date to a structured data array.

Input parameter: $unixtime
An integer representation of the date
Return value
A representation of a date in an array indexed by day, month, and year

Listing 27. Converting dates from an integer to a Drupal internal representation
                
function _announcement_unixtime2drupaldate($unixtime) {
    return array('day'   => format_date($unixtime, 'custom', 'j'),
                 'month' => format_date($unixtime, 'custom', 'n'),
                 'year'  => format_date($unixtime, 'custom', 'Y'));
	
}
	

Summary

This article presents the announcement module described in our series. As well as providing the actual file as a download, each function is described and references to more information about the Drupal hook functions used are provided. We hope this article answers some of the questions we've been asked regarding the announcement module source.

The next article wraps up the series with a recap of lessons learned and a look forward, discussing where Drupal is going with version 5.



Download

DescriptionNameSizeDownload method
announcement module source codeannouncement.module24KB HTTP

Information about download methods


Resources

Learn

Get products and technologies

Discuss

About the authors

Alister's photo

Alister Lewis-Bowen is a senior software engineer in IBM's Internet Technology Group. He has worked on Internet and Web technologies as an IBM UK employee since 1993. Alister was brought to the U.S. to work on the Web sites for the IBM-sponsored sports events, then as senior Webmaster for ibm.com. He is currently helping create semantic Web prototypes.

Louie's photo

Louis Weitzman is a senior software engineer in IBM's Internet Technology Group. For 30 years he has worked at the intersection of design and computation. He helped develop an XML, fragment-based content management system in use by ibm.com, and currently is involved with bringing the design process to emerging projects.

Stephen's photo

Stephen Evanchik is a software engineer in IBM's Internet Technology Group. He has been a contributor to many open source software projects, the most notable being his IBM TrackPoint driver in the Linux kernel. Stephen is currently working with emerging semantic Web technologies.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Sample IT projects, Open source
ArticleID=201812
ArticleTitle=Using open source software to design, develop, and deploy a collaborative Web site, Part 14: The announcement module source code
publish-date=03132007
author1-email=alister.lewisbowen@gmail.com
author1-email-cc=
author2-email=louis.weitzman@gmail.com
author2-email-cc=
author3-email=evanchsa@gmail.com
author3-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).