3

I have a View which lists contents. I have a few fields which are composite and have a somehow convoluted logics. What I do is to add some "dummy" fields (for example, the nid of content, or the rf (reference) of product) to the View, and then in hook_views_prerender I modify the value by the logic. For example:

$brand = $view->result[$key]->taxonomy_term_data_field_data_field_brand_name;
if($brand == WHATEVER){
   $view->result[$key]->field_field_field_rf_product_3[0]["rendered"]["#markup"] = function_to_substitute_complicated_value($parameters);   
 ...
 }  

Now, is it good idea to have this dummy field, field_rf_product_3, or would it be better to create a new field programmaticaly, and if so, how could it be done to be added at the proper place (after a given rendered field) in the View output?

5
  • It depends on the function. You can generate data in this dummy field, but if you do heavy queries in function_to_substitute_complicated_value it might be better to store the value in a real field, so you don't have to do the query every time the view is loaded. If it a simple function this should work as well. Feb 24, 2016 at 8:33
  • The approach of saving the node with the data is very interesting, thanks. I will give it a look. In any case, the question remains, if there is some way of adding fields on the fly, I looked for it but did not find anything that worked or that rendered the field in the correct order.
    – Cesar
    Feb 24, 2016 at 8:37
  • Ah, then I misunderstood the question. Have a look at the function hook_views_data(). In the bottom of the commens there is a comment by me about how to display a dynamic value. Feb 24, 2016 at 8:45
  • That is very interesting. It seems to me that this is the correct way of doing what I done by using that "pseudofield", populating it, which was rather cumbersome. Thanks!
    – Cesar
    Feb 24, 2016 at 9:33
  • I'll write you a detailed answer when I am at my pc in an hour or so. Feb 24, 2016 at 12:04

1 Answer 1

7

Basically you have two options to do this elegantly.

  1. Use the computed field module (it also includes the storing of the results in the database to save on heavy SQL queries as mentioned in the comments). It comes with a lot of documentation and examples at the bottom of that page.

Computed Field is a very powerful field module that lets you add a custom "computed fields" to your content types. These computed fields are populated with values that you define via PHP code. You may draw on anything available to Drupal, including other fields, the current user, database tables, you name it. (Feeling the power yet? :) ) You can also choose whether to store your computed field values in the database with other content fields, or have them "calculated" on the fly during node views. (Although you should note that Views use requires database stored values.) This field is literally the Swiss Army knife of fields. So start cooking up your PHP based values!

  1. Write a custom views field handler (example is for Drupal 7 only!). In drupal 8 some functions like hook_views_api() have been removed and the info file has changed.

This is less flexible and will result in a specific field to choose when building a view. However sometimes less flexible can be desirable.

In order to do this you need to write a custom module. Consisting the following folder and files:

  • module_name
    • module_name.info
    • module_name.module
    • views
      • module_name.views.inc
      • module_name_handler_field_custom_field.inc

The .info file describes the module:

name = Custom Views field
description = Provides an additional field to Views
core = 7.x
package = Views
dependencies[] = views
files[] = views/module_name_handler_field_custom_field.inc

The .module file contains the module, which in this case is only a function to let Views know where to look for its files.

/**
 * Implements hook_views_api().
 */
function module_name_views_api() {
  return array(
    'api' => 3,
    'path' => drupal_get_path('module', 'module_name') . '/views',
  );
}

The file module_name.views.inc performs the logic for Views. If you define a new entity, use hook_views_data(). If you alter an existing entity such as a user or a node, use hook_views_data_alter() but also look at the example code of hook_views_data().

In order to create a new field based on another field, you can do something like this:

/**
 * Implements hook_views_data_alter().
 *
 * Defines a new field with content built by the module_name_handler_field_custom_field class.
 * @see hook_views_data()
 */ 
function hook_views_data_alter(&$data) {
 // This example adds an example field to the users table.
  $data['node']['example_field'] = array(
    'title' => t('Example field'),
    'help' => t('Some example content'),
    'real field' => 'field_existing_base_field', // Enter the base fields system name here.
    'field' => array(
      'handler' => 'module_name_handler_field_custom_field',
    ),
  );
}

Finally the handler, which composes the field. Here we can alter the output of the field using the real field we defined above as input.

class module_name_handler_field_custom_field extends views_handler_field {
  /**
   * Render a computed field value (multiplied by 5).
   */
  function render($values) {
    // Load real field value.
    $real_value = $this->get_value($values);
    // Generate new value.
    $value = function_to_substitute_complicated_value($real_value);
    return $this->sanitize_value($value);
  }
}
1
  • Very complete and detailed answer, thank you very much. I am giving a change to the Computed Field Module, but I think that definitely the winner is the custom Views handler, it is also very valuable to see how to extend other modules.
    – Cesar
    Feb 24, 2016 at 15:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.