0

I am trying to use this code:

<?php if(count(get_post_ancestors($post->ID)) == 2 ) : ?>
        <script>...</script>
<?php endif ?>

to add a script to a page but only if the page is a grandchild page (3rd level down, when it has 2 ancestors):

Desired Result (with code above):

  • Parent Page
    • Child Page
      • Grandchild Page (show script here only)

But the script is showing on child pages as well as grandchild pages. Why would that be?

Actual Result (with code above):

  • Parent Page
    • Child Page (script is showing here)
      • Grandchild Page (script is showing here)

EDIT: this is my query code on the children pages (with a different ID for post_parent, depending on the child page):

<?php $args = array('post_parent' => 21); 
   $loop = new WP_Query( $args ); 
   while ( $loop->have_posts() ) : $loop->the_post(); 
?> 
... 
<?php endwhile; ?>
  • Works when I try it. What is the output of var_dump(get_post_ancestors($post->ID));? – s_ha_dum Nov 24 '15 at 0:46
  • I get this on the parent page: array(0) { } and this on the child and grandchild pages array(2) { [0]=> int(21) [1]=> int(10) } – codeview Nov 24 '15 at 2:16
  • does var_dump($post->ID) yield the correct ID on both pages? – Douglas.Sesar Nov 24 '15 at 5:01
  • Then you child page is not a true child page. You will need to verify your hierarchy, because clearly, from the var_dump() your child page is actually a grandchild. If your hierarchy is correct, your code in which you are running the code above has issues, (using query_posts which will break code, a bad filter or a bad query) in which case it will be best to add all relevant code. – Pieter Goosen Nov 24 '15 at 6:12
  • @PieterGoosen - I'm not quite sure how to decipher the var_dump output. I don't think I'm doing anything strange with my code and the pages are setup as children and grandchildren in the pages menu of the Wordpress admin. – codeview Nov 24 '15 at 19:15
1

Something is changing your results from get_ancestors() or something is changing your query which "changes" your child pages to grandchild pages when queried on the page. It also seems from comments that the post ID's does not stay constant on the page.

What immediately catches my eye from your updated code is that your custom query is not resetted after you are done. You have to remember, the_post() sets the $post global to the current post being looped over in the loop, and once the loop is done, $post will hold the last post object of the loop.

You can add var_dump( $post ); before and after your current code and you will see that the value of $post differs. That is why you must always reset custom queries after you are done. Simply add wp_reset_postdata(); directly after endwhile just before endif. Doing a var_dump( $post ); now before and after the loop should render the same value.

$post is a global variable that is changed by many things, and bad code (like the code in your question) can change the $post global, which in turn returns wrong info, which in turn have you on a wild goose chase to find out why. A more reliable method is to use get_queried_object() to return the current page object. For an explanation, please feel free to check my question and the answer accepted answer from @gmazzap. Note, however this being reliable, query_posts breaks the main query object which holds the queried object.

I also note that you hardcode ID's, do not do that. Every post/page have a post_parent property. If a post type is non-hierarchical, like posts, the post_parent value will always be 0 because non-hierarchical post types don't have any hierarchy. Hierarchical post types like pages will either have 0 as post_parent if it is a top level page or have a numeric value if it is child/grandchild page, the value in post_parent will represent the ID of the page's direct parent.

  • To correctly get the page id of a page being viewed, use get_queried_object()->ID or get_queried_object_id() instead of $post->ID.

  • To get the immediate post parent ID of the current page being viewed, use get_queried_object()->post_parent

  • To get the top level parent, use end( get_ancestors( get_queried_object()->ID, 'page' ) ). Remember, the top level parent will be the last ID in the array of ID's returned by get_ancestors, the first ID will be the direct parent.

To rewrite your code, use something like this to get direct children of the page being viewed:

$page_object = get_queried_object();
// Check if page is top level or not and set $args accordingly
if ( $page_object->post_parent == 0 ) { // Top level page
    $parent_ID = (int) $page_object->ID;
} else { // Page is a child/grandchild page
    $parent_ID = (int) $page_object->post_parent;
}

// Setup query args
$args = [
    'post_parent' => $parent_ID,
    'post_type'   => 'page'
];
$q = new WP_Query( $args );
if ( $q->have_posts() ) {
    while ( $q->have_posts() ) {
    $q->the_post();

        // Run your code to display posts

    }
    wp_reset_postdata(); // EXTEMELY IMPORTANT!!!!!!!
}

To conclude, to determine the current hierarchy of a page, do the following

$current_page = get_queried_object();
if ( $current_page->post_parent == 0 ) {
    echo 'This is a parent';
} else {
    $hierarchy = get_ancestors( $current_page->ID, 'page' );
    $count = count( $hierarchy );
    $child = ( $count == 1 ) ? 'child' : 'grandchild';
    echo 'This is a ' . $child . ' page';
}
  • wp_reset_postdata() was the culprit. I don't have an endif in my loop, but adding wp_reset_postdata(); after endwhile returns the same ID now before and after the loop. Your code rewrite at the bottom of your answer is gonna take me some time to understand but for now my original code is working as I was expecting it to. I didn't expect a simple "echo this script if on a grandchild page" setup to take 2 days to figure out...gotta love coding, eh. Thank you very much for your help. Something little/edit (for future readers): wp_reset_postdat() is missing an "a" at the end. – codeview Nov 25 '15 at 18:04
  • I'm glad you got this solved. Thanks for the note on the missing a. One do miss some minor syntax when posting from small screen devices :-). The last block of code is just for testing basically, so you do not have to break your head on this right now. ;-). Enjoy and good luck on your project – Pieter Goosen Nov 25 '15 at 18:42
0

Try checking the $post->ID right at the wp hook:

add_action('wp','your_awesome_function');


function your_awesome_function()
{
     global $post;
     if( count(get_post_ancestors($post->ID)) == 2 )
          add_action('wp_footer','your_grandchild_script');
}

function your_grandchild_script()
{
     ob_start();
     ?>
          <script>...</script>
     <?php
     echo ob_get_clean();
}
  • Thanks for your time. I appreciate it. A lack of wp_reset_postdata() at the end of my loop was the culprit, as noted in the accepted answer & comment. – codeview Nov 25 '15 at 18:13

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.