Hook_nodeapi to the Rescue

The boss just shot you an email. He wants the user’s profile to get updated whenever that user creates a story node. He also wants to automatically post badges to a user’s profile when their story has been viewed a certain number of times. And you can’t use the statistics module, because it killed his family. Can you have it by this afternoon?

No problem. Hook_nodeapi’s got this.

Hook_nodeapi is a hook you can put in a custom module that will fire your code when certain things happen to nodes. If a node is created, updated, deleted, viewed, validated, shows up in search results, shows up in an RSS feed, has a revision deleted or a few other things hook_nodeapi will let you know.

Let’s build our module from the ground up to get a good idea of how to use hook_nodeapi.

Creating a Quick Custom Module

Drupal.org has a great tutorial on creating custom modules. The short version is that we need to create a directory with an .info file and a .module file.

We’ll call the module badgesexample. Create a badges example directory and save this as badgesexample.info:

name = Badges Example description = Update user profile and post badges based on story nodes core = 6.x

Now we need our module. It isn't a front-facing module so it won't need a menu or any pages. Here's the beginning of our badgesexample.module:

<?php /** * Implementation of hook_nodeapi */ function badgesexample_nodeapi(&$node, $op, $teaser, $page) { if ($node->type == "story") { switch ($op) { case 'insert': // What to do when a story node is created break; case 'view': // What do to when a story node is viewed break; } } }

What we're doing is checking to see if the node is a Story in line 6. Then if it is, we hit the switch statement and do things if a story is being created ('insert' in line 8) or viewed ('view' in line 11). There are other operations you can use too. Check the hook_nodeapi documentation for a complete list.

Tracking our Stories and Views

So to track the number of stories in the user's profile and the number of views each story gets we add two fields, one to the profile content type and one to the story content type:

Profile content type

  • Label: Number of stories
  • Field name: field_num_stories
  • Type: integer

Story content type

  • Label: Number of story views
  • Field name: field_num_views
  • Type: integer

Here's our updated module to track the number of stories in the user's profile:

<?php /** * Implementation of hook_nodeapi */ function badgesexample_nodeapi(&$node, $op, $teaser, $page) { if ($node->type == "story") { switch ($op) { case 'insert': global $user // Pull the $user variable into scope $profile_node = content_profile_load('profile', $user->uid); // Load the content profile node $profile_node->field_num_stories[0]['value'] = profile_node->field_num_stories[0]['value'] + 1; break; case 'view': // What do to when a story node is viewed break; } } }

First we brought the $user variable into scope and used it to load the current user's profile node. This example assumes that the content type you are using for content_profile is called profile.

Then we added one to the Number of Stories field.

Finishing Up

Now let's finish up our module by telling it what to do when someone views it:

<?php /** * Implementation of hook_nodeapi */ function badgesexample_nodeapi(&$node, $op, $teaser, $page) { if ($node->type == "story") { switch ($op) { case 'insert': global $user // Pull the $user variable into scope $profile_node = content_profile_load('profile', $user->uid); // Load the content profile node $profile_node->field_num_stories[0]['value'] = profile_node->field_num_stories[0]['value'] + 1; break; case 'view': $node->field_num_views[0]['value'] = $node->field_num_views[0]['value'] + 1; break; } } }

In hook_nodeapi you already have access to the $node variable so all we had to do was to add 1 to it.

To make your boss happy all you have to do is make a preprocess function that counts the number of views and displays certain badges at various thresholds. Or if it's 4:45 and he needs it now you can tuck some logic into node-profile.tpl.php until you get a change to do it right. We won't judge you.

Now when he asks to make something happen when a user deletes a story, or updates their profile information you know how to make it happen.