Mini Lesson Class Notes -- hook_form_alter (Drupal 5 based)

You are viewing a wiki page. You are welcome to join the group and then edit it. Be bold!

Introduction

Note: Although the material covered here is valid for later versions of drupal, the signature of hook_forms_alter() changed in Drupal 6, so the exact examples will not work correctly. The new signature is hook_form_alter(&$form, $form_state, $form_id)

These are class notes for dmitrig01's mini-lesson on hook_form_alter which I found very effective and useful. The lesson is based on a hands-on approach where you actually write some PHP code and see things happening in your Drupal Test Environment. This lesson concentrates on Form manipulation which can be used by module writers to write interesting modules or administrators to enhance the content of a typical installation according to their needs. Beginners are encouraged to type along with the lesson to understand better.

Prerequisites

It is advisable to know about Form API in general before you start this lesson; although I personally found it intuitive and easy to understand without even knowing about it.

Concepts

Hooks are used by modules in Drupal to interact with the Drupal system; any new module will have to implement some hooks to get things done in Drupal. Hooks are of the form hook_Some_functionality. Any hook will start from hook_, which is a consistent way to declare hooks. Any module wanting to interact with Drupal core needs to implement the hook corresponding to the functionality needed. A module named 'dojo' will implement a hook by simply defining the function in its dojo.module in the form dojo_some_functionality; hence you just have to replace the word 'hook' by the module name and pass the expected parameters.

The API site is a good place to find out the expected parameters and other details about any hook.

Let's Begin

In this lesson we are developing a test module called dojo which is by no means a sensible module. It's a test module to explain the functionality of hook_form_alter.

hook_form_alter takes two arguments:

  1. The form ID of the form to alter
  2. Reference to the form to alter

Note: Don't forget to enable your dojo.module in the site's Administrator section!

How To Find Form ID

The Drupal Theme Engine and themes together render the HTML we see on a Drupal based website. Every different form is given a different form ID which can be found by viewing the source of the page containing the form, or by including a one line PHP code in your hook. Lets see both ways to find out the form ID of some form:

  1. View source:
    Lets see this by using an example. Being faithful to our video lesson, lets try to find out the form ID of a story page. You can exercise this example by simply logging into this group (drupal-dojo) and clicking on the 'create story link' on the right. Open the HTML source of the page and navigate to find out the field with name "form_id". Its value is the form_id we're looking for. For instance in our example it's on line 82 in my Firefox browser.

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

    Similarly Wiki's Form ID is "wikipage_node_form"

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

    and so on...

  2. To use PHP to find out form id:
    Simply print the form_id variable which was passed to hook_form_alter and you will be able to see the form id whenever this hook is fired. Lets see it through our first PHP code:
    <?php
    /**
    *   dojo.module is a test module to display the functionality of hook_form_alter
    *   hook_form_alter is implemented by dojo module
    *   by defining a function of the form dojo_form_alter.
    *   Note For Beginners: You never close PHP tags when you write Drupal modules.
    */
    function dojo_form_alter($form_id, &$form)  {
      print
    $form_id;
    }
    ?>

    This will print the Form ID on the page containing the form and hence you will know the form ID. This should be used only in development time and should be turned off in production...

Lets add form elements to forms using hook_form_alter API

You can add form elements and change its attributes using form API. For instance lets add a checkbox to the form.

<?php
/**
* $form is a reference hence it will alter the form being rendered
* $form is an array with other arrays as its elements.
* You will need to learn about form API to exploit form_alter completely
*/
function dojo_form_alter($form_id, &$form)  {
 
$form['dojo_checkbox'] = array(
   
'#type' => 'checkbox',
   
'#title' => t('Newly Added Checkbox'),
    );

}
?>

Pitfall: The above code will render the checkbox on all pages as we are passing a reference to $form -- hence $form_id comes into picture so we can conditionally add the checkbox on selected pages by comparing form_id which we learned about above.

Correct code: This will add a checkbox only on story pages and wiki pages.

