I was tasked with maintaining a Drupal website that had 44 views. The template.php file for the theme was unwieldy. I spun off all the views template code into another file for ease of maintenance, but it was still 1333 lines1 weighing in at 36.5kb! [1] Just four more lines and it could have been elite!
The quantity of views certainly wasn't pretty, and when I had to add in another view, I decided that enough was enough. It was time to clean it up and develop a system to help keep the views under control.
In order to keep the quantity of views under control, we need to maximize the capability of each view doing multiple jobs. Args will become our best friend.
When embedding views we have a lot of freedom. Don't be afraid to add in multiple arguments. If you set the arg configuration to "display all values" and set the value to NULL when embedding it, you can get more flexibility. Also, we can use our own arbitrary arguments which will be tremendously useful for theming!
Lets use the HarvardScience site as an example. There are several different ways to promote a story. For the homepage, it can be "Breaking News", "Other News", "HarvardScience Matters" and access to all stories chronologically. Using args, there is no need to create a separate view for each presentation of news stories, and we can instead let one view do all the heavy lifting.
I created a "stories" view with the promotion field as an argument. I also wanted this view to handle the feeds for both "Breaking News" and all stories. In the end, I use that view in 24 separate instances, displaying teasers, lists, RSS and XML.
When embedding, we just set the feed argument to NULL. The code then would look like this:
<?php
print views_build_view('embed', views_get_view('stories'), array(NULL, 'breaking_news'), false, 5);
?>The page of the view with no arguments used just displays all stories:
http://harvardscience.harvard.edu/latestnews
And the feed for all stories can be easily accessed at:
http://harvardscience.harvard.edu/latestnews/feed
While the feed for "Breaking News" would be:
http://harvardscience.harvard.edu/latestnews/feed/breaking_news
What do we do about the "HarvardScience Matters" section, or any other time we would want the display of nodes to be different? The views template wizard can help you tweak the view for exactly what you want, however it's current incarnation allows you to only have one template per view.
Using args can now also help you in changing the presentation. The embed code for "HarvardScience Matters" is:
<?php
print views_build_view('embed', views_get_view('stories'), array(NULL, 'harvardscience_matters', 'list'), false, 8);
?>Even though the 'stories' view has only two args set, we can add our own arbitrary args and they will be ignored when generating what nodes to present. I use that extra argument I added to say how to present the nodes:
<?php
function harvard_science_views_view_list_stories($view, $nodes, $type) {
if ($view->args[2] == 'list') {
$output = harvard_science_view_template('views-list-linked_titles', $nodes);
} elseif ($view->args[2] == 'featured') {
$output = harvard_science_view_template('views-list-featured_story', $nodes);
} elseif ($view->args[2] == 'marquee') {
$output = harvard_science_view_template('views-list-marquee', $nodes);
} else {
$output = harvard_science_view_node_teasers($nodes);
}
return $output;
}
?>Instead of having the large amount of views template code generated by the template wizard, we have a small function that even delegates different presentation of the nodes depending on the arguments.
The helper functions I created are harvard_science_view_template() and harvard_science_view_node_teaser(). These allow me to put the bulk of code that gets repeated for each view and just put it into one function.
<?php
/**
* Setup ability to theme a view's list as teasers
*/
function harvard_science_view_node_teasers($nodes) {
$output = '';
foreach ($nodes as $i => $node) {
$node = node_load($node->nid);
$output .= node_view($node, TRUE, FALSE, FALSE);
}
return $output;
}
/**
* Setup ability to theme a view's list as a given template
*/
function harvard_science_view_template($template, $nodes, $listType = 'item_list') {
$total = count($nodes);
$base_vars = array(
'view' => $view,
'view_type' => $type,
'total' => $total,
);
foreach ($nodes as $i => $node) {
$node = node_load($node->nid);
$vars = $base_vars;
$vars['count'] = $i;
$vars['node'] = $node;
$items[] = _phptemplate_callback($template, $vars);
}
if ($items) {
$output = theme($listType, $items);
}
return $output;
}
?>Using these methods, I was able to reduce the quantity of views to 16, and thin out the template code to just 262 lines and a 6.7kb file size. These reductions will make the site much easier to maintain.
The last thing to cover are the templates themselves located at views-list-*.tpl.php. Instead of providing fields in the view's configuration, I found that it was easier to use node_load(). However, do note that if you have too many nodes in the view, this will be server intensive, and it may be better to use fields.
Reuse your views templates whenever possible! You can even use the same template for different content types. In HarvardScience, news stories and external links can be listed in the same view (such as on researcher and program pages). I use the same template for presenting both content types:
<?php
$node = node_load($node->nid);
// Because this template is used for both news_office_story and external_link
// we're setting all the variables
$date = date('F j, Y', strtotime($node->field_date_published[0]['value']));
if ($node->type == 'news_office_story') {
$title = '<a href="'.url('node/'.$node->nid).'">'.$node->title.'</a>';
$source = $node->field_news_source[0]['value'];
} elseif ($node->type == 'external_link') {
$title = '<a href="'.$node->field_media_link[0]['url'].'" class="ext">'.$node->title.'</a>';
$source = $node->field_media_link[0]['title'];
}
print $title.' ('.($source ? $source.', ' : '').$date.')<br />'."\n";
?>Instead of just creating a views template for every view, I instead create a template for every purpose, significantly reducing the number template files to maintain.






I notice how your site name means "skilled". However, you've failed to install the most basic protection against comment spam in your own Drupal installation.
Also, with the examples you've provided, you're vulnerable to XSS attacks because you're failing to use output filters in your templates, such as check_plain() and content_format().
Just thought you might want to brush up on that...
Yes, you are correct.
I thought I would get a little spam, but I hadn't imagined the possibility of the absolute downpour I received. All was fine yesterday after I enabled comments, however as I slept the spammers discovered me. I've since turned on comment moderation.
Filtering output is vitally important when you don't trust the source. I do frequently forget that when I manage sites whose editors are also my clients. These sorts of heads up are exactly the reason I wanted to enable comments.
I've now installed Mollom, and that seems to be working. I turned off comment moderation, and all spam is successfully being blocked so far.
I have to say, I am utterly shocked by the amount of spam. I had no idea how absolutely critical it was to have some sort of spam protection for comments. But I certainly learned that lesson rather quickly.