I've been having headaches figuring out how to get node object when theming views.

How is it possible to get node object (like node id and other information) inside views .tpl.php files?
I want to have access and control over this data when theming drupal views.

Is it maybe still possible to override phptemplate_views_view_list_..() functions inside template.php instead of using template files?
I tried doing that with my latest drupal (6.x) and views version but it didnt work..

Many thanks for help!

Comments

mooffie’s picture

I've been having headaches figuring out how to get node object when theming views.

The node objects aren't loaded for you because of efficiency: Views loads only the fields you asked for.

How is it possible to get node object

The node ID is there in the record fetched from the databse. The record is $row, so the node ID is $row->nid, and you can load this node yourself.

// I assume you want this in views-view-fields--VIEWNAME.tpl.php

$node = node_load($rows->nid);

if ($node->field_gender[0]['value'] == 'male') {
  print 'Hi mister!';
} else {
  print 'Hi ms!';
}
Is it maybe still possible to override phptemplate_views_[...] functions inside template.php

You can, but in the best case it gives you nothing. In most cases you'll lose: you lose all the juicy variables the 'preprocess' functions prepare for you (since 'preprocess' functions are executed for template-files, not for functions).

l2u’s picture

Thank you very much with helping me out with this information.

How can I get/make link/path to $node with the code above? Should I use l() ?

And one more thing: how should I define globals so that every item could be enumerated? I think I should define global $count in views-view-list.tpl.php so I would be able to print it (current $count) in views-view-fields.tpl.php .

Many thanks for help!

mooffie’s picture

How can I get/make link/path to $node with the code above? Should I use l() ?

You can use l(), as in print l($node->title, "node/$node->nid"); You should paste your code here so we can fix it.

But why would you want to do that? There's a 'Node: Link' field that does links for you. You don't need to program.

how should I define [...] global $count in views-view-list.tpl.php so I would be able to print it (current $count)

You can define a global, as in global $MYVIEW_counter; ... print ++$MYVIEW_counter;.

But why would you want to do that? If you pick the 'List' style, then you can configure it to show the list numbered.

in views-view-list.tpl.php

You can define the global right in views-view-fields.tpl.php. But note that you should name it views-view-fields--YOURVIEWNAME.tpl.php or else your template will affect all views. Remember to clear Drupal's cache after you create this file or Drupal won't pick it up (but you don't need to clear the cache if you just modify this file).

l2u’s picture

I want to wrap all fields in one a (link) tag because of css design.

I put this at the beginning of fields.tpl.php:

<?php
$node = node_load($row->nid);
?>
<a href="<?php print base_path() . drupal_get_path_alias('node/'.$row->nid); ?> ">

and by the end:

</a>

It seems to work okay, but I'm unsure if thats a proper/good way of doing it..

Thanks for help!

mooffie’s picture

It's best, and simpler, to use the url() function, which deals with various scenarios for us (clean urls or not, language prefixes, rewrites, etc.):

<?php
$node = node_load($row->nid);
?>
<a href="<?php print check_url(url('node/'.$row->nid)); ?>">
.
.
.
</a>

(Btw, I don't see that you're using the $node object. It's better not to load it if you don't need it.)

want to wrap all fields in one a (link) tag

(Note that according to the HTML standard, {A} tag may only contain inline elements. So you can't have DIV inside it, because it isn't an 'inline' element. If you care about standards, and if you do have DIVs there, you can move that enveloping {A} into 'views-view-field--xyz.tpl.php' --this will make every field separately enveloped by the {A}.)

krancour’s picture

Mooffie,

I'm having the same issue that l2u initially described. I can't figure out of to get a node id from the $row. I found your example above quite helpful and encouraging, but for some reason, $row->nid returns nothing for me. Any thoughts on why that might be?

My code is below. It's supposed to detect the first and last nodes in the "frontpage" view and set a "first" or "last" attribute so that node.tpl.php can add an extra class to the node, if appropriate, so that it can be styled differently. Of course, it doesn't work because of the issue I described.

Many thanks in advance for any insight you can provide!

function my_theme_views_view_unformatted__frontpage($view, $options, $rows, $title) {	
  $count = 1;	
  foreach ($rows as $row) {
    $node = node_load($row->nid);		
    if ($count == 1) $node->first = true;
    if ($count == sizeof($rows)) $node->last = true;
    $output .= node_view($node, false, false, true);
    $count++;
  }
  return $output;
}
mooffie’s picture

I can't figure out of to get a node id from the $row.
[...]
but for some reason, $row->nid returns nothing for me.

Views uses two different components to theme your data:
- A 'row style', that themes an individual piece of data (a row).
- A 'style', that themes the whole pieces together.

l2u's was dealing with a 'row style', and in his case a $row corresponds to a database row.

But in your case you're overriding the theme of a 'style'; and a 'style', unlike a 'row style', doesn't care much about the particulars of the individual pieces. In your case, the $row variable holds the HTML of each piece. The nodes are already rendered at this stage.

It's supposed to detect the first and last nodes in the "frontpage" view and set a "first" or "last" attribute so that node.tpl.php can add an extra class to the node

There are different ways to do this.

If you don't mind having a DIV with that extra class wrap your nodes, instead of putting that class directly on the node, then you can change your existing code: e.g., output a "{div class='node-{$view->name}-first'}" if this is the first item, etc.

But if you want the class directly on your nodes, you can use a "preprocess" function to touch the $node object before it arrives to 'node.tpl.php'. One nice thing Views does for us is to attach a "view" property to the node, and we can inspect it in our preprocess function. So, for example, `if ($vars['node']->view->result[0]->nid == $vars['node']->nid)` we know it's the first node. (I won't write the complete code because then I'll have to test it.)

krancour’s picture

Mooffie,

I tend to obsess about having nice clean markup, so your second suggestion seemed more desirable to me than the first.

And I can't thank you enough for your suggestion! It worked perfectly and you've ended quite a bit of frustration for me. Here's what I ended up with:

/**
* Override or insert PHPTemplate variables into the node template.
*/
function phptemplate_preprocess_node(&$vars) {
  $node = $vars['node'];	
  $view_results = $node->view->result;
  $view_results_size = sizeof($view_results);	
  if ($node->nid == $view_results[0]->nid)
    $node->first = true;
  if ($node->nid == $view_results[$view_results_size - 1]->nid)
    $node->last = true;
}

Thanks again! I really appreciate your assistance.

mooffie’s picture

You're welcome. Improvements to your code:

  • You should condition all in a `if (isset($node->view))`, or else PHP will print many notices --because $node->view isn't always there.
  • Do `$node =& ...` for PHP4 compatibility.
  • $node->first and $node->last will be set for nodes in all views. So perhaps it's better to define a $node->views_classes instead, in the form of "node-view-{$node->view->name}-[first|last]" and then you'll be able to address, in your CSS style sheet, only the desired view.