Theming CCK content type output display and input edit form

in

The Content Construction Kit (CCK) lets you define custom content type with many different kinds of data fields. The default display and input form are generic looking and may not be the way you like. But the look of the node output and the node edit form are completely customizable. I will illustrate how to do this by making change to the active theme. But at the end, I will show how to do this from a module, which is a better approach because it's not married to the active theme. This is better for site maintenance and allows you to freely switch theme.

Theming CCK content output display

Drupal display node content using the 'node' theme hook at the end of node_view():

return theme('node', $node, $teaser, $page);

This ends up calling the template based 'node' theme hook defined by the node module. In one of its preprocess function template_preprocess_node(), a template suggestion is set:

$variables['template_files'][] = 'node-'. $node->type;

This tells the theme system to first look for a node-CONTENT-TYPE-ID.tpl.php template to use if one exists in the theme paths. If not, then use the regular node.tpl.php template. By providing this alternate template in the right place, you can fully control the display format.

Start by copying the node.tpl.php file to node_CONTENT-TYPE-ID.tpl.php to customize. For example, to customize the content type event_listing, name the file node_event_listing.tpl.php.

The note_XXX.tpl.php template is used to render content in several contexts: as teaser, as page, in search result, etc. So your template must work in these different contexts. Pattern it after the default note.tpl.php file.

See Example: Theming a Specific CCK Content Type and Node.tpl.php at drupal.org for more information.

Theming CCK field

Individula CCK field is themed by the content_field theme hook defined by the CCK module. Its preprocess function suggest a whole bunch of different override templates:

    'template_files' => array(
      'content-field',
      'content-field-'. $element['#field_name'],
      'content-field-'. $element['#node']->type,
      'content-field-'. $element['#field_name'] .'-'. $element['#node']->type,

so there can be three different override templates. The search order is from last to first:

  1. content-field.tpl.php default if no override template is found.
  2. content-field-FIELD_NAME.tpl.php is used to theme the field as it occur in every content type.
  3. content-field-CONTENT_TYPE.tpl.php is used to theme all CCK field in that content type.
  4. content-field-FIELD_NAME-CONTENT_TYPE.tpl.php is used to theme that CCK field in that content type.

The default template is in:

cck/theme/content-field.tpl.php

copy it to your theme directory, then make a copy of that and name the file according to the override template name suggestions above. For example, if you have a field field_xyz in CCK content type abc, then in your theme directory, you should have:

content-field.tpl.php content-field-field_xyz-abc.tpl.php

Rebuild the theme registry.If you use the nodereference CCK field, you can provide an override for its output. The template suggestions are:

    $vars['template_files'][] = 'node-nodereference';
    $vars['template_files'][] = 'node-nodereference-'. $field['field_name'];
    $vars['template_files'][] = 'node-nodereference-'. $node->type;
    $vars['template_files'][] = 'node-nodereference-'. $field['field_name'] .'-'. $node->type;

these are in addition to the default override suggestions already set by the node module described previously. Similar to the content-field hook, make sure you have the node.tpl.php template in your theme, then add one of these to override how the node is displayed within a nodereference field.Theming CCK node input form

There are two ways to change the look of the CCK node input form: 1) implement HOOK_form_alter() or 2) implement a custom theme hook to take over the output of the form. Depends on what needs to be achieved, you may need to to do one or the other or both. HOOK_form_alter() is used to alter the form data structure before it's rendered by the theme hook. It can used to turn off certain element or fieldset, change some title text in the form or change form field default value, etc. And theme hook is used to re-arrange the form HTML markup. So pick the appropriate method.

HOOK_form_alter() method

There are two forms alter hooks: HOOK_form_FORM_ID_alter() and HOOK_form_alter(). The first is targeted on a specific form of a given ID, the second is call for every form. It's very important to know Drupal core calls all the HOOK_FORM_ID_alter() hooks first, then call all the HOOK_form_alter() hooks (see Add hook_form_FORM_ID_post_alter() to run after non-specific hook_form_alter() about the implication of this execution order. CCK uses HOOK_form_alter() to add CCK fields fom input elements to the node-form. Use the more specific HOOK_form_FORM-ID_alter() if you only need to alter the node-form itself and not any specific CCK field input form element (you won't see any CCK fields there because CCK's HOOK_form_alter() has not run yet). If on the other hand, you need to alter any CCK field input form elements, you need to implement the HOOK_form_alter() hook and make sure it is called after CCK's by either naming your module alphabetically after 'content' or alter your module's weight in the system table with something like this:

