1

I will really appreciate your help to create a function that will check by a given $my_custom_post_type_name and $post_name and return true if the current page / post is a $post_name or $post_name_child or $post_name_grandchild and so on based on the provided parent slug and custom post type.

Let's say this is the structure:

my_custom_post_type_name

-first_page (example.com/my_custom_post_type_name/first_page)
--first_page_child
---first_page_grandchild
--first_page_child_2

-second_page
--second_page_child
---second_page_grandchild

I want to be able to target all pages that are first_page or its children / grandchildren and so on.

Something like:

if( my_custom_function('my_custom_post_type_name', 'first_page') ){

//do stuff if the current page is 'first_page' OR 'first_page_child' OR 'first_page_grandchild' OR 'first_page_child_2'

}

After some research I was able to come up with the following (still need to change first_page ID to be a slug, and to get rid of in_array() check so the custom function will do it all at once):

function get_posts_children($CPT, $parent_id){

        $children = array();
        $children[] = $parent_id;

        // grab the posts children
        $posts = get_posts( 
            array( 
                'numberposts' => -1, 
                'post_status' => 'publish', 
                'post_type' => $CPT, 
                'post_parent' => $parent_id
            )
        );

        // now grab the grand children
        foreach( $posts as $child ){

            // call the same function again for grandchildren   
            $gchildren = get_posts_children($CPT, $child->ID);
            // merge the grand children into the children array
            if( ! empty($gchildren) ) {
                $children = array_merge($children, $gchildren);
            }
        }

        // merge in the direct descendants we found earlier
        $children = array_merge($children, $posts);

        return $children;
    }

//and then (where 3060 is the first_page ID):

global $post;

if( in_array( $post->ID, get_posts_children( 'my_custom_post_type_name', 3060 ) ) ) {
  //do stuff. As it is now, it is working fine. But would really like to simplify it and to change the first_page ID to be a slug for obvious reasons.
}
0

I guess you want to check if the active page is a) of your custom post type and b) one of the ancestors is your parameter.

First of all, i would advise you to keep on using the ID, as slugs and titles can be non-unique, so one slug could be different posts.

Second, you can use wordpress' own get_post_ancestors-function. Use it like this:

function wpse365743_has_ancestor($postid,$ancestor_id){
  //get all parents and ancestors of $postid
  $ancestors = get_post_ancestors($postid);
  //add in the current post id
  $ancestors = array_merge(array($postid),$ancestors);
  //is the searched ancestor id in the ancestors?
  return in_array($ancestor_id,$ancestors); 
}

You can now use this anywhere on your page like this:

if(('my_post_type_name' == get_post_type($check_post_id)) && wpse365743_has_ancestor($check_post_id,$searched_ancestor_id)){
   //do something
}

Happy Coding!

  • Hi, thanks. But it's not what I need. – Victor May 4 '20 at 15:30
  • Are you sure? Because thats exactly what your function does: checking if the current post is the child/grandchild/same of the given parameter. – HU ist Sebastian May 4 '20 at 17:11
  • Yes I’m sure. Since I asked for a slug not an ID. – Victor May 4 '20 at 17:52
0

Ok I found a way to do that. I hope it will help someone who is facing the same issue. If you want to target only specific posts based on the parent slug or ID (both will work) and a given post type (custom_post_type or a page or a post).

In this case, only affecting:

my_custom_post_type_name

-first_page (example.com/my_custom_post_type_name/first_page)
--first_page_child
---first_page_grandchild
--first_page_child_2

But without affecting:

my_custom_post_type_name

-second_page
--second_page_child
---second_page_grandchild

Here is the function you need:

function get_posts_children($CPT, $post_slug){

    //check if the $post_slug is a string.
    if(is_string($post_slug)){
        $parent_page_obj = get_page_by_path( $post_slug, '', $CPT );
        if ( ! empty( $parent_page_obj ) ) {
            $parent_id = $parent_page_obj->ID; //assign $parent_id to be an integer.
        }
    }

    //check if the $post_slug is an integer(ID) for when the function is calling itself (for grandchildren check).
    if( is_int ( $post_slug ) ){
        $parent_id = $post_slug; //if $post_slug is an integer assign it to $parent_id
    }

    $group = array();
    $group[] = $parent_id; //add $post_slug (in this case coverted to $parent_id already) to be a part of the array. (you can remove it if you only need the children and grandchildren of a given post ID or slug).

    // grab the direct children of the post by given $post_slug or post ID.
    $direct_children = get_posts( 
        array( 
            'numberposts' => -1, 
            'post_status' => 'publish', 
            'post_type' => $CPT, 
            'post_parent' => $parent_id
        )
    );

    // now grab the grandchildren
    foreach( $direct_children as $child ){
        $grandchildren = get_posts_children($CPT, $child->ID); // call the same function again  for grandchildren   

        if( ! empty($grandchildren) ) {
            $group = array_merge($group, $grandchildren); // merge the grandchildren into the children array
        }
    }

    $group = array_merge($group, $direct_children); // merge in the $direct_children into the group array.

    return $group; //return an array of all the IDs found.
}

And then to target these posts/pages from anywhere and compare them to current displayed page/post you need:

global $post;

if(in_array($post->ID, get_posts_children('my_custom_post_type_name', 'first_page'))){
  //do something. If the current displayed page is 'first_page' OR 'first_page_child' OR 'first_page_grandchild' OR 'first_page_grandchild'.

  //But it will not affect if the current displayed page is 'second_page' OR 'second_page_child' OR 'second_page_grandchild'.

  //This is handy to do many things. 
  //I'm currently using it to redirect some specific custom user capabilities from restricted areas. 
  //But allowing them to access second_page and its children for that matter.    
}

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.