2

In a Drupal 7 site, I have an image field that allows unlimited images, called field_gallery_images. I built a template file for this field to create a custom image slider. I want to rewrite the HTML markup for the image to add a lazy-load component. So, instead of:

<img src="/sites/default/files/myimage.jpg" width="668" height="500">

I want:

<img data-lazy="/sites/default/files/myimage.jpg" width="668" height="500" class="lazyload">

Right now, the images are being run through theme_image() and so by the time it gets to the template, the markup is all set. I only want to alter the markup for this one field. I tried theme_preprocess_image(), but that altered all images.

4

I assume that you are using Drupal 7.

Short Answer

Implements template_preprocess_field() and overrides theme_image().

/**
 * Implements template_preprocess_field().
 */
function mytheme_preprocess_field(&$variables) {
  $element = &$variables['element'];

  if ($element['#field_name'] === 'field_image') {
    foreach (element_children($element) as $key) {
      $item = &$element[$key]['#item'];

      $src = file_create_url($item['uri']);
      unset($item['uri']);
      $item['attributes']['data-lazy'] = $src;
      $item['attributes']['class'] = array('lazyload');

      $element['#items'][$key] = $item;
      $variables['items'][$key]['#item'] = $item;
    }
  }
}

/**
 * Overrides theme_image().
 */
function mytheme_image($variables) {
  $attributes = $variables['attributes'];

  if (!empty($variables['path']) || !isset($attributes['data-lazy')) {
    $attributes['src'] = file_create_url($variables['path']);
  }

  foreach (array('width', 'height', 'alt', 'title') as $key) {

    if (isset($variables[$key])) {
      $attributes[$key] = $variables[$key];
    }
  }

  return '<img' . drupal_attributes($attributes) . ' />';
}

Long Answer

By implementing template_preprocess_field(), you can alter the theme variables and also the theme function for a field.

Example code:

/**
 * Implements template_preprocess_field().
 */
function mytheme_preprocess_field(&$variables) {
  $element = &$variables['element'];

  if ($element['#field_name'] === 'field_image') {
    foreach (element_children($element) as $key) {
      $item = &$element[$key]['#item'];

      $src = file_create_url($item['uri']);
      unset($item['uri']);
      $item['attributes']['data-lazy'] = $src;
      $item['attributes']['class'] = array('lazyload');

      $element['#items'][$key] = $item;
      $variables['items'][$key]['#item'] = $item;
    }
  }
}

Remember to change field_image to the field name you defined.

It is the structure of $variables:

Structure of $variables

$variables['items'][0]['#item'] is a typical usage of theme function in render array. The code above has done a couple of things:

  • unset uri, which is used to format the attribute src in theme_image()
  • construct image path and assign it to the attribute data-lazy
  • add lazyload to class
  • synchronise the item array to different location of $variable

The last point is a bit weird, but there are 3 different location always store the same item array. They are

  • $variables['element'][0]['#item']
  • $variables['element']['#items'][0]
  • $variables['items'][0]['#item']

Theoretically, $variables['items'][0]['#item'] is the only one be used in theme function, But, in my opinion, it is better to change them at the same time for preventing any potential issue in future. (Maybe someone can provide more suggestion here?)

The last but not the least, you have to override the theme_image(). It is a global change but won't affect too much.

/**
 * Overrides theme_image().
 */
function mytheme_image($variables) {
  $attributes = $variables['attributes'];

  if (!empty($variables['path']) || !isset($attributes['data-lazy')) {
    $attributes['src'] = file_create_url($variables['path']);
  }

  foreach (array('width', 'height', 'alt', 'title') as $key) {

    if (isset($variables[$key])) {
      $attributes[$key] = $variables[$key];
    }
  }

  return '<img' . drupal_attributes($attributes) . ' />';
}
  • Jimmy Ko, this is awesome. Thanks for such an in-depth response. Worked perfectly. – Colin Jul 26 '16 at 2:49
  • One more question: any thoughts on how I could alter the image src to be a placeholder? I tried adding $item['uri'] = '/' . path_to_theme() . '/images/placeholder.jpg'; The current image src is src="//localhost:3010/sites/default/files/styles/property_slideshow_500h/public?itok=zKlJQsDU" which is essentially no image or a broken image. – Colin Jul 26 '16 at 16:48
  • Do you mean a default image for the field? You can upload one in the field settings. If you need more details, please update this question or just raise a new question. I will follow up. – Jimmy Ko Jul 26 '16 at 22:07

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.