Here’s a handy snippet which I forgot about but have used on a couple of projects in the past. This can be very handy if you have posts of a persons name, so first and last and you need to order the posts in the loop by their last name, i.e for a directory.
There are 2 parts to accomplish this, one is to create a function which orders by the last word alphabetically, the other is a tiny amend to the loop, such as in a WP_Query to then use the new function we created in the first step.
Step 1.
Add the function to your functions.php file:
add_filter( 'posts_orderby', function( $orderby, \WP_Query $q ) {
if( 'wpse_last_word' === $q->get( 'orderby' ) && $get_order = $q->get( 'order' ) ) {
if( in_array( strtoupper( $get_order ), ['ASC', 'DESC'] ) ) {
global $wpdb;
$orderby = " SUBSTRING_INDEX( {$wpdb->posts}.post_title, ' ', -1 ) " . $get_order. " , {$wpdb->posts}.post_title " . $get_order;
}
}
return $orderby;
}, PHP_INT_MAX, 2 );
Step 2.
Add the new orderby line in your loop to use the new function for ordering your posts:
$args = array(
'post_type'=>'my_post_type',
'orderby'=>'wpse_last_word',
'order'=>'ASC',
'posts_per_page'=>-1
);
Bonus tip:
If you want to force a taxonomy, such as a taxonomy for a Custom Post Type, you can add another filter to target any default loop templates using the following:
add_filter( 'pre_get_posts', 'pro_orderby_last_name' );
function pro_orderby_last_name( $query ) {
if( is_taxonomy('my_taxonomy') ) {
$query->query_vars['orderby'] = 'wpse_last_word';
$query->query_vars['order'] = 'ASC';
}
return $query;
}