8.5.x form.api.php hook_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id)
8.0.x form.api.php hook_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id)
8.1.x form.api.php hook_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id)
8.2.x form.api.php hook_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id)
8.3.x form.api.php hook_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id)
8.4.x form.api.php hook_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id)
8.6.x form.api.php hook_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id)
4.7.x core.php hook_form_alter($form_id, &$form)
5.x core.php hook_form_alter($form_id, &$form)
6.x core.php hook_form_alter(&$form, &$form_state, $form_id)
7.x system.api.php hook_form_alter(&$form, &$form_state, $form_id)

Perform alterations before a form is rendered.

One popular use of this hook is to add form elements to the node form. When altering a node form, the node object can be accessed at $form['#node'].

In addition to hook_form_alter(), which is called for all forms, there are two more specific form hooks available. The first, hook_form_BASE_FORM_ID_alter(), allows targeting of a form/forms via a base form (if one exists). The second, hook_form_FORM_ID_alter(), can be used to target a specific form directly.

The call order is as follows: all existing form alter functions are called for module A, then all for module B, etc., followed by all for any base theme(s), and finally for the theme itself. The module order is determined by system weight, then by module name.

Within each module, form alter hooks are called in the following order: first, hook_form_alter(); second, hook_form_BASE_FORM_ID_alter(); third, hook_form_FORM_ID_alter(). So, for each module, the more general hooks are called first followed by the more specific.


$form: Nested array of form elements that comprise the form.

$form_state: A keyed array containing the current state of the form. The arguments that drupal_get_form() was originally called with are available in the array $form_state['build_info']['args'].

$form_id: String representing the name of the form itself. Typically this is the name of the function that generated the form.

See also




Related topics

42 functions implement hook_form_alter()

Note: this list is generated by pattern matching, so it may include some functions that are not actually implementations of this hook.

aggregator_form_aggregator_admin_form_alter in modules/aggregator/aggregator.processor.inc
Implements hook_form_aggregator_admin_form_alter().
block_form_form_test_alter_form_alter in modules/simpletest/tests/form_test.module
Implements hook_form_FORM_ID_alter() on behalf of block.module.
block_form_user_profile_form_alter in modules/block/block.module
Implements hook_form_FORM_ID_alter() for user_profile_form().
book_form_node_form_alter in modules/book/book.module
Implements hook_form_BASE_FORM_ID_alter() for node_form().
comment_form_node_form_alter in modules/comment/comment.module
Implements hook_form_BASE_FORM_ID_alter().

... See full list


modules/system/system.api.php, line 1671
Hooks provided by Drupal core and the System module.


