HowTo: Limit values in exposed filters

marcoBauli - September 14, 2006 - 14:45
Project:Views
Version:5.x-1.6
Component:Documentation
Category:task
Priority:normal
Assigned:Unassigned
Status:active
Description

Howdy,

IMO "Exposed filters" should expose only entities previously selected in "Filters".

I explain better my point of view:

if admin decides to set as "Filter" a condition like Node: Type Is One Of, and restricts it to only 3 content-types (imagine he has 10 all in all), and then decides to expose this filter to his users, i can see no reason for which users should be able to see again all 10 content-types in the dropdown filter menu.

Same can be true for taxonomy terms, stickyness, or whatever else.. admin already made his decision from backend in "Filter" section, so why then allow users to bypass this decision and choose between all the possible choices of that kind from the site?

Thank you

#1

merlinofchaos - September 14, 2006 - 15:21

The problem, unfortunately, is that the lists could also be used as defaults. Right now there isn't a way for views to explicitly remove those options from the list. The answer is to do it with theming.

<?php
function phptemplate_views_display_filters_VIEWNAME($view) {
$form = views_filters_form($view);
$options = $form['filter1']['#options'];
// some code to remove unneeded options here
$form['filter1']['#options'] = $options;
return drupal_get_form("views_filters_$view->name", $form, 'views_filters');
}

#2

merlinofchaos - September 14, 2006 - 15:28

/me prods Drupal. Hey I properly quoted that. :/ Now i have to write it again. Gr.

<?php
function theme_views_display_filters_VIEWNAME($view) {
 
$form = views_filters_form($view);
 
// filter1 or filter2 or filter3 depending on which filter you need
 
$options = $form['filter1']['#options'];
 
 
// ... code to remove options you don't want ...
  // example
 
foreach ($options as $option => $text) {
    if (!
in_array($option, array('page', 'blog', 'story'))) {
      unset(
$options[$option]);
    }
  }
 
$form['filter1']['#options'] = $options;
  return
drupal_get_form("views_filters_$view->name", $form, 'views_filters');
}
?>

#3

marcoBauli - September 15, 2006 - 10:27

Merlin, this solution should anyway be easy enough for php n00bs anyway

Thank you for the precious hint!

#4

alanburke - September 15, 2006 - 12:40

Top notch tip!

Just to add,
I was playing around with this, with a list of taxonomy terms, and you need to specify the term ids, rather than the term itself, when selecting which terms to show.

Thanks,
Alan

#5

merlinofchaos - October 8, 2006 - 06:36
Status:active» fixed

Going to call this fixed; I've set a post in the views snippets area to link to here. Ideally someone with some more time and/or energy could write this up a little more cleanly for that documentation page, but I figured a placeholder would be better than letting this get lost.

#6

Anonymous - October 22, 2006 - 06:45
Status:fixed» closed

#7

Campsoupster - April 15, 2007 - 20:19
Status:closed» active

There's an inconsistency between the two code blocks - one shows "phptemplate..." the latter "theme..."

In either event, with Drupal 5.1 and the latest version of views, I get a undefined function views_filters_form() error message when I add this code to template.tpl.php. Any suggestions?

This is a great tool. I'm really looking forward to getting it working.

cheers,
sean

#8

merlinofchaos - April 15, 2007 - 23:24

Ahh, what you use for the function name is based upon your theme, it's probably phptemplate_ -- though you can probably also get away with theme_.

In Drupal 5.1, you have to do a little extra work. I *believe* what you need to do is *instead* of using views_filters_form, you need to do this:

Replace this section

<?php
  $form
= views_filters_form($view);
?>

<?php
  $form
= drupal_retrieve_form('views_filters', $view);
?>

And replace this section:

<?php
 
return drupal_get_form("views_filters_$view->name", $form, 'views_filters');
?>

with:

<?php
  drupal_process_form
('views_filters', $form);
  return
drupal_render_form('views_filters', $form);
?>

In fact, this bit solves another problem elsewhere. I need to get a documenter to understand this and write this up sanely.

#9

Campsoupster - April 16, 2007 - 05:35

Hmmm...I tried this in the template.tpl.php for my theme, obviously substituting VIEWNAME for the particular view I'm theming, but it didn't have any effect. I'm no longer getting any errors, but "page" and "blog" are not removed from the exposed filter for node type.

