Well, this has been a long and unproductive weekend with major frustration in trying to accomplish what "should" be a simple task in Drupal 6.
I posted a couple of issues over the weekend related to the problem as it evolved from Friday night to Saturday, even ending up on Sunday spending some time in the IRC channel searching for the answer.
The related issues on drupal.org are 497636 and 497530. The issue itself was not easily apparent in my initial work on the Taxonomy Rockstar module. What I'm trying to accomplish at this point is only laying down code for the backend interface, and the API that will allow developers to extend the modules using an easy API to create new layout types and search filters for taxonomy presentation.
The Real Problem
At first the problem seemed to be related to my hook_theme function and somehow it not sending the appropraite $element to the function I created for theme_checkboxes.
The Related Code
hook_theme()
I'm removing as much code as I can for the brevity of this post, but will do my best to explain the issue in better terms than I have in either of the posts on Drupal.org.
The above code is in my hook_theme, in this case named taxonomy_rockstar_theme(). It is declaring that a theme function named theme_tr_layout_checkboxes resides in taxonomy_rockstar.theme.inc. Simple enough. It also declares the "element" argument to be applied and passed to the function as it would by default.
theme_tr_layout_checkboxes($element)
krumo($element);
6">drupal_set_message('using <strong>theme_taxonomy_rockstar_layout_checkboxes()</strong>');
$class = 'tr-layout-checkboxes';
if (isset($element['#attributes']['class'])) {
$class .= ' '. $element['#attributes']['class'];
}
$element['#children'] = '<div class="'. $class .'">'. (!empty($element['#children']) ? $element['#children'] : '') .'</div>';
if ($element['#title'] || $element['#description']) {
unset($element['#id']);
return 6">theme('form_element', $element, $element['#children']);
}
else {
return $element['#children'];
}
}
This function for the purposes of my testing is exactly the same as the default theme_checkboxes function with the additions of krumo($element) and a drupal_set_message() call at the top to do some debugging.
The Form element
'#type' => 'checkboxes',
'#theme' => 'tr_layout_checkboxes',
'#title' => 6">t('Available Layouts'),
'#description' => 6">t('You may choose to enable/disable layouts that are by default enabled by sub modules, and exclude them from the specific vocabulary setting pages. This will prevent admins from selecting one of those layout options for a vocabulary, AND will not allow it to be chosen by users who have the ability to modify the filter/interface. <em>If NO options are selected here, it will be assumed you do NOT want to filter these layout types</em>'),
'#required' => FALSE,
'#default_value' => 6">variable_get('tr-used-layouts', array()),
'#options' => taxonomy_rockstar_generate_layouts(),
);
In the above call, using the #theme declaration, the form element "is" or "should" be told to use my custom theme function declared in hook_theme to render the group of checkboxes. What happens with the above code is that the $element is being passed, however, the #children associated with the element are not being rendered. In this case, the checkboxes are not being generated in the array.
What DOES work.... sort of....
hook_theme
The Form element
'#type' => 'checkboxes',
'#title' => 6">t('Available Layouts'),
'#description' => 6">t('You may choose to enable/disable layouts that are by default enabled by sub modules, and exclude them from the specific vocabulary setting pages. This will prevent admins from selecting one of those layout options for a vocabulary, AND will not allow it to be chosen by users who have the ability to modify the filter/interface. <em>If NO options are selected here, it will be assumed you do NOT want to filter these layout types</em>'),
'#required' => FALSE,
'#default_value' => 6">variable_get('tr-used-layouts', array()),
'#options' => taxonomy_rockstar_generate_layouts(),
);
What happens here in this "working" example is that I'm now telling this to apply to all the checkboxes, and not just my custom ones. I'm using the exact same function to render them, BUT excluding the #theme declaration in the $form element.
This does work, but does not have the desired effect, as I shouldn't be forced to use my function on EVERY implementation of theme_checkboxes.
In some previous work for a client, I had the same issue, but didn't spend much time debugging or looking for a better solution. I in that work, had a very defined path to work with, and could inside my theme function determine the current path, and either use my custom theme code, or call the default if it wasn't on my path.
More information from IRC
<DamZ> himerus: yes, it is not easy to do that in Drupal 6
<DamZ> himerus: '#theme' is the "internal" theme function, while '#type' is the "external" one
<DamZ> himerus: you cannot easily override the external one in Drupal 6
<himerus> I'm blowing my mind on it, and there are no examples of it on the element level. If I let my theme_checkboxes apply to every checkbox creating, it's fine. only when I try to get it to apply just where I need it does it give issue
<DamZ> chx: hey you ;)
<DamZ> himerus: yes, that's because you are not overriding the correct function
<DamZ> himerus: if you set #theme, you will be passed the full $element array, and you will have to render the children yourself
<DamZ> himerus: after that, you will probably want to set #type to 'markup', to avoid the "external" theme function to kick in
<himerus> DamZ: ahhhhh that makes SO much more sense than before. so using #theme essentially overrides everything normally done to the element?
<DamZ> himerus: the rendering workflow is: (1) use #theme to render child elements, or simply call drupal_render() in each child if #theme is not set, (2) use #type to render the enclosing element (and its children)
<DamZ> himerus: we know that this is very confusing, and is already fixed in D7 ;)
<himerus> gotcha... thanks, I think I can run with that
<himerus> DamZ: I was very sad to not find any example of using #theme except on the root of the form. so I've been running circles around core trying to figure it out. Thank you!
<DamZ> himerus: for reference, the central function for that is drupal_render()
<DamZ> himerus: but its flow is not that simple
Conclusion
So at this point, I'm still completely baffled at the issue despite getting some better direction from DamZ in the IRC chat. I was really at the point I was so frustrated on what should be a simple theme implementation using the "Drupal Way" with the appropriate hook and theme functions.
However, at least with the information I have now, I have an alternative path to research, and if it appears to be too much, I will scratch it up to the "I DONT CARE GODS" and just do it in some hackish way to solve the problem for now....
I will post more information on the solution or a decent workaround as I come across it tomorrow once I'm back to the grindstone.


kind of solution for your problem
I would like to thank you for this post. I had the same quesion of theming drupal form elements and your article had helped me to understand basic principles for that.
Trying to repeat your example I've encountered the same problem as you. Even more: I couldn't manage to use your workaround. The possible reason is that I'm doing my first project with Drupal (and third project in web-developing).
So it took a whole night to make it work the way i need. Here is my theme_uc_bmcustoms_theme_checkbox:
$output = '';
foreach (element_children($checkboxes) as $option){
$output .= '';
$output .= drupal_render($checkboxes[$option]);
$output .= '';
}
return $output;
}
Hope it helps,
SAVEL
Post new comment