Hook into other module's field formatter?

by Pebbl   Last Updated January 08, 2018 15:07 PM

Am currently trying to implement a node referenced image field on my Drupal 7 site that will change it's 'view mode' depending on programmatical logic just before render. The field is currently being rendered on a number of content types via their display mode settings, each of which are using the field formatter 'Rendered node'.

first attempt

My first idea was to implement the following, considering a hook is a hook is a hook:

function HOOK_field_formatter_view( $entity_type, $entity, $field ... ){
  switch ($display['type']) {
    case 'node_reference_node':
      /* Programatical logic here to modfy field render settings */
    break;
  }
}

Obviously exchanging HOOK for my module's name.

It didn't really matter if the above would fire before or after the original function node_reference_field_formatter_view in node_reference.module because I would either override it's output entirely or, hopefully, modify its values before rendering. The only problem is, the above hook seems to function only on a per module basis — i.e. it's not site-wide, so basically it doesn't fire for my module.

Now obviously I can write my own field formatter to output a rendered node. But it seems a bit of a waste considering there is already one that exists.

other approaches

My other approaches have been to HOOK_preprocess_node and HOOK_preprocess_field but the former doesn't contain any view_mode information, and the latter contains at least 5 different complicated structures that all have references to a view_mode property at different levels — and it feels rather hacky to have to modify each of their values. Even when I've changed certain view_mode properties the resulting image doesn't change.

question

Does anyone know of a clean way to step in before a field formatter renders (of a contrib module) and change it's settings on a per page request basis — i.e. by not having to change the actual content type's permanent view mode settings?

Tags : fields entities


Answers 4


Ok so I realised why my changes to #view_mode in either hook_preprocess_node and hook_preprocess_fields weren't working. (Thanks to Clive for pointing out that I had totally missed the presence of #view_mode in hook_preprocess_node).

My problem stemmed from the fact that #view_mode had already been processed and converted to the correct #image_style property — something which I had neglected to search for.

Even so, changing this value seems too heavily dependent on which hook you modified it in. I finally got some code working though, that actually changes the rendered image:

function HOOK_preprocess_field( &$vars ){
  $element     = &$vars['element'];
  $entity_type = !empty($element['#entity_type']) ? $element['#entity_type'] : 'unknown';
  $bundle      = !empty($element['#bundle'])      ? $element['#bundle']      : 'unknown';
  $view_mode   = !empty($element['#view_mode'])   ? $element['#view_mode']   : 'unknown';
  $field_name  = !empty($element['#field_name'])  ? $element['#field_name']  : 'unknown';
  switch ( "$entity_type:$view_mode:$bundle/$field_name" ) {
    case 'node:full:mlandingpage/field_lead_image':
      if ( !empty($vars['items']) && 
           ($subelement = &$vars['items'][0]) ) {
        if ( !empty($subelement['field_image']) && 
             ($subfield = &$subelement['field_image'][0]) ) {
          /// this needs to be set to the image_style value, not the view_mode value.
          $subfield['#image_style'] = 'grid-normal-4-cols';
        }
      }
    break;
  }
}

The above still doesn't feel very eloquent, but at least it works. I'll take Clive's word on the fact that such an _alter method doesn't exist for field formatters — it's a shame, formatters are an extremely powerful feature of D7, it would be nice to have more augmenting ability.

Anyway, if any future people have any better ideas, answer away :)

Pebbl
Pebbl
January 24, 2013 17:56 PM

The question mentions that hook_field_formatter_view() is only called on the originating module, but you can take ownership of the field formatter via hook_field_formatter_info_alter().

You should be able to set the module key of the formatter to MYMODULE like:

function MYMODULE_field_formatter_info_alter(&$info) {
  $info['some_field_formatter']['module'] = 'MYMODULE';
}

Then you can implement MYMODULE_field_formatter_view(), optionally feeding through the existing module which handled it to get an element to alter.

function MYMODULE_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  // Your custom logic
  $element = OTHER_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display);
  // Any alterations
}
Graham C
Graham C
August 01, 2014 15:04 PM

The easiest approach will be using the Panelizer.

If don't use Panelizer but default Drupal view modes or Display Suite, try hook_field_display_alter() or hook_field_display_ENTITY_TYPE_alter().

You have entity, display context as well as all the formatter settings there. And you can easily change field render settings. You can even change field formatter to a different one.

The approach works perfect for me. The only disadvantage is that you might be confused with different settings in the the "Manage display" UI.

milkovsky
milkovsky
March 24, 2015 14:55 PM

https://www.drupal.org/node/2130757 It gives a good example. hook_field_formatter_third_party_settings_form() is useful to alter the form of the existing field formatter.

But this doesn't work with field groups.

Pierre Noel
Pierre Noel
January 08, 2018 14:08 PM

Related Questions






How to properly delete fields, programmatically?

Updated March 20, 2017 13:07 PM