WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have a plugin that is returning post IDs based on $_GET data (which searches a secondary DB table). I am attempting to hook into the standard have_posts() function called within a taxonomy page to show the results. Since the data is passed in on the actual page, I can't use the normal pre_get_posts stand-by, like so:

function finder_sort($query) {
    if ($query->is_main_query() && is_tax(array('location_type')) && isset($_GET['finder_action'])) {
        $query->set('post__in', array(1,2,3,4,5));

Because the data returned is not available until after the $_GET requests have been read on the page. So - I was wondering if there's anything I can filter in right before the data is output. For example, here is what I have:

$locations_found = wp_list_pluck($locations, 'id');
while(have_posts()) {
    echo '<tr>';
    echo '</tr>';

$locations_found has a list of IDs - so what I'm looking to do is filter have_posts to only include the IDs listed in $locations_found.

In addition, I need these posts ordered as they are noted in post__in. Since WP 3.5 is going to "fix" this, I've already added in the Sort Query by Post In function fix:

if ( version_compare( floatval( get_bloginfo( 'version' ) ), '3.5', '<' ) ) {

    add_filter( 'posts_orderby', 'sort_query_by_post_in', 10, 2 );
    function sort_query_by_post_in( $sortby, $thequery ) {
        if ( !empty($thequery->query['post__in']) && isset($thequery->query['orderby']) && $thequery->query['orderby'] == 'post__in' )
            $sortby = "find_in_set(ID, '" . implode( ',', $thequery->query['post__in'] ) . "')";
        return $sortby;

so - it'd be a mixture of identifying the post__in and then specifying the order_by param in this magical filter. Any thoughts would be greatly appreciated. Thanks!


The reason I cannot use the meta key (and why I need to return them in the same order they are retrieved by) is because there is a calculation done on each data item that is dependent on another $_GET variable (distance based on zip code).

Addition Info

Added display function that generates query vars

function finder_top_filter($term) {

    ob_start(); ?>

    <section id="sort">
        <form name="search" action="" method="get">
            <label for="finder_zipcode"><?php _e('Zip Code', 'finder'); ?></label>
            <input type="text" name="finder_zipcode" id="finder_zipcode" value="<?php echo isset($_GET['finder_zipcode']) ? $_GET['finder_zipcode'] : ''; ?>" />

            <label for="finder_distance"><?php _e('Radius', 'finder'); ?></label>
            <select name="finder_distance" id="finder_distance">
                $finder_dist_options = apply_filters('finder_dist_options', array(
                    '5'   => '5',
                    '10'  => '10',
                    '25'  => '25',
                    '50'  => '50',
                    '100' => '100',
                    '200' => '200'
                foreach ($finder_dist_options as $key=>$value) {
                    echo '<option value="' . $key . '" ' . (isset($_GET['finder_distance']) ? selected( $_GET['finder_distance'], $key ) : '') . '>' . $value . '</option>';

            <input type="hidden" name="finder_action" value="search" />
            <input type="submit" value="<?php _e('Show/Filter', 'finder'); ?>" />
            <span class="reset"><a href="<?php echo get_term_link($term); ?>">Reset</a></span>
    echo ob_get_clean();


Based on the recommendation of Stephen Harris, I decided to go the route of a JOIN query to alter the data passed to the loop. So, what I've tried is:

function finder_join_locations($join) {
    global $wpdb;

    return '';
add_filter('posts_join', 'finder_join_locations');

$i = 0;
while(have_posts()) {
    echo '<tr>';
    finder_location_teaser_table(get_the_ID(), $locations[$i]['distance']);
    echo '</tr>';


remove_filter('posts_join', 'finder_join_locations');

To see if I can get nothing to show, but that filter is not overriding the have_posts() function - any recommendations? What I'd like to do is pass-in via the post__in param, so after I get past this initial bump, it's figuring out the correct SQL statement to include my data (as $locations_found includes all the post data I need):

$locations_found = wp_list_pluck($locations, 'id');
share|improve this question
I don't understand why you write "Since the data is passed in on the actual page, I can't use the normal pre_get_posts". You should be able to manipulate the main query from you theme's functions.php file and the $_GET is already available at that stage. – Mark Kaplun Dec 2 '12 at 14:58
Hi Zach - so it seems you want to alter the query based on $locations - which is only available in the template? How do you set $locations? All query manipulation (for the 'main' query) should ideally be done outside the template... – Stephen Harris Dec 2 '12 at 15:03
"In addition, I need these posts ordered as they are noted in post__in" - this second part is unrelated to the solution to the first part. Please post it as a separate question. – Chip Bennett Dec 2 '12 at 15:15
@StephenHarris To sum up (hopefully), I'm grabbing all of the locations from an external database table - referencing this article so this calculation done on the fly, based on the zip code entered - so nothing I can store in postmeta (the distance between), I can only store each individual zip code for the location and then run it through the math to get the returned list – Zach Dec 3 '12 at 14:02
@Zach sounds like you want do a JOIN query to sort by distance on the main query rather than running two separate queries. – Stephen Harris Dec 4 '12 at 14:52
up vote 1 down vote accepted

I can see several possibilities for this one.

First, I am not convinced that that you can't use pre_get_posts though maybe you'd have to reorganize your code. You don't have to wait for your theme template to use $_GET. Try:

function tst() {
    // global $_GET; // sometimes necessary

So I think something like:

function finder_sort($query) {
    // I don't know what your complete code for processing $_GET is but
    // that would go here and set $pin
    if ($query->is_main_query() && is_tax(array('location_type')) && isset($_GET['finder_action'])) {
        $query->set('post__in', $pin);

That is one possibility, and from where I sit right now looks like the best one. If for some reason that isn't possible you can always do something like:

$locations_found = wp_list_pluck($locations, 'id');
while(have_posts()) {
    if (in_array($post->ID,$locations)) {
        echo '<tr>';
        echo '</tr>';

I am assuming some things about your data. Your question doesn't have all of the necessary information for me to write code with 100% confidence but that is the idea.

share|improve this answer
Hey s_ha_dum thanks for the response. Commented on the original question which hopfully gives a little more clarity (includes an article link that explains how the $locations are returned as well). Thanks! – Zach Dec 3 '12 at 14:04
This was more the route I went - was able to hook into the standard have_posts() and simply passed along the matched locations to the post__in param in pre_get_posts(). Thanks! – Zach Dec 10 '12 at 16:11

Don't rely on $_GET

I would recommend, instead of relying on $_GET data, to add your custom query parameters to the $query object, using add_query_arg(), and then retrieve that value using get_query_var().

Say, for example, you've got a query variable 'foo', with a value of 'bar', such that:

`$_GET['foo'] = 'bar'`

You could make that key/value pair available to the $query object, like so:

add_query_arg( 'foo', 'bar' );

Do that wherever it is that you're currently appending &foo=bar to the URI.

Now, you can retrieve the value of 'foo' like so:

$foo = get_query_var( 'foo' );

Using pre_get_posts

Since you now have a way to retrieve your URI query value independent of $_GET, you can use that method inside of a pre_get_posts callback:

function finder_sort( $query ) {
    if ( $is_main_query() && is_tax( array( 'location_type' ) ) && isset( get_query_var( 'finder_action' ) ) ) {
        $query->set( 'post__in', get_query_var( 'finder_action' ) );
add_action( 'pre_get_posts','finder_sort' );
share|improve this answer
Hey @ChipBennet thanks for the response. Commented on the original question which hopfully gives a little more clarity (includes an article link that explains how the $locations are returned as well). Thanks! – Zach Dec 3 '12 at 14:03
I'm not sure that it matters how you get $locations. What is important is how are you adding them to the URL query string? – Chip Bennett Dec 3 '12 at 16:11
The URL query string looks like this: ?finder_zipcode=19103&finder_distance=10&finder_action=search So I am then taking finder_zipcode and finder_distance, plugging them into a function that calculates the valid zip codes/locations and returns the locations (with matching zip codes that match). – Zach Dec 3 '12 at 16:19
How does ?finder_zipcode=19103&finder_distance=10&finder_action=search get appended to the URL string? Where and how are you doing the append? – Chip Bennett Dec 3 '12 at 17:07
Added display function to original question – Zach Dec 4 '12 at 14:26

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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