Blog

Eliminating ‘divitis’ from Drupal part 1: Views

I don’t know about you but the markup that gets spit out via Views (or frankly, anything in Drupal) skeeves me out! Don’t get me wrong, I love Views and the wide array of things it can do but 99% of the time I don’t want the markup provided. Drupal has enough ‘divitis’ going on that if I can eliminate as much as possible in my views the better! This post is the first in a series I’m going to write on how to help eliminate the excess markup in various places in Drupal.

Beware!!

As the saying goes ‘with great power comes great responsibility’ and that couldn’t be any more true here. You sincerely need to understand your goals for the markup of your site on a whole scale basis before delving too deep into removing markup. This can seriously cause tons of headaches down the line if you don’t know what you’re doing. Treat ‘divitis’ at your own risk!

Why?

Unnecessary markup can greatly decrease your site’s performance. Since Drupal throws divs everywhere so that you can style nearly everything with ease it gets out of control quickly. Let’s say you’re creating a blog site and basically want to create your own blog landing page showing all the blog teasers. Views makes this insanely easy but then you’re left with extra markup that you don't need.

Default views markup

The views markup is not the only markup that can go here (quite frankly not much is needed after ‘region-content’ and much isnt needed within the node but that's another story), but none of it is needed in this case. I do not need to target the wrapper, the views content, or the views rows because there is no styling that’s specific to them. 

The standard way to remove is to create unique templates for this view and manually remove the content. Easy enough but when you are working on a large site with TONS of views creating 2 template files for each view (and that's if you're using node objects, using fields would require additional templates) is just too much to maintain. 

I’m going to share here my method for removing ALL default markup from multiple views with only 2 templates. You’ll need to evaluate your specific situation to see if removing all the markup is useful for you or not. You may also choose to remove some of the markup and not others, for example if you need the view’s wrapper div for its provided classes.

Modifying markup in Views

For a while now you’ve been able to specify the wrapper element, label element and field wrapper element for each field.

Style settings for views fields

This is great because you can have certain aspects of the markup in code in the view and not need to change/create a template. I use this feature all the time but this is just for fields so you’re still left with all the views wrapper divs that can get excessive if you don’t need them. In a future post I will discuss eliminating markup here.

Getting started

Before I get started explaining I will assume the following:

If you don’t understand any of this, this may be a bit too advanced for you. Feel free to browse the links above from the Definitive Guide to Drupal 7 and then come back.

Creating new templates

The method we’re going to take here is to create views templates that print out the content of the view only with no markup and use these templates for any and all views whose markup we want to remove. Therefore the first step is to identify and create these templates.

To get an idea of what templates are used in a view, click to edit a view and then open the ‘Advanced’ fieldset on the right. Then locate the ‘Theme: information’ link at the bottom and click it. Depending on your view you will see lots of options here (clicking any will show you the default markup) but a basic view displaying node teasers should show:

  • Display output: This is the overall container for the view including pagers, view header, view footer, view empty, exposed filters, views rows etc.
  • Style output: This depends on what you have selected for example if you are using a list this template provides the list markup. This also shows any ‘grouped’ fields.
  • Row style output: This shows for each row the markup for each field, with wrapper, label and field markup. This is not needed when using node teasers but is still listed on the page.

The first template name listed after each is the base template for all views, you could potentially overwrite this but then it would modify ALL of your views. Since we probably want to target specific views we will create new templates:

  • Display output: views-view--content-only.tpl.php
      1. <?php
      2. /**
      3.  * @file
      4.  * Main view template.
      5.  * @ingroup views_templates
      6.  */
      7. ?>
      8. <?php print render($title_prefix); ?>
      9. <?php if ($title): ?>
      10. <?php print $title; ?>
      11. <?php endif; ?>
      12. <?php print render($title_suffix); ?>
      13. <?php if ($header): ?>
      14. <?php print $header; ?>
      15. <?php endif; ?>
      16. <?php if ($exposed): ?>
      17. <?php print $exposed; ?>
      18. <?php endif; ?>
      19. <?php if ($attachment_before): ?>
      20. <?php print $attachment_before; ?>
      21. <?php endif; ?>
      22. <?php if ($rows): ?>
      23. <!?php print $rows; ?>
      24. <?php elseif ($empty): ?>
      25. <?php print $empty; ?>
      26. <?php endif; ?>
      27. <?php if ($pager): ?>
      28. <?php print $pager; ?>
      29. <?php endif; ?>
      30. <?php if ($attachment_after): ?>
      31. <?php print $attachment_after; ?>
      32. <?php endif; ?>
      33. <?php if ($more): ?>
      34. <?php print $more; ?>
      35. <?php endif; ?>
      36. <?php if ($footer): ?>
      37. <?php print $footer; ?>
      38. <?php endif; ?>
      39. <?php if ($feed_icon): ?>
      40. <?php print $feed_icon; ?>
      41. <?php endif; ?>
  • Style output: views-view-unformatted--content-only.tpl.php
      1. <?php
      2. /**
      3.  * @file
      4.  * Default simple view template to display a list of rows.
      5.  * @ingroup views_templates
      6.  */
      7. ?>
      8. <?php if (!empty($title)): ?>
      9. <h3><?php print $title; ?></h3>
      10. <?php endif; ?>
      11. <?php foreach ($rows as $id => $row): ?>
      12. <?php print $row; ?>
      13. <?php endforeach; ?>

Telling Drupal to use our templates

Since these templates don’t follow any naming convention that Drupal or Views knows (that is unless you have a view called ‘content_only’ which would be silly) we have to specify where they should be used.

Each views template has a corresponding preprocess function where various variables are set. In here is a variable, $theme_hook_suggestions that you can use to provide alternate templates that would override this view. In order to implement each template we’ll need to create a preprocess function for each:

  1. <?php
  2. /**
  3.  * Implements template_preprocess_views_view().
  4.  */
  5. function custom_theme_preprocess_views_view(&$vars) {
  6. dsm($vars);
  7. }

So we have our preprocess functions and if we DSM $vars we’ll see all the information about this view. In here you’ll see theme_hook_suggestions is empty and we have a views object. If you click around the views object you’ll see various information about this view and display.

Vars available in preprocess_views_view

Now to target this view directly we could locate it by the view’s name, which is $vars[‘view’]->name. This is the method I will take, but keep in mind that this will affect ALL views with that name. If you have created a view with multiple displays it will change all of them. You will need to target the name and something else (generally I use current_display) to pinpoint a particular display of a view.

  1. <?php
  2. /**
  3.  * Implements template_preprocess_views_view().
  4.  */
  5. function custom_theme_preprocess_views_view(&$vars) {
  6. $view = $vars['view'];
  7. if ($view->name == 'blog'){
  8. $vars['theme_hook_suggestions'] = array('views_view__content_only');
  9. }
  10. }

So here I’m telling the views_view to target the view with the name ‘blog’ and to use my content-only template. Now I need to repeat for the other template.

  1. <?php /**
  2.  * Implements template_preprocess_views_view_unformatted().
  3.  */
  4. function custom_theme_preprocess_views_view_unformatted(&$vars) {
  5. $view = $vars['view'];
  6. if ($view->name == 'blog'){
  7. $vars['theme_hook_suggestions'] = array('views_view_unformatted__content_only');
  8. }
  9. }

Ok cool, if you clear your caches, refresh the page and check the markup you will see all of the excess markup gone.

Views markup removed

Mission accomplished! ...almost

So we’ve changed the markup for this one view but we still have other views we want to change. The method I took here is to create an array that contains the name of each view I want to overwrite. Then check if the current views name is in my array, and if it is use my custom template. Repeat for both templates/preprocess functions.

  1. <?php
  2.  
  3. /**
  4.  * Implements template_preprocess_views_view().
  5.  */
  6. function custom_theme_preprocess_views_view(&$vars) {
  7. $view = $vars['view'];
  8.  
  9. $content_only = array('blog', 'blog_list', 'blog_block');
  10.  
  11. if (in_array($view->name, $content_only)) {
  12. $vars['theme_hook_suggestions'] = array('views_view__content_only');
  13. }
  14.  
  15. }
  16.  
  17. /**
  18.  * Implements template_preprocess_views_view_unformatted().
  19.  */
  20. function custom_theme_preprocess_views_view_unformatted(&$vars) {
  21. $view = $vars['view'];
  22.  
  23. $content_only = array('blog', 'blog_list', 'blog_block');
  24.  
  25. if (in_array($view->name, $content_only)) {
  26. $vars['theme_hook_suggestions'] = array('views_view_unformatted__content_only');
  27. }
  28. }

Now when we want to add another view we simply add it onto our array and clear caches. That’s basically it. As you can see in the grand scheme of Drupal there’s still a TON of unnecessary markup but every little bit helps.

Part 2 of this will talk about how to eliminate 'divitis' when using fields. Stay tuned!