HowTo: Theme a CCK input form

Last modified: February 19, 2008 - 07:12

(Originally posted at http://drupal.org/node/98253)

The reason I have come up with this step by step overview of themeing input forms was that I was working with CCK created content types myself and was trying to figure out how to change the order of the fields of the input form. What I found in the forums was very technical (pointers to the API in 'developer speak') or incomplete, or simply did not cover input forms. There was a lot of help for people looking to modify/theme output, but nothing clear and concise for theming input forms.

So, as a non-developer, semi-technical, marketing/business type person, I set out to discover how to 'theme' my input forms. (All those developers and others that are better informed than I, please feel free to correct me where I am wrong!) I found there are at least two different ways to theme input forms:

  1. Using the Form API (creating new .module files programmed in php and using things like 'hook_form_alter')
  2. Creating tpl.php files

I have found that it is far easier to use the second method. You actually end up having to do a little more than create a custom tpl.php file - you have to modify template.php, which requires a little bit of PHP knowledge as well as work with stylesheets (either edit style.css or create a new one and link it to your theme - more on this later).

First off, there are a couple people who are responsible for the bulk of the content in the tutorial and deserve proper credit: Lyal (http://www.harostreetmedia.com) - thanks for emailing code snippets in the middle of the night. Dublin Drupaller (http://www.dublindrupaller.com) - thanks for the rich depth of knowledge you share with others on the forums from which I have gleaned and repurposed much. jghyde - who has helped out others on this very same quest. Nick Lewis (http://www.nicklewis.org) - whose website is full of helpful and insightful Drupal information.

Now on with the show.

How do you theme a CCK input form?

Assumptions

  • You understand a little CSS (how it works, how you use class= and id= in HTML tags to style the output)
  • You understand a little PHP (nothing serious, at least the ability to understand what a PHP code snippet is doing so you can copy it and modify it a little)
  • You have CCK installed and know how to create content types with it (although I am referring to CCK input forms in this tutorial, I am pretty sure these are the same steps you would use for any custom node type)

Steps

Step 1: Create your CCK content type
Step 2: Create a [yourcontenttype].tpl.php file
Step 3: Modify template.php
Step 4: Modify style.css

You should be able to modify the input form, pretty much anyway you want with this method. For this example, I am going to do the following: Not show some of the automatically generated 'location' fields (I have 'location' module installed and enabled for my CCK content type), then create my own 'collapsible' group and put the elements that I want to in that group, and put some of the input fields side by side instead of each one being on a new line.

Even with the method I am using, there are different ways to accomplish the same thing; for example, I am using tpl.php to order the fields and .css to style them. I think I could just as easily use .css to do everything (but I am no CSS guru) and only use the custom tpl.php file to assign new <div>'s.

Step 1: Create your CCK content type

Create a CCK content type called 'event_listing' and add some fields to it. I have added contact information, location, event information fields etc.

Create at least one node (create an event listing with your new content type).

Screenshot 1

Step 2: Create a [yourcontenttype].tpl.php file

Now create a text file called 'event_listing_edit.tpl.php' and put it in the directory of your selected theme (which is somewhere under the '/theme/' directory. For example, my template.php file is found here: /theme/internet_jobs/). You could call this pretty much anything, but it will make a lot more sense and be easier to manage if you call it something like this.

Now add the following PHP code snippet to the tpl.php file - this is simply sample text to prove that your 'next step' (modifying template.php) is actually working.

<?php
print("yahoo, it works!");
?>

Step 3: Modify template.php

Now the hard part - we need to open and edit your template.php file which is again in the directory of your selected theme (in my case it is located here: /theme/internet_jobs/template.php)

You will need to add two seperate functions in this file, one to call your custom event_listing_edit.tpl.php file when the form is being edited and another one to call it when a NEW node is to be created (you only need one tpl.php file, but as the template.php file modifications are overriding default functionality, it is necessary to instruct drupal to use the custom file for each case.

At the end of the template.php file, add the following snippets which you should be able to see is two seperate override functions:

<?php
// Add Form Start (jghyde)
if ((arg(0) == 'node') && (arg(1) == 'add') && (arg(2) == 'content_event_listing')){
  function
phptemplate_node_form($form) {
    return
_phptemplate_callback('event_listing_edit', array('user' => $user, 'form' => $form));
  }
}
// Add Form End

// Edit Form Start (Dublin Drupaller)
if ((arg(0) == 'node') && (arg(2) == 'edit')){
 
$node = node_load(array('nid' => arg(1)));
  function
phptemplate_node_form($form) {
    return
_phptemplate_callback('event_listing_edit', array('user' => $user, 'form' => $form));
  }
}
// Edit Form End
?>

You can see from the snippets who actually wrote them (although I have modified them slightly from their original) - thank you jghyde and Dublin Drupaller (http://drupal.org/node/85908).

Now try to edit your event_listing node you should see the text 'yahoo, it works' on the page - see screenshot. If you don't get the 'yahoo' message, there a couple of 'suspects' to look at: go check out your naming convention in the template.php file, I tripped up and referred to my tpl.php file incorrectly a few times before I got it right.

Screenshot 2

The next step is to add all the fields you want back onto the input form. You can find out what fields are available to your form by putting the following line of code in your custom tpl.php file (Tip from goose2000 for outputting data into a nicer format)

<?php
print("yahoo, it works!<br>");
print(
"<pre>");
print_r(array_values($form));
print(
"</pre>");
?>

You will see a great big long list of information describing the fields available to your input form, the part you are interested in looks like this (there will be a section like this for every field and object on the form):

[field_website] => Array
  (
    [0] => Array
      (
        [value] => Array
          (
            [link] => www.janze.com
            [title] => Janze.com
            [attributes] =>
          )
      )
  )

In this example, if I want to refer to the website URL, I would refer to it like this:

<?php
['field_website']['0']['value']['link']
?>
. So if I want to add the website URL to my input form I would add the following line to my tpl.php file:

<div id="jpj8"><?php print form_render($form['field_website']['0']['value']['link']); ?></div>

(I have wrapped the line in a 'div id=' tag so I can style it using CSS)

Now if I edit my event_listing node, I will get something that looks like this:

Screenshot 3

Don't forget to delete the test line that adds 'yahoo, it works!'.

Now go ahead and add the rest of the fields you want to the form.

If you want to make a group of fields that collapse, all you have to do is wrap those particular fields with <fieldset class=" collapsible"></fieldset> and if you want the Group to have a name add <legend>Contact Info</legend> right after the opening fieldset. Here is an example:

<div class="jpj8aa">
  <fieldset class=" collapsible">
    <legend>Contact Info</legend>
    <div id="jpj8"><?php print form_render($form['field_name']); ?></div>
    <div id="jpj8a"><?php print form_render($form['field_email']); ?></div>
    <div id="jpj8b"><?php print form_render($form['field_phone_0']); ?></div>
    <div id="jpj8c"><?php print form_render($form['field_website']['0']['value']['link']); ?></div>
    <div id="jpj8e"><?php print form_render($form['field_description']); ?></div>
  </fieldset>
</div>

This will look like:

Screenshot 4

Interesting bits

It is a bit odd, but at the end of your tpl.php file you put the

<?php
print form_render($form);
?>
line which will render all remaining form objects (fields and buttons) that have not previously been referred to. That means it will now display all fields that you have not explicitly added in previous lines of code. Now, if you are like me, the reason you didn't explicity add them to the form is because you DON'T want them to be there!

So, to get rid of the fields that have now been automatically added back in, I have found two methods, one that worked for me (that I am sure is 'wrong' because it isn't very elegant) and another that is very elegant, but didnt' work for me. I would definitely try the 'elegant' route first......which is, you have to override unwanted fields explicity in your template.php file. For example, if I do not want to display the website, I put this text

<?php
$form
['field_website'] = '';
?>
in the template.php file, inside your override function (before the callback). Reading this line of code shows us that we identify the field on the form and set its value to '' - nothing. Here is what the function would look like:

<?php
// Add Form Start (jghyde)
if ((arg(0) == 'node') && (arg(1) == 'add') && (arg(2) == 'content_event_listing')){
  function
phptemplate_node_form($form) {
   
$form['field_website'] = '';
    return
_phptemplate_callback('event_listing_edit', array('user' => $user, 'form' => $form));
  }
}
// Add Form End

// Edit Form Start (Dublin Drupaller)
if ((arg(0) == 'node') && (arg(2) == 'edit')){
 
$node = node_load(array('nid' => arg(1)));
  if (
$node->type == 'content_event_listing'){
    function
phptemplate_node_form($form) {
     
$form['field_website'] = '';
      return
_phptemplate_callback('event_listing_edit', array('user' => $user, 'form' => $form));
    }
  }
}
// Edit Form End
?>

Note that I had to put the code snippet into BOTH the 'Add form' and 'Edit form' sections that I newly added.

The 'not so elegant' way to do it is to add the unwanted fields to your tpl.php file, just like the wanted ones and then simply use CSS 'display: none;' to style it away (see below).

Step 4: Modify style.css

OK, now you have a form with all the fields you want on it, none of the ones you don't want and you may even have grouped some of them together into a collapsible group, now what? Now you can style each of those elements using CSS. I am no CSS guru, so I am only doing a few simple things here: 1) I am showing an example of using CSS to hide a field, and 2) I am also putting two fields side by side.

To use CSS to hide a field, simply identify the <div> ID of the field that you want to hide, then create a style in your style.css file for that <div> (or in your custom, linked css file - I think it is recommended that you actually use your own CSS file so that any modifications you make will survive an upgrade).

Here is an example:

#jpj10 {
  display: none;
}

To use CSS to put to fields side by side, you need to wrap each field that you want side by side in <span> tags instead of <div> tags like this:

<span id="jpj8b"><?php print form_render($form['field_phone']); ?></span>
<span id="jpj8c"><?php print form_render($form['field_website']['0']['value']['link']); ?></span>

Then create styles for them to float left like this:

#jpj8b, #jpj8c {
  float: left;
}

Screenshot 5

Now my two fields will display side by side - I leave it to you to make it look better - this is just the mechanics of getting it to work!

Additional information

FYI, for those playing around with Drupal 5.x; replace form_render() with drupal_render() - thanks to ericelbow.

Alternative way to deal with template.php

dodazzi - December 3, 2006 - 16:57

The following code snippets are not my original creation. I found it somewhere in the forum but I can't remember who posted them and where.
Anyway, this is what I have in my template.php to theme the form of a particular node type:

function phptemplate_node_form($form) {
  if ($form['form_id']['#value'] == 'content_evento_node_form') {
    return _phptemplate_callback('evento_form', array('form' => $form));
  }
}

It works for me and this way you jut need one override statement.
In this case we are overriding a node type called "evento" with a template called "evento_form.tpl.php".

P.S. I'm almost sure that the code above need an update for drupal 5.0.

Another cool thing that can be done once you override the form is to selective change properties/attributes.
The code below, for example, make the taxonomy fieldset not collapsible and gives to the fieldset tag a class(container-inline-taxonomy' in this case) so we can style it via CSS (i.e. to get rid of the borders):

$form['taxonomy']['#collapsible'] = FALSE;
$form['taxonomy']['#attributes'] = array('class' => 'container-inline-taxonomy');

Alternative for multiple forms

rleigh - December 12, 2006 - 08:14

I like the simplicity of the alternative version too, and here's a quick modification for multiple forms.

Just add the items to the array that you'd like to replace, and create files called "content_xxx_node_form.tpl.php", "content_yyy_node_form.tpl.php", etc.

function phptemplate_node_form($form) {
    $customformtypes = array("content_xxx_node_form", "content_yyy_node_form", "content_zzz_node_form");
    if (in_array($form['form_id']['#value'], $customformtypes)) {
    return _phptemplate_callback($form['form_id']['#value'], array('form' => $form));
  }
}

Even simpler

zarko - August 16, 2007 - 19:06

This method is even simpler. Instead of maintaining the array just add this once and then create <content_type>_form.tpl.php for any content type and it will get picked up.

<?php
function phptemplate_node_form($form) {
  if(
file_exists(path_to_theme().'/'.$form['type']['#value'].'_form.tpl.php')) {
    return
_phptemplate_callback($form['type']['#value'].'_form', array('user' => $user, 'form' => $form));
  }
}
?>

A couple mods

aangel - October 10, 2007 - 01:26

This worked well for me once I:

  • added getcwd().'/' in front of path_to_theme()
  • made sure php safe mode was off
  • did a chmod a+rw on the file

Also if you are running Mac OS X 10.4, heed the note for getcwd() at php.net:

"On some Unix variants, getcwd() will return FALSE if any one of the parent directories does not have the readable or search mode set, even if the current directory does."

I Prefer this method as well

jmcclelland - March 2, 2007 - 17:24

Here's some code to display a custom form based on a user's membership in a role:

function phptemplate_node_form($form) {
  if ($form['form_id']['#value'] == 'content_evento_node_form') {
    global $user;
    if (in_array('get special form',$user->roles) {
      return _phptemplate_callback('evento_form', array('user' => $user,'form' => $form));
    }
  }
}

Also - if just want to eliminate fields, you only need to do the following in evento_form.tpl.php:

unset($form['field_evento_paid']);
unset($form['field_evento_paid_date']);
print form_render($form);

5.x

colliny2k - August 20, 2007 - 04:45

5.x

Elegant way of removing things didn't work for me either (although I think that is just clearing what is Inside the item...not clearing the item...so it is really only doing what it was told).

Anyways, I found an easier way to removing an item that doesn't need CSS to hide it. In your tpl.php file simply add
drupal_render($form['locations']);
WITHOUT print
Does the same thing without the css.

replace $form['locations'] with whatever the item is you want removed.

Caveat about hook_form_alter

Coyote - October 4, 2007 - 19:42

If you have any modules installed that call hook_form_alter for a form you are restyling, if the module creator has changed the #theme attribute of the form, it can cause phptemplate_node_form() (or whatever manifestation of hook_node_form that you are overriding) not to fire at all.

I ended up digging through a whole pile of modules, after a few hours of thinking I'd gone crazy, or that hook_node_form had been deprecated while I was asleep. Eventually, I found some notes here and there on the Drupal site hinting that sometimes, module developers were making modules that didn't play nice with hook_form_alter. I believe I ended up having to tweak the date.module, and nodeprofile.module (commenting out lines where the #theme attribute had been directly set on a form via form_alter), before I could finally get phptemplate_node_form to successfully be called.

Thanks so much to everyone who contributed to this discussion! I think I'd have stuck a fork in my eye trying to puzzle through all this on my own!

problems with form render

junedkazi - December 27, 2007 - 05:32

JUNED KAZI
junedkazi@gmail.com

Its a very good article and I tried it as well on drupal 5.5.
But I came across some problems.

When we render the form
u have used
print form_render($form['field_phone']);
but when I tried this it came me an error ie.
Call to undefined function form_render

So I changed it to
print drupal_render($form['field_phone']);
and it worked perfectly fine.

Thanks for the good tutorial and the good links.

Cheers

"The next step is to add all

goose2000 - February 8, 2008 - 20:51

"The next step is to add all the fields you want back onto the input form. You can find out what fields are available to your form by putting the following line of code in your custom tpl.php file:"

May seem obvious to a lot of web people but this helps format the array form:

Instead of :

<?php
  print_r
(array_values($form));
?>

use:

<?php
print("yahoo, it works!<br>");
print(
"<pre>");
print_r(array_values($form));
print(
"</pre>");
?>

To make it more neat / readable.

Pure template.php approach

jfall - February 26, 2008 - 23:57

Here is a similar approach that does not use a type_node_form.tpl.php file, but rather, does the whole job programmatically in template.php. I was trying to achieve a couple things here:

  1. Add a set of related fields into a fieldset
  2. Collapse the taxonomy fieldset by default (as it rarely changes, and detracts)
  3. Disable taxonomy fieldset for non-admin / contributor role users

Note I have provided a generic function to add a set of fields to a fieldset, so it is easy to modify to your circumstances, or even add a few fieldsets on each form. You'll need to replace TYPE with the node type your are trying to theme, and FIELD# with the field names you are trying to add to the fieldset.

<?php
// Theme the node add / edit forms for custom CCK types
function phptemplate_TYPE_node_form($form) {
 
// Collapse taxonomy fieldset by default.
 
$form['taxonomy']['#collapsed'] = true;
 
 
// enforce crude access rights on the taxonomy terms.
 
global $user;
  if (!(
$user->uid==1 || in_array('contributor',$user->roles)) ) {
    unset(
$form['taxonomy']);  // do not render taxonomy fieldset
 
}

 
// These are the fields that should be in the fieldset
 
$fields = array('field_FIELD1', 'field_FIELD2', 'field_FIELD3');

 
// Add fieldsets to the node TYPE input form
 
_add_fieldset($form, 'FIELDSET NAME', $fields);

 
// render the form.
 
return drupal_render($form);
}

//  Add fields to a fieldset programatically
function _add_fieldset(&$form, $name, $fieldsInSet) {
 
// Add a fieldset to the form to hold related fields.
 
$form[$name] = array (
    
'#type'        => 'fieldset',
    
'#title'       => $name,
    
'#collapsible' => 1,
    
'#collapsed'   => 0// ** NOTE **
    
'#weight'      => -2,
    
'#tree'        => 1,
  );
 
 
// Move all the related fields into the new fieldset.
 
foreach ($fieldsInSet as $field) {
    if (
$form[$field]) {
     
$form[$name][$field] = $form[$field];
     
$form[$name][$field]['#parents'] = array ($name, $field);
      unset(
$form[$field]);
    }
  }
}
?>

(don't add the php tags - they are there just for formatting!)

** Now I've got a question for a Drupal pro:
I actually want the fieldset collapsed, but....
If fieldset contains an upload button (for example), then the form
is refreshed, and the fieldset the user was just working on
is collapsed :-( Very poor usability!

I need a way to set the "collapsed" field based on state of form??? Anyone?

Custom Form overrides

cbovard - March 7, 2008 - 00:13

Ok after using this snippet (which is great), I looked at it and said "why is a function being wrapped in an IF statement.
Does the template.php file run the statement everytime versus the function override (phptempate_) being called when needed.

Here is the code I came up with:

<?php
function phptemplate_node_form($form) {
    if ((
arg(0) == 'user') && (arg(2) == 'edit') && (arg(3) == 'user_profile')){//calling a node profile form
         
return _phptemplate_callback('user_register_edit', array('user' => $user, 'form' => $form));
      }
}

function
phptemplate_user_edit($form) {
    if ((
arg(0) == 'user') && (arg(2) == 'edit')){ //this is for the default user name form
       
return _phptemplate_callback('user_edit', array('user' => $user, 'form' => $form));
}
}
?>

Just a thought to streamline the code a bit.
I thought of pulling the arg statements out but then it made sense to leave for specific nodes.

Any questions email me. I integrated this well in Node Profile.
Next step is too build custom forms for rest of the forms for the users. Will post the code when I finish this project.

chris bovard
www.chrisbovard.com

The code I used for a custom form...

cbovard - April 28, 2008 - 22:44

I got an email for some help so I will post the code I used for a custom callback form.

<h2 class="top">New Member Registration</h2>
<p class="top">After filling out the following form, an email will be sent to you confirming your free membership. After confirming your membership, you will be able to access various protected areas of this site.</p>
<h3>Areas of Access Requested</h3>
<p>You are registering as a member with the following access:</p>
<ul id="register">
<li>To be able to submit a proposal</li>
    <li>Download various Teaching Aids</li>
    <li>Register for PIMS events</li>
    <li>Join our online Math Community</li>
    <li>Submit a nomination for a postdoctoral fellow</li>
</ul>
<p class="bot">Items marked with a <span>*</span> are required fields and must be filled out.</p>
<h4>Account Information</h4>
<div id="registration">
    <div id="pri-form">
        <?php
           
//user name overrides here
           
$form['account']['name']['#description'] = "";
            print
drupal_render($form['account']['name']);
           
//email overrides here
           
$form['account']['mail']['#title'] = "Email";
           
$form['account']['mail']['#description'] = "";
            print
drupal_render($form['account']['mail']);
           
//confirm overrides here
           
$form['account']['conf_mail']['#title'] = "Confirm Email";
           
$form['account']['conf_mail']['#description'] = "";
            print
drupal_render($form['account']['conf_mail']);
           
       
?>

        <?php print drupal_render($form['user_profile']['form']['#form']['group_general_information']['field_profile_organization'])?>
        <?php print drupal_render($form['user_profile']['form']['#form']['group_general_information']['field_profile_department'])?>
     </div>
     <div id="gender">
        <?php print drupal_render($form['user_profile']['form']['#form']['group_general_information']['field_profile_gender'])?>
     </div>
     <div id="salutation">
        <?php print drupal_render($form['user_profile']['form']['#form']['group_general_information']['field_profile_salutation_0'])?>
     </div>
    <div id="sec-form">
<?php print drupal_render($form['user_profile']['form']['#form']['group_general_information']['field_profile_first_name'])?>
        <?php print drupal_render($form['user_profile']['form']['#form']['group_general_information']['field_profile_lastname'])?>
        <?php print drupal_render($form['user_profile']['form']['#form']['group_general_information']['field_profile_address1'])?>
        <?php print drupal_render($form['user_profile']['form']['#form']['group_general_information']['field_profile_address2'])?>
        <?php print drupal_render($form['user_profile']['form']['#form']['group_general_information']['field_profile_country'])?>
        <?php print drupal_render($form['user_profile']['form']['#form']['group_general_information']['field_profile_province'])?>
        <?php print drupal_render($form['user_profile']['form']['#form']['group_general_information']['field_profile_city'])?>
        <?php print drupal_render($form['user_profile']['form']['#form']['group_general_information']['field_profile_postcode'])?>
        <?php print drupal_render($form['user_profile']['form']['#form']['group_general_information']['field_profile_tele'])?>
        <?php print drupal_render($form['user_profile']['form']['#form']['group_general_information']['field_profile_fax'])?>
    </div>
</div>
<h4>Confirmation</h4>
<div id="confirmation">
<div id="third-form">
<?php print drupal_render($form['dot_disclaimer'])?>
        <p>This is a simple math test to make sure you are human.</p>
        <?php
        $form
['captcha']['captcha_response']['#description'] = "";
       
$form['captcha']['#title'] = "";
       
$form['captcha']['#description']  = "";
        print
drupal_render($form['captcha'])?>

    </div>
</div>
<?php
//form clean up
$form['account']['#title'] = "";
$form['user_profile']['form']['#form']['group_general_information']['#title'] = "";
$form['user_profile']['#title'] = "";
print
drupal_render($form)?>

Hope this helps.

Drupal 5.x tip

light-blue - April 28, 2008 - 04:40

Thanks to Chris Bovard's help and tip, if you'd like to modify the CCK-modified content types in Drupal 5.x by using _phptemplate_callback() in template.php to load a template file, you probably will need to end your PHP template file with something like

print drupal_render($form);

I kept trying a host of other ways to print the form after my modifications (creating a fieldset around the title and taxonomy areas, which is not 'configurable' via a link through the CCK admin GUI of 5.x), and Drupal kept outputting the entire form without any of my modifications. Once I preceded that function with print, voila!

Also, keep in mind that if

light-blue - September 24, 2008 - 22:15

Also, keep in mind that if you many modules, you may also have many hook_form_alter() functions involved. Sometimes, the order that they run is important. If things aren't happening the way you expect (and you're not doing a 'last minute' alter as suggested on this page through the theming from template.php), try adjusting the 'weights' of the modules in the system table.

Drupal 6

snik - May 26, 2008 - 05:08

How can I do this in Drupal 6?

Any help is much appreciated.

drupal 6 solution

dodazzi - June 8, 2008 - 21:04

Since phptemplate_callback doesn't exist anymore we have to do something different:
1. register the form in the theme registry
2. pass the variables to the template files using a preprocess function
Read Overriding themable output in drupal 6 for further info on this.

Example

Create a custom cck content type called "recipe". Let's add 2 custom textfields
1. ingredients
2. directions

in your template.php file

<?php
// we register the form to the theme registry
function YOURTHEMENAME_theme(){
  return array(
   
'recipe_node_form' => array(
     
'arguments' => array('form' => NULL),
     
'template' => 'recipe-node-form',
    ),
  );
}

// we pass variables to the template
function YOURTHEMENAME_preprocess_recipe_node_form(&$vars) {
 
$vars['recipe_title'] = drupal_render($vars['form']['title']);
 
$vars['recipe_ingredients'] = drupal_render($vars['form']['field_ingredients']); // ingredients field output is assigned to the recipe_ingredients variable
 
$vars['recipe_directions'] = drupal_render($vars['form']['field_directions']); // direction field output is assigned to the recipe_ingredients variable
 
$vars['recipe_tags'] = drupal_render($vars['form']['taxonomy']); // taxonomy output is assigned to the recipe_tags variable
 
$vars['recipe_render'] = drupal_render($vars['form']); // drupal_render['form'] output is assigned to the recipe_rendr variable. This, as usual, will output everything we didn't output explicitly.
}
?>

in a newly created recipe-node-form.tpl.php file

<div class="recipe-node-form">
  <?php print $recipe_title; ?>
  <?php print $recipe_ingredients; ?>
  <?php print $recipe_directions; ?>
  <?php print $recipe_tags; ?>
  <?php print $recipe_render; ?>
</div>

This should do the trick. Remember to clear the cache using the Clear button located at "Administer > Site configuration > Performance".

This is actually not working

robertgarrigos - October 7, 2008 - 10:00

This is actually not working in my installation (maybe due to a later change of the code?...) because the drupal_render function within the preprocess function returns NULL. No variable is passed then to the template. This is the way I found this works:

1.- Register the form theme as above.

2.- We don't need to pass the form items as variables through the preprocess function. In fact, if you do so you will end up with some other problems. So, I don't to declare the preprocess function within the template.php file.

3.- Use the xxx.tpl.php file to output each form element with the drupal_render function. Following the example above:

<div class="recipe-node-form">

  <?php print drupal_render($form['recipe_ingredients']); ?>
  <?php print drupal_render($form['recipe_directions']); ?>

</div>

4.-Remember to add

<?php print drupal_render($form); ?>

so it prints the rest of the form.

You will provably see that the buttons are not printed at the bottom of the page. The way to solve this is by doing something like this:

<?php
/* print your form items */

/* assign the buttons to a variable */
$buttons = drupal_render($form['buttons']);

/* print the rest of the form, which will be without buttons because we have already 'printed'
* them when assigning them to the variable, and print the variable right after
* the rest of the form
*/
print drupal_render($form). $buttons;
?>

STILL, PROBLEMS TO SOLVE:

1.- I couldn't print the item $form['title'] anyway so there is no way to edit it.

---
Robert Garrigos
Professional site: http://garrigos.cat
Catalan Drupal Users Group: drupal.cat

possibly a retarded

dazmcg - October 19, 2008 - 16:58

possibly a retarded question, but I cannot get this working.

One thing I thought might be a reason is the theme name - I'm using the Garland default theme. In template.php (in the garland theme directory), if I give a function name like "block_input_theme()", is this a problem - how does garland know to use it?

If this is incorrect, how should I be doing it?

As you may have guessed I'm trying to create an custom input form (ie without the menu settings/attachment/all other bits) for a block...and as yet I cannot get this working as a standard (non-block) form either, but are there any extra conciderations to take into account for blocks?

My code

dazmcg - October 19, 2008 - 17:37

Template.php

// we register the form to the theme registry
function block_input_theme(){
  return array(
    'ledger_node_form' => array(
      'arguments' => array('form' => NULL),
      'template' => 'ledger-node-form',
    ),
  );
}
?>

note: in template.php by default in my drupal it seems to have the "<?&&php but not the "?>" in the file, so I added in the above at the end of my template.php...(&&'s are to avoid auto code tags)

and ledger-node-form.tpl.php

<div class="ledger-node-form">
        <?php
               
echo "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%";
                print
drupal_render($form['ledger_title']);
                print
drupal_render($form['ledger_date']);
                print
drupal_render($form['ledger_note']);
                print
drupal_render($form['ledger_value']);
                print
drupal_render($form);
       
?>

</div>

In /node/add/ledger it's still showing the default input form...

thanks in advance!

2.- We don't need to pass

shabam - December 16, 2008 - 05:44

2.- We don't need to pass the form items as variables through the preprocess function. In fact, if you do so you will end up with some other problems. So, I don't to declare the preprocess function within the template.php file.

Could you be more specific as to what these "other problems" are? Making it simpler is a good reason for doing it your way, but I would like more specifics on what other problems can arise by using the way that many tutorials are using.

Thanks,

Jason
http://shabamdevelopment.com

STILL, PROBLEMS TO

nimzie - December 19, 2008 - 19:35

STILL, PROBLEMS TO SOLVE:

1.- I couldn't print the item $form['title'] anyway so there is no way to edit it.
Did you ever solve this? I'm having the same issue.

Cheers!
Adam

different edit forms based on role

conniec - December 27, 2008 - 19:30

This is Great! I've now got my custom edit form working for authenticated users with only one cck field and one taxonomy field available for edit.

How do I make the default form show up for admin users so admin roles can edit all fields? I've played around with if statements in the template file for a few days now, but no joy :{

Connie

Drupal 5.x, small change of syntax

mjlF95 - November 7, 2008 - 18:22

FYI: I implemented this with the original code recently in a Drupal 5.10 site like this.

// Add Form Start (jghyde)
if ((arg(0) == 'node') && (arg(1) == 'add') && (arg(2) == 'content_event_listing')){
function phptemplate_node_form($form) {
return _phptemplate_callback('data_entry_1_edit', array('user' => $user, 'form' => $form));
}
}
// Add Form End

However, I had to change the formatting of "(arg(2) == 'content_event_listing')" to the equivalent of "(arg(2) == 'event-listing')" to get it to work. (Note the omission of "content_" and the changing of the "_" to "-".) Just wanted to share this in case it helps anyone else.

How do I theme the node

nimzie - December 19, 2008 - 19:54

How do I theme the node Title input field?

I can't find it in the array and can't enter a title for the nodes I'm theming input forms for.

Thanks for any advice.

Cheers,

Adam

***edit: found it .... silly me
print drupal_render($form['title']);

The only issue is that I want to control the title of the field. This output everything. I really just want the text input for these fields generally.

 
 

Drupal is a registered trademark of Dries Buytaert.