Theming Content Types and Views

At this point the majority of the underlying "functionality" for your Article content type and the Views that will display the Article listings/teasers are now complete. However, it's very unlikely that things are "looking" the way you want them to quite yet. That's where Theming comes into the picture (customizing the "look and feel" of your site). First you'll learn how to customize the theme of the full Article pages (nodes), and then how to theme the Articles: Page and Articles: Block Displays from Views module. You will learn how to gain complete control over the HTML and CSS of every field of information, allowing you to customize them in any way you'd like.

Theming the full Article pages (nodes)

While the page.tpl.php file of your theme is the "highest level" template which controls the layout of your site overall and by default is consistent through all the pages of your site, there are a number of more specific template files that control how sub-elements of pages are themed "within" page.tpl.php, such as the different content that appears on each page throughout the site. The template file in your theme responsible for theming content is called node.tpl.php.

Creating a "custom" node.tpl.php template for Article content

This guide will use the Garland theme to present its examples, however feel free to follow along with your own theme if you prefer.

One of the great features of Drupal's flexible theming system is the ability to create separate "versions" of templates to affect only a specific Content Type. Since the goal is to theme the "Article" pages in a way that may be completely different than other types of pages on the site, this is definitely a useful feature.

  1. To accomplish this, simply browse to your theme's directory... in the example this is themes/Garland (if you're using your own theme it would likely be in sites/all/themes/yourtheme).
  2. Locate the node.tpl.php file, and make a copy of it, renaming the copy to node-article.tpl.php

    Note: you can create a custom template in this way for any Content Type you've created. Simply copy the node.tpl.php file and rename it, adding -content_type_name after the word node in the file name. For Content Type names consisting of multiple words, separate each word with an underscore.

  3. Add a little bit of sample text anywhere in your new custom template, save it, and visit an Article page - Drupal sees the new template immediately and uses it instead of the default template for your Article content (you should see your sample text appear). After confirming the functionality of the new template file, remove the sample text. If you've performed the steps correctly but the sample text is not showing, try going to Administer > Site configuration > Performance (admin/settings/performance) and clicking the "Clear cached data" button to clear the Theme Registry.

Custom theming for node-article.tpl.php

Here is a before and after screenshot to illustrate how an Article page looks right now "out of the box", as well as how it will look after completing the customizations to the theme that will follow in this guide.
[insert screenshot image]

