0
votes

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.

2
it will order the posts as the query finds them. You can just do a foreach loop over the posts to resort the way you want. If this is a set query, cache it to save on performance.David

2 Answers

2
votes

Learned something new myself trying to solve this for you :)

Apparently as of WP 3.5, you can specify an 'orderby' parameter of 'post__in' when creating your WP_Query

https://codex.wordpress.org/Class_Reference/WP_Query#Order_.26_Orderby_Parameters

So essentially what I think you could do would be to snag the post IDs that have the meta values you need and put those IDs into an array in the same order that they're specified in your meta values array. Then if you do a WP_Query on that array, pass in the arg:

'orderby' => 'post__in'

Now, as another commenter pointed out, this is probably a fairly expensive operation, so you'd like want to cache the result to a transient and use that output instead of running this query each time the page is loaded:

https://codex.wordpress.org/Transients_API

0
votes

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.