How to use WP_Query (or direct sql) and return child post if available otherwise parent post?

Sample code:

$args = array(
    'post_type' => 'my-cpt',
    'post_status' => 'publish',
$query = new WP_Query( $args );

My target is that if any post (my-cpt) have child post then return last child otherwise return parent post.

Suppose: following my posts

  • parent-1

    • child-1-parent-1
    • child-2-parent-1
  • parent-2

  • parent-3
    • child-1-parent-3

So i want to return by my query child-2-parent-1, parent-2 and child-1-parent-3

How to modify my query to achieve this?

  • This won’t be achievable in a single query. Jul 7 '18 at 15:57

You'd need at least 2 queries for this task, since it's irregular. For example

// collect all child posts
$allChildPosts = get_posts([
  'post_parent__not_in' => [0],
  'posts_per_page' => -1,

// list child posts and filter one post by parent id
$childPosts = [];
foreach ($allChildPosts as $post) {
    $childPosts[$post->post_parent] = $post;

// get all parent level posts without descendants
$lonelyPosts = get_posts([
  'post_parent__not_in' => array_keys($childPosts),
  'posts_per_page' => -1,

$allPosts = array_merge($childPosts, $lonelyPosts);
// As a drawback, you'd have to sort them manually, since they are glued together
usort($allPosts, 'sorting_function');

First approach utilizes only 2 db queries, but will become inefficient with large quantity of posts

Second approach:

// get all parent posts
$parentPosts = get_posts([
  'post_parent' => 0,
  'posts_per_page' => -1,

$allPosts = [];
foreach ($parentPosts as $post) {
    $descendants = get_posts([
      'post_parent' => $post->ID,
      'posts_per_page' => 1,
      'orderby' => 'whatever'
    if ($descendants) {
        $allPosts[] = $descendants[0];
    } else {
        $allPosts[] = $post;

Second one is more straight-forward and also allows to order descendants (otherwise how to understand which of them must be last?), but since it makes numberOfParentPosts + 1 queries it will become inefficient with large quantity of parent posts.

If you need really efficient solution, you'd have to write clever MySQL manually.

But feel free to prove me wrong :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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