How to invoke a new hook in a Drupal module (and add yourself to a round of beer)

So, you want to allow other modules to hook into your own module. You may have implemented hooks that other modules provide, but does invoking your own hook for a module seem like a dark art? It is as simple as calling one function in your module. All will be revealed shortly, but first, lets look at why you would want to invoke your own hook.

What is invoking a hook?

When you invoke a hook, you are registering a new hook with Drupal that allows other modules to implement and therefore interact with your module. You are providing hook in points in your module which say to other modules “here is a point where you can inject your own data or extend my module”.

Why invoke hooks?

The hook system is at the heart of what makes Drupal powerful. All modules will use hooks to interact with the rest of the Drupal system. By invoking your own hook, you are making your module more powerful and useful because you are allowing other modules to extend it or change its data in some way. If no module invoked hooks, there would be no hooks for you to implement! If it still does not make sense, don’t worry, as the best way to understand it is with an example.

Beer round example

Let’s take a really simple example. Imagine you have a module with some code which returns a list of people included in a round of beer. And then you want to invoke your own hook so that other modules can add to the list of names that are part of the beer round.

Let’s set the module up before invoking the hook. The module is called beer_round. In beer_round.module you firstly need to implement hook_menu() to define the path where we can see the list of names for the beer round.

  1. /**
  2.  * Implements hook_menu.
  3.  */
  4. function beer_round_menu() {
  5. $items = array();
  6.  
  7. $items['beer'] = array(
  8. 'title' => 'Beer round',
  9. 'page callback' => 'beer_round_callback',
  10. 'access arguments' => array('access content'),
  11. 'type' => MENU_CALLBACK,
  12. );
  13.  
  14. return $items;
  15. }

This snippet simply means, when the user goes to the path beer, call the callback function called beer_round_callback(). Anyone who has the access content permission has the necessary permissions to view this page.

Next you need to define the callback function.

  1. /**
  2.  * List of people included in a round of beer.
  3.  */
  4. function beer_round_callback() {
  5. $round = array('Dave', 'Paolo', 'Andrew', 'Mat', 'Paula', 'Mihhail', 'Pete', 'Dima', 'Bhavna', 'Laura', 'Steve', 'San', 'Nick');
  6. $output = theme('item_list', array('items' => $round));
  7.  
  8. return $output;
  9. }

This contains an array of names of people who are part of the beer round. You then pass that array into the theme() function, which will convert it into an unordered list. If you now hit the path beer, you will see the list of names.

Names that are in the beer round

Now it is time to invoke a new hook. To invoke a new hook, all you need to do is call module_invoke_all() and pass in the name of the hook. We will call the hook beer_round. So you will call module_invoke_all(‘beer_round’) and add the result to the array of people in the round.

  1. /**
  2.  * List of people included in a round of beer.
  3.  */
  4. function beer_round_callback() {
  5. $round = array('Dave', 'Paolo', 'Andrew', 'Mat', 'Paula', 'Mihhail', 'Pete', 'Dima', 'Bhavna', 'Laura', 'Steve', 'San', 'Nick');
  6. $round_more = module_invoke_all('beer_round');
  7. $round_all = array_merge($round, $round_more);
  8. $output = theme('item_list', array('items' => $round_all));
  9.  
  10. return $output;
  11. }

Drupal will check every module to see if hook_beer_round has been implemented. If it has, the data the modules provide will be added to $round_more, which will be an array. If two modules implement hook_beer_round(), the array will contain two elements. So now we have two arrays, the original array of people in the beer round, and the additional people added via the hook. So merge the two together with array_merge(), and you have the full round.

To see this in action, implement hook_beer_round() in another module. I have a module called ‘blair’ where I will add myself to the beer round.

My implementation of hook_beer_round is:

  1. /**
  2.  * Implements hook_beer_round();
  3.  */
  4. function blair_beer_round() {
  5.  return 'Blair';
  6. }

Now if you reload the beer page, you will see that my name has been added.

Blair added to the beer round after implementing hook_beer_round

That is all there is to invoking a hook! This is a very simple example to get you started. I will go into a more advanced example in a future post.

Note: real names are used in the example, but nobody was harmed in the production of this tutorial.

Overview of invoking a hook
Overview of invoking a hook

Comments

It is better to invoke it with objects. In this case hooks can not change anything from your list.

Blair Wadman's picture

Thanks for the feedback. This is just a very simple introduction to get people started with how to invoke a hook. I will be writing more articles on this topic in the near future, including invoking with objects etc.

Really enjoying your blog posts so far. It's good to get refreshed on some of the basics.

I hasten to mention though that surely in this case it would be preferable to utilise drupal_alter() instead? Even as a simplified tutorial I don't think that this method is suitable for the scenario involved :(

A wonderful introduction! Super clear and understandable.

I found it a good introduction. I've never created my own hooks before and I'm left wondering if I could have made some of my modules more modular if I had. However, I've only recently moved from being more of a "Themer" to creating my own modules.

Add new comment