function HOOK_install() {
  db_query("UPDATE {system} SET weight = 255 WHERE name = 'MODULE-NAME'");
}

To implement HOOK_form_FORM-ID_alter(), first determine the form id of the CCK node input form. This form id can be found by look at the HTML source of the CCK input form page in something like this:

<input type="hidden" name="form_id" id="edit-club-node-form" value="club_node_form"  />

in this example, the CCK content type is 'club' and its form id is "club_node_form". In other words, the form id is just CONTENT-TYPE-ID_node_form. To turn off the Revision fieldset:

function HOOK_form_club_node_form_alter(&$form) {
  unset($form['revision_information']);
}

However, if you need to alter the CCK fields input form element, you need to use the HOOK_form_alter() for reason I mentioned before:

function HOOK_form_alter(&$from) {
  if ($form['#id'] == 'node-form' && $form['#node']->type == 'club') {
    dpm($form);  // do your thing
  } 
}

Form theming method

The CCK content type input form is themable. When the form is build in node_form(), the #theme attribute is set:

  $form['#theme'] = array($node->type .'_node_form', 'node_form');

This tells the theme system to look for the theme hooks $node->type .'_node_form', then node_form to theme the form. For example, content type event_listing input form can be custom themed with the theme hook event_listing_node_form, if that is defined. If not, then the node_form theme hook from the node module is used. To custom theme this form, define theme hook event_listing_node_form.

This is different from the output side. In there, the 'node' theme hook is template base and an alternative template is suggested by the template_preprocess_node() function. So all you need to do there is add that alternative template file. Here, the form's '#theme' attribute is set with two theme hooks. To make custom theming, you need to implement the first theme hook to override the default second one and this takes programming.

First of all, theme hook can be function or template. See hook_theme() for details. Template base theme hook is used here for illustration. However, function theme hook can be used just as well.

Using zen_classic as example, add the theme hook declaration in hook_theme() in the file template.php. Change it from:

/**
 * Implementation of HOOK_theme().
 */
function zen_classic_theme(&$existing, $type, $theme, $path) {
  return zen_theme($existing, $type, $theme, $path);
}

to:

/**
 * Implementation of HOOK_theme().
 */
function zen_classic_theme(&$existing, $type, $theme, $path) {
  $themes = array(
    'event_listing_node_form' => array(
      'arguments' => array('form' => NULL),
      'template' => 'event_listing_node_form',
    ),
  );
  return array_merge(zen_theme($existing, $type, $theme, $path), $themes);
}

This declares a template base theme hook to Drupal. A preprocess function can then be added:

function zen_classic_preprocess_event_listing_node_form(&$vars, $form, $hook) {
}

This function is usually define in the template.php file inside the theme.

The theme system will call this preprocess function, passing it a reference to an array (we called it vars here), the form array to argument $form and the name of the hook (event_listing_node_form) in $hook.

Note: only template base theme hook can have preprocess function. The other type of theme hook: function theme hook cannot have preprocess function (this is how it is in D6, in D7 both function and template theme hook can have preprocess function).

The theme system looks for the event_listing_node_form.tpl.php file (the value of the'template' key when the theme hook is declared) from the active theme, if not found, the base parent theme and to where the hook was declare if it was a module. Note that this look up process is done ahead of time and at runtime, the there is no lookup, the target template is used right out of the theme registry. For the example here, the template will be found in the zen_classic theme directory.

Rebuild theme registry whenever you add new theme hook and preprocess fucntion by visiting the "admin/build/modules" path.

Now create the event_listing_node_form.tpl.php. A good starting point is by duplicating the node module's default functionality from theme_node_form($form) but use PHP template syntax instead. The exact same $form variable is passed to the template.

Theme with module

Switch a Drupal site to another theme is not easy. Many theming things live inside the theme, like all the examples shown so far. The same changes needs to be done in every and each theme. Even with just a couple of nodes, it's alot of cut and paste that can introduce errors. Not a sustainable solution.

A better approach is to separate the theme modification out from the theme. As it turns out, this is completely doable with a module. Then these theming is encapsulated inside the module and applicable to any theme.

