views module: theming exposed filters
jeff h - August 18, 2006 - 06:12
The exposed filters on my views-created page are contained in a single table row (a design choice which doesn't make a lot of sense to me). So I'd like to modify the HTML generated by the view so that my exposed filter dropdowns and select boxes are presented differently.
Can anyone point me in the right direction? I've read on http://drupal.org/node/42597 the part which says
"This theme function lets you change how the exposed filters are displayed":
<?php
function theme_views_filters($form) {
$view = $form['view']['#value'];
foreach ($view->exposed_filter as $count => $expose) {
$row[] = form_render($form["op$count"]) . form_render($form["filter$count"]);
$label[] = $expose['label'];
}
$row[] = form_render($form['submit']);
$label[] = ''; // so the column count is the same.
return theme('table', $label, array($row)) . form_render($form);
}
?>
...but I don't have a clue how to go about re-coding this so that it doesn't spit out the field elements inside a table row.
Any help much appreciated.
Jeff

Use template.php
Jeff-
You'll want to create a template.php file (at the root of your theme, e.g.
/themes/bluemarine/template.php) and then put a new function in that to override the above function. It should be called phptemplate_views_filters() and contain your own code to generate the form elements:<?phpfunction phptemplate_views_filters($form) {
// my code that does what I want
return $code;
}
?>
As for what you put for 'my code that does what I want'... well, thats up to you, but you'll want to basically create PHP code that prints out the filters in the way that you'd like. Hopefully you know how to code PHP. :-)
David
PHP help needed
Thanks David for your reply. Unfortunately where your instructions end is where I am stuck... I'll look at the PHP functions and see how I go...
Here's how I went...
<?php
function phptemplate_views_filters($form) {
$view = $form['view']['#value'];
foreach ($view->exposed_filter as $count => $expose) {
$label = '<h3>'.$expose['label'].'</h3>';
$formelement = form_render($form["op$count"]) . form_render($form["filter$count"]);
$o .= '<div class="form-element-'.$count.'">'.$label.$formelement.'</div>';
}
$o .= form_render($form['submit']);
return $o . form_render($form);
}
?>
This themes each form element inside its own DIV with a unique class of form-element-x. I got quite a pleasing CSS layout based off this. Would've like something more semantic, but it seems the views module is hardcoding stuff which makes it impossible for now.
Cheers
I've looking for just this. I added the snippet to my template.php and it's much closer to what I'm trying to get. Thanks for the push in the right direction.
a bump in the road
I put the following in my template.php
<?phpfunction phptemplate_views_filters($form) {
$view = $form['view']['#value'];
foreach ($view->exposed_filter as $count => $expose) {
$label = '<div class="form-element-label">'.$expose['label'].'</div>';
$formelement = form_render($form["op$count"]) . form_render($form["filter$count"]);
$o .= '<div class="form-element-'.$count.' form-element-'.$expose['label'].'">'.$label.$formelement.'</div>';
}
$o .= '<div class="form-submit-button">' . form_render($form['submit']) . '</div>';
return $o . form_render($form);
}
?>
I can now arrange the form through css. When I update the veiw with a new filters, the view saves correctly, but I get blank screen and and error in the logs:
Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\themes\mark_two\template.php:19) in C:\xampp\htdocs\includes\common.inc on line 266.Any ideas?
when I've had this error
I've been outputting something twice.
e.g. some test code that's printing out the same variable as a module function.
Hope that helps
.Ben
Further refinements?
Very cool snippet - much better than the table code views uses at the moment.
One thing I'd suggest to make this snippet more semantic / accessible would be using label tags instead of the div to enclose the form elements textual label
<?phpfunction phptemplate_views_filters($form) {
$view = $form['view']['#value'];
foreach ($view->exposed_filter as $count => $expose) {
$label = '<label class="form-element-label">'.$expose['label'].'</label>';
$formelement = form_render($form["op$count"]) . form_render($form["filter$count"]);
$o .= '<div class="form-element-'.$count.' form-element-'.$expose['label'].'">'.$label.$formelement.'</div>';
}
$o .= '<div class="form-submit-button">' . form_render($form['submit']) . '</div>';
return $o . form_render($form);
}
?>
Anyone know of a away to associate the label with the appropriate form element by matching the labels for attribute and form items id?
Nesting?
You can nest input elements inside a label element.
<label>My textfield<input type="text" name="feedMe" /></label>works for me
jeff's code worked for me. a much better layout of the exposed filters - and it fixed a line problem i was having with some themes and exposed views.
form_render() - trouble
<?php
function phptemplate_views_filters($form) {
$view = $form['view']['#value'];
foreach ($view->exposed_filter as $count => $expose) {
$label = '<h3>'.$expose['label'].'</h3>';
$formelement = form_render($form["op$count"]) . form_render($form["filter$count"]);
$o .= '<div class="form-element-'.$count.'">'.$label.$formelement.'</div>';
}
$o .= form_render($form['submit']);
return $o . form_render($form);
}
?>
Pasted this code in template.php, but it gave me
Fatal error: Call to undefined function form_render() in my_site_path/my_theme/template.php on line 6
after clicking on my view...seems its in "form_render()"-function trouble...how to resolve this?
Bad English from me? ;)
form_render
drupal_render instead of form_render?
drupal_render
drupal_render did indeed get this code working for me, with form_render I was getting a blank screen on my views pages.
Is there a way to easily place 3 filters in a row
Jeff's code does work great, but if I have 6 filters, they are listed one on top of the other in one column (thus 6 rows). Is there a way I could easily modify the code above to place, let's say, 3 filters in a row (3 colunns per row)? Thanks for any assistance.
any luck on this?
Hi,
Have you had any luck in figuring this out? I am trying to clean the look of my exposed filter and I in the same boat as you. What I am trying to achieve is an advanced search look. Back to the forum and keep on looking.
Thank you,
Mark
This is how I have done it
This is how I have done it to have my exposed filters in 2 columns:
function phptemplate_views_filters($form) {
$view = $form['view']['#value'];
$number_exp_filters = count($view->exposed_filter);
$i = 0;
$output='<table border="0">';
foreach ($view->exposed_filter as $count => $expose) {
$i++;
$label = '<div class="form-element-label">'.$expose['label'].'</div>';
$formelement = drupal_render($form["op$count"]) . drupal_render($form["filter$count"]);
$filter ='<div class="form-element-'.$count.' form-element-'.$expose['label'].'">'.$label.$formelement.'</div>';
if ($i % 2 == 0) {
$output .= '<td width="50%">'.$filter.'</td></tr>';
}
else
{
$output .= '<tr><td width="50%">'.$filter.'</td>';
}
}
if ($number_exp_filters % 2 != 0) {
$output .= '<td></td></tr>';
}
$output .= '<tr><td colspan="2">' . '<div class="form-submit-button">' . drupal_render($form['submit']) . '</div>' . '</td></tr>';
$output .= '</table>';
return $output . drupal_render($form);
}
hi have been using the code
hi
have been using the code you came up with, and it works very well. One question, how would you make 4 columns rather than 2? Ive tried changing all the 2's to 4's and it just breaks! My PHP is a bit bad! Would you be able to help?
function phptemplate_views_filters($form) {
$view = $form['view']['#value'];
$number_exp_filters = count($view->exposed_filter);
$i = 0;
$output='<table border="0">';
foreach ($view->exposed_filter as $count => $expose) {
$i++;
$label = '<div class="form-element-label">'.$expose['label'].'</div>';
$formelement = drupal_render($form["op$count"]) . drupal_render($form["filter$count"]);
$filter ='<div class="form-element-'.$count.' form-element-'.$expose['label'].'">'.$label.$formelement.'</div>';
if ($i % 2 == 0) {
$output .= '<td width="50%">'.$filter.'</td></tr>';
}
else
{
$output .= '<tr><td width="50%">'.$filter.'</td>';
}
}
if ($number_exp_filters % 2 != 0) {
$output .= '<td></td></tr>';
}
$output .= '<tr><td colspan="2">' . '<div class="form-submit-button">' . drupal_render($form['submit']) . '</div>' . '</td></tr>';
$output .= '</table>';
return $output . drupal_render($form);
}
Thank you for that piece of code
I just wanted to tell you how grateful I am for that piece of code!
My first time to deal not only with modules and customizations but to insert code and only it worked from all the other!
Thank you :)
use CSS
I did this by using CSS to float my DIVs appropriately. With this method you could, for example, float them all left, and give them all a width of 1/3 of your content area. You'll then get two rows of three columns.
Jeff
I could do something
My view is called "vista" and I used the method you wrote, but with little modifications.
I think the code could be optimized because there's a little redundancy (I think) but it's something like this:
<?php
function phptemplate_views_filters($form) { //this call overrides all views filters so I need a condition
$view = $form['view']['#value'];
if ($view->name == 'vista'){ //so I used the view's name, in this case the view I want to do refactoring is 'vista'
foreach ($view->exposed_filter as $count => $expose) {
$row[] = drupal_render($form["op$count"]) ;
$box[] = drupal_render($form["filter$count"]);
$label[] = $expose['label'];
}
$row[] = drupal_render($form['submit']);
$label[] = ''; // so the column count is the same.
$title = $view->page_title;
return _phptemplate_callback('views-filters-vista', array('title' => $title, 'row' => $row, 'box' => $box, 'label'=>$label));
// I use a callback to a tpl called views-filters-vista.tpl.php
}
else{ // in the case it isn't 'vista' it goes through the normal flow as defined in views.module
foreach ($view->exposed_filter as $count => $expose) {
$row[] = drupal_render($form["op$count"]) . drupal_render($form["filter$count"]);
$label[] = $expose['label'];
}
$row[] = drupal_render($form['submit']);
$label[] = ''; // so the column count is the same.
// make the 'q' come first
return drupal_render($form['q']) . theme('table', $label, array($row)) . drupal_render($form);
}
}
?>
aaaand, views-filters-vista.tpl.php is:
<table><tr>
<td width="100">
<?php echo $label[0] . ': '; ?>
</td>
<td width="200">
<?php echo $row[0]; ?>
</td>
<td>
<?php echo $box[0]; ?>
</td>
</tr>
<tr>
<td>
<?php echo $label[1] . ': '; ?>
</td>
<td>
<?php echo $row[1]; ?>
</td>
<td>
<?php echo $box[1]; ?>
</td>
</tr>
<tr>
<td colspan="3" align="right">
<td>
<?php
echo $row[2]; //the submit button
?>
</td>
</tr>
</table>
ps: sorry if I beat my English :-P
This doesn't work...
For me. I did a search and replace on vista with the name of my view, but the results are that I'm missing one of my filters and the Submit button.
What I really need is simple for this specific need (until views makes the display of exposed filters easy to customize within itself).
I have 3 exposed filters, on is a drop down box and the other two are free-tagging. The two free-tagging boxes are way to long and push the bar off the edge of the page. Is there a way to make the boxes shorter?
I'm sure it's defined in a bit of code somewhere, but I have no idea where to start looking for it.
Thanks,
David
http://www.floridapets.org
PS - never mind, I'm a schmuck. I figured it out. Now I just need to clean it up a bit more for my tastes.
Oops
I spoke too soon. So with the code I stole from you I got my view looking correct. here it is:
<?php
function phptemplate_views_filters($form) { //this call overrides all views filters so I need a condition
$view = $form['view']['#value'];
if ($view->name == 'catalog_frontpage'){ //so I used the view's name, in this case the view I want to do refactoring is 'catalog_frontpage'
foreach ($view->exposed_filter as $count => $expose) {
$row[] = drupal_render($form["op$count"]) ;
$box[] = drupal_render($form["filter$count"]);
$label[] = $expose['label'];
}
$row[] = drupal_render($form['submit']);
$label[] = ''; // so the column count is the same.
$title = $view->page_title;
return _phptemplate_callback('views-filters-catalog_frontpage', array('title' => $title, 'row' => $row, 'box' => $box, 'label'=>$label));
// I use a callback to a tpl called views-filters-catalog_frontpage.tpl.php
}
else{ // in the case it isn't 'catalog_frontpage' it goes through the normal flow as defined in views.module
foreach ($view->exposed_filter as $count => $expose) {
$row[] = drupal_render($form["op$count"]) . drupal_render($form["filter$count"]);
$label[] = $expose['label'];
}
$row[] = drupal_render($form['submit']);
$label[] = ''; // so the column count is the same.
// make the 'q' come first
return drupal_render($form['q']) . theme('table', $label, array($row)) . drupal_render($form);
}
}
?>
AND
<table>
<tr>
<td colspan="3">Please use the filters to search for what you're looking for</td>
</tr>
<tr>
<td width="20">
<?php echo $label[0] . ': '; ?>
</td>
<td width="40">
<?php echo $row[0]; ?>
</td>
<td>
<?php echo $box[0]; ?>
</td>
</tr>
<tr>
<td width="20">
<?php echo $label[1] . ': '; ?>
</td>
<td width="40">
<?php echo $row[1]; ?>
</td>
<td>
<?php echo $box[1]; ?>
</td>
</tr>
<tr>
<td width="20">
<?php echo $label[2] . ': '; ?>
</td>
<td width="40">
<?php echo $row[2]; ?>
</td>
<td>
<?php echo $box[2]; ?>
</td>
</tr>
<tr>
<td colspan="3" align="left"><?php
echo $row[3]; //the submit button
?>
</tr>
</table>
But when I submit a search I end up on the front page with this in my address bar:
http://www.technospider.com/~david/drupal5/?filter0=**ALL**&filter1=Xenesthis&filter2=So I don't know if it's just not filtering right or what, those are my filters but no results == I don't know what to do now.
Thanks,
David
http://www.floridapets.org
More than one view
Now the question is, how would you do more than one views form. I have several that I wish to reformat the exposed filters, and you can only use this function once, correct?
dirty but could work
You could create your view with all the exposed filters you want. Then you look at the HTML source that drupal creates.
you'll find:
<form id="views-filters" method="get" action="your_views_path/">Then you can create a php block that builds a custom form with all the variables that your form (filter) expects. Hide the default form with css (display: none).
Its a hacky way to create completely customized filter forms.
Simple and optimised way to theme exposed filters
Hi there,
Based on the previous code, I optimised it to theme exposed filters :
<?phpfunction phptemplate_views_filters($form) { //this call overrides all views filters so I need a condition
$view = $form['view']['#value'];
foreach ($view->exposed_filter as $count => $expose) {
$row[] = drupal_render($form["op$count"]) ;
$box[] = drupal_render($form["filter$count"]);
$label[] = $expose['label'];
}
$row[] = drupal_render($form['submit']);
$label[] = ''; // so the column count is the same.
$title = $view->page_title;
return _phptemplate_callback('views-filters-'.$view->name, array('title' => $title, 'row' => $row, 'box' => $box, 'label'=>$label));
}
?>
The code callback a views-filters-$my_view_name.tpl.php file, if the file don't exist or is empty the _phptemplate_callback execute the default code, so it's useless to create an if() condition to do that.
So, to theme your exposed filters as you want, you only need to create a views-filters-$my_view_name.tpl.php file in your template folder.
Optimized way not working
I like your cleaner example here - but for me it is not working for exposed filters that do not have a template file -> for those filters there is nothing rendered.
help?
Great
I use the method above and it works great. Here's the code
function phptemplate_views_filters($form) { //this call overrides all views filters so I need a condition
$view = $form['view']['#value'];
if ($view->name == 'change_this_to_your_view_name'){ //so I used the view's name, in this case the view I want to do refactoring is 'vista'
foreach ($view->exposed_filter as $count => $expose) {
$row[] = drupal_render($form["op$count"]) ;
$box[] = drupal_render($form["filter$count"]);
$label[] = $expose['label'];
}
$row[] = drupal_render($form['submit']);
$label[] = ''; // so the column count is the same.
$title = $view->page_title;
return _phptemplate_callback('views-filters-directorio_funcionarios', array('title' => $title, 'row' => $row, 'box' => $box, 'label'=>$label));
// I use a callback to a tpl called views-filters-vista.tpl.php
}
else{ // in the case it isn't 'vista' it goes through the normal flow as defined in views.module
foreach ($view->exposed_filter as $count => $expose) {
$row[] = drupal_render($form["op$count"]) . drupal_render($form["filter$count"]);
$label[] = $expose['label'];
}
$row[] = drupal_render($form['submit']);
$label[] = ''; // so the column count is the same.
// make the 'q' come first
return drupal_render($form['q']) . theme('table', $label, array($row)) . drupal_render($form);
}
}
I changed a little the tpl.php file to my need: Very importante, you need to rename the file: views-filters-yourviewname.tpl.. It shows, 6 filters in 2 rows and 3 cols.
<table width="700" border="0" cellspacing="0" cellpadding="0"><tr>
<td colspan="3">Help text here..</td>
</tr>
<tr>
<td width="33%"><strong><?php echo $label[0] . ': '; ?><?php echo $row[0]; ?></strong></td>
<td width="33%"><strong><?php echo $label[1] . ': '; ?><?php echo $row[1]; ?></strong></td>
<td width="33%"><strong><?php echo $label[2] . ': '; ?><?php echo $row[2]; ?></strong></td>
</tr>
<tr>
<td width="33%"><?php echo $box[0]; ?></td>
<td width="33%"><?php echo $box[1]; ?></td>
<td width="33%"><?php echo $box[2]; ?></td>
</tr>
<tr>
<td width="33%"><strong><?php echo $label[3] . ': '; ?><?php echo $row[3]; ?></strong></td>
<td width="33%"><strong><?php echo $label[4] . ': '; ?><?php echo $row[4]; ?></strong></td>
<td width="33%"><strong><?php echo $label[5] . ': '; ?><?php echo $row[5]; ?></strong></td>
</tr>
<tr>
<td width="33%"><?php echo $box[3]; ?></td>
<td width="33%"><?php echo $box[4]; ?></td>
<td width="33%"><?php echo $box[5]; ?></td>
</tr>
<tr>
<td colspan="3"><?php
echo $row[6]; //the submit button
?></td>
</tr>
</table>
<p> </p>
Thanks for the method.
Now how do you get the highlights with views_savefilter
I have 10 exposed filters, so this was a godsend, as prior to implementing this code (the simpler version above), they merely disappeared off the right edge of the page. So thank you to everyone!
BUT (you knew there was a 'but' coming, didn't you? ;-) I'm also using the views_savefilter module. Now here's the kicker. On views where this modification is not done, with the views_savefilter module installed, when I return to a view, the choices are highlighted in the filter multi-select list boxes. However, once I've implementing this rendering, those highlights are gone, even though the views_savefilter is doing exactly what it's supposed to do (which is read the saved-filter from the last time, and modify the view's underlying query to return the same result set). So, the question is, how do I get those choices highlighted using this rendering technique?
Any help would be wildly appreciated!
This code only submits if I
This code only submits if I have a text field contains filter, but when I use filters that are taxonomies or node references, the submit button does not do anything....odd behavior. Any ideas?
Views Filters Multiselect Boxes as Checkboxes
Does anyone have an idea how this function could be used to display checkboxes instead of multiselect fields?
form_alter
This theme function isn't really the right place to be doing that type of modification. I think the Form Tweaker module may do that for you if it's a taxonomy list you're talking about, but if that's not what you're after, it should be done in a custom module with a form_alter function.
Jeff
Check out
Check out http://drupal.org/node/122261. Perhaps here is part of your answer.
Keep exposed filters in row, but...
What if you wanted to keep the exposed filters in a row, but change table alignment/width/padding of the box they sit in? I tried to figure it out but I can't... maybe it's something simple, like making a css class?
I would love some help with this if anyone has ideas.
mosa
Much simpler then described here! Enjoy!
Actually, changing the width of filter fields or label of the submit button is much simpler then described here.
Simply enable the 'devel' module, print the form values with
dprint_r($form), find the values you'd like to change, and change them. Then call the regular callback function to do the rest of the stuff for you.<?php/* Change the width of filter fields and the label of the submit button on the 'board' form */
function phptemplate_views_filters($form) {
if ($form['#view_name'] == 'board') {
$form['filter2']['#size']=15;
$form['filter3']['#size']=15;
$form['submit']['#value']='חפש';
}
return theme_views_filters ($form);
}
?>
I've added this as a views snippet: http://drupal.org/node/220200
Enjoy!
Amnon
-
Professional: Drupal Israel | Drupal Development & Consulting | Eco-Healing | Effective Hosting Strategies | בניית אתרים
Personal: Hitech Dolphin: Regain Simple Joy :)
what is the solution for drupal 6 filter form themes?
can you throw some light on themeing drupal 6 views filter forms.
No submit button
Hi,
When I use exposed filters, I get no submit button.
What am I doing wrog?
can someone help please?
Look above at how I changed the filter submit button
Look above at how I've modified the filter submit button.
Initially, I got no submit botton when I tried to change the label of the button to be Hebrew but didn't save my file in UTF-8.
I'm trying to modify my
I'm trying to modify my exposed views to show on more than one line.. right now I have like 8 exposed views on one view page and they all appear on the same line which extends past my page's normal content area so it looks terrible and I can't use this many exposed views until I can get it to display, for example, 4 exposed views per line.
I would appreciate if anyone who knows php could tell me how I can use the above code to make my exposed views show on multiple lines. Thanks
I'm trying to do something a
I'm trying to do something a little more complex, but I think everyone would use this feature.
I'm trying to get the exposed filter to show the number of nodes that will be shown, if a user exposes the filter.
Example:
Pretend we are narrowing down a taxonomy field that contains colors.
Current: Blue, Green, Purple, Yellow
Desired: Blue 22, Green 25, Purple 3, Yellow 9
My guess is we need to override the function in template.php, to include the count... no?
this is what i was looking for
subscribing
subscribing
subscribing