A lot of people have written me to ask how I generate the Drupal categories block on this website. There are probably a lot of different ways to generate a Drupal categories block these days, but the way I do it is with the PHP script shown below. (Sorry, I'm too lazy to look to see if there is a new Drupal categories block module/solution; I'm pretty content with what I have.)
I run this PHP script periodically during the day to generate the Drupal categories data (from a Linux crontab entry), in the output XHTML format I want, and then include this in my Drupal "Categories" block.
I run this script only once a day because at this point the information isn't that relevant. It doesn't matter too much to readers whether I have 350 blog posts about Java or 375, the fact is there are a lot of them. And from a performance perspective, I'd much rather run the script below just once and then include that content into my Drupal categories block; that's a much less expensive process than running this query every time a page is requested.
My Drupal categories block PHP script
Without any further ado, here is the source code for my Drupal categories block PHP script:
#!/usr/local/bin/php -q
#
# Name: make-drupal-categories.php
# Description: A Drupal "make categories" PHP script.
#
# Copyright 2010 Alvin Alexander, http://devdaily.com
# This script is released under the Creative Commons Attribution-ShareAlike 3.0 License.
# See http://creativecommons.org/licenses/by-sa/3.0/ for more license information.
#
<?php
class Category
{
// combined info from term_data and term_node
var $name;
var $display_name;
var $description;
var $num_posts;
function Category($name, $num_posts, $description)
{
$this->name = $name;
$this->num_posts = $num_posts;
$this->description = $description;
# do a little work to fix category names that have spaces, or where i want to change
# their display name
$this->display_name = str_replace('-', ' ', $name);
if ($this->display_name === "ooa ood") $this->display_name = "ooa/ood";
if ($this->display_name === "jfc swing") $this->display_name = "swing";
if ($this->display_name === "linux unix") $this->display_name = "linux/unix";
if ($this->display_name === "mac os x") $this->display_name = "mac os x";
if ($this->display_name === "page 1") $this->display_name = "page 1";
if ($this->display_name === "product review") $this->display_name = "product reviews";
if ($this->display_name === "software dev") $this->display_name = "software dev";
if ($this->name === "mac-os-x") $this->name = "osx";
if ($this->name === "linux-unix") $this->name = "linux";
}
function print_rec()
{
if ($this->name === "page-1") return;
if ($this->name === "product-review") return;
if ($this->name === "software-dev") return;
printf(" <li class=\"leaf\"><a href=\"/%s\">%s <span class=\"category-count\">(%d)</span></a></li>\n",
$this->name,
$this->display_name,
$this->num_posts);
}
}
function print_header()
{
printf("<ul class=\"menu\">\n");
}
function print_footer()
{
printf("</ul>\n");
}
#--------#
# MAIN #
#--------#
// (1) connect to the database
$link = mysql_connect('localhost', 'MYSQL_USERNAME', 'MYSQL_PASSWORD');
if (!$link) {
die('Could not connect: ' . mysql_error());
}
// the name of your drupal database
mysql_select_db ('drupal');
// (2) create a list of blog objects from the url_alias table
$query = "select td.name, count(tn.nid) as num_posts " .
"from term_node as tn, term_data as td " .
"where tn.tid in (select tid from term_data where vid=1 order by tid) " .
"and tn.tid = td.tid " .
"group by tn.tid " .
"order by td.name ";
$result = mysql_query($query);
$categories = array();
while ($row = mysql_fetch_array($result, MYSQL_BOTH))
{
# all i have now are 'name' and 'num_posts'
$cat = new Category($row[0], $row[1], '');
array_push($categories,$cat);
}
// (X) free up the database resources
mysql_free_result($result);
mysql_close($link);
// print the output
print_header();
$count = count($categories);
for ($i = 0; $i < $count; $i++)
{
$curr_cat = $categories[$i];
$curr_cat->print_rec();
}
print_footer();
?>
Drupal categories block script - discussion
I'm not going to discuss too many of the details here, unless people ask a lot of questions. But in short, I run this script something like this once a day:
make-drupal-categories.php > categories.html
And then I include that HTML output file content into my Drupal categories block, something like this:
<? include "categories.html" ?>
If you haven't used PHP in a Drupal block before, I discuss this in my Custom Drupal PHP block tutorial.
As mentioned, I think including this HTML file on every page request is a much cheaper hit on the system than running that script on every page hit, though there are Drupal caching mechanisms that I don't know at this point.
Drupal categories block script - summary
I hope this Drupal categories block source code and discussion has been helpful. If you have any questions or comments, just use the Comments form below.