Note: the method outline here only address moving template and functions out of the theme. For CSS stylesheet, the CSS Injector module can be used to inject CSS file from outside the theme, keeping the theme easily changeable.

Make the alternative template found in the module directory:

We want to move all custom templates out of the theme and into a module. This involve doing a little surgery to the theme registry to insert our module into the search path array.

function MODULENAME_theme_registry_alter(&$theme_registry) {
  $my_path = drupal_get_path('module', 'MODULENAME');
  $hooks = array('node');  // you can do this to any number of template theme hooks
  // insert our module
  foreach ($hooks as $h) {
    _MODULENAME_insert_after_first_element($theme_registry[$h]['theme paths'], $my_path);
  }
}


function _MODULENAME_insert_after_first_element(&$a, $element) {
  $first_element = array_shift($a);
  array_unshift($a, $first_element, $element);
}
Implement hook_theme() and declare hooks for theming node input forms:
function MODULENAME_theme() {
  return array( 
    'event_listing_node_form' => array(
      'arguments' => array('form' => NULL),
      'template' => 'event_listing_node_form',
    ),
  );
}


function MODULENAME_preprocess_event_listing_node_form(&$vars) {
  if (function_exists('dpm')) {
    dpm($vars);  // dpm() is from the devel module, install that to get this function
  }
}

This inserts the module's path to one after the first in the template search path list. It's done this way so that theme can still provide override in the theme folder or our template will be discovered out of our module if no override is found theme. Note the search for override is done once when the theme registry is built and not at runtime so there is no look up overhead at all at runtime.

Now you can move the node_event_listing.tpl.php and event_listing_node_form.tpl.php to the module directory and leave your theme completely untouched. Note that with this method, you don't need to have the node.tpl.php present in your module. The suggestion templates will be found, so this get around issue http://drupal.org/node/279573 without having to copy the original template

See also a discussion on how to make theming change with a module.

Great article

Brian Williams's picture

This article is great. I have been looking for a way to do this for a long time. Previously i could only find information about how to do it in older versions of Drupal. I got the solution to work using the template.php file, but i would like to use the module solution. I created the module and everything seems to be good, but i get a fatal error, call to undefined function dpm(). Am i doing something wrong? Please help. Thanks!

Got it Thanks

Brian Williams's picture

I found that the dpm() is from the Devel module which i did not have installed. I removed it and have it working now. Thanks again.

Sorry about the dpm() hicup

Alpha Epsilon Delta's picture

The devel module and dpm() is indispensable for development.

questions

Brian Williams's picture

I have not had much luck with the devel module. Every time i install it i end up getting fatal errors. I was wondering if you knew how i could change the markup of my form to change the way radio buttons and checkboxes appear. The default drupal method just puts them in a row going down the page. I wanted to change it so that i could have them going across the page more like a table grid. Using your method i was able to specify my new template, and when i dump out the $form variable i can see the entire data structure, but i'm not quite sure how to change the markup for one individual input. I can print the contents of a field, such as title or body, or even the contents of a fieldset and i get all the nested elements. When i look at the structure of a checkbox input, it contains a item for allowed_values and has all the checkbox items listed, but i'm not sure how to specify the new markup. I know that if i call drupal_render on $form['field_checkbox'] its going to be formatted just the same way as it was before. Do you have any idea how to accomplish this or if its even possible? Feel free to email me directly if that's easier. Thanks.

See my multi-column checkboxes radios module

Alpha Epsilon Delta's picture

http://drupal.org/project/multicolumncheckboxesradios

Making multi-column checkboxes/radios with theming is not possible. Drupal expands checkboxes/radios into a set of chrildren checkbox/radio form element inside. You need to control all the children checkbox inside but if you do it with theming the checkboxes, by the time you get to theme it, it's too late. All the children checkbox are already rendered.

My module does it in a different way.

This is very great blog for

Cell Spyware's picture

This is very great blog for providing the different people in that unique info. I am very much impression for this website and info. Thanks a lot for providing the great info that to using the nice info.

Thank you!

Jon's picture

I have spent all day trying to acheive exactly this, and then stumbled upon this. Worked at once. Thanks a million!

How making this working with other modules ?

Mathieu's picture

