Want to get Lullabot article, videocast, and podcast announcements delivered right to your in-box? Let us know your email address (we won't share it) and we'll let you know when anything exciting happens.

Modifying Forms in Drupal 5 and 6

Drupal versions: 5.x, 6.x

Drupal has a lot of forms to fill out and not all of them may be just the way you want or need them to be. Modifying forms is a topic that is often met with groans but once you understand the two methods to accomplish the task and the basic, underlying concepts, it really isn't that hard to do at all. You'll be a form-modifying, input-customizing wiz in no time. This article will briefly discuss what's going on and then mainly focus on showing working examples for both methods in Drupal 5 and 6. You should be comfortable creating a new function, looking at arrays and a having at least a passing understanding of the Forms API is real handy. Also note that in the examples below I have them wrapped in php tags but you should not include those if you copy/paste. That is just so it looks nice and clear for the article.

Deciding to make the change in the theme or a module

So there are two methods for altering form output in Drupal, one at the theme layer and the other through a custom module. Changes to the HTML can be accomplished with either method so most people will use the method they are more comfortable with already; themers use the theme and developers use a module. There are two situations however where you will want to use a module rather than a theme:

  1. Changing functionality of a form (e.g. adding new validation rules or submission actions) can only happen in a module.
  2. Form elements can be completely removed from the HTML in the theme layer but from an access point of view, someone could still theoretically make use of the field in the form's $_POST because the field is not removed from the form process, only the HTML output is removed. Removing an element in a module can completely remove access to it in any way. This is not often a real problem so removing elements in the theme layer is still acceptable but you should be aware of the distinction.

An example form: User edit

We will not be looking at functional changes here so I'm going to take an example that works well in either method and you can choose the one you prefer. The code is actually quite similar and both rely on two important things: 1) the form's ID and 2) some knowledge of Drupal's Form API.

Our example is altering the form as seen at My Account > Edit in a very simple way to change the name of the Username field from "Username" to say "Login ID" instead.

Find the form ID

All forms in Drupal have a unique ID. You can easily find the form ID in the HTML source code. On your site view the source of the page (Firebug is very handy for this) and look for some hidden fields near the top of the form. One has token stuff in it and another will have the name="form_id". You want to use the value of that form_id input field. In this example it looks something like this (in D5):

<input id="edit-user-edit" type="hidden" value="user_edit" name="form_id"/>

The value for our form ID in this case is "user_edit". In Drupal 6 the form ID is "user_profile_form".

[Note that if you find the form element, e.g. <form id="user-edit" enctype=...) at the top of the form, you will see that is has a very similar id property (in this case "user-edit"). The thing to be aware of is that the form id property uses a hyphen (-) and the form_id that you need for your work has to use an underscore (_).]

Creating your override functions

Now let's start creating the function we will need to hook into the form. Of course, naming and placing the function is slightly different for themes and modules. In all of these examples replace themename and modulename as appropriate. Here is the starting code:

Option 1: Override the theme function

In the theme layer place your function in your theme's template.php file. You will create a new function for each form you wish to modify.
D5 theme override

<?php
 
/**
   * Theme override for user edit form.
   *
   * The function is named themename_formid.
   */
 
function themename_user_edit($form) {
   
// Our kickin' mods go here.
 
}
?>

D6 theme override
In D6 theming this gets interesting. Many forms in D6 now have template files or "registered" functions. For those you can simply edit the .tpl file or override the function as in D5, respectively. For forms that do not have templates or registered functions though, we need to not only create the override function but we also need to register it with the theme system so it knows about it. For more information on this see the handbook page about using the theme registry for special cases. Our user edit form is one such beast. Once you add the following functions to your template.php, reset the the theme registry by clearing cached data on the Administer > Performance page.

Here is the theme registry function we need:

<?php
/**
* Implementation of hook_theme.
*
* Register custom theme functions.
*/
function themename_theme() {
  return array(
   
// The form ID.
   
'user_profile_form' => array(
     
// Forms always take the form argument.
     
'arguments' => array('form' => NULL),
    ),
  );
}
?>

And here is the override function; very much like the D5 version except the form ID.

<?php
 
/**
   * Theme override for user edit form.
   *
   * The function is named themename_formid.
   */
 
function themename_user_profile_form($form) {
   
// Our kickin' mods go here.
 
}
?>

Option 2: Use hook_form_alter() in a module

D5 hook_form_alter()
If using a module, place the hook_form_alter function (D5 and D6) in your .module file. You will use this one function to change as many forms as you want, using the form ID in a switch statement for each one.

<?php
 
/**
   * Implementation of hook_form_alter().
   *
   * The function is named modulename_form_alter.
   */
 
