EDIT (Please see the original answer for full explanation of the code)
The code in my original answer works as expected, but triggers a known bug with usort
(Check the bug report here #50688)
WARNING Error: [2] usort(): Array was modified by the user comparison function
This bug is triggered only when the fields
parameter is set in the arguments in get_posts
, so the only workable workaround I could find was to remove the fields
parameter and go with full posts being retrieved.
Here is the bug free working version
<?php
$args = array (
'post_type' => 'member_data',
'post_status' => 'active',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'first_name',
),
array(
'key' => 'last_name',
),
array(
'key' => 'publicly_listed',
'value' => 'true',
),
),
);
$posts = get_posts( $args );
usort( $posts, function( $a, $b ){
// sort first by last name
$compare = strnatcmp(get_post_meta($a->ID, 'last_name', true), get_post_meta($b->ID, 'last_name', true));
// if last names are identical, sort by first name
if(!$compare) {
return strnatcmp(get_post_meta($a->ID, 'first_name', true), get_post_meta($b->ID, 'first_name', true));
}else{
return $compare;
}
});
if( $posts ) {
echo "Total Members Found: " . count($posts) . "<br>";
foreach ( $posts as $post ) {
$q = get_post_meta($post->ID);
echo "<b>" . $q['first_name'][0] . " " . $q['last_name'][0] . "</b><br>";
echo $q['city'][0] . ", " . $q['state'][0] . " " . $q['zip'][0] . "<br>";
echo "<a href="https://wordpress.stackexchange.com/questions/166522/mailto:" . $q["email'][0] . "'>" . $q['email'][0] . "</a><br>";
echo "<br>";
}
unset( $post );
}else{
echo "<b>Sorry, we found no active members. Please be sure to check back soon.</b>";
}
}
ORIGINAL ANSWER
Unfortunately there is no way to do this type of sorting natively, so you will need to take a different approach here.
-
Use
WP_Query
, or even betterget_posts
retrieve your posts as normal. There is no need to apply any sorting at this stage. In my personal opinion, this is useless as you can sort only by onemeta_value
and not two. I would rather just use php sorting to order the posts as needed. (If you are going to use pagination, rather useWP_Query
). -
You are going to use
usort
to sort your posts, first bylast_name
, then if two or more persons share the samelast_name
, we will sort according tofirst_name
.
Here is the concept:
Before I start, I want to point out a few things
-
Your
meta_query
is a mess unfortunately. Everything is within an array within an array within an array, where as it should be 3 separate arrays within one array -
I would rather use
get_posts
here and also only retrieve the post ID’s as you aren’t going to make use of any postdata or any of the other data returned byWP_Query
-
This is quite a heavy operation as the db is visited two times for each post. You will have to look to make use of transients here.
Now for the solution
As said use get_posts
to construct your query with. We are going to retrieve the posts which matches all three meta_key
‘s
$args = array (
'post_type' => 'member_data',
'fields' => 'ids',
'post_status' => 'active',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'first_name',
),
array(
'key' => 'last_name',
),
array(
'key' => 'publicly_listed',
'value' => 'true',
),
),
);
$posts = get_posts( $args );
We are now going to sort $posts
by last_name
then first_name
using usort
usort( $posts, function( $a, $b ){
// sort first by last name
$compare = strnatcmp(get_post_meta($a, 'last_name', true), get_post_meta($b, 'last_name', true));
// if last names are identical, sort by first name
if(!$compare) {
return strnatcmp(get_post_meta($a, 'first_name', true), get_post_meta($b, 'first_name', true));
}else{
return $compare;
}
});
$posts
should now be sorted alphabetically by last_name
, and if the last_name
is the same for two or more persons, they will be sorted in alphabetical order by first_name
.
Your loop will now follow and look like this
if( $posts ) {
echo "Total Members Found: " . count($posts) . "<br>";
foreach ( $posts as $post ) {
$q = get_post_meta($post);
echo "<b>" . $q['first_name'][0] . " " . $q['last_name'][0] . "</b><br>";
echo $q['city'][0] . ", " . $q['state'][0] . " " . $q['zip'][0] . "<br>";
echo "<a href="https://wordpress.stackexchange.com/questions/166522/mailto:" . $q["email'][0] . "'>" . $q['email'][0] . "</a><br>";
echo "<br>";
}
unset( $post );
}else{
echo "<b>Sorry, we found no active members. Please be sure to check back soon.</b>";
}
}