Thank you for this very interresting and useful article !
No problem to reproduce and use this method but I used the module "conditional field" which allow you to show some CCK Fields only if some values are selected in other input fields (a certain value in a list for example).
Using this method disable functionalities of this module, all my CCK fiels appear without conditions I defined in the node type edit form.
So do you know how I can theme the node edit form with other modules functionalities ?

I'm not familiar with conditional field

Alpha Epsilon Delta's picture

...not sure how this is related to that. I'll need to study that module to see.

Great article. thank you

David's picture

Like others articles that u made. Great!

There is by the middle of the article a code block with the argument "from" that should be "form".
Ciao

Thanks!

Alpha Epsilon Delta's picture

I fixed it.

A great informative blog.Keep

Cell Phone Spy Software's picture

A great informative blog.Keep posting articles like this.You have a great knowledge on subject.Thanks for sharing such an article where education of people matters the most.Your way of expressing articles through words is excellent.!

Views theming in module

Stan's picture

Thanks for the great article!

How I can move my template «views-view-fields--galleries-list.tpl.php» to module directory?

function simple_gallery_theme($existing) { return array( 'views_view__galleries-list' => array ( 'arguments' => array('view' => NULL), 'template' => 'views-view-fields--galleries-list', 'original hook' => 'views_view', ), ); }

This function doesn not works

Interesting post, information

Evelyn Roberts's picture

Interesting post, information about Theming CCK content type output display and input edit form make my knowledge increases, always a spirit and create a new article and i already bookmarked it. reseller hosting | reseller web hosting 

 

It is such an important topic

double cut saw's picture

It is such an important topic and ignored by so many, even professionals! I do enjoy writing but it just seems like the first 10 to 15 minutes are lost simply just trying to figure out how to begin.

This is my first time to

Dried Fruits and Nuts's picture

This is my first time to visit here. I found so many entertaining stuff in your blog, especially its discussion. From the tons of comments on your articles, I guess I am not the only one having all the leisure here! Keep up the good work.

marvelous source of info

Phone Lookup's picture

I visited this page first time and found it Very Good Job of acknowledgment and a marvelous source of info.........Thanks Admin!

Normal 0

logo creator's picture

Normal 0 false false false EN-US X-NONE X-NONE Normal 0 false false false EN-US X-NONE X-NONE /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-qformat:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; text-align:justify; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:"Times New Roman"; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin;} /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-qformat:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; text-align:justify; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:"Times New Roman"; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin;}

I too had been wondering recently as to how I could alter my form markup so as to change the way by which checkboxes and radio buttons look. It seems that this method has not yet been made possible. I guess the current method cannot make it to the inside of the theme in time. Anyway, it would be really nice if you could update us in case of any news regarding the same.

wonderful

Dried Fruits's picture

I created the module and everything seems to be good, but i get a fatal error, call to undefined function dpm(). Am i doing something wrong? Please help. Thanks!

Good Job of acknowledgment

Phone Lookup's picture

I visited this page first time and found it Very Good Job of acknowledgment and a marvelous source of info.........Thanks Admin!

nteresting post, information

Reverse Phone Lookup's picture

nteresting post, information about RATT make my knowledge increases, always a spirit and create a new article and i already bookmarked it

Understood CCK

Find name by phone number's picture

I was always a little confused with CCK.But you have done a great job.I am now clear with it.

Very Good Job of acknowledgment

Phone Lookup's picture

I visited this page first time and found it Very Good Job of acknowledgment and a marvelous source of info.........Thanks Admin!

  The Globe Tech is

SEO Pakistan's picture

 

The Globe Tech is specializing in search engine submission, website optimization, link building, Google Top 10 Services, internet marketing and other web promotion services

http://www.searchmarketinggro

Benson's picture

http://www.searchmarketinggroup.co.uk - Search Marketing solutions to UK businesses looking to promote their websites on the internet and through the search engines.

Using this method disable

allopurinol side effects's picture

Using this method disable functionalities of this module, all my CCK fiels appear without conditions I defined in the node type edit form.
So do you know how I can theme the node edit form with other modules functionalities ?

I guess the current method

what is citalopram's picture

I guess the current method cannot make it to the inside of the theme in time. Anyway, it would be really nice if you could update us in case of any news regarding the same.

Post new comment

The content of this field is kept private and will not be shown publicly.

Navigation

User login