We have a custom module in development, the purpose of which is to fetch the email addresses of the users who review content. Upon revisiting this module (after updating from Drupal-7.41 to Drupal-7.51) its hook_tokens() implementation is no longer being called in the same way it was before.

I cannot understand why this functionality no longer works. I thought this was a proper implementation of these functions. It now no longer fires on nodes, but when an entity is on a node.

Why would hook_tokens() not be called on a node? (The module is enabled, depends on tokens and workbench_access, both of which are enabled.)

Please forgive me if my question is framed inappropriately, I may have an inaccurate understanding of the hook function(s), but I've checked the API and haven't gained clarity. I know for a fact that this module worked earlier this year with Drupal-7.41, but I couldn't find any changes in the related API since that release.

function mymodule_token_info() {
   $info = array();
   $info['tokens']['node']['publisher_one'] = array(
     'name' => t('Section Publisher One'),
     'description' => t('Email address of sections primary publisher.'),
   $info['tokens']['node']['publisher_two'] = array(
     'name' => t('Section Publisher Two'),
     'description' => t('Email address of sections secondary publisher.'),
   return $info;

function mymodule_tokens($type, $tokens, array $data = array(), array $options = array()) {
   $replacements = array();
   if ($type == 'node' && !empty($data['node'])) {
      print_r('inside if conditional');
      $section_users = array();
      $users = entity_load('user'); 
      // Get the current Page's section ID (sID).
      $sID = key(_workbench_access_get_node_section_names($data['node']));
      $user_count = 0;
      // Is a given user 1) assigned to the same section as the node and also
      //  of the role identified as the one to be notified.
      // If so, their email address are acquired.
      foreach($users as $user) {
          $user_sections = _workbench_access_get_user_section_names($user);
          if(array_key_exists($sID, $user_sections) && $user_count < 2){
              $role_type = user_roles(TRUE)[variable_get('waemail_role', '0')];
              if(in_array($role_type, $user->roles)){
                  if($user_count == 0){
                      $section_users['publisher_one'] = $user->mail;
                  else if($user_count == 1){
                      $section_users['publisher_two'] = $user->mail;

      // Assign the values aquired above to the tokens.
      foreach ($tokens as $name => $original) {
          switch ($name) {
              case 'publisher_one':
                      $replacements[$original] = $section_users[$name];
              case 'publisher_two':
                      $replacements[$original] = $section_users[$name];
    } //end if($type == 'node'...
 return $replacements;
  • 1
    Your code looks correct, however, I noticed your hook_token_info() doesn't define a token type. I'm curious if this is what is preventing your $type == 'node' logic from getting missed. Trying adding a 'types' array to your $info in hook_token_info and see if that does the trick. Commented Nov 7, 2016 at 21:16
  • @TheRealWebGuy Thanks for the response! So I added this code in the [module-name]_token_info function prior to the other two tokens: $info = array(); $info['types']['node']['section-publishers'] = array( 'name' => t('Publishers for Access Section'), 'description' => t('Email addresses of the publishers of a given nodes section'), ); I also added that prefix to the other tokens so they are now: ['tokens']['node']['section-publishers']... However, it still doesn't appear to fire. Is that what you meant by adding a type array?
    – Travis
    Commented Nov 7, 2016 at 21:38
  • @TheRealWebGuy Defining a token type is not required. Modules could use the existing ones, like poll_token_info() does.
    – avpaderno
    Commented Nov 7, 2016 at 21:52
  • @kiamlaluno Are you still planning on amending your answer?
    – Travis
    Commented Nov 17, 2016 at 14:10
  • Yes, once I have time to write the code. That means, not before 6:00 PM my time (about 3 hours since now).
    – avpaderno
    Commented Nov 17, 2016 at 14:13

1 Answer 1


hook_tokens() is invoked only when token_generate() is called. Since that doesn't necessarily happens when a node is viewed (or similar events), but it happens when a module calls token_replace(), hook_tokens() not being invoked could not mean your code is wrong.

Assuming that the code you show is not causing any PHP error, that means that a module that was before calling token_replace() is not calling that function anymore, or it is calling it in very specific occasions.
For PHP error I mean:

  • The code is calling a function that doesn't exist anymore (e.g. _workbench_access_get_user_section_names())
  • It is calling a function that is returning a value of a different type from what it previously returned (e.g. _workbench_access_get_user_section_names() returns a value that is not an array)

There isn't any change in the token subsystem from Drupal 7.41 to Drupal 7.51 that could cause your code not to work anymore. The only reason for your hook_tokens() implementation not to be invoked in a change in the code of the module your hook implementation is using, or a change in the code of a module that was generating token when viewing a node (or a similar event).

To test your implementation of hook_tokens(), you should directly call token_replace() passing a string containing a token your module defines and a node object. If the token is not replaced, then you can check for errors in your code; if the token is replaced, then your code is working perfectly, and your hook_tokens() implementation is not invoked simply because no module is replacing tokens in a string when you are expecting it to happen.

I would use the following code, to put in a file in the same directory containing the index.php file that comes with Drupal.

 * @file
 * Test page to check the hook implementation of a custom module work.

 * Root directory of Drupal installation.
define('DRUPAL_ROOT', getcwd());

require_once DRUPAL_ROOT . '/includes/bootstrap.inc';

// Load a node to use as context for the tokens.
// Change the argument for node_load() to match the node ID of
// an existing node.
$node = node_load(1);

// Change the string to the token name for the token that needs to
// be tested.
$token = 'publisher_one';

$result = token_replace("[$token]", array('node' => $node), array('clear' => FALSE));

if ($result == "[$token]") {
  // The token has not been replaced.
  • OK, thank you! I know it's not generating errors, those I tested when it was working before and I've double checked the functions exist and return the proper type, etc. I apologize for my ignorance, but I'm new to this type of development: How/where might I call the token_replace() method in this situation?
    – Travis
    Commented Nov 8, 2016 at 14:59
  • 1
    I will update my answer later.
    – avpaderno
    Commented Nov 8, 2016 at 15:46
  • Any update on this? I've tried to include this a couple places, but I haven't been able to find proper instructions thus far.
    – Travis
    Commented Nov 10, 2016 at 16:16
  • 1
    I added example code that could be used to test a token implementation work. I will update the code if I think of something else that could be tested.
    – avpaderno
    Commented Nov 18, 2016 at 15:54
  • 1
    I would say it was just a matter of cache. If you are asking where to put the code I shown, you should not need it. Rather, I would investigate why clearing the cache made things work. Probably there is a module that should clear the cache and it is not doing it. It's hard to say that.
    – avpaderno
    Commented Nov 25, 2016 at 17:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.