Tech

Creating Custom Triggers in Drupal

27 comments

So after playing around for several hours tonight trying to build my own custom trigger I think I've finally figured it out. I thought I'd post it here for reference.

Though triggers are included in core in Drupal 6 it seems they're very poorly documented. The extent of the documentation I could find was on this trigger page in the handbook. Pro Drupal Development also has a chapter on it but unfortunately isn't really explicit enough for me with some parts.

Disclaimer: I don't really know what I'm doing, so please let me know if I've done anything wrong.

Prereqs:

  • Drupal 6
  • The triggers module should be enabled.
  • A commenter also pointed out that the triggerunlock module is also necessary. If you have your own custom actions this isn't needed though.
  • If you're following this example, you'll also need to CCK type called 'script'.

What I want to do is create a custom trigger in my module. Let's say I want to execute a custom action on my server whenever a node of a type script (as defined in the 'script' module) is created. The first step is to define hook_hook_info.

/**
 * Implementation of hook_menu_alter().
 */
function script_hook_info() {
  return array(
    'script' => array(
      'script' => array(
        'insert' => array(
          'runs when' => t('After script is created'),
        ),
      ),
    ),
  );
}

This will create a new tab in my triggers page that will be named after the name of my module as set in my .info file.

Two things I still need to do to make sure this trigger actually does anything... define hook_script and call it from a module_invoke or module_invoke_all whenever the triggering event happens and call the actions using actions_do(). Since these hooks should be executed on node insert I'll need to use hook_nodeapi().

/**
 * Implementation of hook_nodeapi().
 */
function script_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  switch ($op) {
    case 'insert':
      module_invoke_all('script', 'insert', $node);
      break;
  }
}

The second aspect (calling the associated actions) requires an implementation of hook_script() (the alternative being to just replace the module_invoke line with this functions body.

/**
 * Implementation of hook_script().
 */
function script_script($op, $node) {
  $aids = _trigger_get_hook_aids('script', $op);
  $context = array(
    'hook' => 'script',
    'op' => $op,
    'node' => $node,
  );
  actions_do(array_keys($aids), $node, $context);
}

The first line in the function is a call to _trigger_get_hook_aids which returns the list of action ID's that have been assigned to this trigger. This is a private function, but seems to be the only way to get the list of actions. The last line in the function calls actions_do(), which processes all the actions assigned to this trigger.

In this particular example you'll need a custom content type called 'script'.

And that's all there is to creating your own custom triggers.

Alternatively, I don't need to create a hook for the trigger, instead I could just piggyback off of the nodeapi hook, since this is a node operation.

The hook_hook_info looks a little different with:

function script_hook_info() {
  $info['script'] = array(
    'nodeapi' => array(
      'script' => array(
        'runs when' => t('After script is created'),
      ),
    ),
  );
  return $info;
}

And then just a slight change to hook_script() to change the hook from 'script' to 'nodeapi'.

/**
 * Implementation of hook_script().
 */
function script_script($op, $node) {
  $aids = _trigger_get_hook_aids('nodeapi', $op);
  $context = array(
    'hook' => 'nodeapi',
    'op' => $op,
    'node' => $node,
  );
  actions_do(array_keys($aids), $node, $context);
}

One other thing that was bugging me with triggers was the inability to only use them on specific cck types. There's no way to setup a trigger to only get called when an event happens to a single content type (without using the workflow module, which I found has some problems using variables in actions). Put an "if ($node->type == 'script')" somewhere appropriate, in my code I'd wrap that around the call to module_invoke_all(), for example:

function script_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  switch ($op) {
    case 'insert':
      if ($node->type == 'script') {
        module_invoke_all('script', 'insert', $node);
      }
      break;
  }
}

----

After writing this I found this blog post which also looks quite useful.

I've made some updates to this example, so hopefully it will work for everyone now.

You can download the example module here.

Blog upgrade

3 comments

Decided to spend a bit of time tonight and upgrade my blog to drupal. Some of the old "perma" links probably won't work (but I've tried to create proper aliases to any posts that had been linked to externally), and you may get a bit of funkiness in your feed if you've subscribed, but hopefully not. I think this is the 4th blogging platform I've used in the almost 4 years that I've had this blog.

The last being wordpress (w/ akismet, which caught me a pretty 250,000+ spam comments :) ). Not that I have anything against using wordpress, but I wanted to start doing a bit more development again, and tbh, developing for wordpress has always been much more painful for me than developing for drupal.

