Drupal Colonoscopy: Or, How I learned to theme a CCK field in Drupal 6

Q: How many Drupal themers does it take to perform a custom field label colonectomy?
A:  You don't want to know.

Our journey began with what seemed to be a simple request:  How do you remove the colons from the end of field labels on a Drupal 6 site? 

Should be simple, right? A CSS tweak, a function override in the theme, maybe a hook_form_alter -- standard stuff. No big whoop.  Well, it was not as straightforward as we would have hoped.  But, after some code snippet borrowing, a foray into regex-land, many theme function override attempts and one major "aha" moment, we've finally arrived at a solution we can all get behind (and understand).

Not all fields are created equally

I'll skip right to the punchline.  The main thing to realize is that the HTML output for various fields is not all created equally or in the same place.  Fields provided by Drupal core have their own theme function-- theme_form_element--  an explanation of which can be found on the Drupal API site

Take a look at the theme_form_element code on http://api.drupal.org (every Drupal themer's best friend). This code, if copied into your theme's template.php file can be manipulated to produce the output you desire:

<?php
function theme_form_element($element, $value) {
  // This is also used in the installer, pre-database setup.
  $t = get_t();
 
  $output = '<div class="form-item"';
  if (!empty($element['#id'])) {
    $output .= ' id="'. $element['#id'] .'-wrapper"';
  }
  $output .= ">\n";
  $required = !empty($element['#required']) ? '<span class="form-required" title="'. $t('This field is required.') .'">*</span>' : '';
 
  if (!empty($element['#title'])) {
    $title = $element['#title'];
    if (!empty($element['#id'])) {
      $output .= ' <label for="'. $element['#id'] .'">'. $t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</label>\n";
    }
    else {
      $output .= ' <label>'. $t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</label>\n";
    }
  }
 
  $output .= " $value\n";
 
  if (!empty($element['#description'])) {
    $output .= ' <div class="description">'. $element['#description'] ."</div>\n";
  }
 
  $output .= "</div>\n";
 
  return $output;
}
?>

Turns out, removing the colons from fields that originate from Drupal core modules is pretty simple. Notice there are two places where there is HTML output for field labels.  Each one contains the value '!title:'  That colon, in each place, is what you want to be rid of.  Copy this function into your custom theme's template.php file. Rename it to be [YOUR_THEME_NAME]_form_element.  Delete the two colons.  Save your template.php file. 

Done and done, right?  Kinda, but not entirely...

CCK field theming 101

Because, if you are like the rest of us, you are creating your own content types and fields using the CCK module.  The theme_form_element override does not affect any of your custom-created CCK fields.  A little digging and we figured this one out.

The key revelation was the discovery that the CCK module comes packaged with its own theme folder.  Who knew?  Inside this folder is a file named content-field.tpl.php  This file produces the HTML output for CCK fields-- in much the same way that your custom theme's node.tpl.php produces the HTML for your nodes and page.tpl.php produces the HTML for your pages.  

To override the default output of this template file, leave the content-content-field.tpl.php field in the CCK module's theme folder, but also put a copy of this file into your custom theme's folder, in the same directory with your other template files.  Keep the content-field.tpl.php filename the same to allow the override.  If your CCK module files are not accessible to you (for example in a multi-site managed hosting environment), you can accomplish the same goal simply by downloading a copy of the CCK module from its project page:  http://www.drupal.org/project/cck.  I've also attached a copy of the most recent version of this file (as of 3/17/09) to this tip.  Download this file below if you need it; or view/copy the relevant code here if you'd like to follow along: 

<?php if (!$field_empty) : ?>
<div class="field field-type-<?php print $field_type_css ?> field-<?php print $field_name_css ?>">
  <?php if ($label_display == 'above') : ?>
    <div class="field-label"><?php print t($label) ?>&nbsp;</div>
  <?php endif;?>
  <div class="field-items">
    <?php $count = 1;
    foreach ($items as $delta => $item) :
      if (!$item['empty']) : ?>
        <div class="field-item <?php print ($count % 2 ? 'odd' : 'even') ?>">
          <?php if ($label_display == 'inline') { ?>
            <div class="field-label-inline<?php print($delta ? '' : '-first')?>">
              <?php print t($label) ?>what about one field</div>
          <?php } ?>
          <?php print $item['view'] ?>
        </div>
      <?php $count++;
      endif;
    endforeach;?>
  </div>
</div>
<?php endif; ?>

Once you have this template file in place in your custom theme folder, to follow our example task of removing field label colons, find the lines that print the field label(s)-- denoted by the $label variable.  Notice the ":&nbsp;" which prints a colon and a non-breaking space.  By deleting the ":",  your surgical procedure to remove custom field label colons will be complete.

Done and done, right? Sure, but why stop here?

Getting specific-- refining your CCK field theming for particular situations

This is just the beginning of what you can accomplish using this theming method.  Fairly obviously, besides removing colons, you can impact the HTML in any way you wish by altering the code in this overriding template file.  The commented-out text at the top of the file gives you important information about the variables you have access to:

