Note: This functionality is the Views 3/Drupal 7 equivalent of this older snippet (with some extra features added).
This functionality has also been turned into a module called Views Flipped Table for Drupal 6 and 7.

This Views snippet allows you to render a table format with the columns and rows switched.
Suppose you have the following output (a table with each row being a node):

Title   | Price 1 | Price 2
----------------------------
Node #1 | $10     | $20
Node #2 | $15     | $25

but what you really want are the nodes displayed as columns, and the different prices as the rows:

        | Node #1 | Node #2
----------------------------
Price 1 | $10     | $15
Price 2 | $20     | $25

Save this code as a Views template file, named 'views-view-table.tpl.php' (or a variation thereof), in your theme directory.

You can define any field in the view to be displayed as the column headings by simply giving them a label of 'Column Heading' (i.e. the column headings aren't restricted to the node titles).

You can also define a field in the view whose value will be used as the class name for each cell in its column. This would be useful if you wanted to highlight the 'Node #2' column in the example above using CSS. Simply add a label of 'Column ID' to the field.

Flipped table with title as table caption

<?php
/**
 * @file views-flipped-table.tpl.php
 * Template to display a view as a table with rows and columns flipped.
 *
 * - $title : The title of this group of rows.  May be empty.
 * - $header: An array of header labels keyed by field id.
 * - $fields: An array of CSS IDs to use for each field id.
 * - $class: A class or classes to apply to the table, based on settings.
 * - $row_classes: An array of classes to apply to each row, indexed by row
 *   number. This matches the index in $rows.
 * - $rows: An array of row items. Each row is an array of content.
 *   $rows are keyed by row number, fields within rows are keyed by field ID.
 *
 * @ingroup views_templates
 */
?>
<?php
// Flip the table.
$row = array();
foreach ($rows as $col){
  foreach ($col as $ltr => $value){
    $row[$ltr][] = $value;
  }
}
$first = isset($row['title']);
$element = 'odd';
?>
<table class="<?php print $class; ?>">
  <?php if (!empty($title)) : ?>
    <caption><?php print $title; ?></caption>
  <?php endif; ?>

  <?php if ($first) : ?>
    <thead>
    <tr class="<?php echo $element; ?>">
        <th>
        </th>
      <?php foreach ($row['title'] as $title) : ?>
        <th>
          <?php echo $title; ?>
        </th>
      <?php endforeach; ?>
    </tr>
    </thead>
  <?php
  $first = FALSE;
endif; //$first
  $element = 'even';
  ?>
    <tbody>
    <?php foreach ($row as $field => $rowname) : ?>
      <?php if ($field != 'title') : ?>
        <tr class="<? echo $element; ?>">
            <th>
              <?php echo $header[$field]; ?>
            </th>
          <?php foreach ($rowname as $count => $item): ?>
            <td>
              <?php echo $item; ?>
            </td>
          <?php endforeach; ?>
        </tr>
        <?php
        if ($element == 'odd'){
          $element = 'even';
        } else {
          $element = 'odd';
        }
        ?>
        <?php endif; // field != title ?>
      <?php endforeach; ?>
    </tbody>
</table>

Flipped table without caption thead

<?php
/**
 * @file views-flipped-table.tpl.php
 * Template to display a view as a table with rows and columns flipped.
 *
 * - $title : The title of this group of rows.  May be empty.
 * - $header: An array of header labels keyed by field id.
 * - $fields: An array of CSS IDs to use for each field id.
 * - $class: A class or classes to apply to the table, based on settings.
 * - $row_classes: An array of classes to apply to each row, indexed by row
 *   number. This matches the index in $rows.
 * - $rows: An array of row items. Each row is an array of content.
 *   $rows are keyed by row number, fields within rows are keyed by field ID.
 *
 * @ingroup views_templates
 */
?>
<?php
// Flip the table.
$row = array();
foreach ($rows as $col){
  foreach ($col as $ltr => $value){
    $row[$ltr][] = $value;
  }
}
$first = isset($row['title']);
$element = 'odd';
?>
<table class="<?php print $class; ?>">
  <?php if (!empty($title)) : ?>
    <caption><?php print $title; ?></caption>
  <?php endif; ?>

  <?php if ($first) : ?>
<!--    <thead>-->
<!--    <tr class="--><?php //echo $element; ?><!--">-->
<!--        <th>-->
<!--        </th>-->
<!--      --><?php //foreach ($row['title'] as $title) : ?>
<!--        <th>-->
<!--          --><?php //echo $title; ?>
<!--        </th>-->
<!--      --><?php //endforeach; ?>
<!--    </tr>-->
<!--    </thead>-->
  <?php
  $first = FALSE;
endif; //$first
  $element = 'even';
  ?>
    <tbody>
    <?php foreach ($row as $field => $rowname) : ?>
  <!--    --><?php /*if ($field != 'title') : */?>
        <tr class="<? echo $element; ?>">
            <th>
              <?php echo $header[$field]; ?>
            </th>
          <?php foreach ($rowname as $count => $item): ?>
            <td>
              <?php echo $item; ?>
            </td>
          <?php endforeach; ?>
        </tr>
        <?php
        if ($element == 'odd'){
          $element = 'even';
        } else {
          $element = 'odd';
        }
        ?>
<!--        --><?php /*endif; // field != title */?>
      <?php endforeach; ?>
    </tbody>
</table>

Comments

hartogsmith’s picture

thanks for this -- it displays fine, except that it displays an 'undefined index @ line 36' error.

hartogsmith’s picture

if anyone else experiences this error, tweaking line 36 worked for me:
from this
$row[$field][$node[$col_id]] = $value;
to
$row[$field][$col_id] = $value;

cm_is’s picture

in combination with a flag=true filter, when using above template, only one node shows up. any idea whether its a flag or a views issue?

marcoka’s picture

having that too. used this inseatd

<?php
/**
 * @file views-flipped-table.tpl.php
 * Template to display a view as a table with rows and columns flipped.
 *
 * - $title : The title of this group of rows.  May be empty.
 * - $header: An array of header labels keyed by field id.
 * - $fields: An array of CSS IDs to use for each field id.
 * - $class: A class or classes to apply to the table, based on settings.
 * - $row_classes: An array of classes to apply to each row, indexed by row
 *   number. This matches the index in $rows.
 * - $rows: An array of row items. Each row is an array of content.
 *   $rows are keyed by row number, fields within rows are keyed by field ID.
 *
 * @ingroup views_templates
 */
?>
<?php
// Flip the table.
$row = array();
foreach ($rows as $col){
  foreach ($col as $ltr => $value){
    $row[$ltr][] = $value;
  }
}
$first = isset($row['title']);
$element = 'odd';
?>
<table class="<?php print $class; ?>">
  <?php if (!empty($title)) : ?>
    <caption><?php print $title; ?></caption>
  <?php endif; ?>

  <?php if ($first) : ?>
    <thead>
    <tr class="<?php echo $element; ?>">
        <th>
        </th>
      <?php foreach ($row['title'] as $title) : ?>
        <th>
          <?php echo $title; ?>
        </th>
      <?php endforeach; ?>
    </tr>
    </thead>
  <?php
  $first = FALSE;
endif; //$first
  $element = 'even';
  ?>
    <tbody>
    <?php foreach ($row as $field => $rowname) : ?>
      <?php if ($field != 'title') : ?>
        <tr class="<? echo $element; ?>">
            <th>
              <?php echo $header[$field]; ?>
            </th>
          <?php foreach ($rowname as $count => $item): ?>
            <td>
              <?php echo $item; ?>
            </td>
          <?php endforeach; ?>
        </tr>
        <?php
        if ($element == 'odd'){
          $element = 'even';
        } else {
          $element = 'odd';
        }
        ?>
        <?php endif; // field != title ?>
      <?php endforeach; ?>
    </tbody>
</table>

apprayo’s picture

The code only displays one item, plus error on line 36.

I modified it a bit like this:

<?php
/**
* Table view with rows/columns switched
*/

// Remove the 'cols-x' class from the table
$table_classes = explode(' ', $classes);
foreach ($table_classes as $id => $table_class) {
  if (strpos($table_class, 'cols-') === 0) {
    unset($table_classes[$id]);
  }
}
$classes = implode(' ', $table_classes);

// Get the field IDs of the column ID and heading fields
// I'm unsure what this part is for, so I comment this.
/*$col_id = '';
$col_heading = '';
foreach ($header as $id => $value) {
  if ($value == 'Column ID') {
    $col_id = $id;
  }
  elseif ($value == 'Column Heading') {
    $col_heading = $id;
  }
}*/

// Swap the x and y axis' of the table
$row = array();
foreach ($rows as $node) {
  foreach ($node as $field => $value) {
    $row[$field][] = $value;
  }
}

// Setup variable for assigning odd/even classes
$zebra = 'odd';
?>

<table<?php if ($classes) print ' class="' . $classes . '"'; ?><?php print ' ' . $attributes; ?>>
  <?php if (!empty($title)): ?>
    <caption><?php print $title; ?></caption>
  <?php endif; ?>

  <?php if (!empty($row['col_heading'])): ?>
    <thead>
      <tr>
        <th></th>
        <?php foreach ($row['col_heading'] as $id => $heading): ?>
          <th class="<?php print $id; ?>">
            <?php print $heading; ?>
          </th>
        <?php endforeach; ?>
      </tr>
    </thead>
  <?php endif; ?>

  <tbody>
    <?php foreach ($row as $field => $values): ?>
      <?php if ($field != 'col_heading'): ?>
        <tr class="<?php print $field; ?> <?php print $zebra; ?>">
          <th><?php print $header[$field]; ?></th>
          <?php foreach ($values as $id => $value): ?>
            <td class="<?php print $id; ?>">
              <?php print $value; ?>
            </td>
          <?php endforeach; ?>
        </tr>
        <?php
          if ($zebra == 'odd') {
            $zebra = 'even';
          }
          else {
            $zebra = 'odd';
          }
        ?>
      <?php endif; ?>
    <?php endforeach; ?>
  </tbody>

</table>
Khalonn’s picture

is it possible to add this table view with rows/columns switched without overwriting the old design and keep both?

tr33m4n’s picture

Would love for this to work however I get the following errors when viewing the view

    Warning: Invalid argument supplied for foreach() in include() (line 18 of /var/www/21designs/sites/all/themes/repro/views-view--pricing-table.tpl.php).
    Warning: Invalid argument supplied for foreach() in include() (line 29 of /var/www/21designs/sites/all/themes/repro/views-view--pricing-table.tpl.php).

Any ideas?
Cheers

On the internet, nobody knows you're a dog

sakthiprogrammer’s picture

I have similar problem.
any ideas

blade_ukraine’s picture

I also had this problem, but I managed to find a solution. Here's my version of the file.

<?php
/**
* Table view with rows/columns switched
*/

// Remove the 'cols-x' class from the table
$table_classes = explode(' ', $classes);
foreach ($table_classes as $id => $table_class) {
  if (strpos($table_class, 'cols-') === 0) {
    unset($table_classes[$id]);
  }
}
$classes = implode(' ', $table_classes);

// Get the field IDs of the column ID and heading fields
// I'm unsure what this part is for, so I comment this.
/*$col_id = '';
$col_heading = '';
foreach ($header as $id => $value) {
  if ($value == 'Column ID') {
    $col_id = $id;
  }
  elseif ($value == 'Column Heading') {
    $col_heading = $id;
  }
}*/
if($view->style_plugin->rendered_fields){

$rows = $view->style_plugin->rendered_fields;

// Swap the x and y axis' of the table
$row = array();
foreach ($rows as $node) {
  foreach ($node as $field => $value) {
    $row[$field][] = $value;
  }
}

// Setup variable for assigning odd/even classes
$zebra = 'odd';
?>

<table<?php if ($classes) print ' class="' . $classes . '"'; ?><?php print ' ' . $attributes; ?>>
  <?php if (!empty($title)): ?>
    <caption><?php print $title; ?></caption>
  <?php endif; ?>

  <?php if (!empty($row['col_heading'])): ?>
    <thead>
      <tr>
        <th></th>
        <?php foreach ($row['col_heading'] as $id => $heading): ?>
          <th class="<?php print $id; ?>">
            <?php print $heading; ?>
          </th>
        <?php endforeach; ?>
      </tr>
    </thead>
  <?php endif; ?>

  <tbody>
    <?php foreach ($row as $field => $values): ?>
      <?php if ($field != 'col_heading'): ?>
        <tr class="<?php print $field; ?> <?php print $zebra; ?>">
          <th><?php //print $header[$field]; ?></th>
          <?php foreach ($values as $id => $value): ?>
            <td class="<?php print $id; ?>">
              <?php print $value; ?>
            </td>
          <?php endforeach; ?>
        </tr>
        <?php
          if ($zebra == 'odd') {
            $zebra = 'even';
          }
          else {
            $zebra = 'odd';
          }
        ?>
      <?php endif; ?>
    <?php endforeach; ?>
  </tbody>

</table><?php } ?>
gratefulcreative’s picture

Thx very much blade_A-web - this works well for me, but the labels on the y-axis (product names) have disappeared.

Thx very much,

grateful

Anonymous’s picture

Great post - really helped me on a project that is heavily using views. The only issue I had was not being able to use css to style the td classes because they were numbers. Changed line 68 from this:

print $id; ">

to this:

print "c" . $id; ">

and then was able to style with css using td.c1, td.c2. etc.

timtk’s picture

This works fine for me however, I have columns that I would like to hide when they are empty. When I make the settings change in views>>myview>>format>>table>>settings it saves fine.
However, when I look at the views that should shows multiple nodes, its show the same node repeated. (So if there were meant to be two different nodes it shows the same node twice)
Have done a bit more digging and it maybe related to this.
http://drupal.org/node/1371252

timtk’s picture

Found the solution simply needed to upgrade views from 7.x-3.3 to 7.x-3.5

RKopacz’s picture

I'm going to be working on a D8 version of this. If anyone has tried this already, I'd love to see how you did it. It seems as though the Flipped Views module has no current path for a D8 version.

When I get it done, I'll post the code here.

miphol’s picture

Here is the code to flip table in Drupal 8, there is no need to change twig template, just add a theme preprocess function.

use Drupal\Core\Render\Markup;

function MYTHEME_preprocess_views_view_table(&$vars) {
	$view = $vars['view'];
	$view_id = $view->storage->id();

	if ($view_id == 'flip_table') {
		$rows = $vars['rows'];
		$header = $vars['header'];

		// gather all cells, abandoning row attributes
		$cells = array();
		$cells[]['columns'] = $header;
		foreach ($rows as $row) {
			$cells[]['columns'] = $row['columns'];
		}

		// transpose
		$rows = array();
		foreach ($cells as $num => $col) {
			$index = 0;
			foreach ($col['columns'] as $field => $value) {
				// update attributes
				$value['attributes']->removeAttribute('headers');
				$value['attributes']->removeAttribute('id');
				if ($index == 0) {
					// this is a header cell
					$value['attributes']->addClass('views-field-'.$field);
				}
				// update output format
				if (!is_array($value['content'])) {
					$text = $value['content'];
					$value['content'] = array(0 => array('field_output' => Markup::create($text)));
				}
				// swap cell's position
				if (!isset($rows[$index])) $rows[$index] = array('columns' => array());
				$rows[$index]['columns'][] = $value;
				
				$index++;
			}
		}

		$vars['header'] = $rows[0]['columns'];
		array_splice($rows, 0, 1);
		$vars['rows'] = $rows;
	}
}