7

I am looking for easy ways to theme the user profile form that will allow me to setup a two-column layout for the form and exclude certain elements.

How can I achieve it?

2
  • I created this question for two reasons: First, because it took me a while to figure out my personal method for solving this problem and wanted to save others grief. Second, to see if anybody else has a better way of theming not only the user_profile_form but forms in general. I'll post links to good questions about form theming as I see them; others are welcome to do the same.
    – areynolds
    Sep 2 '11 at 19:34
  • The Drupal documentation on theming node forms is a good place to start for general instruction on form theming: drupal.org/node/1092122
    – areynolds
    Sep 2 '11 at 19:35
7

Aside from using the Display Suite module, most methods for theming forms require a bit of code to be written. In the following method I define variables from the form that can be outputted in a template file to fit whatever HTML structure you'd like. I put all of my code in template.php, but you can just as easily make a custom module to do this.

  1. Add a hook_theme() implementation

    function YOURTHEME_theme($existing, $type, $theme, $path){
      return array(
        'user_profile_form' => array(
          'render element' => 'form',
          'template' => 'user-profile-form',
          'path' => drupal_get_path('theme', 'YOURTHEME') . '/templates', 
          //add '/templates' only if you store template files in an additional folder
        ),
    
      );
    }
    

    This tells the Drupal theming system that there's a template file waiting for it in YOURTHEME/templates.

  2. Next we'll define some variables to pass into that template in a hook_preprocess_HOOK function. We can find the structured array of the form in $variables['form'] and assign the form elements to the variables we'd like to throw around our tpl.php file.

    function YOURTHEME_preprocess_user_profile_form(&$variables) {
      $form_inputs = array(
        'account' => $variables['form']['account'],
        'picture' => $variables['form']['picture'],
        'actions' => $variables['form']['actions'],
      );
      $variables['rendered'] = _YOURTHEME_form_variables_render_all($form_inputs);
    }
    
    function _YOURTHEME_form_variables_render_all($elements) {
        //Create array to return, with element name as key and element as value
        $elements_array = array();
        //For each element, render it and add it to the array
        foreach ($elements as $key => $element) {
            $elements_array[$key] = render($element);
        }
        //Return array
        return $elements_array;
    }
    

    This example will put the general account info fields, the user picture upload field (if pictures are enabled), and the submit actions into a variable called "rendered."

  3. Now that we have defined these variables, we can output them in a template file. Create a template file named user-profile-form.tpl.php in 'YOURTHEME/templates'. This is a demo example:

    <div id="new-form">
      <?php echo $rendered['picture']; ?>
      <?php echo $rendered['account']; ?>
      <?php echo $rendered['actions']; ?>
      <input type="hidden" name="form_id" value="<?php print $form['#form_id']; ?>" />
      <input type="hidden" name="form_build_id" value="<?php print $form['#build_id']; ?>" />
      <input type="hidden" name="form_token" value="<?php print $form['form_token']['#default_value']; ?>" />
    </div>
    

Notice the hidden form fields at the end; these include vital Drupal tokens that help secure forms from attack. Your form won't work without them.

When you visit your user edit page, you should now see only some general account info fields and the picture fields. Create different variables in the preprocess function to separate out form elements and place them wherever you wish in the user-profile-form.tpl.php file, adding whatever markup you like.

4
  • Is there a reason you're avoiding Display Suite Forms? Jun 18 '12 at 2:32
  • 1
    It's been so long I honestly don't remember. I do think that the ability to output forms in a template file (while still having the power of the Forms API to generate powerful, secure forms in backend code) is a big win for flexibility and code separation; much closer to the MVC model Drupal should aspire to.
    – areynolds
    Feb 4 '13 at 3:59
  • Come on, Drupal is not MVC nor should it be. Check garfieldtech.com/blog/mvc-vs-pac (although that post is quite old, it still helps to clear up things). Feb 4 '13 at 11:52
  • 1
    True that, saying that it "should aspire to" an MVC paradigm is definitely just an opinion (and I like the article, by the way). I guess my point isn't that Drupal should follow strict MVC guidelines, but rather that template files often provide themers with little Drupal experience more flexibility than learning another abstraction layer (DS) or a Drupal API. I think that viewpoint is gaining credence; I'm looking forward to a much simpler presentational layer in D8 with the Twig initiative. Code like this is basically just a silly hack to get there.
    – areynolds
    Feb 4 '13 at 16:57
1

Display suites can only be used for the display, not for editing. It were great, if it could handle both.

1
  • Display suite 7.x can be used to edit user edit forms. In a limited way.
    – Druvision
    Oct 15 '13 at 16:12
0

Some fixes for areynolds's code:

Underscore fix in 'render element

function YOURTHEME_theme($existing, $type, $theme, $path){
  return array(
    'user_profile_form' => array(
      'render element' => 'form',
      'template' => 'user-profile-form',
      'path' => drupal_get_path('theme', 'YOURTHEME') . '/templates', 
      //add '/templates' only if you store template files in an additional folder
    ),

  );
}

Fix preprocess function from data overriding (account->picture) and adding action elements (form button).

function YOURTHEME_preprocess_user_profile_form(&$variables) {
  $required_elements[]=$variables['form']['account'];
  $required_elements[]=$variables['form']['picture'];
  $required_elements[]=$variables['form']['actions'];
  $variables['rendered'] = drupal_render($required_elements);
}

But all this manipulations give only appearance of the form. But the form won't work properly as it requires other elements such as validate, submit handlers, etc. So I think the best way to hide unrequired elements in $variables['form'] array leaving all necessary form metadata.

1
  • Thanks @ACD for getting me back here to review my old noob code. I've made the corrections you've suggested and added a couple more refinements (namely, making sure that the form tokens are actually included). Not quite sure how or if this code ever did work; it might have displayed a form, but shouldn't have been able to submit.
    – areynolds
    Feb 4 '13 at 4:02
0

Panels can fully take over the Profile edit form and with a handful of patches (currently) you can pull in Profile2 info as a Panels relationship.

Your Answer

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

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