4

I need to build a view in a matrix format. I have a content type mycontent and a taxonomy vocabulary myvocabulary. The content type has a term reference field in it, which refers to the vocabulary and can have multiple values.

I want to list all contents in a view as columns, and all terms in the vocabulary as a table header, i.e. columns. I want to put a check mark to the corresponding field in the table according to the terms that the content has.

An illustration of what I want to achieve:

+-----------+--------+--------+--------+--------+-----
|           | Term 1 | Term 2 | Term 3 | Term 4 | ...
+-----------+--------+--------+--------+--------+-----
| Content 1 |   x    |   x    |        |   x    |
+-----------+--------+--------+--------+--------+-----
| Content 2 |        |        |        |   x    |
+-----------+--------+--------+--------+--------+-----
| Content 3 |   x    |        |   x    |        |
+-----------+--------+--------+--------+--------+-----
| Content 4 |   x    |    x   |        |        |
+-----------+--------+--------+--------+--------+-----
|    ...    |        |        |        |        |

So, my challenge is to dynamically create a column for each taxonomy term in the vocabulary. I.e. if I add a new taxonomy term, the view should have this column automatically added to the table.

With the default table display I can list the nodes as rows, but it is not possible to make a column for each term in the vocabulary.

I have found 3 different modules which seem to related to my problem:

None of those modules have a stable version for Drupal 7, nor they have a good documentation, if any at all.

I am going to download and install the dev versions of each module and play around. However, before I do that I wanted to ask if anyone has done such a view and if there would be another better approach to achieve such a matrix view.

Other suggestions that doesn't include using Views are also welcome.

