5

while googling and reading documentation and API, I've seen multiple solutions for "combining" 2 forms into one, and thus creating a multistep form.

What I want though, not even sure if it's doable, is to "split" my (huge) user registration form into 2 steps, where the value of one field (the only one in step 1) would determine which fields should show up in step 2.

I wouldn't like to drop the entire registration form and re-create it in code or in another way and somehow re-implement the whole user registration process. Is that possible?

EDIT: to avoid misunderstandings, what I need to do is an "actual" multistep form, with submitions between steps, and not some front-end handling. That is, I want the whole thing to be javascript independant.

EDIT2: to clarify even further, the task is figure out how/if possible to pretty much split any "edit" form to 2 parts. The current question does ask about the user/edit and/or user/register form specifically, but in order to come up with a more generalized solution, one might also want to split a node/edit form in to 2 parts. That's what I am really asking about. Splitting an entity/edit form in to 2 (or more) steps.

6 Answers 6

2

One way to do this would be to use the Conditional Fields module (disclaimer: noted as not ready for production for D7). The way to do it with your own code would be to use the States API (the Conditional Fields module is just a GUI to States API, basically).

Using Conditional Fields, you can set it so that, for example, based on the value selected for Field A, a number of fields would be shown or not shown as per your requirements.

EDIT: To split the form into two steps, you can use the Field Group module, which provides a "multipage steps" feature. To configure this, you will need to create a fieldgroup of type multipage for each page you want to have on the user registration form, and then place the appropriate fields under each page (on the user account manage fields screen).

Note: The Conditional Fields and Field Group module will display everything as one giant page if Javascript is disabled. I don't know any way around this.

10
  • That answers part of the question. How would I go about splitting the "user_register_form" into 2 parts?
    – user5005
    Feb 12, 2013 at 12:39
  • That javascript thing is one of the reasons I am doing it the "hard" way instead of just abusing jquery to make the form meet the requirements. Furthermore, would the multistep thingy also apply to the user edit form? Cause a multistep edit form is highly undesirable. If yes, do you reckon I could tweak this with form_alter and remove the multistep functionality if the form is the edit form?
    – user5005
    Feb 12, 2013 at 12:47
  • Yeah... Just tried the fieldgroup thingy. It's just my "jquery approach" made easy. I want an "actual" multi-step form for my requirements :/ Any ideas on that?
    – user5005
    Feb 12, 2013 at 13:08
  • 3
    user_register_form and user_profile_form are two completely different functions, altering one won't alter the other...
    – Clive
    Feb 12, 2013 at 14:18
  • 2
    btw, wanted to add a +1 for the "Field group" module. Even though it's Javascript based, it fits my personal description of what Javascript should do… it adds functionality to the page without breaking the page for non-Javascript-enabled users (progressive enhancement). It doesn't work in all cases (the OPs question being a case in point), but it's a nice tool to keep in your toolkit.
    – thirdender
    Feb 12, 2013 at 18:29
1

Take a look at the Profile2 module. When I first encountered it, I was a little confused about its purpose and why 18k+ sites found it so useful :-p Turns out it is great for storing and organizing user information when you have many fields associated with each user.

The Profile2 module creates and maintains new profile entities attached to user accounts. For the uninitiated, in Drupal 7 an entity is a set of information, usually with fields attached. Nodes are entities, users are entities, relations are entities, etc. Profile entities behave similar to new nodes, except that they are attached to user accounts. Users are able to edit their profiles on a separate page from the actual account page, or as part of the account page itself (depending on the settings you choose).

For your project, here's what I'd recommend:

  1. Install and enable Profile2. This automatically creates a new default "Main" profile.

  2. Edit the settings for the "Main" profile at admin/structure/profiles/manage/main. Uncheck "Show during user account registration" and check "Provide a separate page for editing profiles".

  3. Add the additional user fields you want at admin/structure/profiles/manage/main/fields. If there are still more fields than should be stored and edited on a single page, create an additional profile type at admin/structure/profiles/add, or use Field group (Javascript based) to break the form down into groups.

  4. Install and enable Rules. Create a Rule that directs new user accounts to the profile edit page: profile-main/[account:uid]/edit. If you needed additional profiles to break down the form further, add additional Rules directing the user to those pages by reacting to the event "After saving a new profile".

Rule export code:

{ "rules_direct_new_accounts_to_profile_edit_page" : {
    "LABEL" : "Direct new accounts to profile edit page",
    "PLUGIN" : "reaction rule",
    "REQUIRES" : [ "rules" ],
    "ON" : [ "user_insert" ],
    "DO" : [ { "redirect" : { "url" : "profile-main\/[account:uid]\/edit" } } ]
  }
}

This has the benefit of being able to separate the account settings (e-mail, username, password) from the information about the user (the profile fields). Using this configuration, you can achieve the desired multi-step user registration form without writing a line of code. The only caveat that you should be aware of is that a user can leave the workflow after creating an account without creating a profile (even though Rules automatically directs them to the profile edit page, there's nothing keeping them from clicking a link to another part of the site). Additional Rules may be necessary to require the user to complete the profile before using the rest of the site.

1
  • Thanks for your reply. Yes I know about profile2 but my model is pretty complex already and adding an extra entity layer in the whole thing could potentially lead to undesired complexity. Furthermore, if you want, read my "EDIT2" part of the question to get more into the spirit of what I am trying to achieve :)
    – user5005
    Feb 13, 2013 at 10:18