<?php
// $Id: content-field.tpl.php,v 1.1.2.5 2008/11/03 12:46:27 yched Exp $
 
/**
 * @file content-field.tpl.php
 * Default theme implementation to display the value of a field.
 *
 * Available variables:
 * - $node: The node object.
 * - $field: The field array.
 * - $items: An array of values for each item in the field array.
 * - $teaser: Whether this is displayed as a teaser.
 * - $page: Whether this is displayed as a page.
 * - $field_name: The field name.
 * - $field_type: The field type.
 * - $field_name_css: The css-compatible field name.
 * - $field_type_css: The css-compatible field type.
 * - $label: The item label.
 * - $label_display: Position of label display, inline, above, or hidden.
 * - $field_empty: Whether the field has any valid value.
 *
 * Each $item in $items contains:
 * - 'view' - the themed view for that item
 *
 * @see template_preprocess_field()
 */
?>

Note, however, that this content-field.tpl.php template file, named as it is, themes the output of all CCK fields, globally across custom content types.  You can become much more powerful when you take control of Drupal and CCK naming conventions and create more specifically named template files.

With a copy of content-field.tpl.php in your custom theme's directory (whether you've modified it or not) you have the ability to theme very specific field situations: 

For example, making sure you do have a copy of content-field.tpl.php in your theme folder (it's important to have this file and have it named content-field.tpl.php, if you wish to theme only one specific custom field, you can add an additional template file named: content-field-[FIELD_NAME].tpl.php. For example, if the machine readable name of your field is field_custom_field, the name of your template file should be: content-field-field_custom_field.tpl.php. The same code from content-field.tpl.php will work as the base content for this file as well.

Refine this method further to isolate the impact to all the fields within a specific content type by adding a template file named: content-field-[CONTENT_TYPE].tpl.php.  Or impact any single field within a specific content type with a template file named: content-field-[FIELD_NAME]-[CONTENT_TYPE].tpl.php

With this theming method at your disposal, you have quite a bit of control over CCK fields, if you determine such control is necessary.  Remember, always use this power wisely and well. 

Your rating: None Average: 4.7 (97 votes)
AttachmentSize
content-field.tpl.php1.66 KB

Comments

Thanks

Your post is extremely clear and it containts the information I was looking about to theme a bit the output of a customized CCK theme. I will work much better with it. I am bookmarking your site for my future reference.

Thanks a lot from sunny Spain :)

Gustavo.

Preprocess

Is there a way to preprocess the variables before they reach the CCK template files? I wanted to add some additional markup around a compound field (flexinode). I had to test for the field type for each item, and then wrapped the item value in the markup I wanted for the individual fields. For example, this is what part of my content-field-dialog_ref.tpl.php looked like.
<div class="field-item <?php print ($count % 2 ? 'odd' : 'even') ?>">
          <?php if ($label_display == 'inline') { ?>
            <div class="field-label-inline<?php print($delta ? '' : '-first')?>">
              <?php print t($label) ?>:&nbsp;</div>
          <?php } ?>
		  <?php if ($item['type'] == 'dialog_field') {?>
			<h3><?php print $item['value']['field_dialog_field_name'][0]['value'] ?></h3>
			<div><?php print $item['value']['field_dialog_field_description'][0]['value']?></div>
		  <?php } else { 
				print $item['view'];
			} ?>
        </div>
I'm wondering if there is a way to move that logic into a preprocess function so that  print $item['view'] will print out my new markup.

Both the original and the copy must be in the same folder

Via http://drupal.org/node/292884

You write "With a copy of content-field.tpl.php in your custom theme's directory" and in retrospect that's clear, but it's a bit counter-intuitive, since the content-field.tpl.php is still in its original location, so why would drupal not use it?

Something like:

1. Copy content-field.tpl.php to your theme's directory ...

2. Still in your theme directory, copy content-field.tpl.php to ...

would eliminate any stumbles.

Don't forget to flush!

You may not see any changes, to your theme until you flush caches. Flush early and flush often.

If you have admin_menu installed (a must-have module!), it's a quick visit to admin_menu/flush-cache.

preprocess

Hmmmm, the code tags didn't work. It heavily filtered out my code example....

Fixed the formatting

Thanks for your post and your question. I've added the proper code to your comment so that the embedded code is visible.

Most probably

There is a lot going on here. The succinct answer to your question is "Yes, most probably."

I'm not the best person to be handing out preprocess advice without some extensive advice from better programmers. But, I did find a thread on Drupal.org that addresses this and has some code examples:

http://drupal.org/node/418894

You might wish to start here.

I'm stoopified or perhaps just stupid. It didn't work for me.

(1) I copied content-field.tpl.php from CCK Theme folder to my theme's folder.

(2) I renamed it content-field-field_title_color.tpl.php to match a CCK field named field_title_color.

(3) I removed the colon from the content-field-field_title_color.tpl.php file.

