Creating complex post ordering using multiple WP_Query calls

I had this situation come up for a client a few days ago and it ended up being trickier than I expected. I thought I could use a complex “orderby” value since that property now accepts an array of parameters to do complex sorting. However, what the client required just wasn’t possible to accomplish in a single query without adding additional data in the form of another Advanced Custom Fields field which would’ve been overkill and annoying to maintain.

The problem: custom post type (CPT) Professional has ACF fields including Job Title (job_title). Professionals use a Service taxonomy which includes terms for all of the various financial services this client provides and each one is tagged with the Service(s) they offer. So on each page for a Service, all Professionals tagged with that Service are called. Professionals on service pages must be ordered in the following pattern:

  1. Managing Directors, alphabetically by Last Name (last_name) ACF field
  2. Directors, alphabetically by Last Name (last_name) ACF field
  3. Senior Mangers, alphabetically by Last Name (last_name) ACF field

Positions are just arbitrary text, they have no delineation for order of importance as far as MySQL is concerned. To add an additional level of complexity, the “Leadership” service term requires the following ordering specific just to this page:

  1. Chief Executive Officer
  2. CFO (who is also a Managing Director)
  3. National Managing Directors, alphabetically by Last Name (last_name) ACF field (though there is only 1 currently)
  4. Regional Managing Directors, alphabetically by Last Name (last_name) ACF field

After numerous failed attempts to at least get the Leadership Professionals ordered alphabetically ascending by job_title and then sub-ordered by last_name alphabetically ascending, I decided to split each job_title into its own WP_Query to at least pull each and have them ordered properly inside of each.

$ceo_args = array(
'post_type'             => 'professionals',
'services'              => 'leadership',
'posts_per_page'        => -1,
'meta_query'            => array(
array(
'key'             => 'job_title',
'value'           => 'Chief Executive Officer',
'compare'         => '=',
)
),
'fields'                => 'ids',
);
$national_manager_args = array(
'post_type'             => 'professionals',
'services'              => 'leadership',
'posts_per_page'        => -1,
'meta_key'              => 'last_name',
'orderby'               => 'meta_value',
'order'                 => 'asc',
'meta_query'            => array(
array(
'key'             => 'job_title',
'value'           => 'National Managing Director',
'compare'         => '=',
)
),
'fields'                => 'ids',
);
$regional_manager_args = array(
'post_type'             => 'professionals',
'services'              => 'leadership',
'posts_per_page'        => -1,
'meta_key'              => 'last_name',
'orderby'               => 'meta_value',
'order'                 => 'asc',
'meta_query'            => array(
array(
'key'             => 'job_title',
'value'           => 'Regional Managing Director',
'compare'         => '=',
)
),
'fields'                => 'ids',
);
$cfo_args = array(
'post_type'             => 'professionals',
'services'              => 'leadership',
'posts_per_page'        => -1,
'meta_key'              => 'last_name',
'orderby'               => 'meta_value',
'order'                 => 'asc',
'meta_query'            => array(
array(
'key'             => 'job_title',
'value'           => 'CFO',
'compare'         => 'LIKE',
)
),
'fields'                => 'ids',
</pre>
);

I created four sets of arguments for the four Leadership positions, ordered by importance as provided by the client. The difference with the “CFO” args is that it uses compare => ‘LIKE’ because his title is actually, “Managing Director, CFO” but since that could change, I only want to search for records that contain “CFO” in the job_title field. The included line:

'fields' => 'ids',

Limits each WP_Query to only returning the IDs of the Professionals CPT items that match the meta_query for each set of arguments. This reduces overhead and makes the next part of this simpler.

With all of the arguments set, it’s time to write the queries and store each job_title as its own variable.

$ceo_query = new WP_Query( $ceo_args );
$cfo_query = new WP_Query( $cfo_args );
$national_manager_query = new WP_Query( $national_manager_args );
$regional_manager_query = new WP_Query( $regional_manager_args );

