Tech Blog :: How to render image fields with Drupal 7


Apr 12 '11 2:00pm
Tags

How to render image fields with Drupal 7

Suppose you have a Drupal 7 site, with a node containing an image field called field_image, and you want to pull the URL of the image into your page template. (As opposed to a node template, where it's already rendered.) For bonus points, you want the image to be rendered through a "style" (aka Imagecache preset).

In Drupal 6, this involved theme('imagecache') and $node->field_image[0]['filepath']. In Drupal 7 it's a little different, because the Files API has been abstracted from the local file system (to handle other types of storage) and Imagecache is now (mostly) in the core Image module.

First, I'm separating this into the preprocessor logic where we check if the image field exists and get the right code, and the template output where we use the finished value. The page preprocessor would probably be in your theme's template.php and look like function THEME_preprocess_page(&$vars), and your page template would look like page.tpl.php.

Fortunately, the node object is already in the page preprocessor's variables, as $vars['node']. Let's break this down a little with the available API functions:

// filename relative to files directory
// e.g. 'masthead.jpg'
$filename = $vars['node']->field_image['und'][0]['filename'];
 
// relative path to raw image in 'scheme' format
// e.g. 'public://masthead.jpg'
$image_uri = file_build_uri($filename);
 
// relative path to 'styled' image (using an arbitrary 'banner' style) in 'scheme' format
// e.g. 'public://styles/banner/public/masthead.jpg'
image_style_path('banner', $filename);
 
// raw URL with an image style
// e.g. 'http://mysite.com/sites/default/files/styles/banner/public/masthead.jpg'
// [passing a raw path here will return a very ungraceful fatal error, see http://api.drupal.org/api/drupal/modules--image--image.module/function/image_style_url/7#comment-12079]
$vars['masthead_raw'] = image_style_url('banner', $image_uri);
 
// html for a styled image
// e.g. '<img typeof="foaf:Image" src="http://mysite.com/sites/default/files/styles/banner/public/masthead.jpg" alt="" />'
$vars['masthead'] = theme('image_style', array('style_name' => 'banner', 'path' => $image_uri));

So to do something useful with this:

function THEME_preprocess_page(&$vars) {
  // pull the masthead image into the page template
  if (isset($vars['node']->field_image) && !empty($vars['node']->field_image['und'][0]['filename'])) {
 
    $filename = $vars['node']->field_image['und'][0]['filename'];
 
    $image_uri = file_build_uri($filename);
 
    // url
    $vars['masthead_raw'] = image_style_url('banner', $image_uri);
 
    // html
    $vars['masthead'] = theme('image_style', array('style_name' => 'banner', 'path' => $image_uri));
  }
}

Now in your page template, you have $masthead (HTML) and $masthead_raw (URL) [with the $vars variables now being independently named] so you can do something like this in a PHP block:

<?php if ($masthead): ?>
  <div id="masthead"><?php echo $masthead; ?></div>
<?php endif; ?>

A quick-and-dirty alternative would be, directly in page.tpl.php:

if (!empty($node->field_image['und'][0]['filename']) {
 echo theme('image_style', array('style_name' => 'banner', 'path' => file_build_uri($node->field_image['und'][0]['filename'])));
}

(note $vars['node'] is now $node)

The shorthand version will work, but separating the logic from the output (with a preprocessor and template) is the "best practices" approach.

I found that field_image['und'][0] already contains a valid uri, while file_build_uri() produces bad results.

field_image['und'][0]['uri'] is public://field/image/filename.jpg
and file_build_uri($filename) simply produces public://filename.jpg

Other than that, great how to!

Use theme_image_style instead: http://api.drupal.org/api/drupal/modules--image--image.module/function/t...

Thanks for the write up, this kind of info is hard to come by for D7.

Thanks a lot for this code snippets!

I was trying to do a simple php test in my .tpl.php file but started getting all sorts off errors because i was testing $content[fieldname]['und']....

and not $node[fieldname]....

one of your snippets above:
if (!empty($node->field_image['und'][0]['filename']) {
echo theme('image_style', array('style_name' => 'banner', 'path' => file_build_uri($node->field_image['und'][0]['filename'])));
}

gave me the clue and saved the day!

Best regards
Elvin Xhimitiku

If you have a separated file directory set like "[current-page:page-title]" you won't get the right url by using the "field_image['und'][0]['filename']".
In addition if you want to have the width and height attribute set you need to get the imagesize... for both special cases I clued something together of the theme_image_style API comments and your blog post.

But notice - its for the node preoprocessing instead.

/**
* Image Style Overwrite
*/
function THEME_image_style($variables) {
$style_name = $variables['style_name'];
$path = $variables['path'];

// theme_image() can only honor the $getsize parameter with local file paths.
// The derivative image is not created until it has been requested so the file
// may not yet exist, in this case we just fallback to the URL.
$style_path = image_style_path($style_name, $path);
if (!file_exists($style_path)) {
$style_path = image_style_url($style_name, $path);
}
$variables['path'] = $style_path;

if (is_file($style_path)) {
if (list($width, $height, $type, $attributes) = @getimagesize($style_path)) {
$variables['width'] = $width;
$variables['height'] = $height;
}
}

return theme('image', $variables);
}

/**
* Node preprocessing
*/
function THEME_preprocess_node(&$vars) {
// Set grid width

// pull the masthead image into the page template
if (isset($vars['node']->field_image) && !empty($vars['node']->field_image['und'][0]['filename'])) {

$filename = $vars['node']->field_image['und'][0]['uri'];

// url
$vars['masthead_raw'] = image_style_url('large', $filename);

// html
$vars['masthead'] = theme('image_style', array('style_name' => 'large', 'path' => $filename, 'alt' => $vars['node']->title,
'title' => $vars['node']->title));
}

}

Post new comment

Don't bother putting in spam links. They'll be set to rel=nofollow and will be removed and reported as spam shortly after submitting.

The content of this field is kept private and will not be shown publicly.
CAPTCHA
Are you human?