Views filter items by price range.

Profile picture for user Phil Frilling
By Phil Frilling, 31 January, 2012
Today I needed to create a view the filtered items by a range of prices. The prices for these nodes were stored in a CCK number field. After searching for an easy 'plug and play' method of doing this I quickly began writing my own code to accomplish this task. To summarize, I accomplished this by using the following functions:
  • hook_form_alter()
  • hook_views_query_alter()

Step 1.

Begin by creating your view and adding your CCK number field as an exposed filter. You'll want to be sure that you use the 'is between' operator. You can leave the Min and Max fields blank.

Step 2.

Using hook_form_alter, alter the exposed filter form and change the current form:
[field_price_value] => Array
        (
            [#tree] => 1
            [min] => Array
                (
                    [#type] => textfield
                    [#title] => 
                    [#size] => 30
                    [#default_value] => 
                )

            [max] => Array
                (
                    [#type] => textfield
                    [#title] => And
                    [#size] => 30
                    [#default_value] => 
                )

        )
to become a 'select' field.
[field_price_value] => Array
        (
            [#tree] => 1
            [min] => Array
                (
                    [#type] => textfield
                    [#title] => 
                    [#size] => 30
                    [#default_value] => 
                )

            [max] => Array
                (
                    [#type] => textfield
                    [#title] => And
                    [#size] => 30
                    [#default_value] => 
                )

            [#type] => select
            [#options] => Array
                (
                    [] => All Prices
                    [1-50000] => Under $50,000
                    [50001-100000] => $50,000 to $100,000
                    [100001-150000] => $100,000 to $150,000
                    [150001] => Over $150,000
                )

            [#multiple] => 
            [#size] => 1
            [#default_value] => All
        )
Set your options array to be the range of prices you would like separated by dashes.

Step 3.

Next I used hook_views_query_alter() to alter the query of this view. My function looks like this:

function MYMODULE_views_query_alter(&$view, &$query){
  // Check your view ID here.  
  if ($view->vid == 1) {
      // Check to see if your exposed filter has a value.
      if(isset($_GET['field_price_value'])) {
        // If a value exists, turn it into an array using the dash as a separator.
        $prices = explode('-', $_GET['field_price_value']);
        switch ($prices[0]) {
          // Check your beginning prices and 
          case 1:
          case 50001:
          case 100001:            
            // Remove the last two pricing elements.
            array_pop($query->where[0]['args']);
            array_pop($query->where[0]['args']);
            
            // Add the correct prices to the args.
            array_push($query->where[0]['args'], $prices[0]);
            array_push($query->where[0]['args'], $prices[1]);
          break;
          case 150001:
            // Remove the last clauses and add our own.
            array_pop($query->where[0]['clauses']);
            array_pop($query->where[0]['clauses']);
            array_push($query->where[0]['clauses'], 'node_data_field_price.field_price_value >= %f');
            
            // Remove the last two pricing elements.
            array_pop($query->where[0]['args']);
            array_pop($query->where[0]['args']);

            // Add the correct prices to the args.
            array_push($query->where[0]['args'], $prices[0]);     
          break;
        }
      }
    }
}
Basically, you end up removing the last two arguments from the queries where clause and then re-adding them with the array_push() function. For the last item we remove the where clauses altogether and only add the greater than clause back to the query. PLEASE NOTE: The code above only works when the exposed filter is the LAST one in your list of filters.