When using hook_load() or hook_node_load() to add information to the node object, is it possible to have this data stored in the cache? I'd like to add several different pieces of data and it would be difficult / impossible to get this data in one database query, however, if it's caching the data with the rest of the node object, it should be fine. How do I do this if it doesn't already?



First of all, you generally don't want to implement hook_load() and hook_node_load() for the same node type. So just FYI.

Secondly: There's a bunch of different caching you could mean... The caching you implement depends on why you need it.

If you trace back the functions that call hook_node_load(), you end up at NodeController::attachLoad(). It just invokes the hooks and then bails to its superclass, DrupalDefaultEntityController. Basically this means that node itself doesn't do any caching.

This gives you a few options:

1) Come up with your own caching system for your own subset of the node's data, which means that you have to mark all nodes using it as uncacheable, since you're caching a little bit of it.

2) Install EntityCache. :-) EntityCache does what you'd do anyway but does it for the whole node entity at the entity layer.

BUT... If the real problem we're solving here is to have a next and previous reference per node, then you want EntityReference, which lets you set that up as fields, and which can then be used with Views and whatnot, for free, without coding anything. :-)


I think by default it won't be cached, so you'll have to do it yourself. There's a really useful post by Jeff Eaton here on caching data in Drupal 7 (see this if anyone's interested in Drupal 6).

I think you'll be looking at something like the following (adapted from the previous link and without a Drupal backend):

function my_module_node_load($nodes, $types) {

  //The other hook_node_load stuff you normally do is here

  $my_data = &drupal_static(__FUNCTION__);
  if (!isset($my_data)) {
    if ($cache = cache_get('my_module_data')) {
      $my_data = $cache->data;
    else {
      // Do your expensive calculations here, and populate $my_data
      // with the correct stuff..
      cache_set('my_module_data', $my_data, 'cache');
  $node->my_stuff = $my_data;
  • what if the data is different on each node? Mar 19 '12 at 18:50
  • It depends on the complexity of the data being added to each node. If it requires some complex logic, you could cache every node (e.g. cache $my_data as a keyed array). Then you could load the cached data once and search the array for each node. This will save multiple SELECT queries. If this is the case let me know and I'll see if I can add to my answer.
    – Chapabu
    Mar 19 '12 at 20:29
  • yeah that would be super helpful, what I am doing is saving the node to the right (next) and the left (previous) of the current node. This involves getting a list of nodes from the database and figuring out the placement in the array. Mar 20 '12 at 13:10

After adding data to nodes using hook_node_load(), will this data be saved in the cache?

No, it will be not. hook_load() and hook_node_load() are invoked by NodeController::attachLoad(), which contains the following code.

  // Call object type specific callbacks on each typed array of nodes.
  foreach ($typed_nodes as $node_type => $nodes_of_type) {
    if (node_hook($node_type, 'load')) {
      $function = node_type_get_base($node_type) . '_load';
  // Besides the list of nodes, pass one additional argument to
  // hook_node_load(), containing a list of node types that were loaded.
  $argument = array_keys($typed_nodes);
  $this->hookLoadArguments = array($argument);
  parent::attachLoad($nodes, $revision_id);

NodeController::attachLoad() is called from DrupalDefaultEntityController::load() (DrupalDefaultEntityController is the base class of NodeController) after the method loaded the entities from the cache.

Don't get confused from the following code.

  if ($this->cache) {
    // Add entities to the cache if we are not loading a revision.
    if (!empty($queried_entities) && !$revision_id) {

What DrupalDefaultEntityController::cacheSet() does is setting DrupalDefaultEntityController::$entityCache; it doesn't use any database cache.

What you can do is using the cache function in your implementation of hook_node_load(), possibly using a static variable to save the content of the cache once retrieved. You should use drupal_static() only if the value would need to be reset (or changed) from an external function. For example, your implementation of hook_node_delete() could remove the reference to the nodes being deleted from that static variable.

If the value needs to be cached per node, I would use code similar to the following one.

function mymodule_node_load($nodes, $types) {
  global $language_content;

  $data = &drupal_static(__FUNCTION__, array());
  $langcode = $language_content->language;

  if (empty($data) && ($cache = cache_get("mymodule_cache:$langcode"))) {
    $data[$langcode] = $cache->data;

  foreach ($nodes as $nid => $node) {
    if (isset($data[$langcode][$nid]) {
      $node->field = $data[$langcode][$nid];
    else {
      // Get the field value.
      // Save the value in $node->field.
      $update_cache = TRUE;

  if (!empty($update_cache)) {
    cache_set('mymodule_cache', $data, 'cache');

The code I shown considers the language currently set; if the value of the field doesn't depend from the language, you can replace "mymodule_cache:$langcode" with "mymodule_cache".

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.