Views 1 theming
Much of the power of Views cannot be fully realized until an administrator gets accustomed to theming. Views may be themed at various levels, with each level providing either more or less control:
- Each field printed may be themed individually (valid in table/list views). This requires understanding the name of the field you want to theme.
- Each view may be themed by type -- meaning a view that provides teasers in page mode and a list in block mode may have each mode themed separately.
- Each view may be completely themed. This requires understanding a bit about what makes up a complete view.
For all of these functions, the _VIEWNAME is optional; if the viewname is not part of the theme function, you will override theming for all of your views.
The Theming Wizard
Views now comes with a new module, views_theme_wizard.module, which will allow you to generate a theming function and template for your views if you happen to be using a PHPTemplate theme. At the moment it only works for list views, but these are the views that are actually difficult. Using the wizard is quite simple; select a view and run the wizard. It generates code for your template.php and a viewname.tpl.php which you can drop right into your theme directory. You can then make adjustments to this.
Note that if you just want to theme a 'teaser' view, the simplest way to accomplish this is to override the teaser function, and change the node_view() function to something like this:
<?php
node_view($node, 'some-identifiable-string');
?>Then, in your node.tpl.php (or node-type.tpl.php) you can do:
<?php
if ($teaser == 'some-identifiable-string')
?>and theme your node as per the normal node theming.
Theme Functions
When using theming functions, you should consult the Drupal theming documentation for detail on what this stuff does and how to deal with it. In particular, read Using Theme Override Functions in order to override Drupal's default theming.
function theme_views_view_TYPE_VIEWNAME($view, $nodes);- This is called after all of the header and before any footer information are displayed. This is likely to be the most commonly used theme function simply due to its relative simplicity. All this function has to do is loop over the $nodes array and display the data based upon the type of the view. By default, the TYPE may be one of:
- list
- table
- teasers
- nodes
but plugins could offer other types that may also be themed (and for these you will need the plugin's theme function name, rather than the plugin type name, ie theme_views_rss_feed_VIEWNAME).
This function themes a particular view for a particular type, thus not interfering with any of your other views.
<?php
/**
* Display the nodes of a view as a list.
*/
function theme_views_view_list($view, $nodes, $type) {
$fields = _views_get_fields();
foreach ($nodes as $node) {
$item = '';
foreach ($view->field as $field) {
if (!isset($fields[$field['id']]['visible']) && $fields[$field['id']]['visible'] !== FALSE) {
if ($field['label']) {
$item .= "<div class='view-label ". views_css_safe('view-label-'. $field['queryname']) ."'>" . $field['label'] . "</div>";
}
$item .= "<div class='view-field ". views_css_safe('view-data-'. $field['queryname']) ."'>" . views_theme_field('views_handle_field', $field['queryname'], $fields, $field, $node, $view) . "</div>";
}
}
$items[] = "<div class='view-item ". views_css_safe('view-item-'. $view->name) ."'>$item</div>\n"; // l($node->title, "node/$node->nid");
}
if ($items) {
return theme('item_list', $items);
}
}
/**
* Display the nodes of a view as a table.
*/
function theme_views_view_table($view, $nodes, $type) {
$fields = _views_get_fields();
foreach ($nodes as $node) {
$row = array();
foreach ($view->field as $field) {
if ($fields[$field['id']]['visible'] !== FALSE) {
$cell['data'] = views_theme_field('views_handle_field', $field['queryname'], $fields, $field, $node, $view);
$cell['class'] = "view-field ". views_css_safe('view-field-'. $field['queryname']);
$row[] = $cell;
}
}
$rows[] = $row;
}
return theme('table', $view->table_header, $rows);
}
/**
* Display the nodes of a view as teasers.
*/
function theme_views_view_teasers($view, $nodes, $type) {
return views_theme('views_view_nodes', $view, $nodes, $type, true);
}
/**
* Display the nodes of a view as plain nodes.
*/
function theme_views_view_nodes($view, $nodes, $type, $teasers = false, $links = true) {
foreach ($nodes as $n) {
$node = node_load($n->nid);
$output .= node_view($node, $teasers, false, $links);
}
return $output;
}
?> function theme_views_view_VIEWNAME($view, $type, $nodes, $level = NULL, $args = NULL);- When Views attempts to display a view, first it attempts to call theme('views_view_VIEWNAME'). If this function does not exist, then it will call theme('views_view'), which is the default method of displaying a view. As a themer, you can override either one, but in general it's better to override the specific one.
The $view argument will be the full definition of the view from the database.
The $type argument will be either 'block', 'page' or 'embed'. (It can actually be other things, but anything else will be user defined. More on this later). This argument is used to control whether page or block specific display is done.
The $nodes argument will be an array with all of the information from the database nicely loaded.
if $level is set to a positive value, this means the view is a summary view, and should be sent to the summary theme instead of the normal type theme.
<?php
/**
* Display a view.
*/
function theme_views_view($view, $type, $nodes, $level = NULL, $args = NULL) {
$num_nodes = count($nodes);
if ($type == 'page') {
drupal_set_title(filter_xss_admin(views_get_title($view, 'page')));
views_set_breadcrumb($view);
}
if ($num_nodes) {
$output .= views_get_textarea($view, $type, 'header');
}
if ($type != 'block' && $view->exposed_filter) {
$output .= views_theme('views_display_filters', $view);
}
$plugins = _views_get_style_plugins();
$view_type = ($type == 'block') ? $view->block_type : $view->page_type;
if ($num_nodes || $plugins[$view_type]['even_empty']) {
if ($level !== NULL) {
$output .= "<div class='view-summary ". views_css_safe('view-summary-'. $view->name) ."'>". views_theme($plugins[$view_type]['summary_theme'], $view, $type, $level, $nodes, $args) . '</div>';
}
else {
$output .= "<div class='view-content ". views_css_safe('view-content-'. $view->name) ."'>". views_theme($plugins[$view_type]['theme'], $view, $nodes, $type) . '</div>';
}
$output .= views_get_textarea($view, $type, 'footer');
if ($type == 'block' && $view->block_more && $num_nodes >= $view->nodes_per_block) {
$output .= theme('views_more', $view->real_url);
}
}
else {
$output .= views_get_textarea($view, $type, 'empty');
}
if ($view->use_pager) {
$output .= theme('pager', '', $view->pager_limit, $view->use_pager - 1);
}
if ($output) {
$output = "<div class='view ". views_css_safe('view-'. $view->name) ."'>$output</div>\n";
}
return $output;
}
?> function theme_views_summary_VIEWNAME($view, $type, $level, $nodes, $args);- If a given view has a summary mode -- in which a listing of possible choices for arguments are given -- theme('views_view_summary_VIEWNAME') will be called instead. This is a very good choice to override, because views doesn't really give the admin many options for how to display this, and there are many different possibilities.
$view contains the database view information.
$type contains the same information as theme_views_view().
$level is a number stating which argument this summary is for, starting from 0. If a view has multiple arguments (for example, view/archive/year/month/day) the summary could be for the year (0), the month (1) or the day (2).
$nodes will be an array of database information for the summary.
$args will be the arguments actually present; in the above example will be an empty array if $level = 0, but will contain the year if $level = 1 and the year and the month if $level = 2.
<?php
/**
* Display a summary version of a view.
*/
function theme_views_summary($view, $type, $level, $nodes, $args) {
foreach ($nodes as $node) {
$items[] = views_get_summary_link($view->argument[$level]['type'], $node, $view->real_url) . " (" . $node->num_nodes . ")";
}
if ($items) {
$output .= theme('item_list', $items);
}
return $output;
}
?> function theme_views_more($name);- This simple theme function formats the 'more' link.
<?php
/**
* Format the 'more' link for a view. Personally I prefer [More] but I've
* been convinced to go with simply 'more'.
*/
function theme_views_more($url) {
return "<div class='more-link'>" . l(t('more'), $url) . "</div>";
}
?> function theme_views_handle_field_TABLENAME_FIELDNAME($fields, $field, $data);- You can theme each piece of individual data by overriding this theme function. Do so with care, as using it properly requires understanding what the data you're receiving is.
<?php
/**
* Themeable function to handle displaying a specific field.
*/
function theme_views_handle_field($fields, $field, $data) {
$info = $fields[$field['fullname']];
if ($field['handler'] && function_exists($field['handler'])) {
return $field['handler']($info, $field, $data->$field['queryname'], $data);
}
if ($info['handler'] && is_string($info['handler']) && function_exists($info['handler'])) {
return $info['handler']($info, $field, $data->$field['queryname'], $data);
}
return check_plain($data->$field['queryname']);
}
?> function theme_views_filters_VIEWNAME($form)- For 4.7: This theme function lets you change how the exposed filters are displayed.
<?php
function theme_views_filters($form) {
$view = $form['view']['#value'];
foreach ($view->exposed_filter as $count => $expose) {
$row[] = form_render($form["op$count"]) . form_render($form["filter$count"]);
$label[] = $expose['label'];
}
$row[] = form_render($form['submit']);
$label[] = ''; // so the column count is the same.
return theme('table', $label, array($row)) . form_render($form);
}
?>- For 5.x: This theme function lets you change how the exposed filters are displayed.
<?php
function theme_views_filters($form) {
$view = $form['view']['#value'];
foreach ($view->exposed_filter as $count => $expose) {
$row[] = drupal_render($form["op$count"]) . drupal_render($form["filter$count"]);
$label[] = $expose['label'];
}
$row[] = drupal_render($form['submit']);
$label[] = ''; // so the column count is the same.
// make the 'q' come first
return drupal_render($form['q']) . theme('table', $label, array($row)) . drupal_render($form);
}
?>
- For 5.x: This theme function lets you change how the exposed filters are displayed.
The savvy reader will note that a large section of this documentation has, in fact, disappeared. Most of it was rendered irrelevant by the compartmentalization of the theming functions. It is the author's hope that the code snippets will be sufficient to guide you into what needs to be done, and that later tutorials can provide more interesting information.

Theming field to trim the title
Took me some time to figure this one out.
<?phpfunction phptemplate_views_handle_field_node_title($fields, $field, $data) {
return l( truncate_utf8($data->node_title, 80, TRUE, TRUE), 'node/'.$data->nid, array('title' => $data->node_title ) );
}
?>
Thanks for the great module Merlin!
Not the *REAL* table name for CCK nodes
Just want to point out the in the phptemplate_views_handle_field_TABLENAME_COLUMNNAME format, the TABLENAME part might not be the actual table name. I had to look at the actual sql query (thanks to the DEVEL module) to see the "alias" name for the table. Apparently Views module uses that alias name as the identifier for that table.
Testing findings...
This TABLENAME and FIELDNAME appear in view_tablefield of the database.
For CCK fields, they show as:
TABLENAME --->
node_data_field_myfield
FIELDNAME --->
field_myfield_value
These can be gathered from the html output at the appropiate td or div class of the view.
Even easier, use the Views
Even easier, use the Views Theme Wizard module, and choose 'List Theme Fields'.
That will give you a list of function names like 'phptemplate_views_handle_field_images_recent_node_title'.
Simply replace the 'phptemplate' bit with 'theme'.
How Do I Theme the Teaser View?
I'm using the Views module. I'm wanting to theme the teaser view on the front page.
I've put this function in template.php (as explained in the article above):
function phptemplate_views_view_teasers($view, $nodes, $type) {return views_theme('views_view_nodes', $view, $nodes, $type, true);
}
and am trying to determine what to name my theme file. I've tried lots of options, including 'views-view-teasers.tpl.php.'
Do I need something more in template.php?
I was able to get the 'list' functionality working (using 'views-view-list-Articles_Mind.tpl.php,' etc...), but realized I wanted teasers.
Somebody needs to make these docs more comprehensive... I'm willing to help. :)
Doc needs update (I think)
I was just trying to figure this out too, and I think I finally got it. It appears to work for me. If this is what was intended, it should be corrected in the section "The Theming Wizard" above and if not, I'd like to know too.
Here's what I did for a view named 'Events'. In template.php, I have ...
function phptemplate_views_view_teasers_Events($view, $nodes, $type) {return views_theme('views_view_nodes', $view, $nodes, $type, 'EventsViewTeaser');
}
Then in node.tpl.php, I have something like ...
if ($teaser === 'EventsViewTeaser') {// output my teaser
}
Notice the
===, which is needed since$teaser == 'EventsViewTeaser'returns true in other contexts when $teaser is equal to 1, which is not what I want.A simpler way to theme
A simpler way to theme teasers (or even full nodes) of a specific view without dealing with template.php is to use this 'if' statement in your node-whatever.tpl.php:
<?php global $current_view; ?>/ This is a new variable introduced in Views module revision v.1.94;
// it conveniently gives one access to the current view
<?php if ($current_view->name == 'viewname') { ?>// change viewname string with the name of your view
// create here the layout as usual (use a page == 0 for teaser view etc.)
<?php }; ?>
This can be set in the node-content_type.tpl.php for CCK views.
If you are only going to show the teasers of a CCK content type using a 'view' (which I assume is be a common usage) then you can just use the content type tpl.php. (See Creating a CCK template).
Assume I have a content type called 'news' and I make a teaser view page for all news items.
I'd put a file in my theme folder called 'node-content_news.tpl.php' and in that file wrap the theming in a if statement e.g.
if ($teaser) {
// this content will be displayed on the teaser view page. So I'll make the title link to the full news item.
} else { // it's an individual 'news' item page (node)...
// ...so the title desn't need to be linked and I'll include a link back to the teaser views page after the content.
}
Hope this helps.
Ben W
For 5.x is just
For 5.x is just node-type.tpl.php
More on themeing cck nodes nere: http://drupal.org/node/62468
Theming a full node
I used the theme_views_view_nodes in my template.php and I want to theme the node title so that it doesn't display as a link. How do I get to the node title using the theme_views_view_nodes function so I can change how it is displayed??
Can anyone help?
Theme Teaser List
I've been searching for days, and there seems to be absolutely no examples for theming a teaser list. While the views theme wizard covers the List type, other types do not seem to have any examples at all.
Can someone put up a snippet who have successfully themed a teaser list page? It would really help in covering this very 'grey' area. The question is what goes in method in template.php and what the views-xxx-xxx.tpl.php would include.
Theming $node_view
You can theme $node_view a little bit by changing the function variables.
node_view($node, $teaser = FALSE, $page = FALSE, $links = TRUE)$node A node array or node object.
$teaser Whether to display the teaser only, as on the main page.
$page Whether the node is being displayed by itself as a page.
$links Whether or not to display node links. Links are omitted for node previews.
So you would get:
function theme_views_view_nodes($view, $nodes, $type, $teasers = false, $links = true) {foreach ($nodes as $n) {
$node = node_load($n->nid);
$output .= node_view($node, $teasers, true, $links);
}
return $output;
}
To display just the node without the title.
I tried doing:
function theme_views_view_nodes($view, $nodes, $type, $teasers = false, $links = true) {foreach ($nodes as $n) {
$node = node_load($n->nid);
$node->body = '<div class="title"><h3>'.$node->title.'</h3></div>'.$node->body;
$output .= node_view($node, $teasers, true, $links);
}
return $output;
}
To display the title in the body of the node. But that didn't work all the time
So far this is all I got.
matrix view of nodes
My goal was to categorize a bunch of images and then display them as examples on a single page - but i wanted them as thumbnails in a matrix (3x3 for example).
an initial view of what i am talking about can be seen here: www.liquidcms.ca/view1.jpg
- to start with a added a few images and then categorized them but tagging them with category "examples"
- next i made a list page view and added fileds:
--- node title
--- image (thumbnail)
--- node body (although htis doesnt work with list view and nothing else works for view theme wizard - so not really necessary or required
- named the new view as: image_view
- used theme wizard to generate code for 2 files (neither of which existed)
--- views-list-image_view.tpl.php
--- template.php
made modification to template.php code:
========================
- NOTE - template.php gets processed AFTER the view.tpl.php gets generated; so if i format my matrix in the tpl file (i.e. put it in a table) then i dont need the tempalte.php to theme as a list - which is what the code the wizard spits out does:
- so i simply replaced:
return theme('item_list', $items);with:
return implode("",$items);which simlpy strings the html code for each node in my view together - to make the entire view
the view template:
===========
- now for putting each node piece into the "view" as a matrix (i.e. table)
<?php
//echo $node->nid;
$node_real = node_load($node->nid);
if ($count == 0) echo "<table cellspacing=20 cellpadding=20><tr>"; ?>
<td width=150 height=150>
<div class="view-label view-field-title">
<?php print $title_label ?>
</div>
<div class="view-field view-data-title">
<?php print $title?>
</div>
<div class="view-label view-field-nid">
<?php print $nid_label ?>
</div>
<div class="view-field view-data-nid">
<?php print $nid?>
</div>
<?php echo $node_real->body;?>
</td>
<?php
if (($count+1) % 3 == 0) echo "</tr><tr>";
if ($count == ($view->total_rows -1)) echo "</tr></table>";
?>
BUGS that needed fixing:
================
A couple bugs in views and categories modules that needed to be fixed/worked around
category bug: for some reason their is a bug in the taxonomy wrapper that doesn't build the term_data table correctly; my fix is posted under cat project as a bug
view wizard:
- states that it exposes a $nid to the tpl.php file - the variable is there; but doesnt contain the nid
- it also doesnt seem to expose basic things like the node->body
- work around for both of these can be seen in my code above.
hope this helps someone,
Peter Lindstrom
www.LiquidCMS.ca
not quite if paging
just noticed if paging occurs with this view that page gets messed up - i know why (has to do with closing table based on number of nodes in view) but will have to post fix later.
Peter Lindstrom
www.LiquidCMS.ca
ok, simply change last line
ok, simply change last line to:
if ($count == ($view->num_rows -1) || $count == ($view->total_rows -1)) echo "</tr></table>";and this should close off the table if at the end of a page or the end of the view.
Peter Lindstrom
www.LiquidCMS.ca
Table view code
Just a note, to get the table view function override to work for me I had to add a missing variable in the views_them_field call.
foreach ($nodes as $node) {$row = array();
foreach ($view->field as $field) {
$cell['data'] = views_theme_field('views_handle_field', $field['queryname'], $fields, $field, $node);
$cell['class'] = "view-field view-field-$field[queryname]";
$row[] = $cell;
}
$rows[] = $row;
}
return theme('table', $view->table_header, $rows);
}
to this
foreach ($nodes as $node) {
$row = array();
foreach ($view->field as $field) {
$cell['data'] = views_theme_field('views_handle_field', $field['queryname'], $fields, $field, $node,$view);
$cell['class'] = "view-field view-field-$field[queryname]";
$row[] = $cell;
}
$rows[] = $row;
}
return theme('table', $view->table_header, $rows);
}
An easy way to theme your exposed filters
Hi there,
function phptemplate_views_filters($form) { //this call overrides all views filters so I need a condition$view = $form['view']['#value'];
foreach ($view->exposed_filter as $count => $expose) {
$row[] = drupal_render($form["op$count"]) ;
$box[] = drupal_render($form["filter$count"]);
$label[] = $expose['label'];
}
$row[] = drupal_render($form['submit']);
$label[] = ''; // so the column count is the same.
$title = $view->page_title;
return _phptemplate_callback('views-filters-'.$view->name, array('title' => $title, 'row' => $row, 'box' => $box, 'label'=>$label));
}
The code callback a views-filters-$my_view_name.tpl.php file, if the file don't exist or is empty the _phptemplate_callback execute the default code, so it's useless to create an if() condition to do that.
So, to theme your exposed filters as you want, you only need to create a views-filters-$my_view_name.tpl.php file in your template folder.
whitescreen
Hi i stuck the code above for theming the filters in my template.php and get a whitescreen. I've created the views-filters... tpl.php file.
I put the code at the end of the template file - is this the right place?
Fixed the whitescreen
Fixed the whitescreen problem - that was me being daft,
For a full explanation on how to theme filters go to this topic:
http://drupal.org/node/79302
It's worth noting that form_render() causes a whitescreen for me and others in that topic - I used drupal_render() as suggested there and it works fine.
Cheers to zmove and other for posting some great ways to theme views
theme_views_view out of date
Just a heads up, the theme_views_view provided here is actually out of date, the version in 5.x-1.6 is:
<?php
function theme_views_view($view, $type, $nodes, $level = NULL, $args = NULL) {
$num_nodes = count($nodes);
if ($type == 'page') {
drupal_set_title(filter_xss_admin(views_get_title($view, 'page')));
views_set_breadcrumb($view);
}
if ($num_nodes) {
$output .= views_get_textarea($view, $type, 'header');
}
if ($type != 'block' && $view->exposed_filter) {
$output .= views_theme('views_display_filters', $view);
}
$plugins = _views_get_style_plugins();
$view_type = ($type == 'block') ? $view->block_type : $view->page_type;
if ($num_nodes || $plugins[$view_type]['even_empty']) {
if ($level !== NULL) {
$output .= "<div class='view-summary ". views_css_safe('view-summary-'. $view->name) ."'>". views_theme($plugins[$view_type]['summary_theme'], $view, $type, $level, $nodes, $args) . '</div>';
}
else {
$output .= "<div class='view-content ". views_css_safe('view-content-'. $view->name) ."'>". views_theme($plugins[$view_type]['theme'], $view, $nodes, $type) . '</div>';
}
$output .= views_get_textarea($view, $type, 'footer');
if ($type == 'block' && $view->block_more && $num_nodes >= $view->nodes_per_block) {
$output .= theme('views_more', $view->real_url);
}
}
else {
$output .= views_get_textarea($view, $type, 'empty');
}
if ($view->use_pager) {
$output .= theme('pager', '', $view->pager_limit, $view->use_pager - 1);
}
if ($output) {
$output = "<div class='view ". views_css_safe('view-'. $view->name) ."'>$output</div>\n";
}
return $output;
}
?>
Easy Views Theming
I've found that http://drupal.org/node/128741 is easier and it is what I'm looking for but for some reason when searching "Theme Views" you always get this book instead the easier one, witch is kind of lost deep inside the Views Docs.
Luis
how to theme/add views table header
Hi, I am having a hard time figuring out how to display the table headers for my views tables. I'm using the following code in my template.php:
/**
* This snippet will override all table views in your site
* Paste this into your template.php file and change the
* attributes in the second last line of the snippet.
*/
function phptemplate_views_view_table ($view, $nodes, $type) {
$fields = _views_get_fields();
foreach ($nodes as $node) {
$row = array();
foreach ($view->field as $field) {
if ($fields[$field['id']]['visible'] !== FALSE) {
$cell['data'] = views_theme_field('views_handle_field', $field['queryname'], $fields, $field, $node, $view);
$cell['class'] = "view-field ". views_css_safe('view-field-'. $field['queryname']);
$row[] = $cell;
}
}
$rows[] = $row;
}
return theme('table', $view->table_header, $rows, array('cellspacing'=>'0', 'border'=>'0'));
}
Only problem is my field labels are just displayed as plaintext and not in the table section of the table but outside in the div like below:
<div class="view view-form-view"><div class="view-content view-content-form-view">
Name File
<table cellspacing="2" border="0">
<tbody>
<tr/>
<tr class="odd">
</tr>
<tr class="even">
<td class="view-field view-field-node-title">Overview of New Grant Protocol</td>
<td class="view-field view-field-node-data-field-form-upld-field-form-upld-fid">
</td>
</tr>
<tr class="odd">
</tr>
</tbody>
</table>
What do I need to do/add to the above code so that it is automatically populated with the label in the table header? I would like it to look similar (with different labels from the view) to the default attachment.
<thead><tr>
<th>Attachment</th>
<th>Size</th>
</tr>
</thead>
Many thanks in advance.