3

In Drupal 7 you can take a theme function and override it.

For example if I want to override theme_form_element, I would place it in my template.php as MYTHEME_form_element.

The only problem is that I then have to copy the entire theme function into my template. For example, for theme_form_element, there is over 60 lines of code.

This seems overkill, if I only want to do something simple as add a class to the attributes array.

Is there any way to only include the part of the theme function I want to override and tell Drupal to refer to the rest of the built in function?

5

If you need to change the content of the variables passed to the theme function, then you can simply implement a preprocess function for that theme, which in Drupal 7 is invoked for every theme function, including the ones not using a template file.
In the case of theme_form_element() the preprocess function for your theme is MYTHEME_preprocess_form_element().

You could also avoid duplicating the code of theme_form_element(), and call it before, but in that case you should call it directly as theme_form_element(), not as theme('form_element') (which would cause an infinite loop).

The problem with theme_form_element() is that it doesn't use $element['#attributes']['class'] to set the attributes of the form element. It uses a local variable that is initialized with the following code, which passes its value to drupal_attributes().

  $attributes['class'] = array('form-item');
  if (!empty($element['#type'])) {
    $attributes['class'][] = 'form-type-' . strtr($element['#type'], '_', '-');
  }
  if (!empty($element['#name'])) {
    $attributes['class'][] = 'form-item-' . strtr($element['#name'], array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
  }
  // Add a class for disabled elements to facilitate cross-browser styling.
  if (!empty($element['#attributes']['disabled'])) {
    $attributes['class'][] = 'form-disabled';
  }
  $output = '<div' . drupal_attributes($attributes) . '>' . "\n";

To add a new class to the form element, you have two alternatives:

  • Copying the code from theme_form_element() to your theme function, and editing it
  • Call theme_form_element() from your theme function, and add a new class to the output returned from theme_form_element() using preg_replace().
  • Thanks for your help, but I am having the same problem as with Clive's code (see my comment above). I'd appreciate it if you could offer any pointers, if possible. Thanks! – big_smile Feb 10 '13 at 19:03
  • I apologize: I missed the part saying you wanted to add a class. I have updated my answer. – kiamlaluno Feb 10 '13 at 20:27
  • preg_replace() is not an alternative.... – gagarine Jan 26 '15 at 10:25
3

If you're just adding a class to the attributes array a template_preprocess hook would be sufficient, and stop you having to copy the entire thing, e.g.

function MYTHEME_preprocess_form_element(&$vars) {
  $vars['attributes']['class'][] = 'another-class';
}

If you need to add a wrapper around the outer element you can do something like this

function MYTHEME_form_element($vars) {
  $original = theme_form_element($vars);
  return '<div class="something">' . $original . '</div>';
}

But if you need to add an extra attribute to an internal element of that theme function, you'll need to copy the whole thing over. PHP offers no way to pick a section of a function to run, it's all or nothing.

  • Thanks for your help! I've tried your code, but it doesn't seem to add the class. I have tried several modifications of the code and have found something interesting that happens when I use this code: function THEMENAME_preprocess_form_element(&$variables) { $variables['element']['#attributes']['class'] .= ' myclass'; kpr($variables); } With this code, the new class doesn't appear in the HTML, but it does appear in the KPR Message (when using Devel). I'd apperciate any ideas you can offer so I can make the class appear in the HTML. – big_smile Feb 10 '13 at 19:02
  • Sorry I didn't check the theme function beforehand, this was more of a general response. The $attributes array is actually initialised in theme_form_element itself so in this case there's no way to override it without overriding the whole theme function I'm afraid – Clive Feb 10 '13 at 19:05

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.