function modulename_form_alter($form_id, &$form) {
   
// Normally a switch is used because you may want to alter more than
    // one form and it is easy to add a new case for each form.
   
switch ($form_id) {
     
// This is our form ID.
     
case 'user_edit':
       
// Our kickin' mods go here.
       
break;
  }
?>

D6 hook_form_alter()

<?php
 
/**
   * Implementation of hook_form_alter().
   *
   * The function is named modulename_form_alter.
   */
 
function modulename_form_alter(&$form, $form_state, $form_id) {
   
// Normally a switch is used because you may want to alter more than
    // one form and it is easy to add a new case for each form.
   
switch ($form_id) {
     
// This is our form ID.
     
case 'user_profile_form':
       
// Our kickin' mods go here.
       
break;
  }
?>

Viewing the $form array

Once you have gotten the form ID and created the function you will need to see the existing form elements you have to work with. If you have Devel module enabled, you can use the shorthand dsm() function to pretty print the $form array. Otherwise a regular PHP print_r() or var_dump() will work fine. Whichever function you use to see the array, place it in your function where the code above says "// Our kickin' mods go here." For example:

<?php
 
function themename_user_edit($form) {
    return
print_r($form);
  }
?>

When you reload the page with the form on it now you should see a whole bunch of yummy array output. If not, make sure you got the form_id correct and that you have named your function properly.

Find the form element and property

There is quite a bit of documentation on FAPI and I'm not going to dive very deeply here. Here are the quickstart guides for D5 and D6. You may also want to have a handy bookmark to the form property reference, D5 and D6.

Basically we are going to look at the $form array, find what we want to change and translate that into FAPI for our function. Let's look at a section of the $form array that I am seeing on my site:

Array
(
  [account] => Array
  (
    [#type] => fieldset
    [#title] => Account information
    [name] => Array
    (
      [#type] => textfield
      [#title] => Username
      [#weight] => 0
      [#maxlength] => 60
      [#description] => Your preferred username; punctuation is not allowed except for periods, hyphens, and underscores.
    )
  )
  [pass] => Array
  (
    [#type] => password_confirm
    // snip...
  )
  // snip...
  [comment_settings] => Array
  (
    [#type] => fieldset
    [#title] => Comment settings
    [#collapsible] => 1
    [#collapsed] =>
    // snip...
  )
)

So basically we need to walk down the array to find the part we want to change. I want to change the title of the Username field. Looking at my array that means I want to target [account][name][#title]. Once I find that, I can just put that in my function and tell Drupal what I want to do with it. If you aren't sure what you can do to a given property, looking at the reference chart linked to above will help out.

$form['account']['name']['#title'] = t('Login ID');

I can do this with any of the FAPI properties. For example I can set the default value of a fieldset to collapsed:

$form['comment_settings']['#collapsed'] = TRUE;

Or I can even remove an element entirely using the unset function. This would remove the Signature text area from the form:

unset($form['comment_settings']);

So, go have fun and get those rascally forms just the way you want them!

Full example functions

Here are the complete, commented example functions.

Theme override: D5

<?php
/**
* Theme override for user edit form.
*
* The function is named themename_formid.
*/
function themename_user_edit($form) {
 
$output = '';
 
// Print out the $form array to see all the elements we are working with.
  //$output .= dsm($form);
  // Once I know which part of the array I'm after we can change it.

  // You can use the normal Form API structure to change things, like so:
  // Change the Username field title to Login ID.
 
$form['account']['name']['#title'] = t('Login ID');

 
// Make sure you call a drupal_render() on the entire $form to make sure you
  // still output all of the elements (particularly hidden ones needed
  // for the form to function properly.)
 
$output .= drupal_render($form);
  return
$output;
}
?>

Theme override: D6

Theme registry function:

<?php
/**
* Implementation of hook_theme.
*
* Register custom theme functions.
*/
function themename_theme() {
   return array(
    
// The form ID.
    
'user_profile_form' => array(
      
// Forms always take the form argument.
      
'arguments' => array('form' => NULL),
     ),
   );
}
?>

Form override function:
<?php
/**
* Theme override for user edit form.
*
* The function is named themename_formid.
*/
function themename_user_profile_form($form) {
 
$output = '';
 
// Print out the $form array to see all the elements we are working with.
  //$output .= dsm($form);
  // Once I know which part of the array I'm after we can change it.

  // You can use the normal Form API structure to change things, like so:
  // Change the Username field title to Login ID.
 
$form['account']['name']['#title'] = t('Login ID');

 
// Make sure you call a drupal_render() on the entire $form to make sure you
  // still output all of the elements (particularly hidden ones needed
  // for the form to function properly.)
 
$output .= drupal_render($form);
  return
$output;
}
?>

Module hook_form_alter(): D5

<?php
/**
* Implementation of hook_form_alter().
*
* This lets you make changes to any form in the site. You can alter, remove
* or add form elements. You can also alter the validation and submission
* behavior. The name will always be modulename_form_alter.
*/
function modulename_form_alter($form_id, &$form) {
 
// Normally a switch is used because you may want to alter more than
  // one form and it is easy to add a new case for each form.
 
switch ($form_id) {
   
// This is our form ID.
   
case 'user_edit':
     
// Print out the $form array to see all the elements we are working with.
      //$output .= dsm($form);
      // Once I know which part of the array I'm after we can change it.
     
      // Change the Username field title to Login ID.
     
$form['account']['name']['#title'] = t('Login ID');
      break;
  }
}
?>

Module hook_form_alter(): D6

<?php
/**
* Implementation of hook_form_alter().
*
* This lets you make changes to any form in the site. You can alter, remove
* or add form elements. You can also alter the validation and submission
* behavior. The name will always be modulename_form_alter.
*/
function modulename_form_alter(&$form, $form_state, $form_id) {
 
// Normally a switch is used because you may want to alter more than
  // one form and it is easy to add a new case for each form.
 
switch ($form_id) {
   
// This is our form ID.
   
case 'user_profile_form':
     
// Print out the $form array to see all the elements we are working with.
      //$output .= dsm($form);
      // Once I know which part of the array I'm after we can change it.
     
      // Change the Username field title to Login ID.
     
$form['account']['name']['#title'] = t('Login ID');
      break;
  }
}
?>

Comments

Forms always confuse me.

I'll have to go over this line by line to understand it. Particularly the code section where they have such a strange way of representing forms.

Just the thing I was looking for!

I love it when an article falls out of the sky with perfect timing... thanks Addi!

Very valuable

Excellent post that helps us understand overriding forms and create custom forms.

Nice trick (or better to

Nice trick (or better to say: approach), thanks for sharing.

The missing piece to the puzzle!

Terrific! You're saving a lot of people agony, time and angst. Thanks for clarifying a woefully underdocumented yet crucial part of how Drupal works.

Awesome!

Great article! Couldn't have come at a better time too.

I needed to figure out how to substitute user profile fields in a user reference field rather than usernames (since I use LDAP for authentication), and this is a much simpler solution than I was considering.

Here's what I came up with:

<?php
function themename_node_form($form) {
 
$output = '';
  foreach (
$form['field_instructor_pref_first']['uids']['#options'] as $uid => $username) {
   
$form['field_instructor_pref_first']['uids']['#options'][$uid] =  t('!first !last', array(
     
'!first' => user_load(array('uid' => $uid, 'status' => 1))->profile_firstname,
     
'!last' => user_load(array('uid' => $uid, 'status' => 1))->profile_lastname)
    );
  }
 
$output .= drupal_render($form);
  return
$output;
?>

Thanks again!

got a question.

this is a great tutorial. I want to customize my forum comment reply form.

<div class="box">
    <h2 class="title">Reply</h2>   
   
    <div class="content">
    <form action="/mom/comment/reply/5"  method="post" id="comment-form">

I want to remove

Reply

, but this is not in the array. is there a way to remove it?

comment.tpl.php

That is coming from your comment.tpl.php file. So you can edit it there directly.

you cannot change it in

you cannot change it in comment.tpl.php file.

<div class="content">
    <?php print $content ?>
  </div>

$content contains that code.

Urgh, sorry - box.tpl.php

Comments are printed inside boxes so you need to use box.tpl.php. Sorry about the misdirection there.

If your theme does not already have a box.tpl.php file you can override the default one by creating one for your theme, using the default one as a template. The default tpl (for D5) can be found at themes/engines/phptemplate/box.tpl.php. In D6 it is located at modules/system/box.tpl.php.

thank you addi

thank you so much. cannot believe I didnt figure out i should change box.tpl.php file.

Themer

I would like to point out to users that the 'themer' module provides body classes by role, path, locale, etc.

This is useful in the case of forms because if you need to hide the input format field for users of a certain role you can achieve this with this simple selector:

body.role-manager fieldset.input-format {
display: none;
}

etc, which is useful for un-cluttering portions of forms very quickly. Keep in mind that if you do not wish them to have access to these fields at all then this is not the way to go.

custom validation for user form

I'm trying to require a checkbox be checked on the user registration form in D6. In D5, I would have done something like:

<?php
function myModule_form_alter($form_id, &$form) {
  if (
$form_id == 'user_register' || $form_id == 'user_edit') {
   
$form['FormSection']['profile_myCheckbox']['#validate'] =
      array(
'myModule_myCheckbox_validate' =>
        array(
$form_id, $form));
  }
}
?>

(sorry about the awkward wrappng.)

I can't seem to figure out the equivalent in D6....

#validate changed in D6

In D5 #validate could be used for both elements and the form itself. This was changed in D6 so that validating an element is now #element_validate and #validate is only used for the form-level validation. So you need to use #element_validate in your example for D6.

another newbie question, how to restyle forms?

I try to restyle comment reply form.

here's part of the code:

<div class="form-item">
<label>your name: </label>

<a href="/mom/user/1" title="View user profile.">feelexit</a>
</div>

right now, "your name" is one line, name input box is on another line, I want to make them one line. what I did right now is to put styles in style.css, make label display inline.

I want to know, if theres a way to change code to

<div class="form-item">
<span style="font-weight:normal;">your name: </span>

<a href="/mom/user/1" title="View user profile." style="text-decoration:underline;">feelexit</a>
</div>

I have the same question on

I have the same question on theming forms so that elements don't wrap lines but stay on the same line. Any suggestions?

render form in D5 with tiny etc

Hi All,

i am trying to render a from in Drupal 5 with all its attributes. My problem is i can render the form like drupal_render($form['group_index']['field_awards'][0]['value'] but this dosn´t give me the tinyMCE wtih the form if i try do go like drupal_render($form['group_index']['field_awards'][0]['value']['#process']['tiny_etcect'] nothing will happen.

Does anyboddy has an suggestion for me?

Dirk

Adding new fields and validating them

Thanks for the article!
How about adding new fields and validating them? Any instructions or articles on that?

Maybe a part 2

Sounds like that would be a good follow up article. I'll see what I can do.

I second that I idea

I'd do a tutorial how to add additional fields to forms, validate them and add save them to the db.

Can't wait to see the tut

Can't wait to see the tut part 2 as well, especially adding fields to comment form and outputting it into the template, perhaps a specific comment_form, if you don't mind. Thanks

profile form field hidden on edit page

First, thank for the great writeup!
I would like to create a textfield in which I can assign (type) different titles to users. That field should be hidden from users when they click 'edit' on their profile (but I, or the user admin, can still see and edit it there) and visible to everyone on the user profile view page.

I was thinking of finding the form field name within the form with the user-edit id and setting that field to hidden (except for the admins). Can I do that in the form attributes?

If not, what would you suggest?
Thanks!

Yes

You can set any FormAPI property. So you can put an if statement around the change in your modification function and set the element's '#type' => 'hidden'.

So, in user-edit (within a

So, in user-edit (within a custom module) I just put:

$form['Personal Information']['profile_year']['#type']='hidden';

and it works, i.e. the year is displayed only on the profile view page and not on the profile edit page.
A quick question: When would I use '=>'and when '=' when assigning form properties?
Could you direct me to a link where I could read more about this?

Thanks and thanks for the great article!

=> is for use inside an array

so if you were setting an element with an array you use =>.

<?php

$form
['foo'] = array(
 
'#type' => 'hidden',
 
'#title' => t('My foo thing'),
);
?>

The = is for straight assignment of a single property in the array.

<?php
$form
['foo']['#type'] = 'hidden';
?>

preg match error

Hi,
First this is great tutorial on using the hook_form_alter. I am using this concept on many projects I am working on.
I believe this is one thing which will push drupal in top of the league of frame works. I just create a module_form_alter.module for my project and then separate functions for the all the altering I require. Once it is on the site is running into the required mode.

I am encountering one strange warning when I am trying to alter the user_register form. I want to change the widget from check boxes to radios so that only one role can be given to users.

case 'user_register':
$form['roles']['#type'] = 'radios';


warning: preg_match() expects parameter 2 to be string, array given in includes\bootstrap.inc on line 771.

I checked up the bootstrap.inc it is doing a check for utf-8.

Can any one throw some light why this behavior?

Hide the password fields for LDAP-auth sites

This is an excellent article. I've been having fun tweaking a module to edit for fields. Here's the best application of this technique I've found so far:

We authenticate users by LDAP (w/ LDAP Integration module). So I don't want users going to their user//edit form, filling out a password field, and then calling the helpdesk when they can't log in with their "changed" password. Solution:

function ulaw_utils_form_alter($form_id, &$form) {
  switch ($form_id) {
    case 'user_edit':
        // hide the password thingy, we're using LDAP! (except for admin)
        if ($GLOBALS['user']->uid != 1) {
          $form['account']['pass'] = array(
            '#title' => 'Password',
            '#type' => 'item',
            '#description' => t('To change your password for this site, you must '.
              l('change your LDAP password.', 'https://ldap/password/form/url'),
          );
        }
        break;
  }
}

This will save us a lot of user education. (for various reasons, I can't use the password-changing feature of LDAP integration, which would be the simpler solution!)

Posting form modification from 'View' page via Ajax?

First tnx, for great explanation.
Ok then. I've got a form on a user profile page (I made a new content type with nodeprofile module and added CCk field) 'View' tab witch I want to modify with custom ajax defined in node-myContentType.tpl.php page witch I've overriden.

Now the problem is that not only I need to modify data, I also had to read new data from response. Any suggestion? Or should I make custom queries from $node object info.? So my problem is, what fns or. query to call? Collecting data and sending them via ajax isn't problem here.

IDEA(in steps):

1.(client)send modifiedValue
   - (server?)oldData + modifiedValue = Sum (write that to database)
   - (server?)echo Sum
2.(client)Update current Sum field

client --> current page (e.g. JavaScript in it)
server --> page I'm sending request to.This is problematic.I don't know where?

Oh.I need custom JS because I'll refresh few other parts on this page based on response value.
Any hint would be grea, tnx.

p.s.I'm only month with Drupal, so bear with me plz ;)

Ok, I'll do a module ;)

You said in beggining that one can only modify data in module. I think it's getting clearer to me. I'll make a kind of helper module for this. It should work I think.
I'm watching http://drupaldojo.com/node/73 lesson now on using jQuery and I'll work something out with that. ;)
Again, tnx for great article.

Always provide the right

Always provide the right answers!

Love the lullabot! :)

Thanks for a great article

This was excactly what i needed, very easy to follow

More on the theme override approach (with template file)

How to theme a Drupal 5 form with a template file goes over a rather robust approach we used at Agaric. For instance, it works for the combined user registration form generated by the Bio module.

Does this hold true for comment forms?

Hi,

Great tutorial. However, is this for non-comment forms? I can't seem to use the above tutorials to customise my comment form.

I've tried using hook_comment in my module file but if I put:

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

after

<?php
case 'form':
?>

part it seems to gibber... any ideas?

Wrong code

You aren't following this tutorial - hook_comment is an entirely different thing that what this tutorial is covering.

bit harsh?

I was following the tutorial actually. I've tried using hook_form_alter to change the comment form, and I got the same result.

There is no 'name' like the other forms for the comment form.

If comment forms can't be modified using this tutorial it might help to make that clear because I couldn't find that information anywhere.

Sorry if this isn't all immediately obvious, but I'm still learning here - that's why I'm using tutorials!

I didn't intend to be harsh

I didn't intend to be harsh at all, but just wanted to point out that hook_comment is a totally different thing that what this tutorial covered so I wasn't sure how that applied to this. When I look at the comment form HTML I can see the ID is comment_form. Remember that you are looking for the "value" of the input that is named "form_id", not the "name." The following code gives me the form array for the comment form in D5:

<?php
function modulename_form_alter($form_id, $form) {
  switch (
$form_id) {
    case
'comment_form':
     
print_r($form);
      break;
  }
}
?>

Thanks

Cheers for that, great help.

I'm trying to use this

I'm trying to use this approach to modify the admin settings form for the Nice Menus module to allow an arbitrary number of menus instead of the 10 that are hardcoded into the module. I'm using hook_form_alter to modify the nice_menus_admin_settings form. The problem I'm having is that I'm unable to modify the form for some reason. I know I've identified the form properly because if I do a print_r($form), the form array is printed out.

Here's what I have:

/**
* Implementation of hook_form_alter()
*
* Modify the admin settings for nice_menus module to allow
* an arbitrary number of menu blocks
*/
function cwl_form_alter($form_id, &$form) {
  switch ($form_id) {
  case 'nice_menus_admin_settings':
$form['nice_menus_number']['#type'] = 'textfield';
break;
}
}

?>

So what I'm trying to do is change the select list to a text field. However, this has no effect. I've also tried just replacing the whole array for this field:
/**
* Implementation of hook_form_alter()
*
* Modify the admin settings for nice_menus module to allow
* an arbitrary number of menu blocks
*/
function cwl_form_alter($form_id, &$form) {
  switch ($form_id) {
  case 'nice_menus_admin_settings':
            $form['nice_menus_number'] = array(
              '#type' => 'textfield',
              '#title' => t('Number of Nice Menus'),
               '#description' => t('The total number of independent nice menus (blocks)                 you want.'),
              '#default_value' => variable_get('nice_menus_number', '2'),
  );
}
}

?>

Is that doable? Is there something obvious I'm missing?

Thanks.

Module weight

This is one of those weird gotchas. Your module is running before Nice Menus because by default they run in alphabetical order. You can change the weight of your module to 1 to make it run after NM and then it should fire correctly. This is in the system table, weight column.

Also, this feature is actually part of the D6 version of Nice menus and could easily be backported to Drupal 5. If you make a patch, I'd be willing to commit it. ;-)

Modifying Drupal Search

I am on the low edge of the curve with hooks and modifying Drupal with functions, and your explanation demystifies a lot. Thanks...

I am modifying a form which is already registered (in Drupal 6), the Theme Search Form (just trying to alter/remove the label), so it works a little differently. Following your instructions, it ends up printing the form twice, the original version and the modified one. Then when I create a search-theme-form.tpl, I seem to fall short on the correct syntax to use there.

This is the array in the core search module that I am trying to modify:
$form[$form_id] = array(
'#title' => t(''),
'#type' => 'textfield',
'#size' => 15,
'#default_value' => '',
'#attributes' => array('title' => t('Enter the terms you wish to search for.')),
);

This should be really simple but for some reason I keep falling short. Can anyone point me to the best way to do this, ... or any way. ;) thanks

module do nothing..

hi all..
i have some working personal module, but the "e_reg_form_alter" doo nothing..
i try this:

<?php
function eaposztrof_signup_form_alter($form_id, $form) {
  switch (
$form_id) {
    case
'user-register':
     
print_r($form);
      break;
  }
}
?>

the module name and filenames is "e_reg" too.. and the drupal is the newest 6.2..
any ideea?

sorry..

the correct code from the enabled module is:

<?php
function e_reg_form_alter($form_id, $form) {
  switch (
$form_id) {
    case
'user-register':
     
print_r($form);
      break;
  }
}
?>

why not working?

Different parameters

Hey there,

The parameters changed in D6 so make sure you are using the right version of the code. What you have there is for D5. The parameters in D6 are &$form, $form_state, $form_id.

This is very helpful, just one question

I agree, this is an extremely helpful tutorial, thank you for writing it. I'm wondering if there's a way in D6 to do the override, but keep the .tpl.php file in the loop. Like the tutorial, if I want to change a form field's label, I know I can do :

function phptemplate_search_block_form($form) {
  $output = '';
  $form['search_block_form']['#title'] = t('Some new title');
  $form['submit']['#value'] = t('Some new button value');
  $output .= drupal_render($form);
  return $output;
}

But any other markup in the .tpl.php file is ignored. So, am I understanding this right that if you do the override function in a theme's template, you effectively take the .tpl.php file completely out of the loop? I was hoping I could just modify the values somewhere in the stack, but keep .tpl.php for rendering. Maybe a preprocess function or something?

This is appreciated - thanks

Forum topics don't really need teaser's on my site. This article was really helpful in removing the Teaser field when submitting new topics. Thanks.

Upon checking the box profile field becomes uneditable

First, thanks for the great writeup!
I used your code to do the following: Using profile module I created a 'verified user' (profile_verify) checkbox field which is visible only to admins/themes. I want that, upon checking the box (by admin), the email field becomes uneditable.

I got it to work, and all is fine but I just want to be sure that what I did is valid and makes sense (in terms of code)

<?php
function formxyz_form_alter($form_id, &$form) {
  global
$user;
  switch (
$form_id) {
    case
'user_edit':
      if (
$form['_account']['#value']->profile_verify=='1') {
    
$form['account']['mail']['#attributes']=array('readonly' => 'readonly');  
     }
      break;
  }
}
?>

again, it works fine, but is that the way to go?
thanks!

how to store the form_alter field values

Hi

I added the text box in the user registration form using the form_alter,

Now tell me , how i store the this textfield values into table,

I thing i have to write some snippet in the INSTALL file also,

Can u tell me please

the below is my code, i want to store the below field values into DB

function user_form_alter($form_id, &$form) {
  if ($form_id == 'user_register' || $form_id == 'user_edit') {
  $form['fname'] = array(
  '#type' => 'textfield',
  '#title' => t('First Name'),
  '#default_value' => $node->title,
  '#size' => 60,
  '#maxlength' => 128,
  '#required' => TRUE,
   );
   $form['lname'] = array(
  '#type' => 'textfield',
  '#title' => t('Last Name'),
  '#default_value' => $node->title,
  '#size' => 60,
  '#maxlength' => 128,
  '#required' => TRUE,
   );
    $form['reset'] = array(
      '#value' => '<input class="form-button" type="reset" value="Reset" />',
      '#weight' => 1001,
    );
  }
}

#access

I'm curious why you'd use unset to remove an element rather than set #access to FALSE (http://api.drupal.org/api/file/developer/topics/forms_api_reference.html...).

Wow, thanks so much for this

Wow, thanks so much for this article! I learnt a lot today.

Here's what I needed to do:

On our site, both anonymous and registered users are allowed to create nodes. We allow them to provide multiple authors for content, so that if a report was made by several people, they can all get proper credit for it.

Anonymous users can fill in their name in a CCK text field; registered users fill in a nodereference field. Both of these fields are required. Hiding one or the other field from one or the other user role is done with cck_field_permissions.

The problem: when admins (who have access to the text field as well as the nodereference field) want to edit a node, they got a validation error, because both fields are required, and one of them is often empty.

Solution: a module that un-requires both fields for admin roles.

<?php
function modulename_form_alter($form_id, &$form) {
  switch (
$form_id) {
    case
'article_node_form':
      global
$user;
     
$allowed = array('admin','edito');
      foreach(
$user->roles as $role) {
        if (
in_array($role, $allowed)) {
         
$form['field_author_reg']['0']['user_name']['#required'] = 0;
         
$form['field_author_anon']['0']['value']['#required'] = 0;
        }
      }
    break;
  }
}
?>

field title change not reflected in preview and view of form

Hi,

I am trying to over-ride the comments form for our drupal 5.8 site. I need to change "Subject" to "Re". I can do this using hook_form_alter:

function hook_form_alter($form_id, &$form) {
switch ($form_id) {
case 'comment_form' :
$node = node_load($form['nid']['#value']);
$subject = $node->title;
$form['subject']['#title'] = "Re";
$form['#submit']['external_page_comment_form_submit'] = array($subject);
$form['#submit'] = array_reverse($form['#submit']);
return $form;
}
}

The problem is that the change doesn't seem to carry over to previewing or posting the comment. The subject label reverts back to "Subject".

I think that I also have to change the subject label in hook_comment but I am not sure how to do this. Can I use the same form api syntax as in hook_form_alter?

Here is what I have in my hook_comment:

function hook_comment(&$comment, $op) {
switch ($op) {
case 'view':
if (variable_get('vote_up_down_widget_comment', 1)) {
//print_r($comment);
$comment->comment = $comment->comment ."". theme("external_page_points_alt", $comment->cid, 'comment') ."";
$comment->comment = $comment->comment . theme("external_page_widget_alt", $comment->cid, 'comment');
}
break;
}
}

I am using vote-up-down and have been able to insert the point info at the bottom of comments, before the comment $links.

I can't seem to figure out how to get at the stuff at the beginning of comments, it's all lumped in $comment->comment.

Thanks for this article and thanks to anyone who can point me to more examples of bending comment forms to my will :-)

Excellent!

Thank's a lot for this tutorial! It's just excellent - and unique!

Do you know if there is a chance to access $node contents within a theme function (option 1)?

What I'm trying to do is to modify the form which is used to add a comment. If I am in a special forum, I want to have a special layout of this form.

So I am overriding the comment reply form (comment_form) which works fine. I just have to check if the user is adding a comment to a topic in that specific forum. Just: how to find out about this? The easiest way is to check the taxonomy term of the parent article. And therefore, access to $node would be nice :-)

Thanks, Gerald

Fantastic!

After sifting through so much confusing Drupal documentation, this article is a real breath of fresh air. Thank you for your thoroughness!

Get the right ID!

Hello.

This is an awesome tutorial - thanks.

Just to clarify something which fooled me for a while. You appear to suggest that using the id attribute from a tag like

<form action="/node/61/edit"  accept-charset="UTF-8" method="post" id="node-form" enctype="multipart/form-data">

is possible, as long as one turns the '-' into a '_'. This is not true (and may not be what you meant to imply). The correct id we require is found in a tag like

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

(in this case, the id is modulename_node_form).

If I spent half an hour trying to work my mistake out, I am sure others will appreciate this being cleared up too.

Apart from that, thanks again for this fantastic tutorial.

Trouble with weight

I don't know if I'm doing something wrong, or if I need to submit a bug report on this one. Figured I'd start here since this is where I got the info...

function fblike_theme() {
   return array(
     'node_form' => array(
       'arguments' => array('form' => NULL),
     ),
   );
}
function fblike_node_form($form) {
if (arg(2) == 'profile') {
  $form['field_first_name']['0']['value']['#size'] = 25;
  $form['title']['#size'] = 25;
  $form['field_age']['value']['#description'] = 'testf';
  $output .= drupal_render($form); }else{
  $output .= drupal_render($form);
  }
  return $output;
}

So that's just some test to see how everything was working, and it worked fine. However, the weight (now operated by the jquery drag and drop) gets all messed up. The form submit, preview, and menu options appear at the top of the node regardless of changes to the "manage fields" and clearing all cache.

Is this incompatible? Suppose to happen? Do I need to define the weight? Anyone having the same problem?

Thanks! - besides this error, the tutorial helped a ton.

More Info

So, if I define the weight it works fine. Who knows that the problem is, but defining the weight will work fine for me. I'm still sure there must be a way to retain the weight as defined in the manage fields tab.

I have the same problem...

I'm trying to arrange the elements on various node edit forms (so the id for each form is 'content_type_node_form').

I first created a module called 'customize_forms', and it worked for some form elements, but not all form elements. Then I read in one of the comments here that modules are run in alphabetical order, so I changed the name to 'zzz_forms'.

This helped, and now I could change the weight for more elements, but not all of them. On top of that, even though I can change the weight for more form elements, they still don't actually change position on the form.

Here's my module's code:

<?php
// $Id$
/**
* @file
* This module is used to customise form alterations, easily.
*/

/**
* Implementation of hook_form_alter().
*
* This lets you make changes to any form in the site. You can alter, remove
* or add form elements. You can also alter the validation and submission
* behavior. The name will always be modulename_form_alter.
*/
function zzz_forms_form_alter(&$form, $form_state, $form_id) {
// Normally a switch is used because you may want to alter more than
// one form and it is easy to add a new case for each form.
switch ($form_id) {
// This is our form ID.
case 'profile_elected_node_form':
case 'profile_constituent_node_form':
case 'profile_committee_node_form':
case 'profile_candidate_node_form':
case 'poll_node_form':
case 'page_node_form':
case 'image_node_form':
case 'header_panoramic_node_form':
case 'forum_node_form':
case 'event_calendar_node_form':
case 'blog_node_form':  
if ($form['revision_information']) {
        // Remove 'Revision Log message' text area
  $form['revision_information']['#type'] = 'hidden';
      }
      if ($form['taxonomy']) {
        // Change titles of form elements
$form['taxonomy']['#title'] = t('Categories');
      }
      if ($form['workflow']) {
        // Adjust form weight.
$form['workflow']['#weight'] = 40;
      }

      if ($form['path']) {
        // Adjust form weight.
$form['path']['#weight'] = 60;
      }

      if ($form['menu']) {
        // Adjust form weight.
$form['menu']['#weight'] = 70;
      }

      if ($form['nodewords']) {
        // Adjust form weight.
$form['nodewords']['#weight'] = 80;
      }

      if ($form['xmlsitemap']) {
        // Adjust form weight.
$form['xmlsitemap']['#weight'] = 80;
      }

      if ($form['author']) {
        // Adjust form weight.
$form['author']['#weight'] = 90;
      }

      if ($form['options']) {
        // Adjust form weight.
$form['options']['#weight'] = 100;
      }
     
// Show form elements and weights.
// Code borrowed from Devel module.
    $children = element_children($form);
    /*
    print '<pre>';
    print_r($children);
    print '</pre>';
    */
if (empty($children)) {
if (isset($form['#type']) && !in_array($form['#type'], array('value', 'hidden'))) {
if (!isset($form['#title'])) {
$form['#title'] = '';
}
$form['#title'] .= " (key=$key_in, weight=". (isset($form['#weight']) ? $form['#weight'] : 0) .')';
}
}
else {
foreach (element_children($form) as $key) {
// We need to add the weight to fieldsets.
if (element_children($form[$key])) { // Which are a container of others.
if (!isset($form[$key]['#title'])) {
$form[$key]['#title'] = '';
}
$form[$key]['#title'] .= " (key=$key, weight=". (isset($form[$key]['#weight']) ? $form[$key]['#weight'] : 0) .')';
}
}
}

// Print out the $form array to see all the elements we are working with.
/*
print '<pre>';
print_r($form);
print '</pre>';
*/
break;
}
}

Here's a link to a screen shot.
http://www.wickwoodonline.com/content/example-weight-problems-node-edit-...

On it you can see that 'Menu' given a weight of 70 from my module, still appears with the 30 weights. Also, CCK fields don't seem to have weight associated with it all, so those form elements are being added after my module.

I tried using the module 'late_form_alter', but this didn't solve anything for me.

Thanks for any help you can give me in advance!
Steve

How to find a particular form..

Actually I want to modify "Body" field Blog edit form. I want to try out Google API to translate the content of blog written in English to Chinese on this page.
I took it's source and found

So as per the your article, my form will be "blog_node_form". I tried to find it, but didn't get any where in Drupal package.

I am new (just 2 days on Drupal) to Drupal. May I know how I can find this form and modify it?

Thanks in advance,

thanks

thanks for this tips.. now i know how to do it... thanks its help me alot..

forms

thank you... exactly what i was looking to do.

Confirms my understanding and really nicely laid out

Confirms my understanding and really nicely laid out. Keep this up lullabot!

how do I access the value of my custom field?

Thanks for the nice tutorial. I've added a couple custom fields to my comment form. Much like this very comment form I'm filling out now: "Name" with a title of 'commentor_name' and "E-mail" with a title of 'commentor_email'. This works fine and the fields show up when filling in the comment.

My question however is, now how do I get access to the values that the user filled in? How do I make the comment node display something like this page does, e.g.

"Submitted on September, 28 by "? Do I have to do my own custom database store of the Name and Email fields or does the comment module do that for me? What file do I have to override in order to output those values when viewing the comments?

Thanks,
Andy

Oops, mangled output

I wrote a custom module to achieve this, here's the code:

function authored_comment_form_alter(&$form, $form_state, $form_id ){
   switch($form_id){
      case 'comment_form':
      //print_r($form);
      $form['commentor_name'] = array(
        '#type' => 'textfield',
        '#title' => t('Name'),
        '#required' => TRUE,
        '#weight' => -5
        );
      $form['commentor_email'] = array(
        '#type' => 'textfield',
        '#title' => t('E-mail'),
        '#required' => TRUE,
        '#description' => t('The content of this field is kept private and will not be shown publicly.'),
        '#weight' => -3
      );
      break;
   }

Now how do I display the value of 'commentor_name' when previewing/viewing the comment?

Nevermind

Just found out that this *is* possible out of the box in Drupal 6, just not in a very intuitive or easy to find way.

You have to enable comment settings on a per content type basis. So, for blog posts you can enable user must enter contact information if posting anonymously.

Well, thanks for the tutorial anyways as now I know how to add fields to a form. If you still feel like answering my question above I'm still interested in how I would have done it.

Address fields?

Hi Addi,

Thanks for the article. I have two questions:

1- Can I add CCK fields to a webform? For example, cck_address.

2- My webform has 3 fields: city, state, zip. How do I get them to be on one line?

Thanks,
Phil

form alter to merge user-edit forms

From what I can see there's no way to call a sub-category of the user-edit form through the Forms API. (e.g. The category specified by the Profile.module) And as these categories are not their own form (no profile-edit-form) I can't see a way of pulling that specific section to merge it with the default "account" category form elements.

I can pull the elements in via direct calls to profile_form_profile() or user_edit($category), but this doesn't load in the $edit data it seems, nor does it save the data put into the merged fields.

Do any of you know how to pull the 'full' user-edit form (including all categories)?

Needed this

I also want to know how to do this, but as I read through drupal docs, this has been a long issue. I would really like to see how to merge two or more user edit categories coz I might be needing this for one of my projects. form_alter I guess will not be of use for this at the moment.

Great overview!

The Form API is a pretty darn powerful way to change how Drupal functions...Much of what we do after all is submitting forms, right? Content "management" system... Thanks for this post, it was VERY helpful. The API was lacking a little documentation and the overall form api is designed extremely poorly. It's far too much code to do what it does and it can throw people off to begin with. It doesn't save any time, a brand new form could be created (with validation) faster...But if you're looking to remain compatible, you're stuck. This article is a life saver.

I guess we just need to understand it's all carried forward from old Drupal code and we are dealing with some severe functionality...Upgrades would start to become difficult if it was overhauled too much. Definitely make sure you're looking at the right documentation for your version of Drupal! I noticed some minor changes that threw me off until I realized my search brought me to information for an older Drupal version.

^^

one of best sources to get drupal tips !
Thanks ^^

Drupal Advance Search

Hi,

In drupal advance search you can see all the (taxonomy ) vocabulary and terms in a single selection box. Is there any way to split up according to the vocabulary as like the vocabulary shown in create content area.

with regards,
DOn

Title Weight

Hi, Thanks for the article. I tried to change the weight of the title without success. Please tell me where I am wrong. I am using Drupal 5.x

I have a CCK content type with 8 fields. The title should go the bottom. I can alter all the weight except Title and Body in CCK. By default title weight is set to -5 and I want to change it into 10. The form id is myspecial_node_from

So, I created a module and activated it. This is the code for newform.module:

?php
function modulename_form_alter($form_id, &$form) {
  switch ($form_id) {
    case 'myspecial_node_form':
    $form['title']['#weight'] = 10;
      break;
  }
}
?>

Thanks.

It works

I misunderstood the comment - The name will always be modulename_form_alter.

Now it works. Thanks.

thanks a lot

hi, thanks for this article. it was really useful. been looking for summin like this for days.

cck and form_alter

Hi,

I wanted to construct a link from a cck content type of 'contact' (name, address, etc) which would go to another cck content type 'activity'. The url will be 'node/add/activity/10', which is the standard url with the contact's node id appended. I want the activity to be a partially pre-filled form (fill in an autocomplete text field + several address fields) based on the '10' (contact's node id).

I've managed to get the node reference autocomplete field to fill in using form_alter with:

//this works
$form['field_customer_name'][0]['#default_value'] = array('nid' => arg(3));

where arg(3) would be '10' in this case.

but the other cck fields don't want to accept a #default_value (this is the array 'path' I found by the technique mentioned above):

//none of these work
$form['field_addr1'][0]['#default_value']['value'] = '325 State Street';

I also tried several other iterations, including :
$form['field_addr1'][0]['#default_value'] = '325 State Street';
$form['field_addr1']['#default_value'] = '325 State Street';

The last one gets the text into the bottom of the fieldset, but not where it's supposed to be...what am I missing?

reply to self...

I found this by webchick (Angie Byron): http://drupal.org/node/144132#pre-render

So I put this in my form_alter:

$form['#pre_render'] = array('assign_default_values');

I then created a function called assign_default_values which did a query and attempted to assign default_values like this:

$form['field_addr1']['#default_value'] = $_result->addr1;
...
return $form

BTW, I kept getting an 'unsupported operand types' error complete with a WSOD. When I read a little further down the page, I found that in D6, you must return the $form variable as it is not passed by reference.

Unfortunately, the default values are still not getting assigned. The query is successful and the result is populated (I'm able to print_r the result). I've also tried to assign the query result values to the array path I described in the above post. No luck.

???

did it with jQuery

As I'm kind of pressed for time, I decided to go the AJAX route.

Probably what I should have done all along...

Cheers!

How About Some Asterisks In The Password Field?

Fantastic article! You really made it all make sense for someone new to all this Drupal craziness.

I'm using this approach to modify the default user_login_block. I have no trouble putting a generic placeholder in for the user name:

<?php
$form
['name']['#value'] = t('name');
?>

But I'd like some asterisks or something to be in the password spot, too, but this doesn't seem to do the trick:

<?php
$form
['pass']['#value'] = t('****');
?>

Any idea how to get it to let me put something there?

Thanks!

My vars won't show up :(

Hi,
I've got Drupal 6.x running and followed the article.
When I try to print out the array with return print_r($form); nothing happens ... so obviously I also can 't change anything in the Edit User page.

Any ideas (I already cleared my cache after changes , so that's not it)

Cleaned links from user_login_block

Using the theme override method I managed to unset($form['links']) to avoid the 'Request New Password' link being rendered.

Thanks.

why can't somebody

just tell me how to create an entirely custom form?

Seriously html forms are pretty staple and take 30 seconds to knock up.

All I want is a simple custom form with the action of my choice on it, is that so hard really? really?

Have you done the tutorial?

Have you walked through the Form API tutorial yet? Covers lots of basics in 10 examples.

Put elements on the same line?

Drupal always put one field at a line by default.
I want to display a text field with some description before it and also after it (on the same line), how to achieve it easily?

e.g.
Your weight + text field + kg

Thanks for any suggestion.

use #prefix and #suffix

You can use #prefix and #suffix in the form field to get the result
http://api.drupal.org/api/file/developer/topics/forms_api_reference.html...

use #prefix and #suffix

You can use #prefix and #suffix in the form field to get the result
http://api.drupal.org/api/file/developer/topics/forms_api_reference.html...

drupal is fascinating

I ran out with all the solutions I know to tweak my drupal apps into something more visually enhancing site but then, I gave up. Good thing, I found your site today and men! you solved it!

Thanks.. - Busby SEO Test

thnks

thanks for any suggestion

Array Won't Print Legibly

First off, thanks for the excellent tutorial. My only problem is that my arrays print out all in one continuous line. I can't figure out the hierarchy, so I can't then figure out how to theme specific form elements. I'm using print_r and var_dump in my theme override function in template.php, but both do the same thing. I also have the Devel module installed, but when I replace print_r or var_dump with dsm, nothing happens (no array output at all on the form pages). Thanks very much for any help.

---

Here's a sample excerpt of what my array print_r outputs:

Array ( [#method] => post [#parents] => Array ( ) [#tree] => [#required] => [#action] => /user/login [#validate] => Array ( [logintoboggan_user_login_validate] => Array ( ) [user_login_validate] => Array ( ) ) [#theme] => user_login [#processed] => [#submit] => Array ( [uc_cart_user_login_form_submit] => Array ( ) [user_login_submit] => Array ( ) ) [#attributes] => Array ( ) [#description] => [#type] => markup [#parameters] => Array ( [0] => user_login ) [name] => Array ( [#type] => textfield [#title] => Username or e-mail address [#size] => 60 [#maxlength] => 60 [#required] => 1 [#attributes] => Array ( [tabindex] => 1 ) [#description] => You may login with either your assigned username or your e-mail address

You can try two things

You can try two things here:
1. Put HTML <pre> tags around the print_r, for example:
$output .= '<pre>'. print_r($form) .'</pre>';

2. View source from your browser.

I'm not sure why a devel dsm isn't working for you. If it is enabled that function should be available.

thanks!

View source worked like a charm, but tags had the same result. Thanks again for all of your invaluable help! Saved me from awful frustration.

Solve my Problem

you solved it! Good thing, I found your site today and men you help me much. Thanks..

Great scripts, I testing

Great scripts, I testing now.
Thanks you very much.

What I'm trying to do is to

What I'm trying to do is to modify the form which is used to add a comment. If I am in a special forum, I want to have a special layout of this form.

Username never gets sent when unsetting its array

Addi:

An unexpected consequence of using the first method to hide parts of the form is the fact that the author field, which ordinarily gets automatically filled with the username, stays empty, thus sending the form with the field empty and making 'Anonymous' the content's author. Is there a way to insert the value without reinstating visually the field? Thanks for such a nice write up (it's been on my bookmarks since I first read it!).

Cheers from México.

Hiding or unsetting form fields without losing the values

Horacio,
If a form field is unset() or not displayed on the screen through drupal_render(), then the default values aren't passed to the submit function. As you found, some values like Title, Published, and Author will either fail validation or will save no value to the database.

This helps protect against cross-site forgery because, according to the D6 FAPI documentation,

Faking a POST is much harder since it won't let values that weren't actually on the form come through to the $form_state['values'] in your submit function

In Drupal 5 it was possible, at least in my experience, to unset() form fields or just call drupal_render() on only a subset of form fields and still successfully submit without losing all the unrendered form values. However, this may not have been the most appropriate method.

The Form API in both Drupal 5 and 6 explain setting ['#access '] = FALSE on any form fields you don't want to be "accessible".

IMPORTANT: Setting #access property should be done within a form_alter() hook. The reason being, in Drupal 6 if hook_theme() is used to register a custom theming function or template (.tpl) for the form then using #access = FALSE will only cause the target form element will disappear. Since the $form variable isn't passed by reference to the theme layer the form processing magic doesn't see the #access change you made and you'll continue getting validation errors or empty values saved to the database.

For example, to remove the author name input field from the form but still maintain the field's previous value after a submit you can use the following inside of a form_alter() hook.

$form['author']['name']['#access'] = FALSE;

Most form elements, and even fieldsets, have an #access property you can toggle to FALSE. Use something like print_r($form); to see which use #access.

Of course, you can still modify/override form values within a form_alter() hook as Addi described. If you want to modify a form field's value and hide it too there are two approaches.

1) Override the #value attribute and use #access to hide it.

$form['author']['name']['#value'] = 'someusername';
$form['author']['name']['#access'] = FALSE;

OR

2) Override the #value and change the form field's #type to 'value', which effective acts like an <input type='hidden'> form element, but without sending anything to the browser.

$form['author']['name']['#value'] = 'someusername';
$form['author']['name']['#type'] = 'value';

You can also use this '#type' = 'value' to pass any data you want over to your form's custom validate() or submit() functions. As the the D6 FAPI documentation points out,

$form['foo'] = array('#type' => 'value', '#value' => 'bar')

This is accessed in $form_state['values']['foo'], with a value of bar. This method is preferred because the values are not sent to the browser.

love it

This was excactly what i needed, very easy to follow

love it

This was excactly what i needed, very easy to follow

what a great post

I ran out with all the solutions I know to tweak my drupal apps into something more visually enhancing site but then, I gave up. Good thing, I found your site today and men! you solved it!

thank you!

thank you!!
your instructions and insight have allowed me to create a unique reg form that is exactly how designer thought it would be. thanks!

my next task is to create a block (on home page only) that will allow user to post into one of the 3 forums we have on the site. i am trying to avoid customizing the normal forum add forms (/node/add/forum) and build a custom entry form in this block.

i've added this to mytheme_theme function in template.php

     'forum_node_form' => array(
       'arguments' => array('form' => NULL),
       'template' => 'block-block-8',
     ),

and in block-block-8.tpl.php

print "HELLO";
drupal_render($form);

on the main forum entry screen (/node/add/forum) i see the form and HELLO. In my block, I am only seeing HELLO. so this tells me that the above is really only for the main entry page, and not targeting the block as i need it to.

some research i've done (forms API docs) tells me that b/c this is adding a node it differs from the normal form entry, a la user-register. that info tells me that i need some additional $node information in the tpl file, but this part is over my head at this point.

ie, drupal_get_form('user_register); displays the register form in that block...but

drupal_get_form('forum_node_form'), gives me the following error

ie, warning: Missing argument 2 for node_form() in /Users/john/Documents/HTMLDOCS/domain_com/modules/node/node.pages.inc on line 93.

and then displays the the Revision, Authoring and Publishing Links, and Submit/Preview links. anonymous users only see the Submit/Preview links.

maybe the $user info is not available so the form can't be completely drawn? not sure.

any help or pointers would be greatly appreciated!

thanks!
div

oh yeah

very nice tuto, god bless you.

I can alter a field title, but CAN'T alter the form redirect?

I want to get rid of the redirect to the homepage after submission of the default site-wide contact form. I'm puzzled as to why this isn't working:

<?php
function mytheme_theme(&$existing, $type, $theme, $path) {
// we're based on zen
$hooks = zen_theme($existing, $type, $theme, $path);

// add a hook for the site-wide contact form
$hooks['contact_mail_page'] = array(
'contact_mail_page' => array(
'arguments' => array('form' => NULL)
)
);

return $hooks;
}

function mytheme_contact_mail_page($form) {
// override the "category" label in the site-wide contact form
// OK, this works
$form['cid']['#title'] = t('Send to');

// override the form redirect - return to contact page
// this one doesn't work - no other valid path works either
$form['#redirect'] = array('contact');
return drupal_render($form);
}

Any insight would be appreciated, thanks

Re: I can alter a field title, but CAN'T alter the form redirect

Never mind. Installed the contact_redirect module and patched it for Drupal 6...

How to print the user profile form in d6?

I've been struggling these past two days trying to print the user profile form on a custom node, however I cannot seem to get it right.

I have tried printing drupal_edit_form:

<?php
// THIS kinda works, but no submit button
global $user;
$uid = $user->uid;
foreach (
$user as $key => $value) {
 
$account[$key] = $value;
}
print(
drupal_get_form('user_edit_form', $uid, $account));
?>

Invoking the user module:

<?php

// no success either
global $user;
print
module_invoke('user', 'form', $user, 'account'));
?>

Trying to print user_profile_form also returns an empty form... I'm kind of puzzled by this problem, has any one gotten this to work? I imagine this must be possible...

Great write up btw, theming forms is always a good exercise !

Fixed, nevermind

OK, we fixed how to do this on the forums:
http://drupal.org/node/368048

Thanks

I ran out with all the solutions I know to tweak my drupal apps into something more visually enhancing site but then, I gave up. Good thing, I found your site today and men! you solved it!

Thanks for the nice

Thanks for the nice tutorial. I've added a couple custom fields to my comment form. Much like this very comment form I'm filling out now: "Name" with a title of 'commentor_name' and "E-mail" with a title of 'commentor_email'. This works fine and the fields show up when filling in the comment.

Maybe I am not getting

Maybe I am not getting something. I am trying to do this with a custom content type. I followed this to the t and am not getting drupal to call the function(yes i cleared cache). Does this only work with core modules or shouldnt it work with all forms?

Close form

Great article and enjoy your site. I was able to modify the form to way I like thanks to your article. I am now just trying to find a way to close the form after the user submits or save the entry. Not sure where to start with this.

great post

Never mind. Installed the contact_redirect module and patched it for Drupal 6...

informative

this was an informative site..

more power..

Drupal Validations module

Hi! I’ve just contributed a new module for validating forms, wisely named “Validations”.

Please feel free to download the new module (http://ageekapart.wordpress.com/2009/03/08/drupal-module-validations/) and send me some feedback. Thanks!

Form_alter doesnot work for me Any Clues ??? (Using DRUPAL 6)

I am using drupal 6

I created a new module name customizedlogin i want to append extra characted to username field after the user has submiited .
i am trying to do as following

function customizedlogin_form_alter(&$form, $form_state, $form_id){

form_set_value($form['name'], $replacement_value);
}

i am not getting wot is expected

printing of $form is giving me an empty array print_r ($form).Any Clues ?

Great Article

Gave me an excellent quick overview and has pointed me in the direction I was looking for.

Admirable

tested it! It's pretty cool. Thanks for these nice tutorial

Modify node, not form

Hi

How do I modify the node view, not the node edit?

I can't find a hook_node_alter or anything like this. I want to use a module to add some content to a particular content type's node view.

How can I do this?

Thanks

Glenn

Nothing I attempt to update seems to have any effect

I'm using a CCK generated form but I want to add word before and after a text field.

when I do some thing like:

<?php
/**
   * Theme override for marathon_entry form.
   *
   * The function is named themename_formid.
   */
 
function a3_atlantis_marathon_entry_node_form($form) {
   
dsm($form);
   
$form['title']['#field_prefix'] = t('Hello');
  }
?>

Nothing happens.
Even when I do:

<?php
/**
   * Theme override for marathon_entry form.
   *
   * The function is named themename_formid.
   */
 
function a3_atlantis_marathon_entry_node_form($form) {
   
dsm($form);
   
$form['title']['#title'] = t('Hello');
  }
?>

The Title stays the same.

any ideas?

more love..

another great, lucid tutorial, thankyou lullabot!

i have tested it. Great

i have tested it. Great tutorial. Thanks lullabot

Thanks for your help

Hey, fantastic stuff. This really helped me figure out drupal forms! I'm still learning, but by mainly combining #prefix and #suffix and a little bit of jquery (I'm still learning) I've managed to get "most" of what I need. Thank you very much for all of the effort that you guys put into educating the rest of us--it really does help.

so far: http://www.vimeo.com/4169918

About themeing the edit form: what if I want to take it over?

Hi Addi!
This article is very easy to follow! Thanks!!
There is one question that pops up when I try to follow it: What if I want to add a certain message for only certain roles, in the edit (and NOT the node/add) page?
I´ve tried

function mythemename_theme() {
  return array(
    'my-cck-nodetype_node_form' => array(
    'template' => 'my-cck-nodetype-node-edit',
    'arguments' => array('form' => NULL),
    ),

  );
}

and this (on the template file)
    function mytheme_my-cck-nodetype_node_form($form) {
$output .= drupal_render($form);
return $output;
  }

But there is no way that the my-cck-nodetype-node-edit.tpl.php file would show up the rendered form.
I´ve tried print $output with no luck.
And i just want to code inside the tpl file a different stuff for each different role.
So, that way, I could completely remove the edit form for role X.

Thanks for your time and your input!

Rosamunda

Drupal 5: force drupal to not re-sort your elements!

I had a giant list of elements in my form which I needed to reorder. I selected them from the original $form array and reordered them and fed the array back into drupal_render();

At this point, drupal was re-sorting my elements even though they were ordered correctly in the array.

YOU MUST set $form['#sorted']=true or drupal_render() will attempt to re-order your elements for you.

Took me far too long to figure this out and thought I would pass it along. Hopefully someone else will not spend hours in frustration like I did.

Thanks for the tip

Thanks for the tip theoldfather.
Sorry for this php-newbie question... how do I set that $form['#sorted']=true line of code? inside the template file I guess, and it should be like

function mytheme_preprocess_myccknode_node_form(&$vars) {
$vars['myccknode_render'] = drupal_render($vars['form']);
$form['#sorted']=true;
}

I´ve tried that already, and so far, it didn´t changed where the submit and preview buttons where displayed.
Any thoughts?

Thanks!!!

I created a story type

I created a story type (ads), get form_id value (ads_node_form)
I try to include the payment form of a payment module inside the module

the button of payment is opening a popup and if I put my code, the module payment make same action than the form button :(

here the code

function garland_ads_node_form($form) {
      $output ='';
      $output .= mymodule_subscriptions();
      $formulaire = drupal_render($form);
      $output .= $formulaire;
      return $output;
}

what is the good code to work correctly ? :-)

theme field type password_confirm

Is there a way to theme the output of field type password_confirm in D5? I want to change the default hidden text fields to clear text fields in form user_edit.

changing page title

I've customized all my forms using this method but I can't change the 'Create [node type]' title of the page. Does anyone know how to change the title of the form by content type?

Thanks for all the great tips

Default value for body textarea

Hello,
Thank you very much for this useful article.
by following your example, I try to set up a default value for the Body textarea, but it is never display in the node form.
Function registration in my homemade theme:

function homemade_theme() {
   return array(
     // The form ID.
     'article_node_form' => array(
       // Forms always take the form argument.
       'arguments' => array('form' => NULL)
     )
   );
}

Function to set the default value to body in the article creation form:
function homemade_article_node_form($form) {
$output = '';
$form['body_field']['body']['#title']="test";
$form['body_field']['body']['#default_value']= "test";
$output .= drupal_render($form);
return $output;
}

I don't understand why the body title is correctly changed but not the textarea body field.

Please help me to understand my error.
Jerome

Change Button Type

Can you use this override to change the button type to image? I tried using:

$form['submit']['#type'] = image;
$form['submit']['#src'] = /images/blue-arrow.gif;

On the search block form but that just made the submit button disappear all together.

Thanks!

I hope this get answered

Firstly, i agree with the hundreds of post, it was a clear and concised, well written tut.

I have a question about different form themes in the same site.

At the moment i am customising the user_rego page and i find that obviously when i edit the form all instances of the form change.

Can this be done?
Can anyone explain how?

Ilan

Some more clarifications.

Hai one and all,

This is elan. I am Having some doubt regard the Hook overriding. I Implemented as per the turorial. But my query is if suppose i want to add any new field with this user block ( let's assume an age) what i have to do. and where i have to add.

I hope a soon reply from you friends.

Thanks & Regards

Elandirayan.J

How do you know if a

Great tutorial, but I have one big question.

Under D6 theme override you say:

For forms that do not have templates or registered functions though, we need to not only create the override function but we also need to register it with the theme system so it knows about it.

But you don't explain how you know whether or not the form has a template or a registered function already. Where does one find that information?

Thanks for your help in advance!
Steve

Useful Tutorial

Thank you so much for this tutorial, my friend are about to learn Drupal and he really need this.. I will give this link to him.. Great post ^^ and nice to know you...

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <blockquote> <h2> <h3>
  • Lines and paragraphs break automatically.
  • Use <!--pagebreak--> to create page breaks.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
  • Web page addresses and e-mail addresses turn into links automatically.

More information about formatting options