15

I have a custom module that is formatting the display of an image field, which can accept multiple values. I would like to know what hook I should use to duplicate the first value of the field (e.g. "[image1]"), and add it back to the beginning of the array (with array_unshift() I guess) before the rest of my functions format the display/theme of the field.

So what was

  • [image1]
  • [image2]
  • [image3]

becomes

  • [image1]
  • [image1]
  • [image2]
  • [image3]

I am then going to theme them separately, but I think I already have that part figured out.

I am currently using hook_field_formatter_view(), and have tried to just add it to the beginning of the $items array at the top of the function, but that didn't seem to work. If I immediately dprint_r() the $items array after this it shows, but only 3 items get output; I am assuming that the number of field gets determined elsewhere.

  • 1
    If you want to just copy image, maybe Javascript is the way? – Codium Jun 17 '11 at 23:38
  • No I'm sorry. I am using js on the results but I need to do other stuff to the data with the hook_field_formatter_view but it only runs once per image. – Chance G Jun 17 '11 at 23:47
  • I looked at it in a debugger and was surprised to find extra deltas added to the array being ignored. – Adam S Jun 20 '11 at 3:13
  • +1 for your question, it's an interesting topic. But to help us think about the real solution, can you be more specific what your main purpose is (so the reason why you want the first image duplicated)? The more info we know, the better answers you could get. :) – Sk8erPeter Oct 13 '12 at 21:33
  • I ended up solving this problem with javascript. But to answer your question; I was trying to implement hoverzoom, which uses one large image per set and then thumbnails of all of the images to allow the user to switch the large image. – Chance G Oct 16 '12 at 16:34
1

You want hook_field_formatter_prepare_view() instead. Note this hook operate on a group of entities, not on a single one.

Here's a working snippet. Some array-fu is needed to not end up writing an ugly loop of ten lines, since deltas must be preserved linear.

<?php

function MODULE_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
  foreach ($entities as $id => $entity) {
    $array = array(0 => $items[$id][0], 1 => $items[$id][0]);
    if (count($items[$id]) > 1) {
      array_splice($array, 2, 0, array_slice($items[$id], 1));
    }
    $items[$id] = $array;
  }
}
0

hook_field_formatter_view() is where your code makes the output that's shown to the user, and so it wants a renderable array as a return value. So just process the first image twice and give it a different css class or something.

Something like:

$output = array();
if (($field == 'myFieldType') && ($display == 'full')) {
  $output[] = renderFirstImage(reset($items));
  foreach ($items as $item) {
    $output[] = renderImage($item);
  }
}
return $output;

Since hook_field_formatter_view() expects a renderable array, and since renderable arrays are marked as rendered when they're rendered, simply making two references to the same object will cause one to be rendered, marked as rendered, and then subsequently ignored the next time.

  • I'm sorry Paul but did you read my question? I was able to add it to the beginning of the items array. The issue was that it was still not being output. – Chance G Jan 24 '12 at 17:27
  • hook_field_formatter_view() gets fields and you must turn them into renderable arrays. If you just make two references to the same array, that item will be marked as rendered, and not rendered again. So you have to make a new renderable array for each item you want. – paul-m Jan 24 '12 at 18:20
  • Is this the answer? – paul-m Feb 13 '12 at 19:18
  • No. I am able to add an extra item to the array. When I dpm the array it shows, it just doesn't print. I accept all answers that are correct. – Chance G Feb 14 '12 at 19:38
  • As I mention, the render system marks items as already rendered. That means that if you simply pass a second image by reference, it will get marked as rendered the first time, and then NOT rendered the second time, since it's already marked. – paul-m Mar 31 '12 at 17:18

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.