Provide a form-specific alteration instead of the global hook_form_alter().

Provide a form-specific alteration instead of the global hook_form_alter().

Modules can implement hook_form_FORM_ID_alter() to modify a specific form, rather than implementing hook_form_alter() and checking the form ID, or using long switch statements to alter multiple forms.

Form alter hooks are called in the following order: hook_form_alter(), hook_form_BASE_FORM_ID_alter(), hook_form_FORM_ID_alter(). See hook_form_alter() for more details.


manimejia’s picture

Here's an easy way to get ALL hook_form_FORM_ID_alter() implementations loaded from a .inc file, WITHOUT declaring them each separately in hook_hook_info() ...

In the file MY_MODULE.module add:

 * implimentation of hook_hook_info_alter()
function MY_MODULE_hook_info_alter(&$hooks) {
  $hooks['form_alter']['group'] = 'form';

Then in the file MY_MODULE.form.inc make sure to add:

 * implimentation of hook_form_alter()
function MY_MODULE_form_alter(&$form, &$form_state, $form_id){
// add all MY_MODULE_form_FORM_ID_alter() functions bellow ...

With the above function MY_MODULE_form_alter() declared in this .inc file (even if it's empty), ALL MY_MODULE_form_FORM_ID_alter() implementations declared in the same file will get loaded properly. WITHOUT this function the file will not be loaded at all!

This works because, in drupal_prepare_form() calls hook_form_alter() (and loads this .inc file) before it calls hook_form_FORM_ID_alter() for each form build.

nagiek’s picture


onegenius’s picture

To see the results of your form alteration go to configuration and clear cache.

doublejosh’s picture

hook_form_FORM_ID_alter() functions always run before hook_form_alter() regardless of module weight etc. Hope that saves someone else the time I wasted :)

letapjar’s picture

You have it backwards - the general hook_form_alter fires BEFORE the specific hook_form_FORM_ID_alter() other wise there would be no point in have the specific form alter hook.

thejtate’s picture

This drove me nuts till I saw this. Thanks!

sergey-shulipa’s picture

doublejosh and onejebius, Thanks a lot!

Barrett’s picture

Anyone know why form_id was added as a parameter in Drupal 7? Seems unnecessary given that we're already specifying the form_id to alter.

brandondrew’s picture

You sound like you're familiar with Ruby, where it would be common to use part of the method name as (in essence) a parameter. I've never seen this done in PHP; I assume it's possible, just not a conventional approach. As I understand it, the FORM_ID in the function name is purely there for the purpose of avoiding a naming collision with other similar functions. The $form_id parameter is then used the way parameters traditionally are. This avoids the extra code in the function to do reflection and extract the FORM_ID. Of course that extra code could presumably be avoided with some meta-programming, but again that's not traditional in the PHP "community". So I think the answer to your question comes down to different values within the cultures that surround different languages. In Ruby writing DRY code is an extremely highly valued goal, and clever tricks to achieve that are idiomatic and considered part of what a good programmer is expected to know. Other things are valued more in PHP.

yakoub’s picture

there is no sense whatsoever in what you are saying .

you don't need to extract the form id from function name programatically, given you write the function name statically in code you can also use constant string inside the body of you function .

but why would you need that anyway ?
this function is called only and only if the form id equals exactly the id part in function name, and it is not as you write that it is there for "avoiding a naming collision" .

you really have absolutely no clue about what you are talking about .

Garrett Albright’s picture

Trying to use hook_form_FORM_ID_alter() with node forms is a pain because the form ID is always "[node-type]_node_form" - that is, it's different for every node type. The Drupal 6 workaround is to use hook_form_alter() and check the form to see if it's a node form (doing something like isset($form['#node'])), but in D7, there's a better way; you can use hook_form_BASE_FORM_ID_alter(). With nodes, the base form ID is "node_form," so you can just create an implementation of hook_form_node_form_alter(). Ah, much better.

laraz’s picture

I want to do it with drupal 7 but I don't understand. Can you explain me better? thanks.

SirClickALot’s picture

If you implement

<yourmodule>_form_node_form_alter(&$form, $form_state) {


i.e. a generic form_node_form flavour without the _ prefix

That seems to do the trick.

taizi’s picture


inventlogic’s picture

View the HTML source code of the page on your website where the form is shown. Look for the form id in the form tag. As an example the form id could look like id="user-register-form" taken from your HTML source.

First convert the form id to user_register_form changing hyphens to underscores. Then substitute FORM_ID with user_register_form in hook_form_FORM_ID_alter which then becomes hook_form_user_register_form_alter

Don't confuse the word form in the hook with the word form in the id they are both needed. In fact it would be a lot less confusing if you don't use the word form in the form id. ie form id="user-register" then the hook becomes hook_form_user_register_alter.

The word hook is then changed depending on where you are running the function to either the name of your theme template if you are putting this in template.php or the name of your module if you are building a module.

Note that within Drupal admin the name of your admin theme may not be the same as the name of your site theme. For example if in Drupal admin you are using the Seven admin theme the name of your hook changes to seven_form_user_register_form_alter or if your form id does not contain the word form seven_form_user_register_alter.

Note also the admin themes directory is at the top level of your websites directory structure. You would therefore place your code in the template.php file in the Seven folder at the top level themes directory. i.e. not in sites/all/themes/seven/template.php but just themes/seven/template.php.

rayfirst’s picture

You've explained clearly.

cdmo’s picture

One thing I ran into is that the form's id attribute value isn't the FORM_ID. I found that the FORM_ID was actually only the first part of the form id attribute. Here's what I'm talking about:

<form class="ctools-auto-submit-full-form ctools-auto-submit-processed" action="/action-here" method="get" id="views-exposed-form-browse-view-page" accept-charset="UTF-8">

So you might think the FORM_ID would be views-exposed-form-browse-view-page (change hyphens to underscores). But, you'd be wrong. Running this was informative:

drupal_set_message("Form ID is : " . $form_id);
drupal_set_message(dprint_r($form, TRUE));

That told me the actual FORM_ID, which was "views_exposed_form".

Not sure if this is documented or not, so I thought I'd mention it here.

wernerglinka’s picture

Just ran into this myself. Is this just true for views forms? I changed an exposed filter where the form id is "views-exposed-form-transactions-history-block" in the html. But the function must be hook_form_views_exposed_form_alter to work.

BWPanda’s picture

Your method of finding the form ID (based on the ID of the form element) will work most of the time, however as it's not generated from the real form ID it's not guaranteed to always work.

Here's how to get the real form ID every time:

  • Look at the HTML source (Firebug's really useful here) and locate the form element
  • Within the form element, locate the hidden field where name="form_id"
  • The 'value' of this field is the form ID

Example: <input type="hidden" value="page_node_form" name="form_id">
This was taken from the 'Create Page' form. The form ID here would be page_node_form (no need to change hyphens to underscores, just use as is).

elperuanito’s picture

Never mind, the reason it was messing up was nothing to do with this function!


swatiphp’s picture

but how can I change the order of the field added.

I have added checkboxes and it is showing after title in the form of content type created from admin panel.

I want to change its order to display it after one of the filed added by manage field

Elijah Lynn’s picture

I am confused, is $form_id required or optional. The documentation implies it is required but I just heard that it is optional. Can someone clarify?

roderik’s picture

When calling a hook_form_FORM_ID function, the 3rd argument is required. But in practice, you never call such a function directly. The Drupal Form API does that.

You define the function that then gets called by Form API code. And in PHP you can define a function without any function arguments, and later get the arguments that the caller passed, using func_get_args().

So, because of this general PHP-ism, it's not illegal to define your function with only 2 arguments, even though it (in practice) always gets called with 3 arguments.

captainkk’s picture

try this
function block_morelink_form_block_add_block_form_alter(&$form, &$form_state)
block_morelink_form_block_admin_configure_alter($form, $form_state);

This form does not change !!!

hutch’s picture

I want the user to be redirected to the user "View" page rather than return to the user "Edit" form on submission of the form

"mymodule" is the name of a bespoke module.

function mymodule_form_user_profile_form_alter(&$form, &$form_state, $form_id){
  if (isset($form_state['user']->uid)) {
    $_GET['destination'] = 'user/' . $form_state['user']->uid;

This also redirects correctly when the editor is admin.

Hope this helps someone.

therobyouknow’s picture

where is a definitive list of the form ids. Hard to know!

For example if you use dpm to get the form id - it shows comment form as having id comment-form but in this function it is comment_form (i think).

gladiatorhl2’s picture

I have an error Notice: Trying to get property of non-object in function MY_MODULE_form_comment_form_alter()
This error is related to the line if ($node->nid == $comment->nid) and I think to $comment->nid

I suppose that it is needed to describe $comment->nid as an object like for $node->nid an expression $node = menu_get_object() was used. I was searching for this similar program code and with no success. I have to use $form['#attributes']['class'][] = 'new-comment-form'; and that is why hook_form_alter is used. Is there a way to do it or another solution to this problem?

The code is:

function MY_MODULE_form_comment_form_alter(&$form, &$form_state, &$comment_count, &$comment) {

if (arg(0) == 'node' && is_numeric(arg(1))) {

$node = node_load(arg(1));
if (isset($node->uid, $GLOBALS['user']->uid) && $GLOBALS['user']->uid == $node->uid && $GLOBALS['user']->uid > 0) {

$form['#attached']['css'] = array(
drupal_get_path('module', 'MY_MODULE') . '/MY_MODULE.css.');


$node = menu_get_object();

if ($form['#node']->comment_count == 0 ){
// hide a field
drupal_add_css(drupal_get_path('module', 'MY_MODULE') . '/MY_MODULE2.css.');

if ($node->nid == $comment->nid) {
$form['#attributes']['class'][] = 'new-comment-form';


Bits8myBytes’s picture

Noticed a strange bug with this hook when logged in as admin. When logged in as an admin this function ran on forms that did not share the same build ID. In my case I was getting an ajax error because I used this hook to add an ajax callback to a specific form ID, but when I was an admin it attempted to manipulate other forms that did not have the same structure causing many errors. I fixed this by just adding a quick check to the $form_id to make sure it is the correct form before I altered the $form reference argument. I hope someone who runs into this obscure bug finds this helpful because I could not find anyone on google who was experiencing the same issue.

The issue may depend on views. In the page.tpl.php theme I had embedded a view which rendered a couple items with a form button. The items in some cases are rendered but never displayed. So I just made sure not to render the items if they are not going to be displayed and that fixed the bug completely. Even after checking for form_id and the form itself I was still having issues with forms getting the wrong ajax callback added to their submit buttons. And this issue only occured when logged in as an admin.

tterranigma’s picture

Keep in mind that if you see a module implementing this hook with eg module_form_sth_like_form_id_here_alter, be sure to check the $form_state variable as mentioned here hook_form_BASE_FORM_ID_alter as these two hooks look the same when implemented.

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'];

merauluka’s picture

Hey @jag1500,

Support requests should really be asked in the issue queues. You will receive an answer to your question more quickly there.

usmanjutt84’s picture

I have got all nodes related to a term by this code:

	$arg = arg();
	$query = db_select('node','n');
	$query->fields('n', array('nid', 'title', 'type'))
	  ->condition('n.type', 'products')
	  ->condition('ti.tid', $arg['2']);
	$result = $query->execute()->fetchAll();
	$dropdown_array = array('' => t('-Select-'));
	$options = array('' => '<select>');
	foreach ($result as $nid => $node) {		
		echo $dropdown_array[$node->title] = $node->title.' [nid =>'.$node->nid.']<br>';

Now, I would like to assign these nodes titles to an existing drop down field (created by WEbForm Module) named as product_name. I tried this but unsuccessful.