closed as too broad by kiamlaluno Jun 7 at 11:15

Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • I think this is possible with views module's table display. Please see knackforge.com/service/professional-support-quiz. But would like to know about your opinion on this before I make any suggestions. – Gladiator Nov 4 '13 at 11:27
  • With the table display, the columns are the view fields. That means in theory I should add a new field for each term. However, I want to have the columns are also generated from the taxonomy terms. For example, if I a new term is added to the vocabulary, the view should have a new column automatically. – Елин Й. Nov 4 '13 at 11:32
  • @ЕлинЙ. I think you can play with slick grid drupal.org/project/slickgrid – Bala Nov 4 '13 at 12:50
  • @Bala I've taken a look at the Slick Grid, but I didn't see any point on its description that it would suit my needs. I think I didn't express well enough what I want to achieve and where the challenge is. I'll update my question to make it clearer. – Елин Й. Nov 4 '13 at 12:55
  • What about the Views Flipped Table module? Here is a quote about it (from the module's project page): > ... provides a views table style with rows and columns flipped. This is useful for views showing few entities with many fields, such as product comparison. – Kasalla Nov 12 '13 at 22:12
6
+50

It can be achieved with the help of hook_views_pre_view() and the Views field template file.

Create a View

Create a view showing content in table format and add two fields:

Content: Title (Title)

The title will populate each row of the first column.

Content: All taxonomy terms (All taxonomy terms)

select: Exclude this field from display

select: Limit terms by vocabulary and tick the vocabulary you want to use.

Your module file

Create a column for each term and populate all the fields with the value from the field Content: All taxonomy terms (All taxonomy terms) Then we'll be able to check if a comma-separated list of terms contains the term of the current column.

/**
 * Implements HOOK_views_pre_view().
 *
 * Adds a field to the "YOUR VIEW NAME" view.
 */
function YOURMODULE_views_pre_view(&$view) {

  if ($view->name == 'YOUR_VIEW_NAME') {
    // the vocabularies defined in the view.
    $vocabularies = array_filter($view->display['default']->handler->options['fields']['term_node_tid']['vocabularies']);
    $terms = YOURMODULE_terms($vocabularies);
    $count = count($terms);
    for ($i=0;$i<$count;$i++) {
      // define the field id.
      $view->display['default']->handler->options['fields']['tid_' . $i]['id'] = 'tid_' . $i;

      // define the table (it has to be the same table for all fields)
      // if you aren't sure what the table name should be, uncomment the line below and take a look at the first field data.
      // debug($view->display['default']->handler->options['fields'], 'VIEW FIELDS', TRUE);
      $view->display['default']->handler->options['fields']['tid_' . $i]['table'] = 'node';

      // here we need to define our custom field output
      // the field "Content: All taxonomy terms (All taxonomy terms)" has a mashine name 'term_node_tid'
      // this field need to be excluded from display because we do not want to display one column only.
      // Instead we will use the data to populate all our custom fields, then we'll be able to define the output for each of them.
      $view->display['default']->handler->options['fields']['tid_' . $i]['field'] = 'term_node_tid';

      // define the field label
      $view->display['default']->handler->options['fields']['tid_' . $i]['label'] = $terms[$i];

      // we need only term names, not links.
      $view->display['default']->handler->options['fields']['tid_' . $i]['link_to_taxonomy'] = 0;
    }
  }
}

A helper function that returns an array of terms. This function will be used twice. First time in hook_views_pre_view() where the argument is available from the View. Second time in YOURMODULE_has_term() where the argument would be hardly to get. That's why I decided to use a static variable here.

/**
 * Helper function that returns an array of terms.
 *
 * @return array
 *   An array of terms from all vocabularies (defined in the view).
 */
function YOURMODULE_terms($vocabularies = NULL) {
  $terms = &drupal_static(__FUNCTION__);
  if (!isset($terms)) {
    $terms = array();
    foreach ($vocabularies as $key => $vocabulary) {
      $vid = taxonomy_vocabulary_machine_name_load($vocabulary)->vid;   
      $taxonomy_tree = taxonomy_get_tree($vid);
      foreach ($taxonomy_tree as $term) {
        $terms[] = $term->name;
      }
    }
  }
  return $terms;
}

A helper function to determine if a field value (comma-separated list of terms) contains the term of current column. This function will be used in a Views field template file.

/**
 * Determines if a comma-seperated list of terms contains the term of the
 * current column.
 *
 * @param $field_alias string
 *   The field alias corresponding to the $field->field_alias value in the view.
 * @param $field_position integer
 *   The column corresponding to the $field->position value in the view.
 * @param $output string
 *   Comma seperated list of terms.
 * @return 'X' if TRUE or bool if FALSE.
 */
function YOURMODULE_has_term($field_alias, $field_position, $output) {

  // because we are using two fields to provide the data
  // we need to skip two positions to get appropriate term keys. 
  $field_position = ($field_position > 1) ? $field_position-2 : $field_position;

  // because this is a second call for this function,
  // we don't need to define vocabularies as an argument.
  $terms = testmodule_terms();

  // each column has their own term name.
  $term_name = $terms[$field_position];

  // first column fields.
  if ($field_alias == 'node_title') {
    return $output;
  }

  // the fields in all terms columns.
  else {

    // explode terms and trim whitespaces.
    $term_names = array_map('trim',explode(",",$output));

    // check the term names array contains the term of the current column.
    if (in_array($term_name, $term_names)) {
      return 'X'; // check mark
    }
    return FALSE;
  }
}

Views field template file

Create a View template file views-view-field--[YOUR-VIEW-NAME].tpl.php and place in your templates folder.

<?php
// We're assuming that this view only has two fields (Content: Title)
// and  Content: All taxonomy terms (All taxonomy terms). 
// All other fields are generated by the HOOK_views_pre_view() function in the
// `YOURMODULE.module` and those should be passed through the
// `YOURMODULE_has_term` function which determines if the $output
// (comma-seperated terms) contains the column term name.
print YOURMODULE_has_term($field->field_alias, $field->position, $output);
?>

I was able to answer this question thanks to a similar post here and added lots of comments to the code. Hope it helps.

  • Thanks a lot Jack-PL. Actually I have already solved this problem using Views Matrix. However, your answer look very reasonable and I'll definitely test it on this weekend and accept your answer. – Елин Й. Nov 15 '13 at 7:44
  • You're welcome. Please don't forget to share your opinion after testing. It might be useful for the others, including myself :) – Jack-PL Nov 15 '13 at 18:34
  • I've just tested your answer and it works. I've already awarded you the bounty. However, as I already stated, I've done it with Views Matrix and it required no template hacks. – Елин Й. Nov 16 '13 at 17:02
0

I solved this issue using Views Matrix module. Although, as I stated in my question, it has only a dev version, it is working without problems.

Views matrix provides a matrix style plugin for Views. This overrides pager settings to display items grouped by a row and column header field. Row items that match a row and column value are grouped into the same cell.

The steps how I did it:

  1. Create a view showing content in Matrix format, which is provided by Views Matrix module.
  2. Add the Relationship to the taxonomy term Content: Term reference field (field_my_term_reference)
  3. Add fields Taxonomy term: Name and Content: Title and exclude them from display, they are for the table headers.
  4. Add more fields to display in table content, or a Global: Custom text field for just showing an "X" or a check-sign or whatever else..
  5. Under Format -> Settings, select for column header Content: Term reference field and for row header Content: Title

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