<?php
function dojo_form_alter($form_id, &$form) {
  if(
$form_id == "story_node_form" || $form_id == "wikipage_node_form")  {
 
$form['dojo_checkbox'] = array(
   
'#type' => 'checkbox',
   
'#title' => t('Newly Added CheckBox'),
    );
  }
}
?>

We can add other attributes such as 'weight' to the checkbox. 'Weight' helps with positioning the checkbox relative to other elements. Values of weight can be in between -10 and 10 following the Unix pattern for priority. Lower value, higher priority

Try adding 'weight' to the above code and observe the position difference.

Altering Pre-existing Form Elements

You can also change the already present form elements by changing the $form array. For example, you can change the text of the title element or make a field as required and so on!

Lets quickly see an example:

<?php
/**
* Changes the title of the Text Box which accepts the wiki titles
* Make the title optional by disabling the red asterix
*/
function dojo_form_alter($form_id, &$form)  {
  if(
$form_id == "wikipage_node_form") {
   
$form['title']['#title']="Suitable Title For Wiki Content";
   
$form['title']['#required']=FALSE;
  }
}
?>

How To Find out about the form Elements on Page

It's inevitable that you will not know the names of various form elements and their attributes unless you are a Drupal geek!! Lukily there is a technique of finding out all the form array element which can be used in development phase. The technique is simply to make your page verbose by print_r($form)

However, simply adding print_r($form) will print intimidating text which is not easy to decipher; hence -- as suggested by dimitri -- use it in <pre> tags.

Add an extra form element which will print the $form value as it will be outputted on command line:

<?php
function dojo_form_alter($form_id, &$form) {
 
$form['form_info'] = array(
   
'#value' => '<pre>'. print_r($form, TRUE) .'</pre>'
 
);
}
?>

The above code will print all the form info and you can easily find out names of all form elements and their attributes.

If you have this information, you can easily manipulate every form element present in the form.

Closing

Well that's it for hook_form_alter. It doesn't return anything, you can easily layout form elements according to your organization's need or create new ones when writing your own module. You can suggest other trails related to this, and your own tricks.

Every aspect of mini lesson is covered without being redundant ... Rest everything is left to the creativity of the developer.

Comments

Wow, thanks Dipen!

Squidgy's picture

Wow, thanks Dipen! I really appreciate the time you put into this. :D I've linked the lesson notes on drupaldojo.com to it.

Drupal Dojo - Thelifeofme.com

thanks ...

dipen chaudhary's picture

thanks squidgy .. I will try to be more useful to the group ...
I am learning a lot through this group ...
So I will like to thank you all !!
regards
Dipen Chaudhary


Dipen Chaudhary
Founder, QED42 http://www.qed42.com Drupal development

Thanks

dmitrig01's picture

That inspired me to do more :)
I am going to do some next week...

nice tutorial

newdru's picture

dipen, could you expand on this by taking the next important step.. which is actually doing something useful with the form data like storing a custom form field in the db (probably a new db table).

i'm not sure if this gets done in hook_nodeapi using submit, validate, update, insert etc "ops" or directly with hook_submit?? if you pursue this, it would be good to show the difference between an add, update and delete on the field

thanks

While that would be great to

Squidgy's picture

While that would be great to see, and Dipen is welcome to go for it, it's important to note that this page is a transcription based on Dmitrig01's videocast - you should harass dmitri about doing that on the irc channel. :)

Drupal Dojo - Thelifeofme.com

credit for dimitri and challenge for me ...

dipen chaudhary's picture

PS: This tutorial is by my first drupal teacher (in all sense of it) DIMITRI .. I transcribed it and its he, who deserve credit and wotever comes with it [:P] ....

@Squidgy: Thanks for coming to the rescue but I am willing to take up the challenge, just that companies are coming for campus in university and its a total chaos, I have to learn freaking synonims and stuff, So you know I am very unhappy with my time spent account but its like a necessary evil as I need to have a job to eat n all .. So probably all fuss is gonna be sooon over, You can expect a addition by this week end or next mid week, as I have already worked a lil on future enhancement..

