In a project I am working on we are trying to combine the power of a wonderful HTML compliant theme with the flexibility of drupal theme functions.
A requested output was that in specific forms the form elements should look like this : http://drupal.pastebin.com/s16UG4Kn
Whenever you’d like to theme a form you could use the theming function theme_form_element(). This function works wonderful until the moment that you need to switch the theming of all the elements in a specific form. To make it more complicated, the forms are for example the user_register form which is heavily modified.
``` function mytheme_form_element($element, $value) { ```
But apparently you can not switch themes within this function depending on the form_id. You could however add a #theme attribute to all the form elements or a custom variable, both solutions suffice. It’s a matter of handing out responsibilities to the right functions.
After doing numerous tryouts we found the following solution gaining the most satisfaction.
``` /** * Implementation of hook_form_alter(). */ function mymodule_custom_form_alter(&$form, &$form_state, $form_id){ foreach($form as $form_element_name => $form_item ) { //add the form_id to every element if(is_array($form_item) && isset($form_item['#type'])) { $form[$form_element_name]['#mymodule_form_id'] = $form_id; } //we use AHAH helper so whenever an element is rebuild we also need the form_id in this element if(is_array($form_item) && isset($form_item['#type']) && isset($form_item['#ahah'])) { $form[$form_element_name]['#ahah']['mymodule_form_id'] = $form_id; } } } ```
This code might seem a bit abstract but does the following.
- Adds form_id to every element as a custom attribute
- Whenever we use a ahah form element the custom attribute is not added to the rebuilded item. (if someone knows why?) so we also need to add it to the AHAH property as a seperate variable.
Then we can use the following theming function to solve our problem :
``` /** * Return a themed form element. * * @param element * An associative array containing the properties of the element. * Properties used: title, description, id, required * @param $value * The form element's data. * @return * A string representing the form element. * * @ingroup themeable */ function mytheme_form_element($element, $value) { if (isset($element['#mymodule_form_id'])) { $mytheme_form_id = $element['#mymodule_form_id']; } else if(isset($element['#ahah']['mymodule_form_id'])) { $mytheme_form_id = $element['#ahah']['mymodule_form_id']; } switch ($mytheme_form_id) { case 'search_form': return mytheme_form_element_search($element, $value); case 'user_register': return mytheme_form_element_user($element, $value); default: return mytheme_form_element_default($element, $value); } // switch } ```
I hope we can at least help 1 other person by posting these instructions. Thankfully Drupal is powerful enough to allow us to override these functions. Drupal and Nick, we’re still good friends ;-)
If you would know a better way (without adding theme function to every element?) please leave a comment! I am still doubting if this is the way to go but I had to get this out there because it is mostly not so easy to find the more optimal solution.