Posted 01/02/2010 - 03:32 by State68
Earlier this year I built my first non-trivial Drupal site. It's pretty simple on the surface, but allows certain users to create nodes which represent a piece of work they've done for the organisation. using Views and Views Calc and a bit of custom code, these nodes are used to produce invoices for each of these users every month.
Most of the rows on these invoices are the same: they show the date the piece of work was done, what type of work it was (there are about ten different types, and there's a different node type for each), and the fee paid. This is fine for all but one node type, which is a catch-all that can be used when a piece of work is completed that isn't represented by any of the other node types. In that case, the user enters a title for the node which will be displayed on the invoice in place of the node type.
Views doesn't handle this sort of thing directly. You can set up a column in a table that displays the node type, and you can set up a column that displays the node title, but you can't set up a column that works like this: if the node type is the catch-all type, then display the node's title; otherwise, display its type. Fortunately, the themeable function that Views uses to display each field can be intercepted and overriden so that it does what you want.
Themable functions are one of the coolest, easiest things about Drupal. They're pretty easy to understand, too. Almost anything that appears on a page on a Drupal site has been generated by a themable function. If you can find out which themable function generated the bit of content you want to change, you can write your own version of the function and, if you give it the right name and stick it in your template.php (and rebuild the theme registry), different content will be displayed.
Here's how to intercept and override the themable function that produces the text that appears in the field in the view (the same principle applies to overriding any themable function). First of all, work out the name of the function that's generating the content that you want to change. By far the easiest way to do this is to use the Theme Developer module (formerly part of the Devel module). Install and enable the module, switch it on, and then click on a piece of content to find out the name of the themable function that generated it. If it's a core Drupal function then use the Drupal API reference to find it; otherwise just Google it.
The function we need to change is theme_views_view_field(). Here's the function, taken from the DrupalContrib API reference:
<?php
function theme_views_view_field($view, $field, $row) {
// Reference safe for PHP 4:
return $view->field[$field->options['id']]->advanced_render($row);
}
?>Copy the whole function, and paste it into your theme's template.php file. Change the word "theme" in the name of the function to your theme's name. Clear the theme registry. As if by magic, whenever Views displays your view's fields it will now use the function that is in your template.php file rather than the function that ships with Views, so you can change the function to make it do whatever you want.
To help you write your new function, try using a debugger. Set a breakpoint inside the function, then see what's available to you in the variables that are in the variable's scope: $view, $field and $row. Then just output whatever you want. In our example, the function looks like this:
<?php
function mytheme_views_view_field($view, $field, $row) {
if ($field->field == 'fieldtype' && $row->node_type == 'mynodetype') {
return $row->node_title;
}
else {
return $field->advanced_render($row);
}
}
?>Done!