Please let me know if you have any problems. I'm going to be trying out mollom to handle comment spam for a while instead of akismet.

geek interaction

1 comment

over the past year (actually.. pretty much since northern voice last year) i've gone to increasingly many "geek" conferences and events. most being in vancouver. you'll see the same faces at many of these events. you get to know who does what, blogger, photographer, developer... maybe you even read some of their blogs or follow them on twitter, jaiku, or flickr. through these ad hoc interactions you get to know the person a little bit. however, you've never really talked to them.

a quote i saw recently i think really fits

i'm not antisocial i'm just shy. you can talk to me!

maybe you've met them, exchanged a few words, but your online interaction as acquaintances far exceeds your real life interaction. so even though people "know" you and you "know" them (through the online world) you're still a bit afraid that... well... maybe they /are/ antisocial. of course, they aren't. so far i haven't met one person in this community that isn't really nice. even when they seem "too cool" or just plain snobby at first, odds are they're just a bit shy and might even /want/ you to talk to them and say hey.

this brings me to another thing i've noticed... ultra-micro celebrities. people who's blogs i read but who i've *never* actually talked to before. they write well, maybe personal blogs, and generally on topics i'm interested in. i see them at these events and feel almost a bit like a stalker. like i know this person, but they don't know me. and then when i do meet them, do i pretend like i don't know who they are? or be like "hey, you've got a great blog... i totally stalk you in my google reader."

DrupalCon Boston 2008 - Some Sessions

no comments

Just for fun... I thought I'd put up a list of a few of the DrupalCon sessions I'm excited about. I'm going to try to blog daily and maybe post photos daily too. I was also thinking... since it seems to be getting popular to take pictures of people taking pictures, I'm gonna try and take as many pictures of people taking pictures of people taking pictures as possible.

Monday 9:30 - Drupal Multimedia (Presenters: Aaron Winborn, James Walker, Darrel O'Pry, Nathan Haug) - "This session will guide you through the steps necessary to build image, video, and audio into your sites."

Monday 1:30 - Mapping business requirements to Drupal modules: a gap-fit process (Presenter: Boris Mann) - "Join me to talk through a process of building repeatable processes in selecting modules and implementing a gap-fit analysis of which modules your new Drupal project is going to need."

Monday 3:30 - OpenID and Identity in Drupal: the future of user.module (Presenter: James Walker) - "This session will not be why OpenID, but rather what’s next with OpenID."

Monday afternoon NowPublic will be at the job fair, so drop by and say hi! :)

Tuesday 9:30 - The Future of Fields (Presenters: Barry Jaspan (bjaspan), Nedjo Rogers (nedjo), Karen Stevenson (karenS), Larry Garfield)

Wednesday 9:00 - SimpleTest: Because clicking on forms is for suckers (Presenters: Angela Byron (webchick), Rok Zlender, Karoly Negyesi (chx), Jimmy Berry (boombatower))

There's plenty more... but I think this is a good start.

And now I'm off to the airport.

EDIT:

Missed one!

Wednesday 9:45 - Practical jQuery - how to act like you're JavaScript-smart (Presenter: Dimitri Gaskin) - Dimitri is Drupal's 12 year old developer. I'm really looking forward to watching this presentation.

Northern Voice 2008 - The feeds

3 comments

Probably would have been more useful to post this before the conference started. Anyway, I decided to try to search out all active Northern Voice feeds to see what I can find, where things are, and how information is disseminated as the conference is in progress.

The focus at Northern Voice / Moosecamp is more or less about blogging, social media, and photography. Search flickr, and find photos of the talk you're currently attending, taken maybe 5 minutes ago. People live blogging the live blogging session, and micro-blogging about people blogging about people blogging at the conference. If you can follow all this, you can get your all your conference sessions and more... all without walking out your front door.

Here's the live feeds I've found (I'm sure I've missed some):

Tags: nv08 northernvoice

Consolidating information is something that facebook has been able to do very well. Photos, groups, events, the wall, inbox, status updates, notes, videos, links, etc. All in one place, easily accessible. In the list above, everything there is more useful that the facebook equivalent, IMHO, however, the ability to link all of this information together is almost as useful as the information itself.

Do tools exist that can link this stuff together, on an event-by-event basis? Or is this going to be my new pet project?

Btw, congratulations to the Duane Storey for winning the Vancouver Blogger competition.