(4) I cleared all caches.

(5) I cried when I didn't see any change.

(6) I deleted the entire contents of the content-field-field_title_color.tpl.php file, cleared all caches, and all the output for that field was all still there. Damm.

(7) I deleted the entire contents of the content-field-field_title_color.tpl.php file, cleared all caches, and all the output for that field was all still there. Damm.

(8) I deleted the content-field-field_title_color.tpl.php from my theme folder and deleted the contents of the original content-field.tpl.php file in the CCK theme folder hoping I would kill all CCK field output. Cleared my caches and much to my bewilderment, all my CCK files were still there. I'm a loser.

(9) I wrote this comment and am hoping someone can shed some light on what I am doing wrong. I'm using D6.13 and CCK v6.x-2.5. My theme is a Zen sub-theme.

Thank you,
Scott

Colons still visible on page

You've explained how to remove them from the node editing mode but how can i get rid of them from the actual front end pages that the user sees?!

Scott, you missed a step

I'm a little late on this, but going through this great bunch of info and about ready to do some modifications to my own site using this & other info.

Anyway, if I understand correctly, Scott, you need to have two files where you have only one in your steps:

"(1) I copied content-field.tpl.php from CCK Theme folder to my theme's folder.
(2) I renamed it content-field-field_title_color.tpl.php to match a CCK field named field_title_color."

According to the previous posts and reading the linked threads from this page as well, I'm pretty sure you need to do something like this instead: (I'm only posting this as a suggestion, like I said, as I've not done this stuff yet. However, this is what I'm reading about)...

(1) Copy content-field.tpl.php from CCK Theme folder to your theme's folder.

(2) Make ANOTHER copy of content-field.tpl.php and rename this one to content-field-my_custom_field.tpl.php to match your CCK field named "my_custom_field". You will now have TWO copies of the original content-field.tpl.php file (one in the original location and one in your theme's folder), along with your newly-renamed copy -- content-field-my_custom_field.tpl.php.

Hopefully that is what you're missing. Three files, not two! :)

(Now I'll go on and try all this for myself... hopefully I'm not speaking too soon about understanding what to do!)

- Paul
www.ThisWorked.com
www.Bragfile.com

Great exposition. Many

Great exposition. Many thanks.

SAved me

You saved me a lot of headache with the tip of having the content-field.tpl.php in my theme folder before I can create additional more field specific theme overrides.
Thanks!

Just Scratching the Surface

Nice work. Digging into the mountain of Drupal source code is an awe-inspiring task. When I analyzed the Drupal source code to count the number of built-in and Drupal specific functions, I found 1350 calls to 235 to built-ins and 5483 calls to 1032 Drupal specific functions.

This might sound like a crazy lot, but Drupal is lighter than some others, meaning Wordpress and Joomla. You can see the some comparisons at http://douglasputnam.com/top100.

Do not print anything if the field is empty node-content-type

Hi do not know if it is a place to ask, but I have the following problem
I have a content type noticias .
I have several fields in the type of noticias content.
Now I want to customize the output in full view of the node I want the escritor field ( tex) is displayed if it´s have content, otherwise we will not show neither the field nor the div.
<?php if ($field_escritor): ?>

<?php print 'Por: ' . $field_escritor[0][value];?>

<?php endif; ?>
In node-noticias.tpl.php, I put the previous sentence, but whether it is empty or containing content, always prints the word Por: and the div
I'm chose exclude en display field.
Someone might suggest how to make the code in node-noticias.tpl.php so that if the field is empty, do not print anything.(ni div , ni Por: )
From already thank you very much and sorry for my English

Thank you

I have to say you for solving my problem of removing the colons from CCK input labels. This post was well written and easy to follow. Thank you, again.

Colons still visible? Shouldn't be...

The customization I outlined eliminates the colon in the HTML output for the field. If edited this way, the colon should not appear on the page visible to all visitors -- not just in the edit form. If this is not what you are experiencing, there must be something else going on.

Doesn't change what the viewer sees

This only removes colons in the editing mode, how do you remove them so they don't appear on the finished website?

Problems getting this to work- possible conflict with module?

Hi,
on a fresh install of Drupal 6.19, I installed CCK, created a content type and text field for it. Followed the instructions above and got what I wanted to work- in my case- I want to remove the label completely.

But, for some reason, no matter how many times I try to do it...I cannot get it to work with another Drupal installation with many other contributed modules and some minor custom theming.

In both cases, I am working with the Basic theme. Not sure where to begin trying to isolate the problem. If anyone has a suggestion, would love to hear it.

Thanks

Wow this was great!

Thanks so much for sharing these awesome tips!

Post new comment

  • Allowed HTML tags: <a> <img><b><i> <em> <h1> <h2> <h3><h4><h5><h6> <sub> <super> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <br> <p><sup>
  • Lines and paragraphs break automatically.
  • Web page addresses and e-mail addresses turn into links automatically.

More information about formatting options