Styling Drupal 5.x search forms
May 9th, 2007 by darylI’m working on a project that requires me to apply a fancy pants style to a Drupal search form. I thought this would be simple enough, as it’s pretty easy to override default themes for pretty much everything else in Drupal, but it turns out either that I’m a dolt or that there’s not much clarity out there on this topic. After screwing around with a lot of things (e.g. poring over debug_backtrace() output, writing die() statements all over the place, temporarily hacking the search and node modules, etc.), I searched Drupal’s site and found a promising link that turned out not to be the solution I needed (it simply didn’t work).
At long last, I tried creating a theme function named mytheme_search_form(). The search module has a function named search_form(), but in all my hair-pulling, I never saw anything that indicated that you could override this function by prepending your theme name to it (I would have expected to find calls to “theme(’search_form’, $args)” somewhere). At any rate, I ultimately created the above-named function and gave it the following definition:
function mytheme_search_form($form){
return _phptemplate_callback('search_theme_form', array('form' => $form));
}
Then I created a file in my template directory named “search_theme_form.tpl.php” and built a custom form.
Next up was adding additional search fields to the form. To do this, I looked at node.module, where the function node_form_alter() adds fields to the default form. It didn’t seem necessary to jump through that hoop since my form was mostly hard-coded anyway, so I just added some radio buttons with the name “category” so that I could filter search results by taxonomy. Simple enough. But the search never actually filtered on my results. Here I did more hair-pulling and weird debugging. Finally, I went back to the hook_form_alter() functionality, having noticed a “processed_keys” key in the $form array. So to make my form honor my category search, I added the following things to my template.php file. It’s not clear to me how much of this is necessary, and I rather suspect I’m doing something stupid here, but it seems to work and I’m on deadline, so I’m rolling with it.
function mytheme_search_keys($type = null){
$keys = search_get_keys();
if($type){
$keys = search_query_insert($keys, 'type', $type);
}
if($_POST['category']){
$keys = search_query_insert($keys, 'category', $_POST['category']);
}
return $keys;
}
/**
* Taking over this function so that I can call mytheme_search_validate to do the advanced search.
*/
function blog_form_alter($form_id, &$form){
if($form_id == 'search_form'){
$form['#validate']['mytheme_search_validate'] = array();
}
}
/**
* Need to call this to add category to the processed_keys array item so that
* the category actually gets searched in the mini-advanced form we generate
* in mytheme_search_form().
*/
function mytheme_search_validate($form_id, $form_values, &$form){
$keys = $form_values['processed_keys'];
$keys = mytheme_search_keys($form_values['module']);
form_set_value($form['basic']['inline']['processed_keys'], $keys);
}
function faq_search($op = 'search', $keys){
switch($op){
case 'name':
return t('content');
default:
$keys = mytheme_search_keys('faq');
return node_search('search', $keys);
}
}
function forum_search($op = 'search', $keys){
switch($op){
case 'name':
return t('content');
default:
$keys = mytheme_search_keys('forum');
return node_search('search', $keys);
}
}
function blog_search($op = 'search', $keys){
switch($op){
case 'name':
return t('content');
default:
$keys = mytheme_search_keys('blog');
return node_search('search', $keys);
}
}
Now for an explanation. The “mytheme_search_keys()” function is a helper that lets me make sure I’m limiting the search to a given node type. It’s not clear to me that this is absolutely necessary, but things seem not to work if I don’t add the “type:
Next up, blog_form_alter(). The hook_form_alter() functions are associated with modules, so I chose one I knew my site would be using that didn’t have a form_alter hook defined already. It feels kind of hacky, but it seems to work. The idea here is that we need to make the form run a validation function in order to add the keys we’re pulling in from mytheme_search_keys(). It was when I added this code that the category filter actually started working, so it seems to be a crucial bit. The key seems to be adding the keys to the $form['basic']['inline']['processed_keys'] array item, which seems to handle adding the search criteria to the URL and to the search itself.
Finally, I added the three
So, there you have it, the long way around to having a custom-themed Drupal search form with additional filters based on node type and category. Hope this saves somebody a few of the 10 or so hours I spent staring incredulously at my screen as solution after solution failed to work.