3

Is there a way to disable user_node_load on non-admin pages without hacking core modules? My theme doesn't use user data so this function results in needless database queries.

5

Disclamer

I am using a hook in a way that is different from the usage that is documented on Drupal.org API. See the notes at the end of the question.

You could achieve what you want by implementing two hooks:

  • hook_module_implements_alter()

    function mymodule_module_implements_alter(&$implementations, $hook) {
      if ($hook == 'node_load') {
        unset($implementations['user']);
    
        // Put mymodule_node_load() to the beginning of the list.
        $group = $implementations['mymodule'];
        unset($implementations['mymodule']);
        $implementations = array('mymodule' => $group) + $implementations;
      }
    }
    
  • hook_node_load()

    function mymodule_node_load($nodes, $types) {
      if (path_is_admin($_GET['q'])) {
        $uids = array();
        foreach ($nodes as $nid => $node) {
          $uids[$nid] = $node->uid;
        }
    
        $user_fields = db_query("SELECT uid, name, picture, data FROM {users} WHERE uid IN (:uids)", array(':uids' => $uids))->fetchAllAssoc('uid');
    
        // Add these values back into the node objects.
        foreach ($uids as $nid => $uid) {
          $nodes[$nid]->name = $user_fields[$uid]->name;
          $nodes[$nid]->picture = $user_fields[$uid]->picture;
          $nodes[$nid]->data = $user_fields[$uid]->data;
        }
      }
    }
    

The code I used for hook_module_implements_alter() is different from the example code shown in the documentation, which just alters the order in which different implementations of the same hook are invoked.

function hook_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'rdf_mapping') {
    // Move my_module_rdf_mapping() to the end of the list. module_implements()
    // iterates through $implementations with a foreach loop which PHP iterates
    // in the order that the items were added, so to move an item to the end of
    // the array, we remove it and then add it.
    $group = $implementations['my_module'];
    unset($implementations['my_module']);
    $implementations['my_module'] = $group;
  }
}

In general, it is not a good idea to avoid a hook implemented from another module is invoked. Modules that change their behavior because a hook implemented from another module is invoked normally use module_exists(), rather than module_implements(), which means those modules normally make the assumption that the module being enabled is sufficient for that specific hook to be invoked.
Generally speaking, there could be modules that depend from the data injected from the hook you are trying to block. It is not said that avoiding user_node_load() executes its SQL queries would avoid another module executes its own SQL queries with a decrement of performance even worse.

If you are sure that none of conditions I described are verified, you could implement the code I shown, at your own risk. Be prepared to verify there aren't any unwanted consequences, and check what the code used by the modules you use in the site is doing.

2

I think you're out of luck here (I'd love to be proven wrong though).

You can stop the hook from running with hook_module_implements_alter(), but the only way I can think of making that happen only on non-admin pages would incur quite a performance hit.

The return from that hook is cached so you'd pretty much have to flush the caches on every page to make that method work (so the cache could be regenerated and your implementation of the hook could check the current path).

Either way a code example for this would be something like:

function MYMODULE_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'node_load') {
    unset($implementations['user']);
  }
}

You'd need to add your condition in there, but that's the basic code. The proof that this works is in the following error message that appears on all node pages, as my theme has a requirement for the data added by user_node_load():

enter image description here

Commenting out the unset() line and clearing the caches removes the error message, confirming the function's success.

There are some awful methods I can think of involving subclassing the NodeController class and overriding its attachLoad() method to become path aware...but you really don't want to go down that path.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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