Get only the grandchildren, not the direct children of page/current page?

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 ) )
            continue;

        // 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 );

        the_title();

    }
    wp_reset_postdata();
}