I know javascript pretty well now but I am new to php and wordpress theme building. I have searched a fair bit and can't find a solution to something that seems like a pretty simple task, all I would like to accomplish is get all the grandchildren of a page only, not the direct children, like so:


  • child 1
    • grandchild 1A
    • grandchild 1B
  • child 2
    • grandchild 2A
    • grandchild 2B

My page is "Portfolio" and I would like to "get_pages" but only the ones that are grandchildren of "Portfolio, so in this case it would return only: -"grandchild 1A", "grandchild 1B", "grandchild 2A", "grandchild 2B".

any suggestions?

  • I think I came to the same conclusions, the "get_pages" was just to illustrate :) Nov 23, 2015 at 10:36

3 Answers 3


There is no native way to do this AFAIK. The easiest way will be:

  • to simply query all the pages in the hierarchy of the page ID passed

  • then return all the parent ID's ($post_parent property of the post object) from all pages in an array

  • loop through the pages and compare the page ID against the ID's in the parent ID's array

  • any page which has its ID in the parent ID's array we will simply skip and exclude

  • any page which ID is not in the parent ID array, we will use this to build a new array, these pages will be the lowest level pages

The easiest will be to build our own custom function which we can call in any page template. Here is the function:

function get_lowest_level_pages( $page_id = '' )
    // Check if we have a page id, if not, return false
    if ( !$page_id )
            return false;

    // Validate the page id
    $page_id = filter_var( $page_id, FILTER_VALIDATE_INT );

    // Check if this is a page, if not, return false
    if ( !is_page() )
        return false;

    // Get all pages in hierarchy of the current page
    $args = [
        'child_of' => $page_id,
    $q = get_pages( $args );

    // Check if there are pages, if not, return false
    if ( !$q )
        return false;

    // Use wp_list_pluck to get all the post parents from all return pages
    $parents = wp_list_pluck( $q, 'post_parent' );
    // Set the $new__page_array variable that will hold grandchildren/lowest level pages
    $new__page_array = [];

    // Loop through all the pages
    foreach ( $q as $page_object ) {
        // Simply skip any page if it has child page
        if ( in_array( $page_object->ID, $parents ) )

        // Create a new array holding only grandchild pages
        $new__page_array[] = $page_object;

    return $new__page_array; 

You can then use it as follow: (Just remember to pass the id of the parent page you need to get the grand children from)

$page_id = get_queried_object_id(); // Returns the current page ID
$q = get_lowest_level_pages( $page_id );

if ( $q ) {
    foreach ( $q as $post ) {
        setup_postdata( $post );


  • Okay a whole bunch of information there, so I store the functions in my function.php, because I learned that was the best way to go about that, then the "use", I in this case use in my "page-portfolio.php, bit where do I pass the id? I know the ID to be 10, is there a way I can pass witht the slug name isntead? Nov 23, 2015 at 17:07
  • Just use my last block of code, get_queried_object_id() will return the ID of the page page-portfolio.php, no need to pass the slug. Passing the slug will lead to other headaches and will slow the code down even more. Nov 23, 2015 at 17:10
  • Any luck on this. Saw your update over on Stack Overflow. My code works, so if you have issues, it should be on your side. Let me know if you need any assistance here Nov 23, 2015 at 17:35

Use get_page_children

$all_wp_pages = get_all_page_ids();

// Get the page as an Object
$portfolio = get_page_by_title('Portfolio');

// Filter through all pages and find Portfolio's children
$portfolio_children = get_page_children($portfolio->ID, $all_wp_pages);

foreach ($portfolio_children as $child) {

    $post_data = array('child_of' => $child->ID);
    $grandchild = get_pages($post_data);

// echo what we get back from WP to the browser
echo '<pre>' . print_r($grandchild, true) . '</pre>';
  • I tried using your code, then added this, to loop through: 'foreach( $portfolio_children as $page ) { echo $page->post_title; }' But it returns the children also, so Child1 and Child2, This I could achieve with get_pages( array( 'child_of' => $post->ID,parent' => $post->ID, ));I am only looking for the grandchildren. Nov 23, 2015 at 11:11
  • @PieterGoosen You are right. Code is from codex.wordpress.org Nov 23, 2015 at 11:11
  • @WilliamLarsenBang check updated code Nov 23, 2015 at 11:29
  • nothing prints? Nov 23, 2015 at 12:18
  • U get no data ? I updated the code again Nov 23, 2015 at 12:24

This for so you can get an idea, havent tested this code but maybe you should try.


    $args = array(
    'post_parent' => 0, //post parent id
    'post_type'   => 'any', 
    'numberposts' => -1,
    'post_status' => 'any' 
    $childen = get_children( $args, OBJECT );

    foreach($children as $child){

      $args = array(
    'post_parent' => $child->ID,
    'post_type'   => 'any', 
    'numberposts' => -1,
    'post_status' => 'any' 
      $grand_children[] = get_children($args, OBJECT);

maybe you can try like that.

  • 2
    Your code makes no sense at all unfortuantely. What is $args and $output Nov 23, 2015 at 10:57
  • if you dont know can you google the get_children function or you are looking for spoon feeding. anyway here is the ref. codex.wordpress.org/Function_Reference/get_children
    – 1inMillion
    Nov 23, 2015 at 11:00
  • 1
    Listen here my friend, your crappy attitude is not welcomed. Please see How to Answer and rather learn how to add a proper answer than just a lot of rubbish that does not make sense. Nov 23, 2015 at 11:03
  • Okay I can't really make sense of this piece of code, would I have to declare $args and $output first? Nov 23, 2015 at 11:22
  • That is why I made a heading of "havent tested this code but maybe you should try' so that he could have an idea. Then from that on he could google what is get_children function is, and before you tell me its make no sense you should know what I am referring to. Where in my statement is rubbish attitude?
    – 1inMillion
    Nov 23, 2015 at 11:22

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.