Basically, I'm trying to follow this tutorial to add an action to the pre_get_posts and create a custom meta_query so I can alter the query within the URL and display babies,children and home books like so:


I'm using the Advanced Custom Fields plugin for my custom fields and my custom field is called 'type' and is set up in WordPress as a Checkbox Field, so it accepts multiple values.

For the life of me, I can't work out how to get it to display the queried posts.

function my_pre_get_posts( $query ) {
if( is_admin() ) { return; }

$meta_query = $query->get('meta_query');
    if( !empty($_GET['type']) ) {               
        $type = explode('|', $_GET['type']);    
        $meta_query[] = array(                          
            'key'       => 'type',
            'value'     => $type,
            'compare'   => 'IN',

$query->set('meta_query', $meta_query); // update the meta query args
return; // always return

Using 'compare' => 'LIKE' just returns random posts, using IN returns a blank results page.

Not sure if it's to do with my $_GET['type'] parameter, which is supposed to be string.

Any help with solving this is appreciated. I'm on my 5th cup of coffee and the evening isn't looking promising.


$args = array(
'post_type'     => 'book',
'posts_per_page'    => 10,

$wp_query = new WP_Query( $args );
while( $wp_query->have_posts() ) {

    get_template_part( 'content', get_post_format() );

This normal loop:

print_r( $wp_query->request );
if ( have_posts() ) {
    while ( have_posts() ) {
        get_template_part( 'content', get_post_format() );
    } // end while
} // end if

outputs this:

SELECT SQL_CALC_FOUND_ROWS blISt3rs871o_posts.ID FROM blISt3rs871o_posts WHERE 1=1 AND blISt3rs871o_posts.post_type = 'book' AND (blISt3rs871o_posts.post_status = 'publish' OR blISt3rs871o_posts.post_status = 'private') ORDER BY blISt3rs871o_posts.post_date DESC LIMIT 0, 10
  • Removed 'compare' => 'IN', you dont need it if your fields not a number or something to compare.
    – Foxsk8
    Commented Jan 10, 2014 at 1:45
  • Removing 'compare' => 'IN'still results in a blank page.
    – realph
    Commented Jan 10, 2014 at 1:48
  • 1
    Change explode('|' to explode(',' becouse in your url is , symbol not |
    – Foxsk8
    Commented Jan 10, 2014 at 1:52
  • I've changed it to explode('|'but that still results in a blank results page.
    – realph
    Commented Jan 10, 2014 at 1:54
  • 1
    Add print_r( $wp_query->request ); to your template, this will show you the SQL query being sent to the database. Copy whatever that outputs, edit your question, and paste it here so we can see what it looks like.
    – Milo
    Commented Jan 10, 2014 at 3:24

2 Answers 2


First, keep in mind that pre_get_posts is a hook that is run on every single query that WP runs, so be very, very careful when utilizing it. That said, it is absolutely the best tool for what you want to do, and certainly better than writing a separate custom query in the page template.

I've added some additional conditions to the start of this function to make sure it is abandoned early if the query is: not for the main loop, running on an admin page, or if the 'type' query string is not present. You should add a few more conditions here to restrict it even further, e.g. if ( ! is_page( 'something' ) ) { return; } or if ( ! is_front_page() ) { return; }.

That said, here is some sample code:

 * Add custom meta filter to main query on any page.
 * @since  1.0.0
 * @param  object $query WP Query object.
function wpse129223_custom_meta_query( $query ) {

    // If not on the main query, or on an admin page, bail here
    if ( ! $query->is_main_query() || is_admin() ) {

    // If 'type' isn't being passed as a query string, bail here
    if ( empty( $_GET['type'] ) ) {

    // Get the existing meta query, cast as array
    $meta_query = (array) $query->get('meta_query');

    // Convert 'type' into an array of types
    $types = explode( ',', $_GET['type'] );

    // Ensure that types aren't empty
    if ( is_array( $types ) && ! empty( $types ) ) {

        // Build a meta query for this type
        $meta_query[] = array(
            'key'     => 'type',
            'value'   => $types,
            'compare' => 'IN',

        // Update the meta query
        $query->set( 'meta_query', $meta_query );

add_action( 'pre_get_posts', 'wpse129223_custom_meta_query' );

This expects the query string to be comma-separated, as you presented it in your example, website.com/whatever/?type=one,two,three. In your code example you were looking for a pipe character, which is what @Foxsk8 was getting at in his comments.

  • Did you not mean to pass $types in the meta query instead of $_GET['type']? It's also probably worth pointing out that type is not safe to pass via GET according to the Reserved Terms section of register_taxonomy in Codex, though I can't get it to break anything query-wise.
    – Milo
    Commented Jan 10, 2014 at 3:02
  • Comma-seperated is fine with me! This is returning a blank page though, I've even tried passing $types in the meta query instead of $_GET['type']like @Milo said above, but still a blank page when doing website.com/books/?type=children.
    – realph
    Commented Jan 10, 2014 at 3:11
  • I've added my post loop to the original question, if that helps.
    – realph
    Commented Jan 10, 2014 at 3:26
  • Oops, good catch Milo. I see from your edit, @realph, that you're running an additional query on your archive page. My code sample will not work because it has been limited to target the main query for the page. Furthermore, you're actually doing double the work on this template now (WP runs the original query before in order to know what template to load and have the contents to populate it, then after the template is loaded you're running a query again in order to load what you deem to be the relevant posts. Commented Jan 10, 2014 at 15:26
  • @BrianRichards So can I fix this by just using the normal loop?
    – realph
    Commented Jan 10, 2014 at 16:08

Here is code, that works.

     $type = explode(',', $_GET['type']);
     $paged = ( get_query_var('paged') ) ? get_query_var('paged') : 1;
     $myquery = new WP_Query(array(
     'post_type' => 'building',
                'key' => 'type',
                'value' => $type,


    if ($myquery->have_posts()) :
    while ($myquery->have_posts()) : $myquery->the_post();
<h1><?php the_title(); ?></h1>
<?php the_content(); ?>
<?php endwhile; endif; ?>
  • Sorry, am I putting that code in my archive-book.php file? The code in my original post was from the functions.php file.
    – realph
    Commented Jan 10, 2014 at 2:33
  • Create a file, for example page-filter.php in your theme folder. Put this code all into this file. In wordpress pages add new page and call it to Filter. Then use page.com/filter/?type=<your value>
    – Foxsk8
    Commented Jan 10, 2014 at 2:35
  • I can't seem to get that to work. I've created a page called "Filter". Set up a new template for that page called "page-filter.php" and added the code to it, giving it a 'post_type' => 'book'. But I'm just still just getting my header and footer but an empty page.
    – realph
    Commented Jan 10, 2014 at 2:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.