Main topic described: Creating content through blocks
Drupal hook described: hook_block

Now, we need to generate the 'onthisdate' content for the block. Here we'll demonstrate a basic way to access the database.

Our goal is to get a list of content (stored as "nodes" in the database) created a week ago. Specifically, we want the content created between midnight and 11:59pm on the day one week ago. When a node is first created, the time of creation is stored in the database. We'll use this database field to find our data.

First, we need to calculate the time (in seconds since epoch start, see http://www.php.net/manual/en/function.time.php for more information on time format) for midnight a week ago, and 11:59pm a week ago. This part of the code is Drupal independent, see the PHP website (http://php.net/) for more details.


/**
 * Generate HTML for the onthisdate block
 * @param op the operation from the URL
 * @param delta offset
 * @returns block HTML 
 */
function onthisdate_block($op='list', $delta=0) {

  // listing of blocks, such as on the admin/block page
  if ($op == "list") {
    $block[0]["info"] = t('On This Date');
    return $block;
  } 
  else if ($op == 'view') {

    // our block content
    // Get today's date
    $today = getdate();

    // calculate midnight one week ago
    $start_time = mktime(0, 0, 0,
                         $today['mon'], ($today['mday'] - 7), $today['year']);

    // we want items that occur only on the day in question, so   
    // calculate 1 day
    $end_time = $start_time + 86400;  
    // 60 * 60 * 24 = 86400 seconds in a day
    ...
  }
}

The next step is the SQL statement that will retrieve the content we'd like to display from the database. We're selecting content from the node table, which is the central table for Drupal content. We'll get all sorts of content type with this query: blog entries, forum posts, etc. For this tutorial, this is okay. For a real module, you would adjust the SQL statement to select specific types of content (by adding the 'type' column and a WHERE clause checking the 'type' column).

Note: the table name is enclosed in curly braces: {node}. This is necessary so that your module will support database table name prefixes. You can find more information on the Drupal website by reading the Table Prefix (and sharing tables across instances) page in the Drupal handbook. Also note that we use placeholders in the query for security:


$query = "SELECT nid, title, created FROM {node} WHERE created >= %d AND created <= %d";

Drupal uses database helper functions to perform database queries. This means that, for the most part, you can write your database SQL statement and not worry about the backend connections.

We'll use db_query() to get the records (i.e. the database rows) that match our SQL query, and db_fetch_object() to look at the individual records:

  // get the links 
  $queryResult =  db_query($query, $start_time, $end_time);

  // content variable that will be returned for display    
  $block_content = '';  
  while ($links = db_fetch_object($queryResult)) { 
    $block_content .=  l($links->title, 'node/' . $links->nid) . '<br />';
  }

  // check to see if there was any content before setting up
  //  the block  
  if ($block_content == '') {    
    /* No content from a week ago.  If we return nothing, the block   
     * doesn't show, which is what we want. */
    return;
  }

  // set up the block  
  $block['subject'] = 'On This Date';  
  $block['content'] = $block_content;
  return $block;
}

Notice the actual URL is enclosed in the l() function. l generates <a href="link"> links, adjusting the URL to the installation's URL configuration of either clean URLS: http://(sitename)/node/2 or not http://(sitename)/?q=node/2

Also, we return an array that has 'subject' and 'content' elements. This is what Drupal expects from a block function. If you do not include both of these, the block will not render properly.

You may also notice the bad coding practice of combining content with layout. If you are writing a module for others to use, you will want to provide an easy way for others (in particular, non-programmers) to adjust the content's layout. An easy way to do this is to include a class attribute in your link, or surround the HTML with a <div> tag with a module specific CSS class and not necessarily include the <br /> at the end of the link. A more comprehensive way to do this is to make your module's output "themeable" (note: the guide linked to there is for Drupal 6! Most of it also applies to Drupal 5, except that you do not have to use hook_theme() to register your theme functions, and you should use the "theme functions" method rather than the "template files" method to define the default behavior). Let's ignore this for now, but be aware of this issue when writing modules that others will use.

Putting it all together, our block function at this point looks like this:


function onthisdate_block($op='list', $delta=0) {
  // listing of blocks, such as on the admin/block page
  if ($op == "list") {
    $block[0]["info"] = t("On This Date");
    return $block;
  } 
  else if ($op == 'view') {
  // our block content
    // content variable that will be returned for display
    $block_content = '';

    // Get today's date
    $today = getdate();

    // calculate midnight one week ago
    $start_time = mktime(0, 0, 0,$today['mon'],
                               ($today['mday'] - 7), $today['year']);

    // we want items that occur only on the day in question, so 
    //calculate 1 day
    $end_time = $start_time + 86400;
    // 60 * 60 * 24 = 86400 seconds in a day

    $query = "SELECT nid, title, created FROM {node} WHERE created >= %d AND created < %d";

    // get the links
    $queryResult =  db_query($query, $start_time, $end_time);
    while ($links = db_fetch_object($queryResult)) {
      $block_content .= l($links->title, 'node/'.$links->nid) . '<br />';
    }
    // check to see if there was any content before setting up the block
    if ($block_content == '') {
      // no content from a week ago, return nothing.
      return;
    }
    // set up the block
    $block['subject'] = 'On This Date';
    $block['content'] = $block_content;
    return $block;
  }
}

Add the code above to your module file. Our module is now functional - we can install, enable and test it. (But just as a reminder... you should make your module's output "themeable" -- note that the guide linked to there is for Drupal 6! Most of it also applies to Drupal 5, except that you do not have to use hook_theme() to register your theme functions, and you should use the "theme functions" method rather than the "template files" method to define the default behavior.)