Drupal 7: Decorate / wrap existing form as separate form with individual path

It's not an untypical situation: You'd like to use an existing Drupal CMS form as base for a custom form under a separate URL. In our example case we will decorate the Registration form "user_register_form" and create a separate registration form under a separate URL. This might be a custom alternative to modules like https://www.drupal.org/project/multiple_registration if they don't match your requirements.

While hook_form_alter helps to alter an existing form and will also be useful for us, we'd like to have our completely separate form with own form_id but prepopulated with the field and logic of the base form. Le'ts see how we can do this in Drupal 7:

First we'll create a separate page containing our custom form, using hook_menu() to make the form

  1. /**
  2.  * Implements hook_menu().
  3.  */
  4. function MY_MODULE_menu() {
  5.   $items['my/custom/form-path'] = array(
  6.     'title' => 'My example form decorator page',
  7.     'page callback' => 'MY_MODULE_user_register_form_wrapper_page',
  8.     'access callback' => 'user_register_access',
  9.     'type' => MENU_CALLBACK,
  10.   );
  11.   return $items;
  12. }

Next we define our form wrapper using hook_forms(). Read the API Documentation for the different methods it offers:

  1. /**
  2.  * Implements hook_forms().
  3.  */
  4. function MY_MODULE_forms($form_id, $args) {
  5.   // Wrap user register form to use it as form base for our custom form:
  6.   $forms['MY_MODULE_user_register_form'] = array(
  7.     // Use user_register_form as form base:
  8.     'callback' => 'user_register_form'
  9.   );
  10.   return $forms;
  11. }

What we do here is to "create" a custom form with form_id "MY_MODULE_user_register_form" which uses "user_register_form" as base form.

This is the form we'll call in drupal_get_form() in our page callback now to render our wrapped form instead of the user_register_form:

  1. /**
  2.  * Custom user register form page callback.
  3.  */
  4. function MY_MODULE_user_register_form_wrapper_page() {
  5.   $form = drupal_get_form('MY_MODULE_user_register_form');
  6.   return $form;
  7. }

Last but not least we alter our custom form now using hook_form_FORM_ID_alter():

  1. /**
  2.  * Implements hook_form_FORM_ID_alter().
  3.  * Decorated / wraps MY_MODULE_user_register_form.
  4.  */
  5. function MY_MODULE_form_MY_MODULE_user_register_form_alter(&$form, &$form_state, $form_id){
  6.   // Add a custom field to the wrapped form
  7.   $form['example_field'] = array(
  8.     '#type' => 'textfield',
  9.     '#title' => t('Example field'),
  10.     '#required' => TRUE,
  11.     '#weight' => 20,
  12.   );
  13.  
  14.   // Optionally add validation / submit handlers or alter them:
  15.   $form['#validate'][] = 'MY_MODULE_user_register_form_validate';
  16.   $form['#submit'][] = 'MY_MODULE_user_register_form_submit';
  17. }

That's it! Now we've created a separate registration form with form_id "MY_MODULE_user_register_form" which acts like a native Drupal form but is based on user_register_form.
Of course this kind of decorator can be used with every other Drupal form.

The final code:

  1. /**
  2.  * @file Example implementation for decorating / wrapping the user_register_form
  3.  * with a custom form on a custom page.
  4.  */
  5.  
  6. /**
  7.  * Implements hook_menu().
  8.  */
  9. function MY_MODULE_menu() {
  10.   $items['my/custom/form-path'] = array(
  11.     'title' => 'My example form decorator page',
  12.     'page callback' => 'MY_MODULE_user_register_form_wrapper_page',
  13.     'access callback' => 'user_register_access',
  14.     'type' => MENU_CALLBACK,
  15.   );
  16.   return $items;
  17. }
  18.  
  19. /**
  20.  * Implements hook_forms().
  21.  */
  22. function MY_MODULE_forms($form_id, $args) {
  23.   // Wrap user register form to use it as form base for our custom form:
  24.   $forms['MY_MODULE_user_register_form'] = array(
  25.     // Use user_register_form as form base:
  26.     'callback' => 'user_register_form'
  27.   );
  28.   return $forms;
  29. }
  30.  
  31. /**
  32.  * Implements hook_form_FORM_ID_alter().
  33.  * Decorated / wraps MY_MODULE_user_register_form.
  34.  */
  35. function MY_MODULE_form_MY_MODULE_user_register_form_alter(&$form, &$form_state, $form_id){
  36.   // Add a custom field to the wrapped form
  37.   $form['example_field'] = array(
  38.     '#type' => 'textfield',
  39.     '#title' => t('Example field'),
  40.     '#required' => TRUE,
  41.     '#weight' => 20,
  42.   );
  43.  
  44.   $form['#validate'][] = 'MY_MODULE_user_register_form_validate';
  45.   $form['#submit'][] = 'MY_MODULE_user_register_form_submit';
  46. }
  47.  
  48. /**
  49.  * Custom user register form page callback.
  50.  */
  51. function MY_MODULE_user_register_form_wrapper_page() {
  52.   $form = drupal_get_form('MY_MODULE_user_register_form');
  53.   return $form;
  54. }
  55.  
  56. /**
  57.  * Implements hook_form_validate().
  58.  * @see MY_MODULE_user_register_validate()
  59.  */
  60. function MY_MODULE_user_register_form_validate($form, &$form_state){
  61.   // Custom validation for MY_MODULE_user_register_form().
  62. }
  63.  
  64. /**
  65.  * Implements hook_form_submit().
  66.  * @see MY_MODULE_user()
  67.  */
  68. function MY_MODULE_user_register_form_submit($form, &$form_state){
  69.   // Custom submission logic for MY_MODULE_user_register_form().
  70. }

Comments

Post new comment

The content of this field is kept private and will not be shown publicly.

More information about formatting options