Always great if someone wants to use better, more correct and more efficient ways to get things done. To achieve what you need is not difficult.
WORKSFLOW:
-
Use the
usort()
to create your custom sort order -
Use the
the_posts
filter to sort and return the sorted array of posts just before the loop is executed -
Inside the loop, all you need to do is to compare the previous post and current post terms and act on that
THE CODE:
Lets look at the code:
First, get the sorting done using usort()
and the_posts
filter: (Requires at least PHP 5.4+. If you don’t have at least PHP 5.4, then you are sure to run into security issues. Also note, all the code is untested and might be buggy)
add_filter( 'the_posts', function ( $posts, $q )
{
if ( $q->is_main_query() // Target the main query only
&& $q->is_tax() // Change to target only specific term or taxonomy
) {
/**
* We will now sort the $posts array before the loop executes. We will use usort()
*
* There is a bug in usort causing the following error:
* usort(): Array was modified by the user comparison function
* @see https://bugs.php.net/bug.php?id=50688
* This bug has yet to be fixed, when, no one knows. The only workaround is to suppress the error reporting
* by using the @ sign before usort
*/
@usort( $posts, function ( $a, $b )
{
/**
* Get the respective terms from the posts
* We will use the first term's name
*/
$array_a = get_the_terms( $a->ID, 'TAXONOMY_NAME_HERE' )[0]->name;
$array_b = get_the_terms( $b->ID, 'TAXONOMY_NAME_HERE' )[0]->name;
// Sort by term name, if they are the same, sort by post date
if ( $array_a != $array_b ) {
return strcasecmp( $array_a, $array_b ); // Sort terms alphabetically, ascending
// return strcasecmp( $array_b, $array_a ); // Sort terms alphabetically, descending
} else {
return $a < $b; // Sort by date if terms are the same. Change < to > if the post date order is incorrect
}
}
}
}, 10, 2 );
This should take care of the sorting. As I have stated, just make sure the date sorting is correct within the terms. If not, just change <
to >
Now we can display the term names inside the loop. Adjust and modify as needed
if ( have_posts() ) {
// Define variable to hold previous post term name
$term_string = '';
while ( have_posts() ) {
the_post();
global $post;
// Get the post terms. Use the first term's name
$term_name = get_the_terms( $post->ID, 'TAXONOMY_NAME_HERE' )[0]->name;
// Display the taxonomy name if previous and current post term name don't match
if ( $term_string != $term_name )
echo '<h2>' . $term_name . '</h2>'; // Add styling and tags to suite your needs
// Update the $term_string variable
$term_string = $term_name;
// REST OF YOUR LOOP
}
}