Ask your WordPress questions! Pay money and get answers fast! Comodo Trusted Site Seal
Official PayPal Seal

Search / Filter posts selecting multiple custom fields options WordPress

  • SOLVED

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

Answers (2)

2010-06-11

Jignesh Patel answers:

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(); }

2010-06-11

Lew Ayotte answers:

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