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 */

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.


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';

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 :)

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.

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