I have a set of modules for survey data entry and lab data upload (+parsing) that work fine in Drupal 5.x, with the exception of a very specific issue (I cannot replace form elements during hook_validate and still be able to have the replaced elements render properly). The bug I just described motivated me to migrate to Drupal 6.x, with its form_state['rebuild'] trigger, which seemed just the ticket.

Unfortunately, the survey form is huge and unwieldy, unless themed into a more compact layout. I wrote a hook (theme_cortisol_form) to handle the output of the node creation form (cortisol_form), updated the parameters to everything, fixed all glitches noted by the Coder module, and still I cannot get the theme handler to be fed the form itself. In Drupal 5.x, this was as simple as

...
$form['#theme'] = 'survey_form';
return($form);

And the appropriate magic ensued in theme_survey_form. Alas, even after registering it using

function cortisol_theme() {
$themes = array(
'survey_form' => array(
'arguments' => array('form'),
'function' => 'theme_survey_form',
),
);
return( $themes );
}

It still never gets a copy of the form. By default (I modified some of the core includes in 6.0 to look at this), it just gets theme_node_form (or some variant of same), never the actual theme I specify.

Looking through the Drupal 5.x -> 6.x upgrades and Form API documentation, I don't see any hint of this having changed. Any ideas why declaring the theme for a form no longer does anything?!?

I suppose I could use theme('survey_form',drupal_get_form('cortisol')) or some such, but the method I was using in Drupal 5.x worked fine, and I'd like to figure out why it broke.

I have xDebug running, Devel, Coder, etc. and for the life of me I just can't figure out what' going on here.

Thank you for your input,

--tim

Comments

dvessel’s picture

Are you using hook_form to catch the form? You positive you're passing in the right arguments? From what I understand, there were a few subtle changes. Don't remember the details. I would check with func_get_args from your form and inspect the form that's passed to it. This is assuming hook_form is typically used in these situations. Me not 100%.

Node forms are usually themed by node type, e.g., theme_NODETYPE_node_form falling back to theme_node_form. Both are passed using the new *wild card* feature in 6. Basically passes an array as the theming hook. You might have to array_unshift your theming hook into what's already there.

http://api.drupal.org/api/function/node_form/6

joon park

timtriche’s picture

I looked a little closer and the module in question (I called it 'cortisol' for reasons too boring to discuss) was getting the following array of themes for the form:

array(
[0] => 'cortisol_node_form',
[1] => 'node_form'
);

Therefore, in a fit of laziness unusual even for me, I just registered the same function as the handler for theme_cortisol_node_form as for survey_form. Presto, now it Just Works. And it's prettier than under 5.x, as well. The new API bits are quite nice once a person gets used to them, it's just hard to change once I'm set in my ways.

Thanks for your suggestion -- it is in fact the most practical way to approach the matter. I do think it would help if this change were documented, so I'll try and figure out how to ''patch'' the Form API documentation accordingly. It would be nice if I could pass on the favor to others.

Best regards,

--tim

dvessel’s picture

Great, I'm sure others would appreciate it.

joon park

john.karahalis’s picture

Could you please explain your solution? Maybe you could provide some source code?

I am unable to theme my form in Drupal 6. I think I tried your solution, but it didn't seem to work for me.

yasir farooqui’s picture

I was also looking for a solution to theme my forms in drupal 6. Got a more straight forward solution.

You need to implement hook_theme first, for example

function mymodule_theme() {
	$themes = array(
		'my_form' => array(
			'arguments' => array('form'),
			'function' => 'theme_my_form',
		),
	);
	return( $themes );
}

then

function theme_my_form($form) {
	// generate theme output here
	//return $output;
}

after doing this, you will need to clear you cache by going to admin >> settings >> performance.

I just followed the same steps and it worked for me.

ss81’s picture

Hello yasir farooqui,

Thanks a lot. It works.

Best regards,
Sergei

Best regards,
Sergei

radman16’s picture

You can also use a ".tpl.php" file:
Put this in your template.php file.

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

This would use a file name mytemplate.tpl.php to theme your input and edit forms.

ianchan’s picture

In Drupal 5 the following would select a form template file based on node type:

_phptemplate_callback('forms/' . $form['type']['#value'].'_form', array('user' => $user, 'form' => $form));

how do I replicate this in Drupal 6?

Also, when I use

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

it bypasses phptemplate_preprocess_node_form

Head of Library Technology Initiatives and Development
California State University San Marcos
http://biblio.csusm.edu/

EmanueleQuinto’s picture

Well, assuming the form doesn't add already a theme implementation, you have 2 ways to override the form rendering with hook_theme:

  • function in your template.php
  • file in your template directory

To add a function you can either specify a 'function' value in the array or leave empty (according hook_theme)

function: If specified, this will be the function name to invoke for this implementation. If neither file nor function is specified, a default function name will be assumed. For example, if a module registers the 'node' theme hook, 'theme_node' will be assigned to its function. If the chameleon theme registers the node hook, it will be assigned 'chameleon_node' as its function.

So this is the code:

function MYTHEME_theme($existing, $type, $theme, $path) {
  return array(
    'MYFORM_form' => array(
      'arguments' => array('form' => NULL),
    ),
  );
}

function MYTHEME_MYFORM_form($form) {
  $form['#title'] = 'New form title'; // minimal change but you can do anything here
  return drupal_render($form);
} 

BTW changes like the one above would be better handled on a form_alter hook...

On the other hand if you want to play with a file you should enter a value for the 'template' key:

template: If specified, this theme implementation is a template, and this is the template file without an extension. Do not put .tpl.php on this file; that extension will be added automatically by the default rendering engine (which is PHPTemplate). If 'path', above, is specified, the template should also be in this path.

So the code would be:

function MYTHEME_theme($existing, $type, $theme, $path) {
  return array(
    'MYFORM_form' => array(
      'arguments' => array('form' => NULL),
      'template' => MYFORM,
    ),
  );
}

Then the template file would be MYFORM.tpl.php.

rashad612’s picture

Here is a simple tutorial:
http://drupal.org/node/859392

svergeylen’s picture

Hi yasir farooqui,

I was wondering if anybody can help to get other parameters to the theme_name_form function ?

example : I fill the form variable with the item I want. I call tje theme_name_form with render the form correctly.

How can I have another variable which come from name_form into my theme_name_form() ??

This is what I tried :
in the .module file :

    'macommande_formulaire' => array(
	'arguments' => array('commandes' => array(), 'total_commandes' => null ),
	'file' => 'macommande.page.php',

and in macommande.Page.php

function theme_macommande_formulaire($form) {
	if ($total_commandes) output.= "Yess :-) ";

I assume the second function doesn't know at all about my variable $total_commandes... but how can I pass this value (without a static variable of course ;-) )

Thanks !

Rory’s picture

@yasir farooqui:
Thank you yasir farooqui,

Your directions worked for me!