Getting the value of a CCK field without node_load

in PHP, drupal, d6, cck, filefield, imagefield

More often than not, you'll come to a point where you need a field value of a node. Not the whole node, just a field. The most common case would appear to be when you need an image (say a promotional image). Some ways are easier than others for it, however you need to think of what you are doing under the hood.

For all examples, we'll assume that you've managed to get a hold on the node id that interests you.

First, the "normal", or "proper" way to do this -- by the Drupal API. In this case, you'd invoke node_load() using your nid, get the node object, and dig through it to get the value you need. For an imagefield, that might look like this:

$node = node_load($nid); // Load your node object
$value = $node->field_promoimage[0]['filepath'];
// Do something with that path

This is a very simple approach, but unfortunately, this will invoke every enabled module via hook_nodeapi() and creates a fairly large object memory wise (which is mostly a constraint for small hosting plans). Especially if you need to load a number of images (say for a list of offers) this might be a no-go.

The second method, would be to use a view. Views is especially good at getting only the parts needed, and cache as much as possible. Creating such a view should be fairly simple, and not in the scope of this post.

However, in some cases you'll encounter modules that are not views-aware, or needing to process quite a bit before formulating the criteria for selecting the nodes. You have two options in this case -- either create a view and load it programmatically (which will be to content of another post), or simply using the following snippet:

// Replace with your field machine name
$db_info = content_database_info(content_fields('field_promoicon')); 
foreach($nids as $nid) {
  $value = db_result(db_query("SELECT %s FROM {%s} 
      WHERE nid=%d ORDER BY vid DESC LIMIT 1",
      $db_info['columns']['value']['column'], $db_info['table'], $nid));
  $values[] = $value;
}
If you are not using revisions in your content types, you can safely omit the ORDER BY vid DESC LIMIT 1 in the above query
Some people suggest using a simple query such as SELECT field_something_value FROM content_type_mytype. This is incorrect, since the table structure can change by CCK depending on how you use your fields (eg reusing a field on a different content type will create a table for it, and replace your value with a reference).

If you mean to use the above for filefields or image fields, there is one minor tweak -- those fields don't use "value" but "fid", which refers to the files table. The following snippet will get the fid, fetch the file object, and create a URL to a resized version of the image via imagecache :

// Replace with your field machine name
$db_info = content_database_info(content_fields('field_promoicon')); 
foreach($nids as $nid) {
  $fid = db_result(db_query("SELECT %s FROM {%s} 
      WHERE nid=%d ORDER BY vid DESC LIMIT 1",
      $db_info['columns']['fid']['column'], $db_info['table'], $nid));
  // Get filepath from fid
  $icon  = field_file_load($fid);
  $urls[] = imagecache_create_url('my_preset', $icon['filepath']);
}
You can use the full file object just by accessing the properties of the $icon object above, such as filename.

As long as you don't forget to replace the my_preset imagecache preset name with something that exists on your site, you should now have a list of URLs pointing to imagecache'd images.

Image source is here.