We now have four arrays of IDs for CPT entries matching the necessary job titles. The next step is to combine those separate arrays into a single array in the order required by the client.

$professionals_combined = array_merge($ceo_query->posts, $national_manager_query->posts, $regional_manager_query->posts, $cfo_query->posts);

Finally, we need to create the arguments for calling all of the associated post data for each of those IDs in the $professionals_combined array so that we can iterate over them and output the Professionals tagged with the “Leadership” Service taxonomy term in the order the client requires. We’re only returning the IDs included in the $professionals_combined array and limit the query to them by using the ‘post__in’ attribute:

$professionals_query = new WP_Query( array(
'posts_per_page'        => -1,
'post_type'             => 'professionals',
'services'              => 'leadership',
'post__in'              => $professionals_combined,
'orderby'               => 'post__in'
));

Important note: ‘orderby’ => ‘post__in’ is extremely important, otherwise WP_Query will order them by ID ascending.

With this new query created, we’re ready to move onto non-“Leadership” service terms. To keep things simple, the $professionals_query variable is used for both “Leadership” and non-“Leadership” Service taxonomy terms so that I only had to create a single WP_Query loop iterator. I set up an over-arching conditional statement to check for the ID of the specific “Leadership” page so that when it is that page, the above code is used and, if not, the below code is used (the $prof_sort variable is the value of the service for the given page):

$managing_director_args = array(
'post_type'             => 'professionals',
'services'              => $prof_sort,
'posts_per_page'        => -1,
'meta_key'              => 'last_name',
'orderby'               => 'meta_value',
'order'                 => 'asc',
'meta_query'            => array(
array(
'key'             => 'job_title',
'value'           => 'Managing Director',
'compare'         => '=',
)
),
'fields'                => 'ids',
);
$director_args = array(
'post_type'             => 'professionals',
'services'              => $prof_sort,
'posts_per_page'        => -1,
'meta_key'              => 'last_name',
'orderby'               => 'meta_value',
'order'                 => 'asc',
'meta_query'            => array(
array(
'key'             => 'job_title',
'value'           => 'Director',
'compare'         => '=',
)
),
'fields'                => 'ids',
);
$senior_manager_args = array(
'post_type'             => 'professionals',
'services'              => $prof_sort,
'posts_per_page'        => -1,
'meta_key'              => 'last_name',
'orderby'               => 'meta_value',
'order'                 => 'asc',
'meta_query'            => array(
array(
'key'             => 'job_title',
'value'           => 'Senior Manager',
'compare'         => '=',
)
),
'fields'                => 'ids',
);
$managing_director_query = new WP_Query( $managing_director_args );
$director_query = new WP_Query( $director_args );
$senior_manager_query = new WP_Query( $senior_manager_args );
$professionals_combined = array_merge($managing_director_query->posts, $director_query->posts, $senior_manager_query->posts);
$professionals_query = new WP_Query( array(
'posts_per_page'        => -1,
'post_type'             => 'professionals',
'services'              => $prof_sort,
'post__in'              => $professionals_combined,
'orderby'               => 'post__in'
));

All of the code above is laid out in the following conditional:

if(get_the_ID() === 567):
// Returning only the Professionals tagged with the 'leadership' Service taxonomy
// term for /our-company/leadership/ which is post ID 567
// code for $ceo_args, $national_manager_args, $regional_manager_args, and $cfo_args
else: 
// code for $managing_director_args, $director_args, $senior_manager_args
endif;

Now with everything setup to properly order each Service taxonomy term’s related Professional CPT items by the required job_title and then alphabetically by last_name within in each job_title, we can create our custom Loop iterator:

if ($professionals_query->have_posts()): 
while($professionals_query->have_posts()):
$professionals_query->the_post();
// code including HTML structure for outputting each Professional
endwhile,
endif;
wp_reset_postdata();

Now our Professionals are properly ordered and being output as such!

Contact Me

Have a question for me? Get in touch with me here and I'll respond as quickly as I can!
  • This field is for validation purposes and should be left unchanged.
Loading...