46

In Drupal 7, I have created a View that lists several fields. The fields are grouped by another field (the term ID of the field). The mark up looks like this:

<h3>[Term 1]</h3>
<div class="views-row views-row-1 views-row-odd views-row-first"> [Field Content] </div>
<div class="views-row views-row-2 views-row-even"> [Field Content] </div>
<div class="views-row views-row-3 views-row-odd views-row-last"> [Field Content] </div>

<h3>[Term 2]</h3>
<div class="views-row views-row-1 views-row-odd views-row-first"> [Field Content] </div>
<div class="views-row views-row-2 views-row-even"> [Field Content] </div>
<div class="views-row views-row-3 views-row-odd views-row-last"> [Field Content] </div>

<h3>[Term 3]</h3>
<div class="views-row views-row-1 views-row-odd views-row-first"> [Field Content] </div>
<div class="views-row views-row-2 views-row-even"> [Field Content] </div>
<div class="views-row views-row-3 views-row-odd views-row-last"> [Field Content] </div>

However, I need the mark up to look like this:

<div id="term_1">
     <h3>[Term 1]</h3>
     <div class="views-row views-row-1 views-row-odd views-row-first"> [Field Content] </div>
     <div class="views-row views-row-2 views-row-even"> [Field Content] </div>
     <div class="views-row views-row-3 views-row-odd views-row-last"> [Field Content] </div>
</div>

<div id="term_2">
     <h3>[Term 2]</h3>
     <div class="views-row views-row-1 views-row-odd views-row-first"> [Field Content] </div>
     <div class="views-row views-row-2 views-row-even"> [Field Content] </div>
     <div class="views-row views-row-3 views-row-odd views-row-last"> [Field Content] </div>
</div>

<div id="term_3">
     <h3>[Term 3]</h3>
     <div class="views-row views-row-1 views-row-odd views-row-first"> [Field Content] </div>
     <div class="views-row views-row-2 views-row-even"> [Field Content] </div>
     <div class="views-row views-row-3 views-row-odd views-row-last"> [Field Content] </div>
</div>

I know that you can use views-view-unformatted.tpl.php (Style Output) to over ride the view and then insert a DIV to wrap the group.

However, I need my wrapper DIV to be like this <div id="term_ID_{number of ID}">. The number ID will correspond to the term that has been used to group the fields. By default, if you use views-view-unformatted.tpl.php, you cannot insert tokens for term IDs into it.

Any help would be appreciated.

11 Answers 11

52

I needed to do this same thing recently. You can create a template file:

  • Find the template under /modules/views/themes/views-view-unformatted.tpl.php.
  • Copy it into your /sites/all/themes/<your-theme> folder and rename to views-view-unformatted--<nodetype>.tpl.php.
  • Edit the file adding a div around the entire template. The <h3> tag is the group name.

Here is what the modified template file might look like.

<div class="your-class">
<?php if (!empty($title)): ?>
    <h3><?php print $title; ?></h3><!--this is the group name-->
<?php endif; ?>
<?php foreach ($rows as $id => $row): ?>
  <div class="<?php print $classes_array[$id]; ?>">
    <?php print $row; ?>
</div>
<?php endforeach; ?>
</div><!--end your div-->
4
  • 4
    This just worked for me too, ta muchly :)
    – Clive
    May 15, 2012 at 22:22
  • You saved my time buddy! Nov 22, 2015 at 5:41
  • 1
    For anyone reading this answer wondering how to work out what to name their tpl file, see the answer here drupal.stackexchange.com/questions/11468/… tldr; in your view edit page, under advanced, click theme: information Apr 16, 2016 at 18:36
  • Although the Q and A are Drupal 7, the same works for Drupal 8.
    – Duncanmoo
    Jun 28, 2017 at 10:59
17

Try Format:HTML list. That will wrap the whole thing in an item-list. For my purpose it's perfect (a list of taxonomy items). Hope this helps.

1
  • This is good. I wanted to add the group field as a class on the wrapper so I can style accordingly but can't seem to do that in views UI itself. What I've done instead if it helps someone is: SORT by that field also firstly, and then use css first selector.
    – klidifia
    Jun 11, 2017 at 21:57
10

Have you tried the Rewrite results feature? Click on the field you wish to edit and scroll down until you see Rewrite results. Check the box for Rewrite the output of this field and then customize the HTML as necessary. For the tokens, you can use the Replacement Patterns shown in the box below the text input area.

Regarding the Replacement Patterns, note the warning that Views displays:

Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.

If this isn't enough, try adding a new field, Global: Custom text. This will allow you to add some arbitrary HTML and the Replacement Patterns are available here as well. You can use two separate Global: Custom text fields to add the <div> start and end tags.

