Drupal 7 custom node view modes

Monday, December 20, 2010 - 16:06

One of the cool new things in Drupal 7 is the ability to easily add new “View modes” for nodes. View modes are available for other entities like comments also, but I’m gonna only cover the nodes for this time. 

Before, Drupal had only two “hard-coded” node view modes, the full node view and the teaser view. These two provided us just enough flexibility for most simple content listings, but quite often we needed to turn to Views in Fields mode to get more flexibility. By flexibility in this case I mean displaying the same content in different ways in different contexts.

In Drupal 7 we can create additional view modes by simply implementing hook_entity_info_alter() in our custom module.

 

/**
* Implements hook_entity_info_alter().
*/
function MYMODULE_entity_info_alter(&$entity_info) {
  $entity_info['node']['view modes']['another_teaser'] = array(
    'label' => t('Another teaser'),
    'custom settings' => TRUE,
  );
}

 

After defining the new view mode, we can go to content type’s “Manage Display” page and select which fields to display plus some additional options for fields, like which image style to use for image fields, for example.

display_fields.jpeg

Next we need to get this view mode used somewhere. We’re gonna create a View for that. Set the View to Style = Unformatted, Row style = Node and select the “Another teaser” view mode from the row style options. Optionally you can create a page display with a path for the View for easier testing.

views-select-view-mode.jpeg

Up to this point nothing is that different than creating a view in “fields” mode, and select the desired fields one by one in the view itself. The differences are mostly how we can apply some theming and custom layout for the content.

To get the most out of this we’ll propably want to add a custom node.tpl.php template for this view mode. Custom node template enables easy and flexible theming and we can use standard hook_preprocess_node() function for example to control the variables we have available in the template. To make Drupal use a different .tpl.php file for view mode we need to add a new template suggestion in hook_preprocess_node().

/**
* Implements hook_preprocess_node().
*/
function MYMODULE_preprocess_node(&$vars) {
  if($vars['view_mode'] == 'another_teaser') {
    $vars['theme_hook_suggestions'][] = 'node__' . $vars['type'] . '__another_teaser';
  }
} 

Duplicate standard node.tpl.php for the content type you need, like node--article--another-teaser.tpl.php. (NOTE: use underscores in template suggestions, dashes in the filename).

There are many other ways to get the exactly same outcome, like the Display Suite module, but seems to be an overkill for a simple need what we just covered. While Views in fields mode is still most often the way to go, this opens a completely fresh option if you need to reuse the templates in multiple views, or you need to display every content type in a different way in the same listing without doing gigantic template files for views.

Comments

This really rocks!

Impressive! This will change forever how I view content type display and usage.

:). Can't wait to start developing with D7. (but first I must to finish my current projects :(

I searched a lot for that !!!

I also tried Display Suite for this, but currently it doesn´t work correctly with views and of course is an overkill. THANKS AGAIN !!!

I was literally looking for this feature yesterday and found your post on drupal planet. Talk about good timing.

Also thanks for the drupal 7 tips. Looking forward to working on new projects so can start with D7.

Thanks for this cool highlight of the feature.

This is especially powerful in D7 since you can now define field order per view mode (in CCK D6, field display order = form display order, for all view modes)

Note that Display Suite in D7 got notably skimmed down since much of its features are now handled in core, or can plug directly on the main core field UI, instead of having to develop a complete alternate UI in D6.

Display Suite notably offers a UI to create your own custom view modes - although, as you point, creating them through code is quite straightforward.

Thanks, that was helpful. Two remarks about your code:
AFAIK $vars['build_mode'] is not available in preprocess_node functions, but $vars['view_mode'] is.

I took the creation of template suggestions a small step further by doing this:

/**
* Implements hook_preprocess_node().
*/
function MYMODULE_preprocess_node(&$vars) {
$vars['theme_hook_suggestions'][] = 'node__' . $vars['type'] . '__' . $vars['view_mode'];
}

As a result, I can now use this file naming pattern for all possible node type & view mode combinations: node--NODE-TYPE--VIEW-MODE.tpl.php.

You are right, $vars['build_mode'] doesn't seem to exist in hook_preprocess_node. It might be that I used an outdated Drupal 7 or something. I corrected it to $vars['view_mode'] now. Thanks!

Thanks for the hint to use a general vars['view_mode'] in the template suggestions.

Hi!

I am very new to Drupal and can´t figure out why my html codes doesn´t work in content when saved. If i check the preview -- "Preview Trimmed Version" is how i want it to be displayed in content when saved. Now "content" displays in the "Preview full version" which is not how the html codes should turn out. I checked the html codes and they are correct. Please, if any one knows how to solve this it would be great! Thank you.

hello

it's perfect for what i need, but where i put the code :

/**
* Implements hook_entity_info_alter().
*/
function MYMODULE_entity_info_alter(&$entity_info) {
$entity_info['node']['view modes']['another_teaser'] = array(
'label' => t('Another teaser'),
'custom settings' => TRUE,
);
}

