hotel price comparison logic using wordpress posts

Consider a situation, I’ve post meta fields:

  1. Min_Price
  2. Max_Price

So every post has these two fields, and value can be any integer from non zero to 1000.

Read More

Lets take an example:

  1. post #1 min_price = 5; max_price = 100
  2. post #2 min_price = 50; max_price = 150

I’d like to make custom order logics to use with query_posts. So users can select price ranges and see posts with selected values.

Now if I had only 1 price and 1 field, it would be easy to let users select price range and get posts which fall into these range, like so:

query_posts( array(
    'post_type' => 'product',
    'meta_query' => array(
        array(
            'key' => 'price',
            'value' => array( 100, 200 ),
            'compare' => 'BETWEEN',
            'type' => 'numeric',
        )
    )
) );

So here every post with price between 100-200 would be visible.

But I have a range of values… and I thought this would work:

query_posts( array(
    'post_type' => 'product',
    'meta_query' => array(
        array(
            'key' => 'min_price',
            'value' => array( 100, 200 ),
            'compare' => 'BETWEEN',
            'type' => 'numeric',
        ),
            array(
            'key' => 'max_price',
            'value' => array( 100, 200 ),
            'compare' => 'BETWEEN',
            'type' => 'numeric',
        )
    )
) );

Here client selected range 100<->200
Both post #1 and post #2 have values that fall in this range, so visitor will be interested in both of them. Unfortunately my query logic excludes them.

My brain is not working well right now, so I’m missing something simple. Any hints?

Related posts

Leave a Reply

2 comments

  1. I now know your way should work, except McNab is probably right (there are plenty of examples right here: http://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_Parameters) but I’ll let my old answer remain. Someone might find it useful for non-standard stuff.

    I don’t know if you can do this using query post parameters, but I looked it up in the source code and this is how the query looks:

    SELECT $found_rows $distinct $fields 
    FROM $wpdb->posts $join 
    WHERE 1=1 $where 
    $groupby 
    $orderby 
    $limits
    

    And these are filters corresponding to the relevant query variables:

    $where = apply_filters_ref_array('posts_where', array( $where, &$this ) );
    $join = apply_filters_ref_array('posts_join', array( $join, &$this ) );
    

    So that means that the problem can be reduced to SQL:

    function postmeta_join( $join )
    {
        $join .= "
        LEFT JOIN $wpdb->postmeta AS max_price ON max_price.meta_key = 'max_price'
        LEFT JOIN $wpdb->postmeta AS min_price ON min_price.meta_key = 'min_price'";
        return $join;
    }
    
    function filter_prices($where)
    {
        $where .= " AND max_price.max_price BETWEEN 100, 200 AND min_price.min_price BETWEN 100, 200";
        return $where;
    }
    
    add_filter( 'posts_where', 'filter_prices' );
    add_filter( 'posts_join', 'postmeta_join' );
    

    Now I’m not an SQL expert so there may be problems with this. But if you don’t get any other answer, you could play with this. (And BTW, you probably want to remove the filters when you’re done with them.)

  2. What you’ve done should work but you’ve missed the ‘relation’ parameter. It should be;

                    'meta_query' => array(
                        'relation' => 'AND',
                        array(
                            'key' =&gt; 'min_price',
                            'value' =&gt; array( 100, 200 ),
                            'compare' =&gt; 'BETWEEN',
                            'type' =&gt; 'numeric',
                        ),
                            array(
                            'key' =&gt; 'max_price',
                            'value' =&gt; array( 100, 200 ),
                            'compare' =&gt; 'BETWEEN',
                            'type' =&gt; 'numeric',
                        )
                    )
    

    The other thing to note is that in the first instance the meta_id is ‘price’ and in the second you are using ‘min_price’ and ‘max_price’. Have these definitely been set?

    I’m mentioning this because recently I had a hard time on these meta_queries with multiple sub-arrays and the AND relation where the values had been submitted by the user in a form (exactly like my understanding of your question). There was an issue where the query didn’t work where there are null values for items in the array. This is meant to be fixed by scribu;

    http://core.trac.wordpress.org/ticket/18158

    But I could not get this to work at all. Tearing my hair out. I ended up checking the submitted value to see if there was one and then creating the arrays individually. The query would work if either $min_array or $max_array was NULL, but not at all if either of the meta_values was NULL and it was built the way you are doing it. I hope this makes sense, my code is below;

                    if ($min_price) {
                      $min_array = array('key' => 'min_price','value' => $min_price, 'value' => '=', 'type' => 'numeric');
                    }
    
                    if ($max_price) {
                      $max_array = array('key' => 'max_price','value' => $max_price, 'value' => '=', 'type' => 'numeric');
                    }
    
                    'meta_query' => array(
                        'relation' => 'AND',
                        $min_array,
                        $max_array
                    )