Entity view (Content)

How to properly use PHP on Drupal views fields

By manuel
Twitter
Dec. 8, 2014

Every once in a while, as a Drupal website developer you will come across this problem. The view is working perfectly, you are almost there, but wait, the specification calls for this special piece of markup that well, is different depending on what results you are displaying, or might display nothing at all sometimes, etc. Not a problem you think, I'll just shove some PHP in!

The problem with this is that you break views caching and you are saving executable code as configuration. Not something that will make your colleagues, nor your client happy at all. Not to worry, there are better ways!

So, depending on what you need to do, views api has you covered. You can write an area plugin in case you need a dynamic header, footer, etc. You can also or define your very own field, and handle your special case that way. It sounds more daunting than it is. In this post I will explain how to provide your own custom field to views.

For example, a field which will check if the rest of the fields in the current row are populated, and if any of them are empty, then display a link markup to prompt the editor to take care of that.

OK, so first things first, our module will be called appnovation_fillout_viewsfield, and we need to let views know that we will be providing functionality, and where, so in our appnovation_fillout_viewsfield.module file we just write:

<?php
/**
 * Implements hook_views_api().
 */
function appnovation_fillout_viewsfield_views_api() {
  return array(
    'api' => 3,
    'path' => drupal_get_path('module', 'appnovation_fillout_viewsfield') . '/views',
  );
}

This tells views that our files for it will reside inside the views directory under our module's directory. Easy.  

Next, we'll tell views that we have a new field, and for which table our field is available. We do this by implementing hook_views_data. Note that there is also hook_views_data_alter, which you could use to replace an existing field with your new field, like for example, if you wanted to append the author to EVERY node title displayed by views or something crazy like that. Our field will be used with the node table, so:

<?php
/**
 * Implements hook_views_data().
 */
function appnovation_fillout_viewsfield_views_data() {
  $data = array();
  $data['node']['fillout'] = array(
    'title' => t('Fillout field'),
    'help' => t('Will display a link to node edit ONLY if any of the current row\'s listed fields is empty.'),
    'field' => array(
      'handler' => 'appnovation_fillout_viewsfield_handler_fillout',
    ),
  );
  return $data;
}

 Note that our handler is called 'fillout', so the array is keyed appropriately. Also the handler is named as MODULE_handler_HANDLERNAME.

 Great, so let's actually write the handler that provides the field. Create a file called appnovation_fillout_viewsfield_handler_fillout.inc inside our views directory, which will be picked up by views: 

<?php
/**
 * @file
 * Definition of appnovation_fillout_viewsfield_handler_fillout.
 */

/**
 * Provides a field which will display a link to edit the node if any other listed fields are empty.
 */
class appnovation_fillout_viewsfield_handler_fillout extends views_handler_field_node_link_edit {
  /**
   * Override views_handler_field_node_link_edit::render_link()
   */
  function render_link($node, $values) {
    // Get all field handlers on this display
    $fields = $this->view->display_handler->get_handlers('field');
    // Check if ANY field is empty
    foreach($fields as $key => $field) {
      // ignore our field (duh)
      if ($key !== 'fillout') {
        if (empty($field->get_value($values))) {
          // Let the views hanlder provide the link, it checks for access etc ;)
          return parent::render_link($node, $values);
        }
      }
    }
  }

}

Since we only provide an edit link, we'll just extend views_handler_field_node_link_edit handler, which is battle tested and provides the necessary access checks, etc. We only have to check the rest of the display's field values for the row, and if we find any that are empty, then we call the views handler for the link, return it, done!

That's it. Very few lines of code, and a lot of functionality, thanks to views OO approach. Not only is this much cleaner and easier to debug, but you can also reuse the same code across all other views on the site, and easily include it on other future projects! So next time you think about inserting PHP in a view, take a minute to think about how to go about it using this approach - and share the code!

Post Tags: