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

Comments

merlinofchaos’s picture

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');
}

merlinofchaos’s picture

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

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');
}

marcoBauli’s picture

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

Thank you for the precious hint!

alanburke’s picture

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

merlinofchaos’s picture

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.

Anonymous’s picture

Status: Fixed » Closed (fixed)
seanberto’s picture

Status: Closed (fixed) » 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

merlinofchaos’s picture

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

  $form = views_filters_form($view);
  $form = drupal_retrieve_form('views_filters', $view);

And replace this section:

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

with:

  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.

seanberto’s picture

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.

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

seanberto’s picture

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.

dakala’s picture

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:

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);
}
jlee’s picture

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!

tignux’s picture

I have the same errors of jlee

Just to confirm

jlee’s picture

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

Anonymous’s picture

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?

Anonymous’s picture

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

mrgoltra’s picture

subscribing.

Xabi’s picture

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!

dakala’s picture

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.

rinnert’s picture

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:
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:
if(!in_array($option, $filters['value'])) {
into:
if(!in_array($option, array('value'))) {
Than I only get two rows of warning: Invalid argument supplied

rinnert’s picture

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 ;)

// 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);
}
armand0’s picture

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.

jonfhancock’s picture

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:

// 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);
}
Eugene Fidelin’s picture

This code work for me:

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

SocialNicheGuru’s picture

subscribing

ron_s’s picture

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.

big_smile’s picture

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.

^_^

sylv3st3r’s picture

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

upupax’s picture

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

sun’s picture

Title: "Exposed filters" expose too much » HowTo: Limit values in exposed filters
Component: Code » Documentation
Category: feature » task

Could someone please add this to the handbooks?

nicks’s picture

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.

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);
}
doc2@drupalfr.org’s picture

Works great except the ALL option which isn't selected by default.

A feature request for PHP noobs: I have many views using the same filters/exposed filter in the same order. How do I use this code once for them all, please?

BTW, noob may know that the view's name is to take place instead of "browser" in the above-code snippet. And must not be used in the snippet used in template.php.

Still, thank you very much for this great snipet.

eliza411’s picture

Here's another approach that worked for us. It's placed in the custom module we keep for things like this.

It was important for us that when a user chose All, All meant the choices in pick list, not all the items before they were limited. Also, the arguments for the function make it easy to add new views and filters. They're bolded below. The first one is the position of the filter in the Filters (not Exposed Filters) part of the view and the second one is the id of the filter in the HTML. Both start counting at zero. Unfortunately, the All option still isn't selected by default.

<?PHP

/**
* Implementation of hook_form_alter().
*/

if ($form_id == 'views_filters'){
if ($form['#view_name'] == 'NAME OF A VIEW') {
_<YOUR CUSTOM MODULE NAME>_limit_to_defaults($form, 0, 'filter0', array());

}
}

/**
* array - the form we are altering
* int - the number of the filter (not exposed) which holds the default options
* str - name of the filter to limit, ie. filter1
* array - any extra non default options that should be allowed
*/

function _<YOUR CUSTOM MODULE NAME>_limit_to_defaults(&$form, $default_filter_num = 0, $target_filter = 'filter0', $add_enabled_options = array()) {
//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['view']['#value']->filter[$default_filter_num]['value'];

// Add in our extended options if any - '**ALL**' shouldn't probably be added since it has been redefined as the defaults below.
$enabled_options = array_merge($enabled_options, $add_enabled_options);

//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]);
}
}
$options = array_merge(array('' => 'All'), $options);
//Write the updated $options array back into the form
$form[$target_filter]['#options'] = $options;
}

?>

clown10’s picture

I tried more or less all the above, but nothing works for me. There is no change and nothing gets displayed.

I use Drupal 6.4 and views2.

Does this code work for the above configuration?

sun’s picture

@clown10: No, this issue is about Views 1.x on Drupal 5.

clown10’s picture

Ah, too bad, but thats what I thought. But is there a way for D6 and views 2?

upupax’s picture

But is there a way for D6 and views 2?

subscribe this..

merlinofchaos’s picture

Because Views 1.x and 2.x are basically different pieces of software, we're not answering Views 2 questions in a Views 1 thread; it completely pollutes the thread.

lelizondo’s picture

subscribing

lee20’s picture

Subscribing...

zlex’s picture

subscribing...

was there ever any more work done on this issue? I too have several views that would need this applied to them.

goose2000’s picture

Very helpful, thanks people. I am now thinking that I could alter the 'options' as well as limiting them as this thread shows. I'm faced with the problem the CCK user reference displays to the end user a list of usernames (when looking at an exposed filter), and not something friendlier like a last or full name.

I know this was tackled by the RealName module for D6 and Views 2 but not satisfactorily for D5. I think this will help...

esmerel’s picture

Status: Active » Closed (fixed)

No more serious work is going into views 1.