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.

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).

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.

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.

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'].

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):

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 CSSID 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):

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:

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

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):

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.

"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: (code)"

Garland already declares a phptemplate_node_submitted().
It's better if you say to add or change that function into the template.php.

This is an awesome site. I am a newbie in Drupal and this is the site where I got to know how to work with customized node.tpl.php file. However, I am eagerly waiting for the next part about how to customize the layout using CSS.

Thanks :) Yes there is still more work to complete for the lesson. I only recently began adding the Imagefield/imagecache part, and haven't had a chance to finish adding it to the whole lesson quite yet. I am going through the lesson as well while I add that to make adjustments/corrections to account for changes/fixes that have happened in CCK (and possibly Views) since the time this was written (since both CCK and Views were in alpha or RC stages at that time).

Stay tuned :) If you run into any specific issues in the lesson, please let me know so I can correct them.

I just need the correct 'calls' I guess you call them (don't know PHP either) for displaying, rendering whatever, an entire fieldgroup (and it's children, if any). If you know the answer to this and could let me know, sure would be appreciated.

Have tried, but no workie, after installing and looking into variables with ConTemplate as you suggested:

I looked into this and the closest I was able to find was this post: http://drupal.org/node/135616
However in my tests (using my own CCK type and fieldgroups I created for it, adjusting the code example to match) it does not appear to work in Drupal 6. I will ask around if anyone can update it for you.

Well you won't be happy hehe, though the easiest solution is going to be CSS. It's not hard :P Make sure you have magical Firebug and all will be well :)
First add a div around the $content area in the node template (or just add an extra class to the existing div) and ensure that $content is wrapped with a class called "fieldgroup-test" (or whatever you need in your case, just this is what my CSS will be using). You want something unique around it so that this will only affect this content type, and not all of them.

"First add a div around the $content area in the node template (or just add an extra class to the existing div) and ensure that $content is wrapped with a class called “fieldgroup-test” (or whatever you need in your case, just this is what my CSS will be using). You want something unique around it...."

Pardon - newb to the max.... this is all Ggeek-Greek to me. Explaination, demonstration por favor.

Here's a helpful guide as well on theming CCK input forms: http://drupal.org/node/101092
Note that the original guide was written (I believe) for Drupal 4.7, contains notes regarding Drupal 5, and there is info about Drupal 6 adjustments in the comments of the page. Perhaps I will try writing a Drupal 6 updated guide myself some time when I get a chance.

I went ahead and put together a little guide on another approach to theming CCK input forms (the method recommended by the previous commenter), including some examples based on code I wrote for my own site the other day.