1

Have you looked into the Chaos Tools form wizard implementation found here. I have done something similar for a registration form following those instructions and integrating some profile2 fields in the multistep form as well. Had to create a custom module that had the page callbacks and also handled the form fields. I can get into more detail about how I handled it if this is a path you're wanting to follow.

1
  • I've looked into that. That would require me to re-implement the whole user_register_form and split it accordingly. What I want is to split the form itself into 2 steps. The form itself is created by the fields attached to the user entity.
    – user5005
    Feb 13, 2013 at 10:14
0

Here's a totally different approach to adding an "actual" multi-step form that may or may not work for you. I did something similar to the following on a site I built.

On this site, users had four possible roles. They could have any combination of the roles: all 4, none, or role A and B but not C and D, etc. Each role has its own set of associated profile fields that should only be shown to users of that role.

On the user registration form, I allowed users to select their roles with checkboxes. Then, using the Rules module, I awarded the roles upon account registration to each user. I also used Rules to automatically created a set of nodes for each user upon account registration. These nodes are special content types that contain the profile questions for each role. They are linked to the user account via the Relation module.

Then, I built a set of views and laid out the user profile with the Panels module so that it shows the fields from the different nodes for the roles on the user profile page. This was a very complex set up, but it allows me to give users separate edit links to the different parts of their profile, ensures that only users with the appropriate role will be asked to fill in certain parts of the profile, and works without Javascript.

3
  • Indeed very complex, and smart. But unfortunatelly I don't think my requirements are that complex to go with your solution. What I came up with was to use hook_menu, and replace the /user/register path with a markup containing 2 links, each adding an argument to the URL, and according to the argument, produce the form in the "correct state" with prepopulated values and/or hidden fields.
    – user5005
    Feb 12, 2013 at 13:49
  • @magtak Sure, no problem if your requirements aren't that complex-- I wouldn't have gone with this solution unless I had to. If you found a solution, please go ahead and add that as the answer yourself and accept that. Feb 12, 2013 at 13:50
  • I am not sure that's correct Patrick since I actually use a trick to avoid the "actual" multistep implementation. I will however describe my solution after I've tested it.
    – user5005
    Feb 12, 2013 at 14:18
0

I'm just starting in Drupal and working on something similar but I have not really pursued it - I used the Workflow module what it does is I am able to add a (workflow) field to the registration form to link to another view. There maybe some issues on the data but I was thinking that all I had to do was play around with the registration state (promote it). As mentioned I am just a beginner and I have not really seen this working in totality. but I think you should look into this as a possible solution.

0

a. for multistep node form, use msnf. it works great! b. for creating multistep (server side) user registration i haven't found any module to fit my needs so i had to do it myself. here's what i did:

my setup: email_registration + ife + asaf

/**
 * Implements hook_form_FORM_ID_alter().
 */
function custom_form_user_register_form_alter(&$form, &$form_state, $form_id) {
    // initialize step
  if (empty($form_state['step'])) {
    $form_state['step'] = 1;
  }

    // adjust form for step 1
  if ($form_state['step'] == 1) {
        // hide default submit button
    $form['actions']['submit']['#access'] = FALSE;
        // add custom button
    $form['actions']['next'] = [
      '#value' => 'Next step',
      '#type' => 'submit',
      '#validate' => [
                // step 1 validation callback
        '_custom_user_register_form_step1_validate',
                // only if you use ife
        'ife_form_validator'
      ],
            // step 1 submit callback
      '#submit' => ['_custom_user_register_form_step1_submit'],
            // limit validation only for fields below
      '#limit_validation_errors' => [
                // add all fields that should be validated in step 1
        ['field_phone'],
        ['mail'],
      ],
    ];

        // hide all fields that belong to step 2
    $form['field_age']['#access'] = FALSE;
  } else if ($form_state['step'] == 2) {
        // hide fields that belong to step 1
    $form['field_phone']['#access'] = FALSE;
    $form['account']['#access'] = FALSE;
        // limit validation only for fields below
    $form['actions']['submit']['#limit_validation_errors'] = array(
            // add all fields in step 2
      array('field_age'),
    );

        // add custom validation callback for step 2
    $form['#validate'][] = '_custom_user_register_form_step2_validate';
        // only if you use ife
    $form['actions']['submit']['#validate'][] = 'ife_form_validator';

        // add custom submit
    array_unshift($form['#submit'], '_custom_user_register_form_step2_submit');
  }
}

and the callbacks:

function _custom_user_register_form_step1_validate(&$form, &$form_state) {
  // validate here
}

function _custom_user_register_form_step1_submit(&$form, &$form_state) {
  // increase step
  $form_state['step'] = 2;
  // store step 1 values for later use
  $form_state['storage'] = $form_state['values'];
  // rebuild form
  $form_state['rebuild'] = TRUE;
}

function _custom_user_register_form_step2_validate(&$form, &$form_state) {
  // validate here
}

function _custom_user_register_form_step2_submit(&$form, &$form_state) {
  // add values from $form_state['storage'] to $form_state['values'] 
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy