2

In hook_node_view of one node I add a node form of a different content type as follows:

global $user;
$node_form = (object) array('uid' => $user->uid,
                            'name' => (isset($user->name) ? $user->name : ''),
                            'type' => 'my_type',
                            'language' => LANGUAGE_NONE
                            );
//create form state
$form_state['build_info']['args'] = array($node_form);

form_load_include($form_state, 'inc', 'node', 'node.pages');
$form = drupal_build_form('my_type_node_form', $form_state);

//change default save button
$form['actions']['submit']['#value'] = t("Nice Save");
$form['#validate'][] = 'my_module_my_validate';

//hide few fields
if(!in_array('administrator', $account -> roles)) {
    $form['field_field_1']['#access'] = FALSE;
    $form['field_field_2']['#access'] = FALSE;
    $form['field_field_3']['#access'] = FALSE;
}

$node -> content['my_form'] = $form;

All of above works great. Form is nicely displayed, fields are hidden, submit button value is changed and additional validation handler seems to be added correctly as debug($form['#validate']) returs:

array (
  0 => 'node_form_validate',
  1 => 'my_module_my_validate',
)

default validation is trigged as one of the fields in embedded form is required and left empty Drupal as expected returns: My required filed field is required. Node is created just fine using this form.

The problem is that for some reason my custom validate handler is not called at all.

/*
 *
 */
function my_module_my_validate($form, &$form_state) {
    debug('test');
    form_set_error('', 'error');
}

Am I missing something? I could potentially use hook_form_alter but I would like to get this working correctly.

13
  • Try adding the validation handler to the button itself. Note how form_execute_handlers() uses either the button handlers or the form-level ones.
    – Andy
    Commented Jun 2, 2014 at 13:12
  • @Andy do you mean like that: $form['actions']['submit']['#validate'][] = 'my_module_my_validate';
    – sylwester
    Commented Jun 2, 2014 at 13:25
  • Yup. No joy? ..
    – Andy
    Commented Jun 2, 2014 at 14:00
  • 1
    Those are handled at render time, whereas the input processing (and therefore handler execution) are done at form build time.
    – Andy
    Commented Jun 2, 2014 at 14:56
  • 2
    Or to put it another way, consider the form returned by drupal_build_form() as nothing more than a render array that happens to render a form. If you want a form array proper, you need to get the form via an alter (ie before drupal_process_form() is called on it).
    – Andy
    Commented Jun 2, 2014 at 15:03

1 Answer 1

2

You do need a form alter. You're modifying the form array after it's already been built, which includes caching the form and processing the input.

Form is nicely displayed, fields are hidden, submit button value is changed

Those are handled at render time, whereas the input processing (and therefore handler execution) are done at form build time. Or to put it another way, consider the form returned by drupal_build_form() as nothing more than a render array that happens to render a form. If you want a form array proper, you need to get the form via an alter (ie before drupal_process_form() is called on it).

You can use hook_form_FORM_ID_alter() if you want to target just one content type form, or hook_form_BASE_FORM_ID_alter() if you want to target multiple types or be dynamic. If you need to know within the form alter whether the form's embedded via a hook_node_view() you can pass that state via $form_state.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.