0

I made a script which checks if the currently viewed page has a parent page and if it does, it prints both the parent title and child title. But if there is no parent page I still get a title of the currently viewed page printed out twice. What's the deal? My code:

<div class="entry-content">
        <?php
        if(get_the_title(get_top_ancestor_id())) {
                    echo get_the_title(get_top_ancestor_id());
                    echo get_the_title();
                } else {
                    echo get_the_title();
                }.....

function get_top_ancestor_id() {

    global $post;

    if($post->post_parent) {
        $ancestors = array_reverse(get_post_ancestors($post->ID));
        return $ancestors[0];
    }
    return $post->ID;
}
6

Your conditional is always true. To understand why, consider what happens in this function when there is no post parent:

function get_top_ancestor_id() {

    global $post;

    // no parent so this doesn't run:
    // if($post->post_parent) {
    //     $ancestors = array_reverse(get_post_ancestors($post->ID));
    //     return $ancestors[0];
    // }
    return $post->ID;
}

Which simplifies to:

function get_top_ancestor_id() {
    global $post;
    return $post->ID;
}

So if there is no parent post, it returns the ID of the current post, which means your calls simplify to this:

                echo get_the_title();
                echo get_the_title();

My recommendation is to change the get_top_ancestor_id so that it returns false, or use this code:

    global $post;
    if( $post->post_parent ) {
        echo get_the_title(get_top_ancestor_id());
    }
    echo get_the_title();

Security

This code does not escape its output! If an administrator copy pasted a script tag with dangerous code into a post title, it would render in the browser!

Lets fix that with esc_html:

    global $post;
    if( $post->post_parent ) {
        echo esc_html( get_the_title(get_top_ancestor_id()) );
    }
    echo esc_html( get_the_title() );

The code is now safe, and any dangerous content is broken, preventing its execution. Similarly, use esc_attr for attributes, esc_url for URLs, and wp_kses_post if you need images/links/headings/etc

  • Thanks for a great explanation. Works fine, but weirdly enough, I'm not getting the parent page for woocommerce products. Which is fair enough, because woocommerce products are not stored together with my other pages and I didn't give them a parent page manually. But when I click on a certain product I still can see in the slug default woocommerce page product before every product name. So the slug for example looks like this: website.com/product/iphone I wonder how can I output both, iphone product page name and its parent product? – Limpuls Feb 18 '18 at 22:02
  • I take it you're using a page template to display them? Those products won't have a parent page, because they're not pages, and that's not how WooCommerce products work. you'll have to take a look at their developer resources and contact their support to find that answer, as WooCommerce specific questions are out of scope of this site – Tom J Nowell Feb 18 '18 at 22:33

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.