0

I have an array of IDs stored for custom post type "service". Some of these are parent IDs and some of these are child IDs.

So "service" post type here is hierarchical.

Now from this array of IDs, I want to list pages in the format so that:

  1. They are sorted by post title, ascending order.

  2. They are listed in parent > child pattern like this:

    Service 1
        A Child
        B Child
    Service 2
        X Child
        Y Child
    Service 3
    
  3. Also as the array contains any IDs, if there is child ID in the array, but parent ID is not then show the parent post automatically.

So far below is the code I have implemented:

$args = array(
    'post_type' => array( 'service' ),
    'posts_per_page' => '-1',
    'orderby' => 'title',
    'order' => 'ASC',
    'post__in' => $service_ids_array,
);

$all_services = new WP_Query( $args );

But, this just gets all the services from the array of IDs sorted by title.

Here is a logic I am trying to implement, but if there is a better solution, I am happy to use that.

So my logic was, to get all the posts from array that are on root level. So parent ID = 0. After that I run a loop of these IDs and in the loop I check if their child IDs exist in the $service_ids_array or not. And show if they exist.

But what if there are only child IDs in the array? In that case this logic will not succeed.

2
  • How did you end up with this array? I have to wonder if you are trying to solve the wrong problem. Perhaps you need a better array?
    – vancoder
    Commented Aug 31, 2021 at 18:36
  • The array is coming from a custom field data Commented Sep 1, 2021 at 1:47

1 Answer 1

0

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...
  }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.