Drupal theming: Applying the "Sustainable" method to Views
by Colleen Carroll
I might be going a little far by continuing to call our sustainable method of theming "getting your hands dirty", but it makes me smile. So everyone will have to deal with it for at least 1 or 2 more blog posts.
On that note, I wanted to give the Drupal theming community a couple of examples of approaches we here at Palantir take for implementing a sustainable theme. I'm going to focus specifically on a very recent method we've implemented at Palantir for theming Views.
What are the things that frustrate me most about theming in Drupal? The taxonomy view and views, menus, and blocks added by a client post-launch that don't inherit anything from the theme. In my world that's a FAIL. Sure, you can't anticipate everything that the site is going to need after it launches, but can't we make it so that the things you think you can modify through the admin at least look good? And if not all of them, at least 50% of them?
Views tpl files
They are wonderful. And they're even more wonderful in D6. I suppose they weren't around in D5, but there was the theming wizard, which sorta was like having templates, just not as useful. But what do I love even more than the tpl files???? The CSS classes. Yes I said it, the classes! All of them! Every last stinking one. Why? Because they help you layer in design logic, a very important technique for theming.
In fact, I asked Merlin if I could have more and he said, "No, use the tpl files," and he's right. I just wanted to avoid adding a tpl file to add a CSS class to the wrapping div, because that's really all I need.
So what we've decided to do at Palantir is to insert a handful of views tpl files into our starter kit theme (which, BTW, is Zen, of course) to help us speed up the process of building a theme for a site. Our goal is to add a consistent set of CSS classes to the wrapping div and the listed items of the view for all display types and style types -- for every site we build.
First things first: global views styling.
(focusing on just 2 display types: Page & Block)
- Add 2 tpl files to our sitetheme:
- views-view-page.tpl.php
- views-view-block.tpl.php
- Copy the code that views provides for each of these display types in the "theme information" section of that display type, within the Views UI. The code may or may not be different depending on whether or not it's a page, block, rss feed, panel pane, etc.
- Example:
[php]
view-id-<?php print $name; ?> view-display-id-<?php print $display_id; ?> view-dom-id-<?php print $dom_id; ?>"> <?php if ($admin_links): ?><?php // class view ?> <?php endif; ?> [/php]<?php print $admin_links; ?><?php endif; ?> <?php if ($header): ?><?php print $header; ?><?php endif; ?> <?php if ($exposed): ?><?php print $exposed; ?><?php endif; ?> <?php if ($attachment_before): ?> <?php endif; ?> <?php if ($rows): ?><?php print $rows; ?><?php elseif ($empty): ?><?php print $empty; ?><?php endif; ?> <?php if ($pager): ?> <?php print $pager; ?> <?php endif; ?> <?php if ($attachment_after): ?> <?php endif; ?> <?php if ($more): ?> <?php print $more; ?> <?php endif; ?> <?php if ($footer): ?> <?php endif; ?> <?php if ($feed_icon): ?> <?php endif; ?> - Add a class to the wrapping div that helps globally identify this display type. In the case below we've added "view-page-display".
- Example:
[php]
view-id-<?php print $name; ?> view-display-id-<?php print $display_id; ?> view-dom-id-<?php print $dom_id; ?>"> [/php]You'll notice that we added "view-page-display" as a class to the wrapping div.
Second: style tpl files.
- views-view-list.tpl.php or views-view-unformatted.tpl.php
- Put these tpls in your theme and add another global class of "views-row-item" to your item li or div markup.
- Example:
[php]
<?php if (!empty($title)) : ?>[/php]<?php print $title; ?>
<?php endif; ?> <<?php print $options['type']; ?>> <?php foreach ($rows as $id => $row): ?>- clear-block"><?php print $row; ?>
<?php endforeach; ?> >
You can now globally style all view pages, in listed or unformatted format, for example: a 25px margin bottom and bottom border because you now can declare .view-page-display .views-row-item {}.
Third: the taxonomy view. What do we do? Here are the steps:
- Create a view for taxonomy by cloning the one in core to a new one named taxonomy_term_sitetheme.
- Modify it to use fields instead of the full node display, and set it to HTML list style b/c that's the way I prefer to semantically layout listed content even when it's blobs 'o text.
- Then use previously added classes (view-page-display) to help me theme this taxonomy page view.
- Export the view to code and include it in the custom.module of the site along with some CSS added to our Zen view-styles.css so that we can use this on other sites.
- views-view-list.tpl.php or views-view-unformatted.tpl.php
- Example:
Comments
On the same page
Good to hear that I am following the same approach as such an esteemed Drupal shop. I am a coder by background and found modules like conTemplate cumbersome and unnecessary overhead. The more that's in the file system the better!
I too have a starter theme built on Zen and have built out various "unformatted" tpl files for view/content type combos. It really speeds up Dev time when you share a design philosophy across projects. All design & theme shops should really consider this.
individual view tpl files
Hi,
I am fairly new to PHP and Drupal. I am building a site that uses views in a few different locations, and want to create specific view.tpl files for each view. Is that possible? Say one is a list of dance classes (I want to use a definition list) and another is a page of thumbnails for a photo gallery (I want to use an unordered list). Sorry it is not live yet I am working off my local box.
I differ with you on the classes... I mean I see the point I guess but when all is said and done I don't want a div class that is 15 words long... I want my output html as short and sweet as possible, I'll take care of everything else in the CSS file(s). Probably I just don't understand theming. I just want to output my own fields and have html level access to each.
I want to have a view.tpl where I can get at each individual data column output and style it. Like in a content-type specific node, like this for example:
--
<?php print $node->field_title['0']['view']; ?>
<?php print $node->field_artist['0']['view']; ?>
--
Is there a
<?php print $view->field_artist['0']['view']; ?>or something similar?Sorry for the long post and thanks for your original post. I found you by Googling "style unformatted view drupal"...
Thanks a lot!
Jim S
Jacksonville, FL
Let me ask you first,...why
Let me ask you first,...why does your HTML need to be short and sweet and specifically why don't you want it to be "15 words long"? What does it actually impact besides your own preferred style? I could see the need to have it clean for page weight issues but even then we're not talking about huge amounts of page weight. Drupal is not a build a template first system, its a install a module and theme it system. IMO the templates are there when you need to override something that just isn't working, not override it because you wish there was one last div.
Or are you specifically saying that you want to change the name of the classes that are provided? For instance: "views-field-field-lead-value". If this is the case, I highly recommend that people get over the issue of "long css class names" and just embrace it. That class may look "ugly" but it is highly informative. You can essentially theme all view fields that are CCK and named "lead", and you don't need to add extra tpl files to your site to do so. That class was constructed in that way for a reason. You're essentially getting a unique class for that field. Leveraging things like these structured classes is what helps you theme more than just 1 item at a time. Isn't that the point of CSS, and especially theming?
Also you're theming for progressive enhancement. You're tapping into something that a contrib module is spitting out at you, and the chances of that structure changing are low, especially if its a module like Views. Its potentially more likely that method for applying tpl files to Views will change.
I think that people need to stop trying to fiddle with the HTML layer in Drupal. Its not worth it, its not that interesting, and everything can be done with CSS anyway, and should be.
Ok lets put that aside and answer your question. You can add a view*.tpl file for a particular view and even a particular display within that view. You find that information within the same place "Theme information for that display". The tpls are listed in order of specificity from most general to most specific. Now the question is, what part of the view do you need to be specific? The field? all the content, etc? Chances are you need to theme the field, which means you'll want the tpl that is listed for "row output". Took me a little while to figure out what that tpl was used for.
The display tpl are going to let you affect the wrapping elements of the view. The wrapping markup, the pager, etc.
The style tpl lets you alter the markup for all items. So for instance you mention wanting to use a definition list. I'd recommend using the unformatted style and then taking that tpl and adding in the definition list tags. Don't use listed style b/c that inherently means you're using the theme list function.
As for image galleries, I'd use the grid layout and configure it to be horizontal. Then just theme what gets spit out at you. You can then group items in the view. Here's an example of a grid specific layout where I tweaked the display tpl (views-view-grid--portfolios--page.tpl.php):
<?php if (!empty($title)) : ?>
<?php print $title; ?>
<?php endif; ?>
<?php foreach ($rows as $row_number => $columns): ?>
<?php
$row_class = 'row-' . ($row_number + 1);
if ($row_number == 0) {
$row_class .= ' row-first';
}
elseif (count($rows) == ($row_number + 1)) {
$row_class .= ' row-last';
}
?>
<?php foreach ($columns as $column_number => $item): ?>
<?php print $item; ?>
<?php endforeach; ?>
<?php endforeach; ?>
In this particular snipped I added the "thumb" div.
The snippet that you are listing above (where you're reprinting fields), I'd add a row tpl file for that specific view and "break apart" the foreach loop, but try to use the same format that is happening within that tpl so that you can reprint the fields you want, and wrap them with your preferred markup. This one definitely takes a bit more PHP skills but essentially looks something like this:
<?php $field = $fields['title']; ?>
<?php if (!empty($field->separator)): ?>
<?php print $field->separator; ?>
<?php endif; ?>
<<?php print $field->inline_html;?> class="views-field-<?php print $field->class; ?>">
<?php if ($field->label): ?>
class; ?>">
<?php print $field->label; ?>:
<?php endif; ?>
<?php
// $field->element_type is either SPAN or DIV depending upon whether or not
// the field is a 'block' element type or 'inline' element type.
?>
<<?php print $field->element_type; ?> class="field-content"><?php print $field->content; ?>element_type; ?>>
inline_html;?>>
Above we're "breaking out" the foreach piece and replacing it with:
<?php $field = $fields['title']; ?>
And reprinting the rest below it per field.
*Disclaimer: I may have not properly described this process in PHP/Drupal language and it might also not be iron clad. Please use this approach as a launching pad and not necessarily best methods approach :).
New views-row class in 6.x-2.6, and ID tweak suggestion
Great info Colleen :)
I wanted to mention here (and perhaps you can make a note up in the article) that Views 6.x-2.6 now includes a "views-row" class, which means the unformatted/list template overrides in this article are no longer required. I didn't notice this myself until I'd already made the new templates, so a note in the article would be helpful.
Also on a separate note, I wanted to share a tweak that I add to my views-view--page.tpl.php and views-view--block.tpl.php files. I found that sometimes I want to make a Page display and also set one or more block displays from the same view to appear on that page. There are enough classes that can be .chained.together to get a unique hold on a specific display for a specific view, though evidently this is not IE6 compatible. Without targeting the display uniquely I found myself often accidentally affecting other displays in the same view, or alternately displays from other unrelated views.
So I have added the following ID to the templates which gives me a fully unique hook of "view-name-display_ID" for every Page/Block display (showing the whole opening div here):
Hope this helps :)
Good stuff, but...
Thanks for the informative article. I've been using most of the same techniques but have found a few good tips here ;)
And btw, i've also had a pet peeve with the fact that there's no "views-row-item" class, only unique classes :P
On to that 'but...', does this naming convention really work for you?
views-view-page.tpl.php
I have to use two dashes after 'view' in all my views tpls:
views-view--page.tpl.php
Good point. I looked at the
Good point. I looked at the "Theme information" in views again, to refresh my memory. The global tpl that would get picked up for all views of that style, row, etc. appears to only need 1 dash. The more specific you get, then you need 2 dashes.
For ex:
views-view-fields.tpl.php
vs.
views-view-fields--additional-galleries.tpl.php