I think you’ll just need to loop the loop and first build a helper array to contain the hierarchy, then work with that to print out any necessary html. Caching the resulting helper array to a transient might be a good idea to save processing time.
// is there a transient?
$transient = get_transient( "parent_children_ids_{$post_id}" );
if ( ! $transient ) {
// initial query
$all_services = new WP_Query( $args );
// first sort found posts to a helper associative array
$posts_by_id = array();
foreach ($all_services->posts as $service) {
$posts_by_id[$service->ID]$service;
}
// create hierarchy array
$parent_children_ids = array();
// track parents IDs that are not in found posts
$missing_parent_ids = array();
// WP_Query by default returns array of WP_Post objects
// WP_Post has a property post_parent, which is the ID of the parent post, if such is set
foreach ($all_services->posts as $service) {
// add parents as top level keys
if ( ! $service->post_parent ) {
if ( ! isset($parent_children_ids[$service->ID]) ) {
$parent_children_ids[$service->ID] = array();
}
continue;
}
// add the parent to the array, if it hasn't been added already
if ( ! isset( $parent_children_ids[$service->post_parent] ) ) {
$parent_children_ids[$service->post_parent] = array();
}
// should the parent be queried
if ( ! isset( $posts_by_id[$service->post_parent] ) ) {
$missing_parent_ids[] = $service->post_parent;
}
// append the post to the child array
$parent_children_ids[$service->post_parent][] = $service->ID;
}
// query the missing parent posts
if ( $missing_parent_ids ) {
$missing_parents = new WP_Query('post__in' => $missing_parent_ids);
// push the found posts to the posts helper array
foreach ($missing_parents->posts as $service) {
$posts_by_id[$service->ID]$service;
}
}
// do some further sorting, if needed..
// perhaps save the $parent_children_ids to an transient
// to skip the previous processing for a suitable length of time
// remember to clear the transient when the source data changes to have the transient rebuilt
set_transient( "parent_children_ids_{$post_id}", $parent_children_ids, DAY_IN_SECONDS );
} else {
$parent_children_ids = $transient;
}
// loop the parents and chilrend array
foreach ($parent_children_ids as $parent_id => $child_ids) {
$parent = $posts_by_id[$parent_id];
// parent code..
foreach ($child_ids as $child_id) {
$child = $posts_by_id[$child_id];
// child code...
}
}