Here's a flexible way to alter form elements such as CCK widgets. It lets you alter any form element by defining its name, and it'll find it wherever it is in the form structure.
It introduces a new custom hook, hook_node_form_element_alter(), that lets you alter selected elements. You need to register which elements you want to alter using the MODULENAME_node_form_element_alter_register() function, that you'll have to call in a #after_build callback function defined in hook_form_alter().
If all this sound greek (or geek) to you, have a look at the code below and hopefully you'll see what to do :)
/**
* Implementation of hook_form_alter().
*
* Add after build callback to node forms. Use additional checks to only apply
* to certain node types.
*/
function MODULENAME_form_alter(&$form, &$form_state, $form_id) {
if (isset($form['#node']) && isset($form['type']['#value']) && $form_id == $form['type']['#value'] .'_node_form') {
if (!isset($form['#after_build'])) {
$form['#after_build'] = array();
}
$form['#after_build'][] = 'MODULENAME_node_form_after_build';
}
}
/**
* "After build" callback for node forms. Register the fields you want to alter.
*/
function MODULENAME_node_form_after_build($form, &$form_state) {
// For each field you want to alter, register it like this:
MODULENAME_node_form_element_alter_register($form, 'field_FIELD_NAME');
// For example, to alter the "Add more items" button of an image field:
MODULENAME_node_form_element_alter_register($form, 'field_my_imagefield_add_more');
return $form;
}
/**
* Implementation of hook_node_form_element_alter().
*/
function MODULENAME_node_form_element_alter($name, &$element) {
if ($name == 'field_my_imagefield_add_more') {
$element['#value'] = t('More images, please!');
}
}
/**
* Register a node form element for alteration by modules implementing the
* hook_node_form_element_alter() hook.
*/
function MODULENAME_node_form_element_alter_register(&$elements, $name) {
foreach (element_children($elements) as $key) {
if (isset($elements[$key]) && ($elements[$key]['#name'] == $name || $elements[$key]['#field_name'] == $name || $elements[$key]['#group_name'] == $name)) {
foreach (module_implements('node_form_element_alter') as $module) {
call_user_func_array($module .'_node_form_element_alter', array($name, &$elements[$key]));
}
}
else {
MODULENAME_node_form_element_alter_register($elements[$key], $name, $callback);
}
}
}
It was pretty quickly thrown together based on the other code snippets for altering elements. Not much planning went into it, and it can probably be improved a lot.
Comments
Thanks
Was trying to find a way of adding custom drop down options, this works great.
Not sure how I would have ever figured this out.
$callback
this is really helpful - wondering, though, about this line
MODULENAME_node_form_element_alter_register($elements[$key], $name, $callback);
$callback isn't defined anywhere and that parameter doesn't seem to be used anyway - can that be removed? or is that meant to stand for something that's not explicitly in the example?
How can I use this method to
How can I use this method to add autocomplete to a given field? I have tried:
function mymod_node_form_element_alter ( $name, &$element ) {
if ( $name == 'field_myfield') {
$element[0]['#autocomplete_path'] = 'user/autocomplete';
$element[0]['value']['#autocomplete_path'] = 'user/autocomplete';
}
}
And this does not seem to work. Is there something else I need to add to the $element array?
I also question the $callback parameter...
Many thanks for this -- I don't think I would have come up with this on my own!
fixed...
while using 'user/autocomplete' as a quick and dirty test case, I forgot that a user will need to have access to the path for this to work. In my case, I did not.
Works like a charm
I worked for me. Thanks for this beautiful post !!!