logo

$20
Search / Filter posts selecting multiple custom fields options

Hi guys/experts!

I was wondering if someone could explain me how to set up a search functionality on the front-end to get posts based on different custom fields values that these might have.

Say I want to sort by price, location and taste
Price custom value could be: 100 - 200 | 201 - 300
Location custom value could be: Buenos Aires | Cordoba
Taste: A | B | C

How could I create a nice little widget that could have these values + "All" for every field (meaning that could be any value)?

Thanks!

Chocks

chocks | 06/10/10 at 10:40pm | Edit


(2) Possible Answers Submitted...

  • avatar
    Last edited:
    06/10/10
    11:14pm
    Lew Ayotte says:

    I've done something like this recently...

    You need to setup a custom query function, something like:

    function get_custom_posts( $price = "%", $location = "%", $taste = "% ) {
    global $wpdb;

    $price = mysql_real_escape_string($price);
    $location = mysql_real_escape_string($location);
    $taste = mysql_real_escape_string($taste);

    $query = "" .
    "SELECT DISTINCT p.ID " .
    "FROM $wpdb->posts p " .
    "LEFT JOIN $wpdb->postmeta as price on price.post_id = p.ID " .
    "LEFT JOIN $wpdb->postmeta as loc on loc.post_id = p.ID " .
    "LEFT JOIN $wpdb->postmeta as taste on taste.post_id = p.ID " .
    "WHERE p.post_status LIKE 'publish' " .
    "AND (price.meta_key LIKE 'price' AND price.meta_value <= " . $price . ")" .
    "AND (loc.meta_key LIKE 'location' AND loc.meta_value LIKE " . $location . ")" .
    "AND (taste.meta_key LIKE 'taste' AND taste.meta_value LIKE " . $taste . ")";

    $post_rows = $wpdb->get_results($query, OBJECT);

    return $post_rows;
    }


    I'm assuming your values are in the postmeta table... and I assumed the names of they keys and values, but that gives you an idea.

    Next you need to setup a form, you can use POST or GET...
    <form action="<?php echo htmlspecialchars($_SERVER['REDIRECT_URL']); ?>" method="POST">


    You also need to deal with the posts from your query...
    You want to make sure $price, $location, and $taste have default values of "%" so it doesn't screw up the query:

    $posts = get_custom_posts($price, $location, $taste);
    foreach ($posts as $post) {
    $post_ids[] = $post->ID;
    }

    $args = array( 'post__in' => $post_ids );
    query_posts( $args );


    Then proceed as normal.

    I hope this helps, it's pretty complicated, took me a day to figure out everything I needed.

    Lew


  • avatar
    Last edited:
    06/26/10
    11:22am
    Jignesh Patel says:

    Hello,

    I've done such search feature already. Yours is bit easy. Here we go:

    You will need to create a function named get_post_meta_multiple()
    Here is the function..



    function get_post_meta_multiple( $aMetaDataList = array(), $szType = 'post', $szCategory = NULL, $isPagination = false , $with = '')
    {
    global $wpdb,$wp_query;

    $szQuerystr = '';
    $szQuerystrInPart = '';
    $tableAlias = "p";

    $szQuerystrInPart .= "SELECT p.* FROM wp_posts AS p ";

    $szQuerystrInPart .= " WHERE ";
    if(count($aMetaDataList) > 0) {

    $aInnerqry = array();
    $aInnerqryPrice = '';

    foreach($aMetaDataList as $szKey => $szValue)
    {

    $szQuerystrInPart .= "p.ID IN ( ";
    $szQuerystrInPart .= "SELECT post_id FROM $wpdb->postmeta WHERE ";

    if($szKey == 'price'):
    $szValueE = explode('-',$szValue);
    $szQuerystrInPart .= "(meta_key = '$szKey' AND meta_value >= ".$szValueE[0]." AND meta_value <= ".$szValueE[1].")";
    else:
    $szQuerystrInPart .= $wpdb->prepare( "(meta_key = %s AND meta_value = %s)", $szKey, $szValue );
    endif;

    $szQuerystrInPart .= " GROUP BY post_id ";
    $szQuerystrInPart .= "HAVING count(*) > 0 ";
    $szQuerystrInPart .= ") AND ";
    }
    }

    $szQuerystrInPart .= " p.post_status = 'publish' AND p.post_type = '".$szType."'";
    $szQuerystr = $szQuerystrInPart;
    $szQuerystr .= " GROUP BY p.ID ";

    # put limit in query built above
    $ppp = intval(get_query_var('posts_per_page'));

    if(!$isPagination) :
    $on_page = intval(get_query_var('paged'));
    if($on_page == 0){ $on_page = 1; }
    $offset = ($on_page-1) * $ppp;
    $szQuerystr .= " LIMIT $offset,$ppp";
    endif;

    $aMetaResults = $wpdb->get_results($szQuerystr, OBJECT);

    if($isPagination) :
    $wp_query->found_posts = count($aMetaResults);
    $wp_query->max_num_pages = ceil($wp_query->found_posts / $ppp);
    $on_page = intval(get_query_var('paged'));
    if($on_page == 0){ $on_page = 1; }
    $offset = ($on_page-1) * $ppp;
    endif;

    return $aMetaResults;
    }



    The form should be submitted with GET method (this will help in pagination). Form code should be like below.



    <form name="searchform" method="GET" action="<?=bloginfo('url'); ?>/listings">
    <select name="price">
    <option value="">--ALL--</option>
    <option value="100 - 200">100 - 200</option>
    <option value="201 - 300">201 - 300</option>
    </select>

    <select name="location">
    <option value="">--ALL--</option>
    <option value="Buenos Aires">Buenos Aires</option>
    <option value="Cordoba">Cordoba</option>
    </select>

    <select name="taste">
    <option value="">--ALL--</option>
    <option value="A">A</option>
    <option value="B">B</option>
    <option value="C">C</option>
    </select>

    <input type="hidden" name="searchsubmit" value="submit" />
    <input type="submit" value="Go" />
    </form>



    Put the code below anywhere above you put the form tag..



    $categoryArray = array();
    $aMetaDataList = array();

    if($_GET['searchsubmit'] == 'submit'):
    # unset old search criteria
    unset($_SESSION['searchvars']);
    if($_GET['price'] != '') $aMetaDataList['PropertyType'] = $_GET['price'];
    if($_GET['location'] != '') $aMetaDataList['Bedrooms'] = $_GET['location'];
    if($_GET['taste'] != '') $aMetaDataList['Bedrooms'] = $_GET['taste'];
    endif;
    if(count($aMetaDataList) > 0) $_SESSION['searchvars']['metas'] = $aMetaDataList;



    I created the page with slug 'listings' & assigned the template to it. You can create a new template (php file) in your theme directory & assign it to the page.
    Inside that file put the php code below.



    if(!is_category()) :
    if(count($_SESSION['searchvars']) > 0) :
    // exclude posts having category with id '7' or '17'. Change as per your need..
    $allcats = delimited_cat(',',array(7,17));
    get_post_meta_multiple( $_SESSION['searchvars']['metas'] , 'post', $allcats, true);
    $my_posts = get_post_meta_multiple( $_SESSION['searchvars']['metas'], 'post', $allcats, false);
    else :
    // exclude posts having category with id '7' or '17'. Change as per your need..
    $allcats = delimited_cat(',',array(7,17));
    get_post_meta_multiple( array() , 'post', $allcats, true);
    $my_posts = get_post_meta_multiple( array() , 'post', $allcats);
    endif;
    else:
    $allcats = get_query_var('cat');
    get_post_meta_multiple( array() , 'post', $allcats, true);
    $my_posts = get_post_meta_multiple( array() , 'post', $allcats);
    endif;




    The whole code uses 'wp-pagenavi' plugin as well for pagination.

    Put the code below in the template to get pagination..


    if(function_exists('wp_pagenavi')) { wp_pagenavi(); }

This question has expired.





Current status of this question: Completed