2

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:

http://website.com/books/?type=babies,children,home

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.

archive.book.php

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

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

    $wp_query->the_post();
    get_template_part( 'content', get_post_format() );
}

This normal loop:

<?php 
print_r( $wp_query->request );
if ( have_posts() ) {
    while ( have_posts() ) {
        the_post();
        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 Jan 10 '14 at 1:45
  • Removing 'compare' => 'IN'still results in a blank page. – realph Jan 10 '14 at 1:48
  • 1
    Change explode('|' to explode(',' becouse in your url is , symbol not | – Foxsk8 Jan 10 '14 at 1:52
  • I've changed it to explode('|'but that still results in a blank results page. – realph Jan 10 '14 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 Jan 10 '14 at 3:24
1

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

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

    // 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.

| improve this answer | |
  • 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 Jan 10 '14 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 Jan 10 '14 at 3:11
  • I've added my post loop to the original question, if that helps. – realph Jan 10 '14 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. – Brian Richards Jan 10 '14 at 15:26
  • @BrianRichards So can I fix this by just using the normal loop? – realph Jan 10 '14 at 16:08
0

Here is code, that works.

<?php
     $type = explode(',', $_GET['type']);
     $paged = ( get_query_var('paged') ) ? get_query_var('paged') : 1;
     $myquery = new WP_Query(array(
     'post_type' => 'building',
     'meta_query'=>array(
            array(
                '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; ?>
| improve this answer | |
  • 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 Jan 10 '14 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 Jan 10 '14 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 Jan 10 '14 at 2:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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