@newdru: Thanks for the idea, I was working on node API before I left drupal for my job fair (momentarily mind u) and I made a form for dojochos's to submit lessons, (obviously custom stuff) so yehh I am gonna expand on that, And thats why I asked that question of "how to make a screencast" ...

Dipen Chaudhary
http://ajaxkarma.blogspot.com
www.dipen.co.nr (under construction)


Dipen Chaudhary
Founder, QED42 http://www.qed42.com Drupal development

How did you do the screencast Dmitrig01?

newdru's picture

i'm wondering how to make little screencasts like this.

I understand from above that Dmitrig01 did the sceencast for this tutorial. Dmitrig01 if you're following this thread at all, could you say more about how you did that:

1) it looks like you have some kind of screen recorder and you're simply just recording what you're actually doing on the screen in real time. is that correct?

2) which screen recorder did you use & any tips that you learned from doing these to share to save someone else time / mistakes (assuming there are any)?

3) did you do any post editing to the screen cast afterwards? if so:

  • what TYPES of edits? (i ask because you either type really fast or it looks like you sped some things up ;-))

  • what software did you use to edit if not the original screen capture sw?

  • do you know if you can pull the screen capture into other more powerful editors to clean them up?

i partly ask because i was wondering if one could add some music to the presentation or something.
or if you could have recorded your voice over and after the intitial screencast had been recorded .

4) What format does the screen capture sw you use save to (flv, mov, mpeg4... etc...) and what encodeing did you have to encode it for inclusion on blipp.tv?

thanks for any help you can provide on this. (sorry if this got cross posted via email)

Some stuff

dmitrig01's picture

for the screen recorder, I use copernicus, for mac, which is a piece of crap. (I now have iShowu many thanks to joshk) tips: figure out what you are going to say, then print it out. Set up a site beforehand, make yourself a custom module, and enable it. have it already open in a text editor

3
a. I removed the time in which I selected the text and deleted it. it looks so fast because of the very low framerate, where iMovie somehow crammed them into 24 fps, so it is 3 times shorter (I am unhappy about this)
b. to edit I used iMovie
c. You could use any editor. I just use iMovie because I have it
(extra) I could put music but I wouldn't be sure what to put
4: mov or mp4

ShowMeDo

Small mistake

DiJae's picture

Hi,

thx for the great tutorial. But there is one small mistake. It has to be:

$form['form_array'] = array('#value' => '<pre>'. print_r($form,1) . '</pre>');

Your version didn't work for me. So I guess it's a mistake. If not please take my excuses.

Take care
DiJae

hi ..

dipen chaudhary's picture

hi ..
its not print_r($form,1)
its print_r($form)

I think that is the reason

Dipen Chaudhary

http://ajaxkarma.blogspot.com
www.dipen.co.nr (under construction)


Dipen Chaudhary
Founder, QED42 http://www.qed42.com Drupal development

...

dmitrig01's picture

either will work

How do your save data

DiJae's picture

Hello,

how do your save the fields of the altered form? I just put a select-list in die form of node 'story'. And now I like to save the informations of the select-list in a new table. But I can't get it working.

Cheers
DiJae

[]

jowan's picture

Hi

could you please explain what happens to the results of the new elements of a form added with form_alter.
for example,
if i am using 'hook_form_alter' on 'page_node_form' and i add an extra 'checkbox':
-where do the results of the checkbox go?
-how would i enter them into the database?
-can they go into a different table than the one the _node_form uses ?
-how do i retrieve the result so that if i navigate back to edit that page_node the checkbox in the same state?

in this example i would like to add an extra checkbox but for the result of that to be stored in a custom table in my db, but would this mean having a separate submit function? if so would it not submit the rest of the form?
and many other questions...

cheers

+=

jowan's picture

so far i have figured out,

inside your implementation of hook_form_alter you need to make a validation and a submit function.
but you still need to execute the original validate and submit functions for the form you are altering so you can use '+=' to include rather than overwrite
eg

<?php
function testmod_form_alter($form_id, &$form) {
 
// Add some elements
  // And then this:
 
$form['#submit'] += array('testmod_form_submit' => array($form_id, &$form_values));           
 
$form['#validate'] += array('testmod_form_validate' => array());
}
?>