function hook_form_alter(&$form, &$form_state, $form_id) {
  if (isset($form['type']) && $form['type']['#value'] . '_node_settings' == $form_id) {
    $form['workflow']['upload_' . $form['type']['#value']] = array(
      '#type' => 'radios',
      '#title' => t('Attachments'),
      '#default_value' => variable_get('upload_' . $form['type']['#value'], 1),
      '#options' => array(


mpapet’s picture

To modify a form, check $form['#id'] for the name of the form.

It wasn't obvious to me, but you are only supposed to modify $form.

A way to discover the name of forms is to add this line to your hook_form_alter on your dev site


watchdog('cg_volunteer', 'cg form_alter has run %formly', array('%formly' => $form['#id']), WATCHDOG_NOTICE, $link = NULL);
seanr’s picture

The best way to do that is with drupal_set_message, or even better with the devel module's dsm() function. Then you can do handy stuff like this:

function example_form_alter(&$form, &$form_state, $form_id) {
  dsm($form_id);  // print form ID to messages
  dsm($form);  // pretty print array using Krumo to messages

That way you get it right there in the page you're looking at without having to go dig around in the watchdog. Here's the equivalent without devel (though why you wouldn't want to use devel I don't know...):

function example_form_alter(&$form, &$form_state, $form_id) {
  drupal_set_message($form_id);  // print form ID to messages
  drupal_set_message(print_r($form, TRUE));  // print array to messages

One obvious advantage of using devel's dsm() function is you don't even have to know wether the variable is a string, array, or object - devel takes care of all that for you so you don't have to use print_r().

johnlaine’s picture


supriyarajgopal’s picture

drupal_set_message('' .print_r($form,TRUE). '');
prints $form array as-is by preserving the array structure thereby making it more readable :)

plummera’s picture


rimu’s picture

I usually just use the browser's dev tools to look for a hidden field called 'form_id', the value of which is the ID of that form.

esod’s picture

If for some reason devel is not installed:

function mytheme_form_alter(&$form, &$form_state, $form_id) {
  $print = '<pre>' . print_r($form, TRUE) . '</pre>';
  if (module_exists('devel')) {
    dsm($form_id); // print form ID to messages
  else {
    drupal_set_message($form_id); // print form ID to messages
  if (module_exists('devel')) {
    dsm($form); // pretty print array using Krumo to messages
  else {
    drupal_set_message($print);  // print array to messages

Wrapping print_r($form, TRUE) with <pre> tags returns the variable data in a easier to read format, although Krumo is better.

sunchaser’s picture

function <themename>_form_alter(&$form, &$form_state, $form_id) {
    drupal_set_message("This is the form id : $form_id");

just doesn't fire in my node/add form

any thoughts ?

chellman’s picture

If the theme you're editing is not active on the page of interest, this won't work. If, for example, is the default theme, but you're using Seven as your admin theme (and your admin theme is used for content editing -- checking the settings at the bottom of the Appearance page), this form_alter won't be called on node/add or node/*/edit pages.

If you're sure you have the themes set correctly, you should try clearing the Drupal cache to make sure the form_alter is being picked up. This is on Admin > Configuration > Development > Performance.

Fix those two things, and you should be in business.

(I posted this in the forum, then remembered I saw it here first, so I'm reposting it here).

yaworsk’s picture

nope, it doesn't look like hook_form_alter fires on node add forms. I'm calling it from template.php and it works on other forms on my site, just not node add forms....

Fabien Crépin’s picture

Same here.
It works on another site with another theme.
It works within modules.
But on one site, no way to have it fired when in template.php.

emmanuelbakare@yahoo.com’s picture

Chellman is right. fire your hook_form_alter in your administrative theme as started.
If you are like most who use the Seven theme as their admin theme, then put your hook_form_alter in the template file of the Seven theme.

For example if you are using a bartik theme but your administrative theme is Seven, then your hook_form_alter will be in the template file of your Seven theme like this
seven_hook_form_alter(&$form, &$form_state,$form_id)

vegantriathlete’s picture

Are you seriously suggesting to hack core? Or were you just giving an example of how the function would be named?

fyberoptik’s picture

I had a similar issue as I was running my site from a folder on the live site(site.com/testsite), this meant the global URL was working against the main site (site.com) and didn't work with the form_alter function.

I would find out the form ID using the web inspector. The form id should be referenced in the html source code. The form id my case was user_pass, and the solution was this:


A much better solution as it will run the script against a specific form. This saves processing power as it doesn't check the script against every form on the site.

Hope this helps

fyberoptik’s picture


subhojit777’s picture

Suppose you have created a custom module and you want to create hook_form_alter for that module. Here are some easy steps to implement and test the working of hook_form_alter.

Suppose you want to add a new field in your in your comments form , say a checkbox. You can do this using the hook_form_alter of your custom module. Before doing this make sure that writing comment is enabled in your content type. hook_form_alter takes three parameters $form, $form_date and $form_id. If you just want to see the working of form_alter then you need to worry about only $form_id.

Just write this piece of code in your mymodule.module file:

function mymodule_form_alter(&$form, $form_state, $form_id)  {
  	switch ($form_id)  {
  	 	case 'comment_form_id':
  	 		$form['your_comment_form_name'] = array (
  	 		  '#type' => 'checkbox',
  	 		  '#title' => t ('Subscribe to replies to this comment'),

The name of comment form is of your choice.

If you are wondering what $form_id would in your case, then add this piece of code before switch($form_id):

You will see all the form_id's of your page after refreshing the page. Just copy the form_id of your comments form and paste it in place of comment_form_id.

Enable your module and view your comments form. You will see the checkbox in there.
Even if you dont see the checkbox in your comments form, try clearing the cache. If you have followed the above steps correctly, you will surely see the checkbox in comments form.

I hope I have made myself clear :)

Thank you Mukesh for your guidance

Aparato’s picture

Not sure about your use of $form_id .. if you use that then the form name is a 'base' form name not a specific form name.

For example, if I use $form_id then I get the name "views-exposed-form", if I use $form['#id'] then the name (in my case) is "views-exposed-form-classifieds-page".

So using $form_id would apply the alter code to ANY page that had a views exposed form (ie the code intended just for page XXX would be run on pages XXX, YYY, ZZZ etc. Is this correct or have I misunderstood?

schlicki’s picture

Hey guys..

I searched the internet for hours and didnt find a solution.
I want to add form states in hook_form_alter. Therefore I tried the following code:

  $form['field_dependent']['#states'] = array(
    'visible' => array(
      ':input[name="field_dependee"]' => array('empty' => false),

All fields are textfields and I minimized my modules code to exactly this and created a node type with the fields available.. The result is: nothing happens.
What am I doing wrong? Any ideas? or am I on a completely wrong way to achieve the goal of putting dependencies into forms that already exist?

Thanks in advance,

schlicki’s picture


Now i should have waited with commenting ;)

As a last attempt I tried:

  $form['field_dependent']['#states'] = array(
    'visible' => array(
      ':input[name="field_dependee[und][0][value]"]' => array('empty' => false),

.. and it worked. I dont get the logic behind that, but it works ;)

Vincent.R’s picture

It seems that this function can only be called in the mymodule.module file,elsewhere like mymodule.admin.inc give no response when you use dsm($form_id); inside this hook function

reign85’s picture

you can pass arguments to your hook_form_alter via drupal_get_form

drupal_get_form('content_type_node_form',$node_to_modify, $some_value);

and then catch the value on the hook_form_alter with $form_state['build_info']['args']:

function agency_form_alter(&$form, $form_state, $form_id)
if($form_id == 'content_type_node_form'){
        //do some stuff with this

Obviously, don't forget to send in first parameter your node object for the edit node page ($node_to_modify), or if you want the add node page, send an new empty node:

module_load_include('inc', 'node', 'node.pages');
	$new_node_form = new stdClass;
	$new_node_form->type = 'content_type_node_form';
	$new_node_form->language = LANGUAGE_NONE;
	return drupal_get_form('content_type_node_form',$new_node_form, $id_agency);
alfarider’s picture

i want to add some html code in the body field when the user click on preview button so i set


in the hook_form_alter but no changes the body always empty any solution for this problem ?

bighoc’s picture

How I may to add new field in registration form ?

MikaT’s picture

Example on how to replace your own token from webform description field

function hook_form_alter(&$form, &$form_state, $form_id) {
  $form['submitted']['my-webform-field']['#description'] = str_replace('project:my-token', $replace_value, $form['submitted']['my-webform-field']['#description']);
girishmuraly’s picture

Please note that the order of invocation of the various form alteration hooks hold good only within each module.

"Within each module, form alter hooks are called in the following order: first, hook_form_alter(); second, hook_form_BASE_FORM_ID_alter(); third, hook_form_FORM_ID_alter(). So, for each module, the more general hooks are called first followed by the more specific."

So if you have two modules named A and B; A_form_FORM_ID_alter() would be called before B_form_FORM_ID_alter().

So the order of invocation of hooks is within each module. You need to change the weights of the modules to get specific hooks in different modules called ahead of the others in line.

fast_luca’s picture

As the subject, there is a way to add a field to all nodes form (both in add form and edit form)?
Here is the code that i've tried, but it doesn't work..

if (isset($form ['type']) && $form ['type']['#value'] . '_node_form' == $form_id) {
        $form['expert'] = array(
            '#type' => 'fieldset',
            '#title' => t('Expert settings'),
            '#weight' => 100,
            '#collapsible' => TRUE,
            '#collapsed' => FALSE,
        $form['expert']['name'] = array(
            '#type' => 'textfield',
            '#title' => t('Candidate Experts'),
            '#weight' => -1,
            '#maxlength' => 60,
            '#autocomplete_path' => 'user/autocomplete',
Robert Broen’s picture

I was looking to change some values in a form altered with a hook_form_alter() implementation.
Drupal kind of prevents this in drupal_build_form by overriding my changes with $form_state_before_retrieval.

The answer I found was adding the name of a validator function to the altered form. The validator was able to change the values.

If anyone knows a better way, please tell me how.

ShaunDychko’s picture

hook_module_implements_alter() can also be used to change the order of execution of modules for "hook_form_alter".

jag1500’s picture

I have my own address field (just the street address, not city or state) for a content type. I also have locations module installed. I want to copy the value of my address field into the street field of the location. I tried using the hook_form_alter and also the hook_form_FORM_ID_alter in a customer module using the .info and .module file but no results, it does not even show me any printed values. This is on Add Content form for content type venue. Any help is appreciated.

function copyfield_form_alter(&$form, &$form_state, $form_id)


if (!empty($form_state['values']['field_address']))
$form['street']['#value'] = $form_state['values']['field_address'];

davidkp’s picture

If you're looking to change the 'Create' and 'Edit Content Type' title prefix on the node add and/or edit forms... throw this code in your themes template.php file (and don't forget to flush all caches).

 * Change the title prefix on all the node add and edit forms.
function mytheme_form_alter(&$form, &$form_state, $form_id) {
  switch ($form_id) {
    case (isset($form['type']) && $form['type']['#value'] . '_node_form'):
      if ($form['nid']['#value']) {
        drupal_set_title("Change " . $form['title']['#default_value']);
      else {
        drupal_set_title("New " . ucfirst($form['type']['#value']));

You can change the contents of drupal_set_title() as you please.