Query Loop order by multiple custom fields

I have a staff post type that I’d like to show N people in the 1, 2, 3 positions then for the rest of the staff they should be in alphabetical order (by last_name custom field).

I’d like to use the Query Loop block and order my staff post type by multiple custom fields. First by display_position then by last_name. Would I be able to do this with the generateblocks_query_loop_args filter or will I need to do a custom query for this (if so, could I still use the Query Loop block)?

Currently I have this:

add_filter( 'generateblocks_query_loop_args', function( $query_args, $attributes ) {
    if (
        ! empty( $attributes['className'] ) &&
        strpos( $attributes['className'], 'in-custom-order' ) !== false
    ) {
        return array_merge( $query_args, array(
            'meta_key' => 'display_position',
			'meta_type' => 'NUMERIC',
            'orderby' => 'meta_value',
            'order' => 'ASC',
        ) );
    }

    return $query_args;

}, 10, 2 );

And this will correctly order people who have a display_position set, but if someone doesn’t have that field set, they will show up first, then the custom ordering will start after.

In the past I’ve had to do 2 queries then merge them together which required significantly more code and I assume that would require a different hook.

Hopefully this made sense. Thanks ahead of time for the help.

I was able to figure it out. I guess this is really more a question about ordering custom fields then it is about GenerateBlocks. But they needed to be put together and here is my solution.

/* Custom order for Query Block, apply class 'in-custom-order' to grid
 * Ordered by lowest display_position first, then alphabetical by last_name */
add_filter( 'generateblocks_query_loop_args', function( $query_args, $attributes ) {
    if (
        ! empty( $attributes['className'] ) &&
        strpos( $attributes['className'], 'in-custom-order' ) !== false
    ) {
        
		$meta_query = array(
			'display_position' => array(
				'key' => 'display_position',
				'compare' => 'EXISTS',
				'type' => 'NUMERIC',
			),
			'last_name' => array(
				'key' => 'last_name',
				'compare' => 'EXISTS',
			),
		);
		$orderby = array(
			'display_position' => 'ASC',
			'last_name' => 'ASC'
		);

		$query_args['meta_query'] = $meta_query;
		$query_args['orderby'] = $orderby;
		
		return $query_args;
    }

    return $query_args;

}, 10, 2 );

These posts have custom fields for display_position and last_name. The default display position is 100, anyone set lower will be sorted to the front. Also make sure that the display_position uses a numeric value.

1 Like