5

I have a project where I've created a View with some basic information, showing for example Year, Manufacturer, Product Type. They are all custom text fields. I can expose a filter on them which lets me manually enter in a search, for example, 2008 for year and it correctly shows me all the entries for 2008.

Is there any way to have these fields available as a dropdown selection based on the content saved within each node, eg so that the Year field shows 2001, 2002, 2003 ..... 2012 etc, or Product Type shows "Table, Chair, Lamp etc" that the user can choose from? I'm fairly new to using Views and struggling to find an answer.

I'm using Drupal 7 and Views 3.3.

5 Answers 5

4

The problem here is that the fields are custom text fields. If the "product type" field was of the type "List (text)" instead it would be a drop down in Views when exposed.

Maybe the product type would be good to have as taxonomy terms instead? Then product types could easy be added to the vocabulary as the site grows. The field in your content type would then be a "Term reference" to the Taxonomy vocabulary product type. If the product types rarely or never change you could stick with "List (text)"

I would probably make the field year into a date field or taxomomy, or list (integer).

I hope you see where I am trying to go here, the fields needs to be of the correct type for Views to be able to interpret the fields correctly and "automatically" give you dropdowns when the filters are exposed etc.

1
  • Thanks for that - I've just had a bit of a 'Doh' moment! When looking in Views I had tried using the List (text) field but when it showed me the option for 'Select List' I stupidly took it to mean select an option in that dropdown, which of course was only giving me the checkbox option. Hadn't realised 'Select List' was an option itself. Got it all working for now :)
    – user9363
    Commented Aug 17, 2012 at 15:50
2

If you would like to write a module for this task, you could solve the problem as follows. I adapted this code from here.

Create a module directory in sites/all/themes/modules and name it custom_exposed_year_filter.

Create a file custom_exposed_year_filter.info containing the following:

; custom_exposed_year_filter.info
name = Custom Exposed Year Filter
description = Sorts exposed years filter into a dropdown instead of a textfield
core = 7.x
files[] = custom_exposed_year_filter.module

Then, create a file named custom_exposed_year_filter.module and insert this code:

<?php
// custom_exposed_year_filter.module

function custom_exposed_year_filter_form_views_exposed_form_alter(&$form, &$form_state) {
    $field_id = 'field_reference_year_start';

    // Only alter forms with the necessary field
    if (isset($form[$field_id . '_value'])) {
        // Build a query to get all node ids having the specified field
        $query = new EntityFieldQuery();
        $results = $query->entityCondition('entity_type', 'node')
                ->fieldCondition($field_id, 'value', 'NULL', '!=')
                ->fieldOrderBy($field_id, 'value', 'ASC')
                ->execute();

        // Attach the field values to the nodes
        $nodes = $results['node'];
        field_attach_load('node', $nodes, FIELD_LOAD_CURRENT, array('field_id' => $field_id));

        // Add a default so the filter is optional
        $options = array('' => '<select>');

        // Buld the options array based on the query results, overwriting duplicate entries
        foreach ($nodes as $node) {
            $value = $node->{"$field_id"}['und'][0]['value'];
            $options[$value] = $value;
        }

        // Alter the field
        $form[$field_id . '_value']['#type'] = 'select';
        $form[$field_id . '_value']['#options'] = $options;
        $form[$field_id . '_value']['#size'] = 1;
    }
}

Lastly, adjust the following line so it matches the name of the field that you would like to filter for:

$field_id = 'field_your_field_name';

Then, clear the cache, enable your new module in Drupal, create a filter for your field, and check the 'exposed' box to make the filter available to visitors.

Should you need to turn multiple filters into dropdowns, you might adapt the code above or just create multiple modules for each field.

You might run into performance problems if you have a very large number of items in your view. It works like a charm for me, though.

2
  • This worked great for me!
    – Kirkland
    Commented Mar 15, 2016 at 20:29
  • You don't need the line files[] = custom_exposed_year_filter.module
    – mbomb007
    Commented Jan 7, 2020 at 19:52
