views:

216

answers:

3

I have a module that builds a form that includes a fieldset. Instead of using the <legend> element to render the fieldset title, I want to place this content in a <div> element instead. But I want to change the behavior only for the form returned by my module, so I don't want to place any new functionality into my theme's template.php file.

In mymod.module I have defined:

// custom rendering function for fieldset elements
function theme_mymod_fieldset($element) {
  return 'test';
}

// implement hook_theme
function mymod_theme() {
  return array(
    'mymod_fieldset' => array('arguments' => array('element' => NULL)),
    'mymod_form' => array('arguments' => array())
  );
}

// return a form that is based on the 'Basic Account Info' category of the user profile
function mymod_form() {
  // load the user's profile
  global $user;
  $account = user_load($user->uid);

  // load the profile form, and then edit it
  $form_state = array();
  $form = drupal_retrieve_form('user_profile_form', $form_state, $account, 'Basic Account Info');

  // set the custom #theme function for this fieldset
  $form['Basic Account Info']['#theme'] = 'mymod_fieldset';

  // more form manipulations
  // ...

  return $form;
}

When my page gets rendered, I expected to see the fieldset representing 'Basic Account Info' to be wholly replaced by my test message 'test'. Instead what happens is that the <fieldset> and <legend> elements are rendered as normal, but with the body of the fieldset replaced by the test message instead, like this:

<fieldset>
  <legend>Basic Account Info</legend>
  test
</fieldset>

Why doesn't my #theme function have the chance to replace the entire <fieldset> element? If I wrap a textfield in this function instead, I am able to completely replace the <input> element along with its label. Furthermore, if I provide an override in my site's template.php for theme_fieldset, it works as expected and I am able to completely replace the <fieldset>, so I know it is possible.

What's different about providing #theme functions to fieldsets inside a module?

A: 

This is just off the top of my head but maybe the difference is because a fieldset is not a form element but just a seperator or a grouper, if you will. Maybe the #theme callback is only for form elements?

Amar Ravikumar
The callback is called, but it seems that it can only render the contents of the fieldset, and not the fieldset element itself. So basically, if I copy and paste the original definition of theme_fieldset into my custom #theme function, I get a fieldset embedded inside a fieldset. Not what I was hoping for :(
Rob Crowell
A: 

The concept of your code works, meaning you can do what you want to do.

There are some things that can explain why it doesn't work.

  • The fieldset is not $form['Basic Account Info'].
  • Need to clear cache.
  • $form['Basic Account Info']['#theme'] is lost/overridden later in the code execution.

Try to take a look at $form before you do any of the moderations. When I tried to copy your code I run into a bug:

  • user.pages.inc file needed to be loaded
googletorp
A: 

Have you tried overriding theme_fieldset() instead of using the #theme function? I believe you could do something like this in your .module file:

function mymodule_fieldset($element) {
  // do something;
  return $html;
}

This would apply to all fieldsets. You could do some kind of check on $element for the fieldsets you want to affect and then use the default implementation for all others.

Take a look at: http://api.drupal.org/api/function/theme_fieldset/6