WordPress: query posts with multiple custom fields

When you use custom fields to define multiple properties of posts and want to provide filtered views based on a combination of filters, you’ll first come to the function query_posts.

I assume here you know how to properly use query_posts e.g. you know you have to reset the query after using it (with wp_reset_query).

You can define what you want to retrieve in the arguments of the function e.g.:

query_posts( 'p=53' ); //will query the post with ID=53
query_posts( 'cat=6' ); //will query all posts in the category with ID=6

If you want to perform some more complex queries it is generally better to provide a query parameter array as argument than a query string:

$args=array('category_name' => 'my-category-slug', 
			'posts_per_page' => 10, 
			'orderby' => 'date', 
			'order' => 'ASC');
query_posts($args);

It makes it more readable and allows you to add a meta_query element to also filter according to a custom field:

$args=array('category_name' => 'my-category-slug', 
			'posts_per_page' => 10, 
			'orderby' => 'date', 
			'order' => 'ASC',
			'meta_query' => array(array('key' => 'my_custom_field_key',
										'value' => $my_custom_field_key))
			);
query_posts($args);

Or even with multiple custom fields:

$args=array('category_name' => 'my-category-slug', 
			'posts_per_page' => 10, 
			'orderby' => 'date', 
			'order' => 'ASC',
			'meta_query' => array(array('key' => 'my_custom_field_key',
										'value' => $my_custom_field_key),
								  array('key' => 'my_custom_field_key2',
										'value' => $my_custom_field_key2))
			);
query_posts($args);

While implementing the search form on kinderautositz-kaufen.de, I had to do something like this:

If the user chooses the value “value1″ in the filter, then display posts with the custom field set to “value1″ or “value1 or xxx” or “xxx or value1″.
If the user chooses the value “value2″ in the filter, then display posts with the custom field set to “value2″ or “value2 or xxx” or “xxx or value2″.

This makes it of course easier to directly work with SQL than to use arrays to define the criteria.

Here’s how I did it:

First you need to setup some filters to add the fields, joins and where clauses to the generate statement.

Add the following to your functions.php file (e.g. at the end of the file):

<?php function my_posts_fields ($fields) {
   global $my_global_fields;
   if ($my_global_fields) $fields .= $my_global_fields;
   return $fields;
}
function my_posts_join ($join) {
   global $my_global_join;
   if ($my_global_join) $join .= $my_global_join;
   return $join;
}
function my_posts_where ($where) {
   global $my_global_where;
   if ($my_global_where) $where .= $my_global_where;
   return $where;
}
function my_posts_orderby ($orderby) {
   global $my_global_orderby;
   if ($my_global_orderby) $orderby = $my_global_orderby;
   return $orderby;
}
add_filter('posts_fields','my_posts_fields');
add_filter('posts_join','my_posts_join');
add_filter('posts_where','my_posts_where');
add_filter('posts_orderby','my_posts_orderby');
?>

You then need to update the global variables $my_global_fields, $my_global_join, $my_global_where and $my_global_orderby in your page template:

<?php
	if(!empty($_REQUEST['my_custom_field_key'])) {
		$mam_global_fields = $mam_global_fields . ', my_custom_field_key.meta_value my_custom_field_value';
		$mam_global_join = $mam_global_join . " JOIN $wpdb->postmeta my_custom_field_key
			ON ({$wpdb->posts}.ID = my_custom_field_key.post_id AND my_custom_field_key.meta_key = 'my_custom_field_key'
			AND (my_custom_field_key.meta_value = '{$_REQUEST['my_custom_field_key']}' OR my_custom_field_key.meta_value LIKE '%%{$_REQUEST['my_custom_field_key']} or %%' OR my_custom_field_key.meta_value LIKE '%% or {$_REQUEST['my_custom_field_key']}%%'))";
	}
	if(!empty($_REQUEST['my_custom_field_key2'])) {
		$mam_global_fields = $mam_global_fields . ', my_custom_field_key2.meta_value my_custom_field_value2';
		$mam_global_join = $mam_global_join . " JOIN $wpdb->postmeta my_custom_field_key2
			ON ({$wpdb->posts}.ID = my_custom_field_key2.post_id AND my_custom_field_key2.meta_key = 'my_custom_field_key2'
			AND (my_custom_field_key2.meta_value = '{$_REQUEST['my_custom_field_key2']}' OR my_custom_field_key2.meta_value LIKE '%%{$_REQUEST['my_custom_field_key2']} or %%' OR my_custom_field_key2.meta_value LIKE '%% or {$_REQUEST['my_custom_field_key2']}%%'))";
	}
	query_posts();
?>

You can then display the results like this:

<?php while ( have_posts() ) : the_post(); ?>
    <div class="entry">
        <header class="entry-header">
          <h2 class="entry-title"><?php the_title(); ?></h2>
        </header>
		<div class="entry-content">
			  the_content(); 
		</div> <!-- entry-content -->
	</div> <!-- entry -->
<?php endwhile; // end of the loop. ?>

2 thoughts on “WordPress: query posts with multiple custom fields

  1. Hi,

    Thank you for this wonderful tutorial. Im having trouble integrating this on my query. im having 2 custom fields namely bedrooms and bathrooms, would you mind giving instructions on how to update this to fit on the code below? thanks for your help


    postmeta my_custom_field_key
    ON ({$wpdb->posts}.ID = my_custom_field_key.post_id AND my_custom_field_key.meta_key = 'my_custom_field_key'
    AND (my_custom_field_key.meta_value = '{$_REQUEST['my_custom_field_key']}' OR my_custom_field_key.meta_value LIKE '%%{$_REQUEST['my_custom_field_key']} or %%' OR my_custom_field_key.meta_value LIKE '%% or {$_REQUEST['my_custom_field_key']}%%'))";
    }
    if(!empty($_REQUEST['my_custom_field_key2'])) {
    $mam_global_fields = $mam_global_fields . ', my_custom_field_key2.meta_value my_custom_field_value2';
    $mam_global_join = $mam_global_join . " JOIN $wpdb->postmeta my_custom_field_key2
    ON ({$wpdb->posts}.ID = my_custom_field_key2.post_id AND my_custom_field_key2.meta_key = 'my_custom_field_key2'
    AND (my_custom_field_key2.meta_value = '{$_REQUEST['my_custom_field_key2']}' OR my_custom_field_key2.meta_value LIKE '%%{$_REQUEST['my_custom_field_key2']} or %%' OR my_custom_field_key2.meta_value LIKE '%% or {$_REQUEST['my_custom_field_key2']}%%'))";
    }
    query_posts();
    ?>

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>