Then any additional function for submit, eg, insert additional form elements into new table in db
<?php
function testmod_form_submit($form_id, $form_values) {
 
db_query("INSERT INTO {tablex} (a, b) VALUES ('%s', '%s')", $form_values['x']['1'], $form_values['x']['2']);
}
?>

and any additional function for validate
<?php
function testmod_form_validate() {
 
// validations such as checking db
}
?>

some who knows more, please correct, i would like to realize the correct way for submitting and validating additional form elements added using hook_form_alter

Looks good

dmitrig01's picture

-=-

Confusing changes in drupal 6

frylock's picture

This and other similar posts are the only thing I was able to find about using form_alter. It is a great guide and pointed me in the general direction. The only problem with that is form_alter has changed.

In Drupal 6 not only does it take 3 arguments instead of 2 it also takes them in a different order.

From above:
function dojo_form_alter($form_id, &$form) {

As of 6.2:
function dojo_form_alter(&$form, $form_state, $form_id){

There was no error for me doing it the way mentioned in this guide. It just would not work. This is incredibly confusing since I was checking the $form for form id and putting my changes in $form_state (see order). As well as not using the real form ID.

Could this be updated or can someone point to a similar guide that covers 6.x?

Modifying Forms in Drupal 5 and 6

Matt V.'s picture

Addison Berry posted an article recently on the Lullabot site covering Modifying Forms in Drupal 5 and 6. It might be what you're looking for.

dual form actions

Anonymous's picture

Is it possible to add an extra submit button that performs a separate action using a single already existing field and does NOT refresh the page?
I would like to take the 'Title' field info and send it to a script to perform some background functions while allowing a user to complete the rest of the form as usual.
I'm just learning module development and form customization following this tutorial but I cannot seem to pin down whether this is possible the way I want to do it.
Is form_validate going to be the way to do it? I'm really putting some hours into getting this working as it's pretty integral for my site.
Any light shed on this will be highly appreciated.

Steve

Dependent Dropdowns in CCK

jjesus's picture

Hi, Steve,

Not sure if it's exactly what you want, but, I solved a similar problem based on this helpful article:

http://blue.live4all.co.il/~mooffie/cms/node/15

Instead of multiple buttons, the solution uses a single button and some Javascript to 'push the button' without redoing the entire page.

I'm not an expert, but, I got it to work.

Cheers.

--John

John Jesus | Worldwide Clarity | IRC: jjesus

fake form validation

Anonymous's picture

I'm having a problem now fooling the form into being validated while a non submitting button refreshes the page.
Here is the code:

<?php
function wopform_form_alter(&$form, $form_state, $form_id) {
$form['field_url']['button'] = array(
     
'#weight' => 20,
    );
   
$form['field_url']['button']['update'] = array(
     
'#type' => 'button',
     
'#value' => t('capture'),
    );
   
$form['field_url']['button']['help'] = array(
     
'#value' => '<p>'. t('Take screenshot') .'</p>',
    );

    if (isset(
$_POST['op']) && ($_POST['op'] == t('capture')) ) {
     
// We don't want to trigger validation when this button is pressed, so we
      // mark all field as if passed validation already.
     
_form_validate($form, $form_state, $form_id);
     
$validated_forms[$form_id] = TRUE;
}

}
?>

I can't, or don't know how to, find out where this is not working. This is mostly just cut and pasted though I've tried a million different things. But I don't know it it's the "if (isset($_POST....." not referring correctly to the non-submitting button or the bit below that. I am working from a D5 example but converting it to D6 so I'm full of problems.
Any help would be appreciated but bear in mind it may be more than 1 problem.

Steve

nice code.

geshan's picture

nice code.

Geshan

Thanks for this! Great

giorgio79's picture

Thanks for this!
Great explanation, as well as the tip on form submit and validate functions which are just as well necessary.

****Me and Drupal :)****
Clickbank IPN - Sell online or create a membership site with the largest affiliate network!
Review Critical - One of my sites