2

I had a list of manufacturers from several countries and I wanted to add an exposed filter with all countries found in that manufacturers list. I followed a similar approach in anthonygore's solution above (thanks mate!) but with a hook_views_exposed_form_alter in template.php:

function your-theme_form_views_exposed_form_alter(&$form, &$form_state){

if ($form['#id'] == 'your-form-id') {

// query distinct field values for all nodes in content type

$query = db_select("field_data_your-exposed-views-filter-field}", 'f');
$options = $query
  ->fields('f', array('your-exposed-views-filter-field_value'))
  ->condition('entity_type', 'node')
  ->condition('bundle', 'fornecedor')
  ->orderBy('your-exposed-views-filter-field_value', $direction = 'ASC')
  ->distinct()
  ->execute()->fetchCol();
  }

// Create an assoc array with equal keys and values from the query array

$result = array_combine($options, $options);

// Add the option "All" to the array

$result = array_merge(array('All' => '- Any -'), $result);

// Convert the textfield exposed filter to a select list

$form['your-exposed-views-filter-field']['#type'] = 'select';
$form['your-exposed-views-filter-field']['#size'] = 'null';

// Update the form options with the query array

$form['your-exposed-views-filter-field']['#options'] = $result;


// Important! Remove "An illegal choice has been detected. Please contact the site administrator." error. More info at https://www.drupal.org/node/1177882#comment-8891105 
$form['your-exposed-views-filter-field']['#validated'] = true;

} 
1
  • Thanks for the tip with "An illigal choice...". I would spend ages to look for the solution for this issue.
    – David
    Commented May 24, 2017 at 14:17
0

I had a problem where I need to filter blog posts by created date, but the date field in Views would only show a range e.g. -10 years to 0 years.

The problem with this is that would show years where their were no blog posts e.g. lets say there were no posts in 2007, you'd still have it as an option.

The solution to filter out unneeded years is as follows:

  1. In the exposed filter form there will be a field for date e.g. $form['date_value']. It should have a processing callback, in my case it was $form['date_value']['value']['#process'][0] = 'date_select_element_process'.
  2. Make an alter hook on the callback e.g. mymodule_date_select_process_alter(&$element, $form_state, $context)
  3. Query your nodes with EntityFieldQuery() to figure out which years are in use by your existing nodes
  4. Filter your list of dates accordingly e.g. unset($element['year']['options'][2007]);

Here's an example implementation

/**
 * Implements hook_date_select_process_alter().
 */
function mymodule_date_select_process_alter(&$element, $form_state, $context) {

  if (!empty($context['form']['#id'])) {

    // Check to ensure we're modifying the correct exposed form
    if ($context['form']['#id'] == "views-exposed-form-blog-page-1") {

      // Query the blog nodes to see which dates we have
      $field_id = 'field_date';
      $query = new EntityFieldQuery();
      $results = $query
        ->entityCondition('entity_type', 'node')
        ->entityCondition('bundle', 'blog')
        ->fieldCondition($field_id, 'value', 'NULL', '!=')
        ->fieldOrderBy($field_id, 'value', 'ASC')
        ->execute();

      // Attach the field values to the nodes
      $nodes = $results['node'];
      field_attach_load('node', $nodes, FIELD_LOAD_CURRENT, array('field_id' => $field_id));

      // Build the options array based on the query results
      $options = array('' => "-Year");

      foreach ($nodes as $node) {
        $value = $node->{"$field_id"}['und'][0]['value'];
        $date = DateTime::createFromFormat("Y-m-d H:i:s", $value);
        $year = $date->format("Y");
        $options[$year] = $year;
      }

      // Add the filtered options back to the element
      $element['year']['#options'] = $options;
    }
  }
}
-1

Found a solution. Worked for me.Check it here. http://bryanbraun.com/2013/08/06/drupal-tutorials-exposed-filters-with-views

1
  • 2
    That doesn't solve the problem; it's just a very basic tutorial for how to use View Filters. Commented Jun 15, 2015 at 23:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.