6
  • Hi Thanks for your help. I am trying to alter the grouping field (under Page: Style options > Grouping field Nr.1) There does not seem to be any options to alter the output of this grouping field. Using Global: Custom text effects the row within the group but not the outside of the group,
    – big_smile
    May 1, 2012 at 10:48
  • When you select Grouping field Nr.1, there are options for Use rendered output to group rows and Row class. Neither of those does what you want? May 1, 2012 at 10:54
  • 1
    Hi Thanks for your help. Those options just add wrapper DIvs around the individual fields as opposed to the entire group (that is created by Grouping field Nr.1).
    – big_smile
    May 1, 2012 at 11:12
  • @PatrickKenny Do you know if this method has bad impact on the view's rendering time?
    – user5950
    Jul 11, 2013 at 12:26
  • @user5950 I use rewrite results all the time but I've never noticed a performance hit. I think that other common views tasks like adding relationships are more likely to hamper performance before Rewrite Results will. Jul 11, 2013 at 13:31
4

These days I ran into the same issue. And what I needed beside the group wrapper was a css class like first/last per group.

So I added in views-view-unformatted.tpl.php the following php code:

<?php
  #### defs
  // call a global variable every time the template is called
  global $static;
  // be aware of the key_name for the global variable to keep it 
  // unique for every display
  // I call the same view in one panel several times with 
  // different arguments 
  $key_name = $view->name . '_' . $view->current_display ;
  foreach ($view->args as $value) {
    $key_name .= '_' . $value;
  }
  // init classes array
  $group_classes = array();
  ## groups counter - store in global variable 
  if (!isset($static[$key_name]['gc'])) {
    $static[$key_name]['gc'] = 1;
  }
  else {
    $static[$key_name]['gc']++;
  }
  #### classes
  ## counter
  $group_classes[] = 'group-' . $static[$key_name]['gc'];
  ## first
  if ($static[$key_name]['gc'] == 1) {
    $group_classes[] = 'first';
  }
  ## last
  // get max row "id" per group
  foreach ($rows as $id => $row) {
    $max_id = $id;
  }
  // count results (-1 because $id starts with 0)
  $count_results = count($view->result) - 1;
  //
  if ($max_id == $count_results) {
    $group_classes[] = 'last';
  }
  ## ret
  $group_class = implode(' ', $group_classes);
?>

Here the html part with the wrapper and classes:

<div class="views-group <?php print $group_class; ?>">
  <?php if (!empty($title)): ?>
    <h3><?php print $title; ?></h3>
  <?php endif; ?>
  <?php foreach ($rows as $id => $row): ?>
    <div <?php if ($classes_array[$id]) { print 'class="' . $classes_array[$id] .'"';  } ?>>
      <?php print $row; ?>
    </div>
  <?php endforeach; ?>
</div>

The output will be:

<div class="views-group group-1 first">
  content of first group
</div>
<div class="views-group group-2">
  content of second group
</div>    
<div class="views-group group-3 last">
  content of third group
</div>

Might be helpful - enjoy

2

So I guess the biggest riddle is how to generate the class using the value of the $title within h3 tags. I'd try Transliteration module and the following snippet:

<?php
  $group_class = function_exists('transliteration_get') ? transliteration_get($title) : $title;
  $group_class = trim($group_class);
  $group_class = str_replace(' ', '-', $group_class);
  $group_class = strtolower($group_class);
?>

This worked for me when I had to make named anchors within a view.

1

Very useful - I needed to add in some alpha / omega classes for a grid based layout and also some odd even to be able to clear both for each row. I edited the line from:

$group_classes[] = 'group-' . $static[$key_name]['gc'];

to this:

$group_classes[] = 'group-' . $static[$key_name]['gc'] . ($static[$key_name]['gc'] % 2 ? ' alpha even' : ' omega odd');

Which gives the required output.

1

You don't need the transliteration module. Drupal core has the drupal_html_class function for this.

1

I had a similar issue today, but needed a specific class on the wrapper html, in my case the view is grouped by taxonomy terms, and we need a specific style on each term, so a specific class per term. Here's how we changed the view unformatted template:

<?php if(is_numeric($title)) { $term = taxonomy_term_load($title); $title = $term->name; } ?>
<div class="term-<?php print $term->tid;?>">
<?php if (!empty($title)): ?>
    <h3><?php print $title; ?></h3><!--this is the group name-->
<?php endif; ?>
<?php foreach ($rows as $id => $row): ?>
  <div class="<?php print $classes_array[$id]; ?>">
    <?php print $row; ?>
</div>
<?php endforeach; ?>
</div><!--end your div-->

In the view the display of the taxonomy term field is set to: "Show entity id". So we get the id as part of the class name, and then loads the title based on the same id.

1

For anyone who doesn't want to dive into the code and mess about with templates there's an easy way to do this by stripping the default div classes using Fences and adding your own div into the prefix and suffix of the field using Simple field formatter . If you have multiple fields simply add the the containing div in the prefix of the first field, and the in the suffix of the last field.

So the native structure with the prefix and suffix areas unstripped would look something like:

<div class="field field-name-field-test field-type-text field-label-above">
 <div class="field-label">Foobar field:&nbsp;</div>
  <div class="field-items">
   *:prefix posted here*
   <div class="field-item even">Leaner markup means better front-end performance.</div>
   *:suffix posted here*
 </div>
</div>

If you were going to add the class "foo" It would become

   <div class="foo"> *:prefix posted here*
    Leaner markup means better front-end performance.
   </div> *:suffix posted here*
1

The answer from chrisjlee above explains it well except for what to name the template file. If you want to change only one view, the new file must include the machine name of the view. You can find this in the url for the view's edit page. It's explained very well in this comment on a similar issue: https://www.drupal.org/node/1383696#comment-6729128

I needed a class around the rows using the value of $title so that I could render them in 2 columns. Here's the code:

<?php if (!empty($title)): ?>
  <h3><?php print $title; ?></h3>
<?php endif; ?>
<div class="<?php print strtolower($title); ?>" > <!--added div with class-->
<?php foreach ($rows as $id => $row): ?>
  <div<?php if ($classes_array[$id]) { print ' class="' . $classes_array[$id] .'"';  } ?>>
    <?php print $row; ?>
  </div>
<?php endforeach; ?>
</div> <!--end of added div-->
1

I came across a similar issue. I wanted my grouped rows to display within a bootstrap accordion. I couldnt have it working with the Views Bootstrap module.
Comment #4 solved my problem.
Here is what my views-view-unformatted-[my_view_name]-[my_display_name].tpl.php looks like

<?php

/**
 * @file
 * YOUR_THEME simple view template to display a list of rows.
 *
 * @ingroup views_templates
 */
?>

    <?php
    #### defs
      // call a global variable every time the template is called
      global $static;
      // be aware of the key_name for the global variable to keep it 
      // unique for every display
      // I call the same view in one panel several times with 
      // different arguments 
      $key_name = $view->name . '_' . $view->current_display ;
      foreach ($view->args as $value) {
        $key_name .= '_' . $value;
      }
      // init classes array
      $group_classes = array();
      ## groups counter - store in global variable 
      if (!isset($static[$key_name]['gc'])) {
        $static[$key_name]['gc'] = 1;
      }
      else {
        $static[$key_name]['gc']++;
      }
      #### classes
      ## counter
      $group_classes[] = 'group-' . $static[$key_name]['gc'];
      ## first
      if ($static[$key_name]['gc'] == 1) {
        $group_classes[] = 'first';
      }
      ## last
      // get max row "id" per group
      foreach ($rows as $id => $row) {
        $max_id = $id;
      }
      // count results (-1 because $id starts with 0)
      $count_results = count($view->result) - 1;
      //
      if ($max_id == $count_results) {
        $group_classes[] = 'last';
      }
      ## ret
      $group_class = implode(' ', $group_classes);
      $group_id = implode($group_classes); // helps me having a id whithout spaces for my accordions panels.
    ?>

    <div class="panel panel-default <?php print $group_class; ?>">
        <?php if (!empty($title)): ?>
          <?php if($group_id == 'group-1first'): ?>
                <!--<h3><?php //print $title; ?></h3>-->
                <div class="panel-heading" role="tab" id="heading<?php print $group_id; ?>">
                    <h3 class="panel-title">
                        <a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse<?php print $group_id; ?>" aria-expanded="true" aria-controls="collapse<?php print $group_id; ?>">
                            <?php print $title; ?>
                        </a>
                    </h3>
                </div>
                <div id="collapse<?php print $group_id; ?>" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="heading<?php print $group_id; ?>">

            <?php else: ?>
                <div class="panel-heading" role="tab" id="heading<?php print $group_id; ?>">
                    <h3 class="panel-title">
                        <a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse<?php print $group_id; ?>" aria-expanded="false" aria-controls="collapse<?php print $group_id; ?>">
                            <?php print $title; ?>
                        </a>
                    </h3>
                </div>
                <div id="collapse<?php print $group_id; ?>" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading<?php print $group_id; ?>">

            <?php endif; ?>
        <?php endif; ?>                                                 

                    <div class="panel-body">
                        <?php foreach ($rows as $id => $row): ?>
                                    <div<?php if ($classes_array[$id]) { print ' class="' . $classes_array[$id] .'"';  } ?>>
                                        <?php print $row; ?>
                                    </div>
                        <?php endforeach; ?>
                    </div>
            </div>
    </div>

of course, for the accordion to work, you also need to edit views-view-[my_view_name]-[my_display_name].tpl.php in order to have

<?php if ($rows): ?>
    <!--<div class="view-content">-->
    <div class="view-content panel-group" id="accordion" role="tablist" aria-multiselectable="true">
      <?php print $rows; ?>
    </div>
  <?php elseif ($empty): ?>
    <div class="view-empty">
      <?php print $empty; ?>
    </div>
  <?php endif; ?>

I left the default code from the module between html comments.
Hope it helps.

Your Answer

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

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