user1371519 user1371519 - 2 months ago 22
PHP Question

WP_Query Order Posts By Custom Meta Value Array Not in Codex

I have a different sort of post order I'm trying to return that I can't find anywhere with an answer. I'm using a wp_query to try to order posts by a list of meta values. However non of the standard orderby options do what I'm trying to achieve.

My meta values are stored as a comma list string like so:

1, 5, 10, 3, 21, 6

Then I grab those values and explode them to an array like so:

$banner_nums = get_option('banner_numbers');
$nums_array = explode( ',', $banner_nums );


I do a standard wp_query, but the catch is, I'm trying to order the display of these posts by the actual order in my $banner_nums variable, not by any normal wp_query orderby such as 'ID', 'date', 'title', 'meta_value', etc.

Display like so:

1st: post with meta_value = 1

2nd: post with meta_value = 5

3rd: post with meta_value = 10

4th: post with meta_value = 3

5th: post with meta_value = 21

6th: post with meta_value = 6

If, for example, I want to display the post with meta_value = 6 as the 2nd post I'd change my list to: 1, 6, 5, 10, 3, 21.

Here is my query that grabs my posts fine, I just can't get them to order correctly.

$slider_args = array(
'post_type' => 'property',
'posts_per_page' => -1,
'nopaging' => true
);

$my_query = array();

foreach( $nums_array as $k => $v ) {
$my_query[$k]['key'] = 'property_id';
$my_query[$k]['value'] = $v;
$my_query[$k]['compare'] = '=';
}

$slider_args['meta_query'] = $my_query;
$slider_args['meta_query']['relation'] = 'OR';

$slider_query = new WP_Query( $slider_args );

if ( $slider_query->have_posts() ) {
stuff...
}


Printing my $slider_args looks like this, which looks fine:

[post_type] => property
[posts_per_page] => -1
[nopaging] => 1
[meta_query] => Array
(
[0] => Array
(
[key] => property_id
[value] => 1
[compare] => =
)

[1] => Array
(
[key] => property_id
[value] => 5
[compare] => =
)

[2] => Array
(
[key] => property_id
[value] => 10
[compare] => =
)

[3] => Array
(
[key] => property_id
[value] => 3
[compare] => =
)

[4] => Array
(
[key] => property_id
[value] => 21
[compare] => =
)

[5] => Array
(
[key] => property_id
[value] => 6
[compare] => =
)

[relation] => OR
)


I just can't figure out how to display the posts in the correct order of

1, 5, 10, 3, 21, 6

I hope I'm making sense? Any help is much appreciated.

Answer

Thanks Greg for the input. I was using the 'orderby' => 'post__in" arg, but didn't think about having to add the array of post IDs too. I had to add the additional arg of 'post__in' => array(IDs) so the orderby would work correctly. So I had to do, like you said, and add an expensive query to get those IDs. My final code looks like so:

$banner_nums = get_option('banner_numbers');
$numbers = explode( ',', $banner_nums );

// ** new code
$wpIds = array();
// need post ids to keep the sort order same as in string above
foreach( $numbers as $num) {
    $args = array(
        'post_type' => 'property',
        'meta_query' => array(
            array(
                'key' => 'property_id',
                'value' => $num
            )
        )
    );
    $getPosts = new WP_Query($args);
    if( $getPosts->have_posts() ) {
        while( $getPosts->have_posts() ) {
            $getPosts->the_post();
            // builds array of posts IDs in same order as $numbers array above.
            array_push($wpIds, get_the_ID());
        } // end while
    }
}
// ** end new code

$slider_args = array(
    'post_type' => 'property',
    'posts_per_page' => -1,
    'nopaging' => true,
    'post__in' => $wpIds,  // ** new code
    'orderby' => 'post__in'
);

$my_query = array();

foreach( $numbers as $k => $v ) {
    $my_query[$k]['key'] = 'property_id';
    $my_query[$k]['value'] = $v;
    $my_query[$k]['compare'] = '=';
}

$slider_args['meta_query'] = $my_query;
$slider_args['meta_query']['relation'] = 'OR';

$slider_query = new WP_Query( $slider_args );

Yes this is an expensive query, but for my case, using this to build a homepage slider of 2-6 slides, I can deal with it.