This page is about how to create custom layout for your custom form.

Assumptions:

  • Experience with PHP
  • Experience with module writing
  • Experience with theme writing

This document has following structure:

  • Module
    • mymodule.module: function mymodule_menu()
    • mymodule.module: function myformgene()
  • Theme
    • template.php: mytheme_theme()
    • template.php: mytheme_preprocess_myformname()
    • mytemplate.tpl.php

Some strings, functions, etc are prefixed by 'my' to clearly show what you have to define yourself.

During development remember to clear Drupal cache so that it would reread your hooks and theme.

Module

Assume you have created module mymodule. Here you create structure of your form and method of displaying it.

mymodule.module: mymodule_menu()

By default you create menu entry for the form, which further makes structure builder function callback.

function mymodule_menu() {
  return array(
    'mypath' => array(
      'title' => 'My title',
      'page callback' => 'drupal_get_form',
      'page arguments' => array('myformgene'),
      'access callback' => true,
      'type' => MENU_CALLBACK,
    ),
  );
}

This module lets you see the form at

http://myhost/mypath

See also: hook_menu()

mymodule.module: myformgene()

Then you create function which actually defines the structure of your form. It will be called by drupal_get_form().

function myformgene( &$form_state, &$obj ) {
  return array(
    'mysecret' => array(
      '#type' => 'hidden',
      ...
    ),
    'myitem1' => array(
      ...
    ),
    'myitem2' => array(
      ...
    ),
    '#theme' => 'myformname',
  );
}

This form will be themed by identifier myformname.

See also: drupal_get_form(), Forms API reference

Theme

template.php: mytheme_theme()

Announce that your theme handles theming of myformname object.

function mytheme_theme( $existing, $type, $theme, $path ) {
        return array(
                'myformname' => array(
                        'arguments' => array( 'form' => NULL ),
                        'template' => 'mytemplate',
                ),
        );
}

By convention myformname and mytemplate are identical, except usage of _underscores_ in former and -dashes- in latter. For example: my_cool_form becomes my-cool-form.

See also: hook_theme()

template.php: mytheme_preprocess_myformname()

Next you have to do some preprocessing for that form. Specifically you specify which elements you render yourself.

function mytheme_preprocess_myformname( &$vars ) {
  foreach( $vars['form'] as $k => $v ) {
    if( preg_match( '/^[a-z]/', $k ) ) {
      $vars[$k] = $vars['form'][$k];
      unset( $vars['form'][$k] );
    }
  }
}

Usually you want to place visible elements yourself in your theme. If you need only some elements to render yourself, then you have to adjust this function and "manually" unset these.

See also: preprocessing

mytemplate.tpl.php

Lastly, finally, we reach to theming

<table>
  <tr>
    <td> <?php print drupal_render( $myitem1 ); ?> </td>
    <td> <?php print drupal_render( $myitem2 ); ?> </td>
  </tr>
</table>
<?php print drupal_render( $form ); // probably useless ?>

Remember:

  • If your template file is empty (zero length file), then your template will be ignored.
  • If your template contains only
    print drupal_render( $form ); 

    then all elements will be rendered.

  • If you do render some of the fields yourself, then this addition does nothing.

Note that hidden fields and form tags will be added around your form outside of your template, its automatic.
Note that

print drupal_render( $form ); 

DOES NOT print out form tags.

<form ...>
<input type="hidden" ... />
...
your-rendered-template
...
</form>

During development remember to clear Drupal cache so that it would reread your hooks and theme.

Comments

deensdale’s picture

Working with the example above didn't process my _submit function. I solved it by adding the following lines to mytemplate.tpl.php

<?php print drupal_render($form_build_id);?>
 <?php print drupal_render($form_token);?>  
 <?php print drupal_render($form_id );?>