Generating the block content
The next step in this tutorial is to generate the content of the block. This will involve accessing the Drupal 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.
To tell Drupal what content we want in the block, we use the 'view' operation of hook_block(). So, we'll need to add some code to our previously-defined onthisdate_block() function.
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.
<?php
/**
* 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) {
if ($op == "list") {
// Generate listing of blocks from this module, for the admin/block page
$block = array();
$block[0]["info"] = t('On This Date');
return $block;
}
else if ($op == 'view') {
// Generate 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
// more coming...
}
}
?>If the site you are running on might not have content for the date exactly one week ago, you might want to change the end time to the following, in order to show something in the block:
$end_time = time(); // get all posts from one week ago to the presentThe 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 types 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).
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) with our SQL query:
<?php
$query = "SELECT nid, title, created FROM " .
"{node} WHERE created >= '%d' " .
" AND created <= '%d'";
$query_result = db_query($query, $start_time, $end_time);
?>This illustrates how to do a "safe" query in Drupal: create your query string with "placeholders" such as %d and %s, and then pass variables into the
db_query() function to fill the "placeholders". This type of practice prevents SQL injection hacks, especially when user-generated content is used in a query. Another Drupal-specific custom to note here is that table names in Drupal database queries are always enclosed in curly braces, such as {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. Finally, note that in this example, we are not being careful about access permissions for nodes. Normally, all queries on nodes should employ the db_rewrite_sql() function, which makes sure the user viewing the page has permission to see each node that is returned, but this is beyond the scope of this tutorial.
Now, we'll use db_fetch_object() to look at the individual records returned by the query. For each node that we found, we'll generate a link to the node, with the node's title as the link text:
<?php
// content variable that will be returned for display
$block_content = '';
while ($links = db_fetch_object($query_result)) {
$block_content .= l($links->title, 'node/'. $links->nid) .'<br />';
}
?>Notice the actual link is created by the l() function.
l generates <a href="link"> links from Drupal paths, adjusting the URL to the installation's URL configuration of either clean URLS: http://(sitename)/node/2 or not http://(sitename)/?q=node/2 (the path to any node is always "node/#", where # is the ID number of the node).
Finally, we need to return the content we just generated to Drupal for display:
<?php
// check to see if there was any content before returning
// the block view
if ($block_content == '') {
// no content from a week ago
$block['subject'] = 'On This Date';
$block['content'] = 'Sorry No Content';
return $block;
}
// set up the block
$block = array();
$block['subject'] = 'On This Date';
$block['content'] = $block_content;
return $block;
?>We return an array that has 'subject' and 'content' elements, which is what Drupal expects from a block function. If you do not include both of these, the block will not render properly.
The example above assumes that if there is no content on the given date one week ago, you want the block to say "Sorry No Content". You may choose, instead, to simply omit the block completely if there are no results. To do that, you substitute this code into the appropriate section above:
if ($block_content == '') {
/* No content from a week ago. If we return nothing, the block
* doesn't show, which is what we want.
*/
return;
}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. An even better practice in Drupal is to make your module's output "themeable". 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:
<?php
function onthisdate_block($op='list', $delta=0) {
if ($op == "list") {
// Generate listing of blocks from this module, for the admin/block page
$block = array();
$block[0]["info"] = t('On This Date');
return $block;
}
else if ($op == 'view') {
// Generate 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'";
$query_result = db_query($query, $start_time, $end_time);
while ($links = db_fetch_object($query_result)) {
$block_content .= l($links->title, 'node/'.$links->nid) . '<br />';
}
// check to see if there was any content before returning
// the block view
if ($block_content == '') {
// no content from a week ago
$block['subject'] = 'On This Date';
$block['content'] = 'Sorry No Content';
return $block;
}
// set up the block
$block['subject'] = 'On This Date';
$block['content'] = $block_content;
return $block;
}
} // end onthisdate_block
?>Our module is now functional (although it would be better to make the output "themeable", we're ignoring that in this tutorial) - we can install, enable and test it (see next tutorial page).

Use switch/case instead of if/else if
If we have several choices for $op: list, view, save, configure, it might be easier to use a switch/case structure instead of if/else if
for example
switch ($op) {
case "list":
// Generate listing of blocks from this module, for the admin/block page
$block = array();
$block[0]["info"] = t('On This Date');
return $block;
break;
case "view":
// Generate 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']);
... // more code here
break;
case "save":
... // some code here
break;
case "configure":
... // some code here
break;
}
Don't forget to put in the break; at the end of each case block.