function hook_form_FORM_ID_alter

You are here

7 system.api.php hook_form_FORM_ID_alter(&$form, &$form_state, $form_id)
6 core.php hook_form_FORM_ID_alter(&$form, &$form_state)
8 system.api.php hook_form_FORM_ID_alter(&$form, &$form_state, $form_id)

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.

Parameters

$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

hook_form_alter()

hook_form_BASE_FORM_ID_alter()

drupal_prepare_form()

forms_api_reference.html

Related topics

File

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

Code

function hook_form_FORM_ID_alter(&$form, &$form_state, $form_id) {
  // Modification for the form with the given form ID goes here. For example, if
  // FORM_ID is "user_register_form" this code would run only on the user
  // registration form.

  // Add a checkbox to registration form about agreeing to terms of use.
  $form['terms_of_use'] = array(
    '#type' => 'checkbox',
    '#title' => t("I agree with the website's terms and conditions."),
    '#required' => TRUE,
  );
}

Comments

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:

<?php
/**
* 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:

<?php
/**
* 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.

brilliant.

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

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 :)

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.

This drove me nuts till I saw this. Thanks!

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.

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.

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.

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

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.

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.

You've explained clearly.

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.

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.

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).

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

Thanks!

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

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?

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.

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 !!!

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.

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).