?
I must create a new module just for that?

Im a newbie...

sorr for my poor english

Hi! Thanks for your comment. Yes - you need a custom module where these snippets are placed. I didn't cover the steps to create a custom module, because there's a lot resources for that available on the web.
See: http://drupal.org/node/361112

Another useful tip relating to theming custom node views...

Instead of creating separate template files per view mode you can use the $view_mode variable in your default node type template file.

for example in your "node--news_post.tpl.php" file, you can set the output of your "another_teaser" custom view mode with the following...

custom teaser output code here

Thanks for the info. However, I'm a bit stuck with the part on the views, using Views 3 (currently RC1). I've got something working, but I'm not sure I've done it the right way. "Style settings" appears to no longer exist, the closest I can find is "unformatted list".

Could you, or anybody who feels like it, comment on how you should do do this using Views 3?

And is a view really necessary? It seems like overkill to me, what good is a display mode in core if you can't use it without a contrib module...

thx for the nice snipped. Did'nt work for me. If you also have problems with the code, try defining TRUE as a string ('TRUE')....

I had the same problem. Set TRUE as a string helped for me!

you shouldn't use a string if you use then php interprets it always as TRUE , you probabely didn't activate your custom view mode under `Custom display settings` in `MANAGE DISPLAY` tab.

I have been using Views_datasource in D6 for a while, to output JSON files. One of the things I do is output the URL of Images as oppose to the images them selves. I have mobile apps that consume this data.
I want to try doing this in D7 and VIews3, but no luck out of the box. So I ran across your article, and I am wondering if this could be a solution.

So one of the "another teaser" I would create a view of type JSON. and all of the FILES, and IMAGES would be URL's. The output would have a path with a .json extension. What more am I missing, and am I going int he right direction? perhaps there is some sample code out there that I could look at?
thanks

Excellent and to-the-point article on a super helpful topic. Thank you. This is an excellent addition to D7, too bad it's not documented. (Also the post by marcvangend really helps too).

In case it helps anyone else, I discovered the 'hook_entity_info_alter' feature in the node_example module (example_node_list), but they failed to mention where this modification would manifest itself in the Drupal admin area. It didn't even occur to me that it added a new view mode in the Manage Display tab. So simple! That detail would be helpful.

Anyway, thanks for helping me connect the dots!

Great. Works for me. My views looks a little different but works with Format:unformatted list and show:content. Well I have an error message I haven't looked into yet but it's using my template file so that's good enough for me for now.

How do I use this view with a specified node? I don't want to look at all the nodes on the same page. I want to be able to select one node and then perhaps switch between view modes for just that node. I imagine I can possibly pass an argument to the view and filter the view based on that argument but I don't know how or if there is an easier/better way.

Thanks again.

hi

I am not sure what wrong I am doing. I created new module in sites\all\modules\ as energy_landing. Created .info and .module file enable module but still I cant see new view mode.. Please help

I'm at the same place. Did you solve this yet?

Very nice tip. It might not work when used for the first time until you clear the cache twice: once after adding the new hook and then second time. Duno why, but without second cache clearing I had the custom view mode checkbox checked, but the mode didn't appear in the horizontal view modes list. Now it's ok.

Yes, this was my pick after researching, after reading this article. I think this module uses the system described here, but its handy if you do not want to mess with the code and writing own modules... Anyway, article is great. And tjhis module simplifies much for me now :)

Just wanted to thank you for the custom view mode tip. So thanks! :)

This post helped me again ;) Thanks Juha!

Hello, I don't know if i'm at the right place for that. In fact, i'm fed up to search on the web for this.
I want , when i create a content, to choose multiple node/pages to display my content. For exemple when i'm creating my article i want a fields who allow me to select multiple link of my website.

Is there a way to do that with, just creating a new view or content type ? Or should i alter a module or create a new one for my purpose ?

A link with a turtorial or similar case should be fine too ;)
thank you in advance for your response.

Thank you very much!!!

wow, impressive, I'm newbie, so if someone could give me a little example of how to select the title of the node in this node--type--view_mode.tpl.php...

Thanks.

Thanks for the help, one addition:

If you want to adjust the visibility of a field from within the code, so you don't have to mess around with the UI at all, you will likely have to do something like this:

$node->content['my_field_of_interest']['#hidden'] = FALSE;

otherwise the field may be hidden in your new view mode. It may be worth noting this alternative as part of the tutorial, below where you say «we can go to content type’s “Manage Display” page and select which fields to display».

Oh, that's for use in hook_node_view, of course.

Exactly how I like it. Hands down this is the best and most useful Drupal mini-tutorial I've come across so far, earning my keep with Drupal for about 3 years now. Also your preview feature yields a 503, seems like varnish config problems. :P

If you set
'custom settings' => FALSE,

if won't be enabled by default (on all content types) and you can choose which content types to enable it on.