Skip to main content

Enhanced Views and Rules in Drupal 7

9th October, 2014

How to enhance Views and Rules in Drupal by creating custom modules.

An enhanced view of a tropical paradise. Not Drupal related in any way.

Setting up the site

To start, we'll create a new composite field (or pseudo-field) for Views. To develop this module we first install Drupal and a few modules.

Drupal 7.31

Module list

Other

Or use Drush with the make file which you can download using this link or from the files link at the bottom of this article.

You will next need to enable the following modules:

  • Administration   
  • Module filter (module_filter)
  • Chaos tool suite
  • Chaos tools (ctools)
  • Development
  • Devel (devel)
  • Devel generate (devel_generate)
  • Other
  • Entity API (entity)
  • Entity tokens (entity_token)
  • Token (token)
  • Rules
  • Rules (rules)
  • Rules UI (rules_admin)
  • Views
  • Views (views)
  • Views UI (views_ui)
  • drush
  • en
  • module_filter
  • ctools
  • devel
  • devel_generate
  • entity
  • entity_token
  • token
  • rules
  • rules_admin
  • mymodule
  • views
  • views_ui

Then create some node types – type 1 and type 2 – each one with some integer fields. The fields use the default settings, but can be changed if required.

NOTE: this module will only expect single value fields. Adapting for multiple value fields is left as an exercise for the reader.

Drupal Field Type 1

Drupal Field Type 2

 

Add some dummy content using drush and devel.

$ drush genc 10 –types=type_1,type_2

 

Then create a new view.

Create a View in Drupal 7

 

View now created in Drupal 7

On this View, we want to display the the total of the numeric fields on all the nodes, so we'll get to work developing our module.

Telling Drupal about the module

To start, we go through the standard way to create a new module (https://www.drupal.org/developing/modules/7).

So in our sites/all/modules directory we create a new folder called mymodule. And in there, create two files called mymodule.info and mymodule.module.

info and module files created in D7

In mymodule.module add the php start tag

<?php

And in mymodule.info we add

name = My Module

description = Tutorial module for extending views

core = 7.x

package = Tutorial

 

Now we can see our module at /admin/modules.

The module is now in the module list in Drupal 7

 

Before activating it, we tell Drupal that Views is required to enable the module, so add a line to mymodule.info.

dependencies[] = views

After refreshing /admin/modules, we can enable the module.

Module now enabled in the module view in Drupal

The module, of course, does nothing right now, so let's disable it and then we can tell Views about it.

 

Telling Views

To let Views know about our module, we need to add some code to mymodule.module.

/**

* Implements hook_views_api().

*/

function mymodule_views_api() {

 return array(

   'api' => 3,

   'path' => drupal_get_path('module', 'mymodule') . '/views',

 );

}

With this, Views will try to load views/mymodule.views.inc, so we should now create this.

Creating files for Views to find in Drupal module development

 

<?php

/**

* Implements hook_views_data

*

* Registers field to get progress from Entityform

*/

function mymodule_views_data() {

 $data = array();

 return $data;

}

Now we have a “complete” Views plug-in. Unfortunately it still does nothing. So next, we need to specify something for it to do.

To define our new field we add to the views/mymodule.views.inc file.

 $data['node']['total'] = array(

   'title' => t('Total'),

   'help' => t('Sums the numeric fields in a node'),

   'field' => array(

     'handler' => 'mymodule_sum_fields',

   ),

 );

 

Now when the module is enabled, we can find the new field in the list.

Add Field 1 for this Drupal Views and Rules tutorial

But if we try to add it we get:

Message returned in Field from Views in Drupal

As suggested, a “handler” needs to be created.

Creating a Handler

A handler contains the code which needs to be run. There are a few different handlers for views (https://api.drupal.org/api/views/views.api.php/group/views_handlers/7) but, for the moment, we are only interested in field handlers.

So let's create a file for the handler.

File created for handler - Fields, Views and Rules in Drupal 7

And tell Drupal about it in mymodule.info.

files[] = views/mymodule_sum_fields.inc

Now, in views/mymodule_sum_fields.inc, we'll sub-class one of the standard handlers, views_handler_field_numeric, and start to implement the handler.

Now when the module is enabled and the field is added, a lot of extra functionality is added from the parent class.

Field 3 screenshot for Drupal tutorial

But a new problem has come up:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'node.total' in 'field list'

To fix this, we'll over-ride the query function in our handler and stop the addition of the field to the SQL query.

 /**

  * {@inheritdoc}

  */

 function query() {

   $this->ensure_my_table();

   $this->add_additional_fields();

 }

 

Now, with the module enabled and the field added we get can see the view.

The View almost complete Drupal 7 tutorial

All is going well except the output is correct. We are getting 0 for everything.

Another over-ridden function is needed. This time it's the render method.

To keep the added functionality of the numeric field handler, we'll copy the super class's code into our module and then change it as necessary.

 /**

  * {@inheritdoc}

  */

 function render($values) {

   $value = $this->get_value($values);

   if (!empty($this->options['set_precision'])) {

     $value = number_format($value, $this->options['precision'], $this->options['decimal'], $this->options['separator']);

   }

   else {

     $remainder = abs($value) - intval(abs($value));

     $value = $value > 0 ? floor($value) : ceil($value);

     $value = number_format($value, 0, '', $this->options['separator']);

     if ($remainder) {

       // The substr may not be locale safe.

       $value .= $this->options['decimal'] . substr($remainder, 2);

     }

   }

  

   // Check to see if hiding should happen before adding prefix and suffix.

   if ($this->options['hide_empty'] && empty($value) && ($value !== 0 || $this->options['empty_zero'])) {

     return '';

   }

 

   // Should we format as a plural.

   if (!empty($this->options['format_plural'])) {

     $value = format_plural($value, $this->options['format_plural_singular'], $this->options['format_plural_plural']);

   }

  

   return $this->sanitize_value($this->options['prefix'], 'xss') . $this->sanitize_value($value) . $this->sanitize_value($this->options['suffix'], 'xss');

 }

 

The piece of code that needs changing is the first line:

   $value = $this->get_value($values);

 

As it stands, this gets the value from the database, but we don't want that.

 

First, we set $value to be 0 and load the node and put it into an entity wrapper.

   $value = 0;

   $node = entity_load('node', array($values->nid))[$values->nid];

   $wnode = entity_metadata_wrapper('node', $node);

 

Next, set up a loop to go through each property and check if it is a field and it is an integer. And for each of these, add the field's value to the $value variable.

   foreach ($wnode->getPropertyInfo() as $key => $val) {

     if (isset($val['field']) && $val['type'] == 'integer') {

       $value += $wnode->$key->value();

     }

   }

 

A refresh of the view shows us desired output.

The final View outputting as desired. Drupal 7 tutorial complete!

We hope you found that useful. Happy Drupal-ing!

John Cook
Drupal Developer

John is an accomplished standards-driven developer specialising in Drupal backend.

-->
  • "Factors In Selecting A Mobile Prototyping Tool https://t.co/Uj2odbaiXl"
  • Follow @CurveAgency
    -->