Custom post type search using $_SESSION and pre_get_posts

I’ve been hacking all day at a custom post type search/filter system. So far I have this:

function kdev_property_query($query) {

if(isset($_POST['rooms_n'])) $_SESSION['rooms_n'] = $_POST['rooms_n'];
if(isset($_POST['univer'])) $_SESSION['univer'] = $_POST['univer'];
if(isset($_POST['area_t'])) $_SESSION['area_t'] = $_POST['area_t'];

$query_post_type = $query->query_vars["post_type"];

if( !is_post_type_archive( 'properties' ) || $query_post_type == 'nav_menu_item' ) return;

//Show all available properties
$query->set('posts_per_page','-1');

$meta_query = array();
$tax_query = array();

global $query_string;
if(isset($_SESSION['rooms_n'])) $room_query = $_SESSION['rooms_n'];
if(isset($_SESSION['univer'])) $uni_query = $_SESSION['univer'];
if(isset($_SESSION['area_t'])) $area_query = $_SESSION['area_t'];

if(isset($room_query)) {
    $meta_query[] = array(
        'key' => '_rooms',
        'value' => $room_query
    );
}

if(isset($uni_query)) {
    $tax_query[] = array(
        'taxonomy' => 'university',
        'field' => 'slug',
        'terms' => $uni_query
    );
}

if(isset($area_query)) {
    $tax_query[] = array(
        'taxonomy' => 'area',
        'field' => 'slug',
        'terms' => $area_query
    );
}


if( ! empty( $meta_query ) )
        $query->set( 'meta_query', $meta_query );
if( ! empty( $tax_query ) )
        $query->set( 'tax_query', $tax_query );


}

add_action('pre_get_posts', 'kdev_property_query', 1);

I use the following form to search:

Read More
function display_area_university_filter_form(){
?>
<div id="search-filters">
<form method="post" action="">
<h3 id="property-search"><span>property search</span></h3>

<?php
    if(isset($_SESSION['univer'])) $uni = $_SESSION['univer'];
    else if(is_tax( 'university' ) ) $uni = get_query_var( 'term' );
    if(isset($uni)) $uni = strtolower($uni);?>
<p><label for="univer">University:</label> <select name="univer"><option value="NULL">Any</option>
<?php 
    $uni_terms =  get_categories('taxonomy=university'); 
    if (isset($uni)){
        foreach ($uni_terms as $term) {
            $option = '<option value="'.$term->slug.'"';
            if ($uni == $term->slug){
                $option.= ' selected="selected"';
            }
            $option .= '>'.$term->name;
            $option .= '</option>';
            echo $option;
        }
    }else{
        foreach ($uni_terms as $term) {
            $option = '<option value="'.$term->slug.'"';
            $option .= '>'.$term->name;
            $option .= '</option>';
            echo $option;
        }
    }
?>
</select>
</p>
<input type="hidden" name="custom_filter" value="area_uni">

<p>

    <?php
    if(isset($_SESSION['area_t'])) $area = $_SESSION['area_t'];
    else if(is_tax( 'area' ) ) $area = get_query_var( 'term' );
    if(isset($area)) $area = strtolower($area);?>
    <label for="area_t">Area:</label> 

    <select name="area_t">
        <option value="NULL">Any</option>
    <?php 
        $area_terms =  get_categories('taxonomy=area'); 
        if (isset($area)){
            foreach ($area_terms as $term) {
                $option = '<option value="'.$term->slug.'"';
                if ($area == $term->slug){
                    $option.= ' selected="selected"';
                }
                $option .= '>'.$term->name;
                $option .= '</option>';
                echo $option;
            }
        }else{
            foreach ($area_terms as $term) {
                $option = '<option value="'.$term->slug.'"';
                $option .= '>'.$term->name;
                $option .= '</option>';
                echo $option;
            }
        }
    ?>
    </select>
</p>

<p>
<?php 
if(isset($_SESSION['rooms_n'])) $rooms = $_SESSION['rooms_n'];

?>
    <label for="rooms_n">Bedrooms:</label> 
    <select name="rooms_n">
        <option value="NULL">Any</option>
        <?php 
        $room_array = array(3,4,5,6,7);
        foreach($room_array as $no) {
        $output = '<option ';
        if(isset($rooms) && $rooms == $no) $output .= 'selected="selected" ';
        $output .= 'value="'.$no.'">'.$no.'</option>';
        echo $output;
        } ?>

    </select>
</p>


<p><input class="<?php if(is_archive()) echo 'new-search '; ?>button" type="submit" name="search_props" value="<?php if(is_archive() || is_post_type_archive('properties')) echo 'New '; ?>Search"></p>

</form>
</div>
<?php

}

If I search for all three values at once (university, area and rooms) the page displays the correct results. However, if any or all of the option fields are left blank, then no posts are returned.

$GLOBALS[‘wp_query’]->request is all options are selected returns:

SELECT   wp_posts.* FROM wp_posts  INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) INNER JOIN wp_term_relationships AS tt1 ON (wp_posts.ID = tt1.object_id) INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id) WHERE 1=1  AND ( wp_term_relationships.term_taxonomy_id IN (5) AND tt1.term_taxonomy_id IN (18,15) ) AND wp_posts.post_type = 'properties' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') AND ( (wp_postmeta.meta_key = '_rooms' AND CAST(wp_postmeta.meta_value AS CHAR) = '4') ) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC 

…and if only university and rooms options are selected:

 SELECT   wp_posts.* FROM wp_posts  INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id) WHERE 1=1  AND 0 = 1 AND wp_posts.post_type = 'properties' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') AND ( (wp_postmeta.meta_key = '_rooms' AND CAST(wp_postmeta.meta_value AS CHAR) = '4') ) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC 

Please help! This is killing me! If you need any more info please ask.

Related posts

Leave a Reply

1 comment

  1. On your search form you use NULL (as a string) for Any selection.

    When the form is submitted it is sent as a string with the contents of the word null.

    Your isset then sees that, its set and sets the session to null (as a string). Which in turn messes up your query.

    To fix use:

    <option value="">Any</option>
    

    and check with:

    !empty()