Question

I have a custom post type where the title is a name, and I want to sort the loop by the last word in title, the surname.

I can easily break the names apart and filter by the last word in a custom query, but I don't want to re-write the main loop / pagination for the archive page. Is it possible to pass a callback to the orderby param in the action pre_get_posts or is this a lost cause?

Thanks!

Was it helpful?

Solution

No you can't pass a callback function. Callback functions are PHP, so they can't be run in MySQL. For that to work it would need to query the results from the database first, but you'd get the wrong results because they're unsorted.

You would need to use the posts_orderby filter to do this as part of the SQL query:

add_filter(
    'posts_orderby',
    function( $orderby, $query ) {
        if ( ! is_admin() && $query->is_post_type_archive( 'post_type_name' ) ) {
            $orderby = "SUBSTRING_INDEX(post_title, ' ', -1) ASC, post_title ASC";
        }
        
        return $orderby;
    },
    10,
    2
);

That uses the SUBSTRING_INDEX() MySQL function to order results by everything after the first last space in the post title, and then by the post title so that results with matching surnames are sorted by first name.

OTHER TIPS

Just posting my code for posterity, I made some small changes to @Jacob Peatite's code, if anyone needs a drop-in solution:

add_filter('posts_orderby', __NAMESPACE__ . '\surname_orderby', 10, 2);
function surname_orderby($args, $wp_query)
{
    //make sure this is not an admin dashboard query.
    if (is_admin()) {
        return;
    }
    //check if this is the main query, rather than a secondary query such as widgets or menus.
    if (!is_main_query()) {
        return;
    }

    // the wp query at this filter is literally just the orderby value, we need to fetch the queried object
    $queriedObj = $wp_query->get_queried_object();
    
    if (isset($queriedObj->name) && $queriedObj->name === the_one_I_want ) {
        $args = "SUBSTRING_INDEX(post_title, ' ', -1) ASC, post_title ASC";
        return $args;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top