<?php
function phptemplate_views_display_filters_VIEWNAME($view) {
 
$form = drupal_retrieve_form('views_filters', $view);
 
// filter1 or filter2 or filter3 depending on which filter you need
 
$options = $form['filter1']['#options'];

 
// ... code to remove options you don't want ...
 
foreach ($options as $option => $text) {
    if (!
in_array($option, array('page', 'blog', 'story'))) {
      unset(
$options[$option]);
    }
  }
 
$form['filter1']['#options'] = $options;
 
drupal_process_form('views_filters', $form);
  return
drupal_render_form('views_filters', $form);
}
?>

Any ideas? I really do appreciate the help and will keep playing. I'll post if I figure any more out.

-s

#10

Campsoupster - April 16, 2007 - 05:46

Actually, this code did work. I am interested in figuring out how to add the "" option - but this is a good start. Then, I'm also working to figure out how to use this with the views_filter_block module.

#11

dakala - April 21, 2007 - 11:46

Assuming you don't know if the view filter is filter0, filter1 or filter2 etc. or you don't want to enter the filter fields here again. Try this:

<?php
function phptemplate_views_display_filters_VIEWNAME($view) {
 
$form = drupal_retrieve_form('views_filters', $view);
 
 
$view = $form['view']['#value'];
    foreach(
$view->filter as $key => $filters) {
     
$options = $form['filter'. $key]['#options'];
   
    foreach (
$options as $option => $text) {
      if(!
in_array($option, $filters['value'])) {
        unset(
$options[$option]);
      }
    }
   
$form['filter'. $key]['#options'] = $options;
  }
 
 
$form['filter1']['#options'] = $options;
 
drupal_process_form('views_filters', $form);
  return
drupal_render_form('views_filters', $form);
}
?>

#12

jlee - May 18, 2007 - 06:37

dakala - Just wanted to confirm if the above code is working for you on Drupal 5? I get the following errors when pasting the code into template.php (and applying the appropriate VIEWNAME)

# warning: in_array() [function.in-array]: Wrong datatype for second argument in /home/mysite/public_html/themes/mytheme/template.php on line 32.
# warning: Invalid argument supplied for foreach() in /home/mysite/public_html/themes/mytheme/template.php on line 31.

Thanks!

#13

tignux - June 7, 2007 - 13:38

I have the same errors of jlee

Just to confirm

#14

jlee - June 8, 2007 - 02:21

tignuw - I ended up using Comment #9 from Campsoupster to get this to work...

#15

TfR75 - June 21, 2007 - 14:43

Hey - it seems you have developed a solution for my problem! I would love to test this, but I am not 100% sure where to put the php code, i.e. which file would it have to go to into?

#16

TfR75 - June 25, 2007 - 16:28

I have now found the answer (never used template.php before) and can confirm that the code submitted by dakala works for me!

#17

mrgoltra - June 25, 2007 - 23:23

subscribing.

#18

Xabi - June 28, 2007 - 21:30

I'm getting this error with dakala fix:

warning: Invalid argument supplied for foreach() in /var/www/themes/mytheme/template.php on line 67.

Please help! We need this one for 5.x!

#19

dakala - July 29, 2007 - 08:14

The code works for Drupal 5.1 and both Garland and Bluemarine themes. If your theme is phptemplate-based I believe it should work. Cheers.

#20

rinnert - August 30, 2007 - 09:05

alright dakala I tried it with garland and I receive this only when I have changed the:
phptemplate_views_display_filters_VIEWNAME
in the right VIEWNAME

warning: Invalid argument supplied for foreach() in ../public_html/themes/garland/template.php on line 100.
warning: in_array() [function.in-array]: Wrong datatype for second argument in ../public_html/themes/garland/template.php on line 101.
warning: in_array() [function.in-array]: Wrong datatype for second argument in ../public_html/themes/garland/template.php on line 101.
warning: in_array() [function.in-array]: Wrong datatype for second argument in ../public_html/themes/garland/template.php on line 101.
warning: Invalid argument supplied for foreach() in ../public_html/themes/garland/template.php on line 100.

I receive this if I put in:

<?php
   
if(!in_array($option, $filters['value'])) {
?>

a value that is in one of the options of the first exposed filter:
warning: in_array() [function.in-array]: Wrong datatype for second argument blabla and a hondred rows more
I don't know what I have to do more, but could you give me some instructions about what to change to get this work with garland? Thanks in advance
I tried to change:
<?php
    
if(!in_array($option, $filters['value'])) {
?>

into:
<?php
    
if(!in_array($option, array('value'))) {
?>

Than I only get two rows of warning: Invalid argument supplied

#21

rinnert - September 1, 2007 - 08:27

I got it working now, I prefer to filter by term id but don't know how, if somebody knows how please let me know :)
This is what I used and added some comments in it for non php experts ;)

<?php
// template.php in themes/yourtheme directory
// VIEWNAME = The unique identifier of the view
function phptemplate_views_display_filters_VIEWNAME($view) {
$form = drupal_retrieve_form('views_filters', $view);
$view = $form['view']['#value'];

// Enter filter name (you can view this in the source code of the page if your not sure)
$options = $form['filter0']['#options'];

foreach (
$options as $option => $text) {

/*
Enter in array('') the number from it's place inside a '' seperated with a comma for example:
if you have 5 options than the first option has the number 0, the second option number 1 and so on
*/
 
if(in_array($option, array('0', '4', '5'))) { unset($options[$option]); }
}

// Enter the same filter name as above and your finished
$form['filter0']['#options'] = $options;

drupal_process_form('views_filters', $form);

return
drupal_render_form('views_filters', $form);
}
?>

#22

armand0 - September 23, 2007 - 02:42

Thank you, I finally understand something of form_alter().
I see that it is necessary to locate it in template.php. And how to make that it affects certain View and to which Filter.
Now, my question is: How do I make me that an exposed filter only shows the parents of a taxonomy terms?
Conserving the depth of the search.
For example. If in my taxonomy the parents are States and the children are Cities. The filter only shows the States but conserving that when selecting a state and submit, the result it includes the nodes of all the Cities of that State.

#23

jonfhancock - October 4, 2007 - 17:00
Version:4.7.x-1.x-dev» 5.x-1.6

For php n00bs like myself, it may not be completely obvious how to use this method to adjust multiple fields within the same form. Here is how:

<?php
// template.php in themes/yourtheme directory
// VIEWNAME = The unique identifier of the view
function phptemplate_views_display_filters_absense_list($view) {
$form = drupal_retrieve_form('views_filters', $view);
$view = $form['view']['#value'];

// Individual filters go below this line

// Enter your first filter here (in place of filter0)
$options = $form['filter0']['#options'];
foreach (
$options as $option => $text) {
//  Enter the options you want removed from the first filter here encased in ' and separated by commas.
 
if(in_array($option, array('***CURRENT_USER***', '**ALL**', 'admin'))) { unset($options[$option]); }
}
$form['filter0']['#options'] = $options;
// End of first filter adjustment

// Enter your sencond filter here (in place of filter1)
$options = $form['filter1']['#options'];
foreach (
$options as $option => $text) {
// Enter the options you want to remove from the second filter here.
 
if(in_array($option, array('**ALL**', 'event', 'page', 'story'))) { unset($options[$option]); }
}
$form['filter1']['#options'] = $options;
// End of second filter adjustment

// Individual filters go above this line.
drupal_process_form('views_filters', $form);

return
drupal_render_form('views_filters', $form);
}
?>

#24

Eugef - May 29, 2008 - 12:51

This code work for me:

<?php
function phptemplate_views_display_filters_<VIEWNAME>($view) {
 
$form = drupal_retrieve_form('views_filters', $view);
 
$view = $form['view']['#value'];

 
$options = $form['filter!n!']['#options']; //number of exposed filter
 
$filters = $view->filter[!m!]; // number of filter which is correspond to exposed
 
foreach ($options as $option => $value) {

    if (
is_array($value->option)) {
     
$option_id = array_keys($value->option);
     
$option_id = $option_id[0];
      if(!
in_array($option_id, $filters['value'])) {
        unset(
$options[$option]);
      }
    }
  }
 
$form['filter!n!']['#options'] = $options;

 
drupal_process_form('views_filters', $form);
  return
drupal_render_form('views_filters', $form);
}
?>

Replace !n! and !m! with real numbers

#25

activelyOUT - June 7, 2008 - 16:29

subscribing

#26

ron_s - June 12, 2008 - 14:53

I tried using the code in #24 and the code in #11 AND the code in #9 and none of them worked for me in Drupal 5.7. This is what I got to finally work. Please note, I also have added in here a $options[''] = ''; line since I want to have an option of leaving it blank. Just remove this and the asort line if you don't need them.

<?php
function phptemplate_views_display_filters_<VIEWNAME>($view) {
 
$form = drupal_retrieve_form('views_filters', $view);
 
$view = $form['view']['#value'];

 
$options = $form['filter*X*']['#options']; //number of exposed filter
 
$filters = $view->filter[*Y*]; // number of filter which is correspond to exposed
 
foreach ($options as $option => $value) {
    if(!
in_array($option, $filters['value'])) {
        unset(
$options[$option]);
    }
  }
 
$options[''] = '';
 
asort($options);
 
$form['filter*X*']['#options'] = $options;

 
drupal_process_form('views_filters', $form);
  return
drupal_render_form('views_filters', $form);
}
?>

Also note that you must change *X* and *Y* to be the right numbers. The easiest way to figure out which numbers you need is to add the following lines right beneath the $filters = line.

<?php
print '<pre>'; print_r ($options); print '</pre>';
print
'<pre>'; print_r ($filters); print '</pre>';
?>

This will print out to the screen the $options and $filters arrays so you can identify what numbers you need to use.

#27

big_smile - August 23, 2008 - 11:33

Am I correct in thinking that the code in #26 / #24 doesn't require a string of text in template.php that lists the options you want to show (e.g. blog, story)
[where as the code in #2 does require such a string].

I can get the code in #2 to work perfectly in Drupal 5.7 (when using the updates in #8). However, when I try the code in #26, I get a Parse error: syntax error, unexpected '<', expecting ' message. Does anyone have any pointers for how I can overcome this.

^_^

#28

sylv3st3r - August 27, 2008 - 10:17

Simple, just remove <?php from #26 code (p^ ^)---O

#29

upupax - September 1, 2008 - 08:12

what about drupal 6.x and views 2.0? is it ok even for that?

#30

sun - September 20, 2008 - 21:20
Title:"Exposed filters" expose too much» HowTo: Limit values in exposed filters
Component:Code» Documentation
Category:feature request» task

Could someone please add this to the handbooks?

#31

nicks - September 28, 2008 - 17:47

Here's a slightly revised version of #26, which should be slightly easier to understand. Note that this solution (and #26) work by reusing the list of default options as the list of options that should appear to the user. #26 uses $view->filter[*n*]['view'] to obtain this list, whereas I use $form['filter*n*']['#default_value'], since I think this makes the behaviour more explicit.

If you want to set a default that is different from the set of visible options, then simply set the $enabled_options variable to be an array containing the options you want to shown to the user. I think this is probably the preferable way of doing things when using a dropdown box, since a dropdown can't correctly represent the situation where multiple items are selected.

<?php
function phptemplate_views_display_filters_browser($view) {
 
$form = drupal_retrieve_form('views_filters', $view);
 
 
//Each filter in a view has a filter number. Set the target_filter to the one we wish to manipulate
 
$target_filter = 'filter1';
 
//retrieve a copy of the array of options for this filter
 
$options = $form[$target_filter]['#options'];
 
 
// Set the enabled options to be the default options for this field, as set on the Views UI page.
 
$enabled_options = $form[$target_filter]['#default_value'];
 
 
//Also allow the "ALL" field.
 
$enabled_options[] = '**ALL**';
 
 
//Go through each option in turn, disabling it if is not one of the enabled options
 
foreach ($options as $option => $value) {
    if(!
in_array($option, $enabled_options)) {
        unset(
$options[$option]);
    }
  }
 
 
//Write the updated $options array back into the filter1 form
 
$form[$target_filter]['#options'] = $options;
 
drupal_process_form('views_filters', $form);
  return
drupal_render_form('views_filters', $form);
}
?>

 
 

Drupal is a registered trademark of Dries Buytaert.