Use pre_get_posts to sort meta_key by an array of values

After some more testing it became apparent that the results weren’t in
fact doing natural sorting. I made a few changes. It’s ugly… but it
works.

Okidokes, so I wasn’t able to get this to sort the way I wanted using WordPress’ sorting functions so I did go the usort route, and I think it turned out pretty nicely. (except for a PHP warning that is apparently a bug.)

Here’s what I did. (I should have mentioned that I am using the ACF plugin.)

In archive.php, just before where I loop the query:

<?php if (have_posts()) : 
        // here we are going to populate the "menu_order"
        $statusArr = ['Gold','Silver','Bronze']; // set up the desired order in which the posts should arrive
        while (have_posts()) : the_post(); // start a loop
            $position = array_search(get_field('partner_status'), $statusArr); // find the index number of the post's "partner_status" relevant to everything in the array
            //$post->menu_order = $position; // update the menu order for the post with that index number (thus building a layered reference)
            if ( empty( $post->menu_order ) ) wp_update_post( array('ID'=>$post->ID,'menu_order'=>$position) ); // here we physically write a menu order into the post so that on subsequent visits, it will sort correctly
        endwhile;

        function home_orderby( $a, $b ) { // this function does the comparison for the usort
            global $posts;
            $apos = $a->menu_order; // compare menu_orders
            $bpos = $b->menu_order;
            return ( $apos < $bpos ) ? -1 : 1;
        }
        //@usort( $wp_query->posts, "home_orderby" ); // If all you want is to sort by the order, then you could still use this

    rewind_posts(); // rewind posts to use in the main loop that creates the HTML ?>

In functions.php I then use the pre_get_posts action hook like this:

function my_pre_get_posts( $query ) {
    // do not modify queries in the admin
    if( is_admin() ) {
        return $query;   
    }

    if( isset($query->query_vars['country']) ) {  
        $query->set('orderby',array( 'menu_order' => 'ASC', 'title' => 'ASC' ));
    }
}

add_action('pre_get_posts', 'my_pre_get_posts');

I now see my custom post type posts ordered in the order I specified at the top in my $statusArray. Happy days!

Thanks for your input, Pieter. It got me thinking along the right path. 🙂