Open up the new node-article.tpl.php file you just created, and locate <?php print $content ?> in the code. This one PHP variable is what is responsible for displaying just about every field of the content on the page (the exception being the node's Title field, which is usually displayed by the page.tpl.php template).
<?php print $content ?> displays a combination of the Body of the node, as well as all of your custom CCK fields.

Since the goal is to achieve more flexible control over the HTML of all the custom CCK fields in the Article Content Type, what needs to happen is for the $content variable to be broken up into each individual field, instead of combined all into one which you cannot control.

If you'd like, the Contemplate module can be a useful tool to help you "look inside" the $content variable, and pick and choose the code for the fields you want to copy and paste into your template file. If you'd prefer to use Contemplate, please see the guide on How to use Contemplate module.

However, it is often (and most likely) the case that using Contemplate for this purpose is unnecessary (and more unwieldy than it is worth). Simply copy the bits of code below, and you'll be able to use them in future Content Type template files as well simply by changing the name of the field (in most cases). In any case, it doesn't hurt to have Contemplate around for reference, in situations where certain types of fields use different code than below.

Adding individual/separate fields to node-article.tpl.php

Several short bits of code will be used to replace the $content variable, providing you with essentially the same output, only now with direct control over each field.

  1. Begin by copying and pasting the following line into your node-article.tpl.php file, completely replacing the <?php print $content ?> line. This new line displays the content of the Body field (note that the code for displaying the Body field is a bit different than the code for displaying custom CCK fields):
    <?php print $node->content['body']['#value'] ?>

    Important: though ['#value'] is used in this specific case, it should never be used in other fields unless you know how to make it secure (e.g. using the check_plain() function). Other fields should always use ['view'].

  2. Next, add the Article Subtitle field (field_article_subtitle) to the page, right above the line that says <?php if ($submitted): ?> (note that a div tag has been added around the field_article_subtitle field, so that it will be easy to style with CSS later):
    <div id="article-subtitle">
      <?php print $node->field_article_subtitle[0]['view'] ?>
    </div>
  3. You can easily insert other custom CCK fields in the same way as in Step 2. Simply copy and paste the above code, and change the name of the field as appropriate (you need to always use the "machine-readable name" of the field, which can be found by going to Administer > Content management and clicking on the "manage fields" link in the Article row (Direct path to this page: admin/content/node-type/article/fields) -- the field names to use are listed in the Name column. Every field automatically has the field_ prefix added before the custom part of the name which you chose when creating the field. Do not use the "Label" version of the field name.

    For instance, if you had a field in your Content Type called field_drupal_rules you would change field_article_subtitle instead to field_drupal_rules. This often works, though for some other field types you might need to use Contemplate to acquire the code (or Devel module can assist you with this as well if you prefer). Be sure to surround every field with a unique CSS ID or Class in a div or span tag, since that will make it much easier to add your own custom style/design to each field.

    Multi-value fields
    If you need to add a CCK field that has "multiple values" (for example has the Number of values setting set to Unlimited or a number other than 1), you can use the following bit of code, customizing just the field name (feel free to customize or remove the div tag):

    <?php foreach ((array)$field_drupal_rules as $item) { ?>
      <div class="field-item"><?php print $item['view'] ?></div>
    <?php } ?>

    Adding a field label

    When you manually print out a CCK field in your template, the Label defined for it does not appear by default (only the content of the field itself is included). Here is a code example to use if you'd like to print out the Label:

    <?php print $node->content['field_drupal_rules']['field']['#title'] ?>

Customizing "Submitted by..."

There is a line in your node-article.tpl.php file which contains <?php print $submitted; ?>, which is what produces the "Submitted by..." line. By default, the line it creates looks something like this (how the date is formatted depends on the settings at admin/settings/date-time):
Submitted by Username on August 7, 2008 - 4:05pm

If your goal is simply to remove the "time of day" portion of the date (a common request), have a look at this excellent article which covers how to do that in both Drupal 5 and 6: No time of day in node date (scroll down to the line "To modify the medium-size format for dates..." above the first screenshot). In Drupal 6 it can be done with the Custom format setting under Medium date format, located at Administer > Site configuration > Date and time (admin/settings/date-time), while in Drupal 5 some copy/paste code into your theme is required.

If your goal involves more detailed customization of $submitted, then pasting in a bit of code is necessary.
If you'd like your $submitted line to read as: Posted August 3rd, 2008 by Username

Then replace <span class="submitted"><?php print $submitted; ?></span> with the below code:

<span class="submitted"><?php print t('Posted ') . format_date($node->created, 'custom', "F jS, Y") . t(' by ') . theme('username', $node); ?></span>

With a tiny bit of understanding of a simple PHP feature called concatenating strings (the name of which sounds much more complicated than it really is), you can easily "rearrange" the various words and bits of code to however you need. The key to how it works is the period (.) which separates each part of the code.

In Drupal 6, the above method still works, but you can also accomplish this for every Content Type on your site overall in one step, by pasting the following into the template.php file of your theme (or changing the pre-existing function if your theme, such as Garland which is Drupal's default theme, already has this function... since you cannot have the same function twice):

function phptemplate_node_submitted($node) {
  return t('Submitted by !username on @datetime',
    array(
      '!username' => theme('username', $node),
      '@datetime' => format_date($node->created),
    ));
}

In the return t('Submitted by !username on @datetime', line, rearrange !username and @datetime however you prefer. You can also feel free to customize the date format by exchanging $node->created for $node->created, 'custom', "F jS, Y" (or any other custom date format).

If you'd like to remove the $submitted line altogether (in case you don't want it included at all on the page), you can either simply delete the $submitted line from node-article.tpl.php or you can turn it off for the Article content type at admin/build/themes/settings under the "Display post information on" setting.

Theming Views

Until I get a chance to finish this page, this post I made on drupal.org should provide a little help:
http://drupal.org/node/299406#comment-978324