17

How would I get the top-level parent of a given term?

I am using wp_get_object_terms to get taxonomy terms on posts, but instead of showing all tagged terms, I only want to show tagged terms' top-level parents.

So if these are my selected terms, I only want to show Breakfast, Lunch and Dinner.

x BREAKFAST
   x Cereal
   x Eggs
  LUNCH
     Hamburger
   x Pizza
  DINNER
     Fish
        Bass
      x Salmon
        Trout
     Lasagna

How can I do this?

8 Answers 8

24

Since 3.1.0, get_ancestors() is available. It returns an array of ancestors from lowest to highest in the hierarchy.

2
  • 1
    This is the correct answer in my opinion.
    – numediaweb
    Commented Jul 5, 2015 at 10:14
  • 1
    This is the best answer.
    – Mark
    Commented Jul 22, 2015 at 21:28
24

Thanks to Ivaylo for this code, which was based on Bainternet's answer.

The first function below, get_term_top_most_parent, accepts a term and taxonomy and returns the the term's top-level parent (or the term itself, if it's parentless); the second function (get_top_parents) works in the loop, and, given a taxonomy, returns an HTML list of the top-level parents of a post's terms.

// Determine the top-most parent of a term
function get_term_top_most_parent( $term, $taxonomy ) {
    // Start from the current term
    $parent  = get_term( $term, $taxonomy );
    // Climb up the hierarchy until we reach a term with parent = '0'
    while ( $parent->parent != '0' ) {
        $term_id = $parent->parent;
        $parent  = get_term( $term_id, $taxonomy);
    }
    return $parent;
}

Once you have the function above, you can loop over the results returned by wp_get_object_terms and display each term's top parent:

function get_top_parents( $taxonomy ) {
    // get terms for current post
    $terms = wp_get_object_terms( get_the_ID(), $taxonomy );
    $top_parent_terms = array();

    foreach ( $terms as $term ) {
        //get top level parent
        $top_parent = get_term_top_most_parent( $term, $taxonomy );
        //check if you have it in your array to only add it once
        if ( !in_array( $top_parent, $top_parent_terms ) ) {
            $top_parent_terms[] = $top_parent;
        }
    }

    // build output (the HTML is up to you)
    $output = '<ul>';
    foreach ( $top_parent_terms as $term ) {
          //Add every term
          $output .= '<li><a href="'. get_term_link( $term ) . '">' . $term->name . '</a></li>';
    }
    $output .= '</ul>';

    return $output;
}
4
  • I'd love to see a modification that wouldn't just print out the top-level terms but, rather, all terms beneath the top-most parent, hierarchically. Commented Dec 22, 2018 at 0:14
  • @RobertAndrews If you just need the children of a single term, you can use WordPress's built-in get_term_children( $term, $taxonomy ) (documentation). If you wanted to to get all children of a given term's top-level parent, you could pass the above result into it, like this: get_term_children( get_term_top_most_parent( $term, $taxonomy ), $taxonomy ).
    – supertrue
    Commented Jan 4, 2019 at 21:12
  • What is $term in this case, ie. the object, the name of the term, the prefixed taxonomyname_number? In all cases, this method is extremely long to load. I've been waiting for the page to load for several minutes now. Commented Jan 4, 2019 at 21:54
  • 1
    As originally written it expected an ID, but I edited the answer to allow a term ID or WP_Term object. You're not the only one reporting an issue with this code—ideally it should be rewritten to use WP's built-in get_ancestors function, which was new and not well documented when the answer was written. I will post a new answer when I've had time to test.
    – supertrue
    Commented Jan 5, 2019 at 4:14
9

Here is a simple function that will get you the top most parent term of any given term:

function get_term_top_most_parent( $term_id, $taxonomy ) {
    $parent  = get_term_by( 'id', $term_id, $taxonomy );
    while ( $parent->parent != 0 ){
        $parent  = get_term_by( 'id', $parent->parent, $taxonomy );
    }
    return $parent;
}

Once you have this function you can just loop over the results returned by wp_get_object_terms:

$terms =  wp_get_object_terms( $post->ID, 'taxonomy' );
$top_parent_terms = array();
foreach ( $terms as $term ) {

    //Get top level parent
    $top_parent = get_term_top_most_parent( $term->ID, 'taxomony' );

    //Check if you have it in your array to only add it once
    if ( !in_array( $top_parent->ID, $top_parent_terms ) ) {
        $top_parent_terms[] = $top_parent;
    }
}
11
  • Thanks! I'm trying this now. FYI I think you're missing a close paren in line 1 of the function.
    – supertrue
    Commented Aug 3, 2011 at 13:19
  • do I need to add $taxonomy as a second parameter in $top_parent?
    – supertrue
    Commented Aug 3, 2011 at 13:20
  • I added the $taxonomy parameter but am getting an error when I use this code, here: gist.github.com/1122631
    – supertrue
    Commented Aug 3, 2011 at 13:33
  • yeah you do. i updated the answer.
    – Bainternet
    Commented Aug 3, 2011 at 13:33
  • 1
    your function seems broken your foreach loops are overlapping try this: pastebin.com/u48dxzap and if you still get an error paste all of you code and i'll check
    – Bainternet
    Commented Aug 3, 2011 at 17:36
5
/**
 * Get top level term
 */
function get_top_level_term($term,$taxonomy){
    if($term->parent==0) return $term;
    $parent = get_term( $term->parent,$taxonomy);
    return get_top_level_term( $parent , $taxonomy );
}
1
  • 1
    Please add an explanation along with your code.
    – s_ha_dum
    Commented Oct 18, 2013 at 4:43
4

I had the same problem and I solved easily. Check this out:

Define $taxonomy. It can be the slug of the taxonomy you want to get the data. After doing this, you can simply do this:

<?php
    $postterms = wp_get_post_terms($post->ID, $taxonomy);   // get post terms
    $parentId = $postterms[0]->parent;                      // get parent term ID
    $parentObj = get_term_by('id', $parentId, $taxonomy);   // get parent object 
?>

Now you got something like this:

object(stdClass)#98 (11) {
  ["term_id"]=>
  int(3)
  ["name"]=>
  string(8) "Esportes"
  ["slug"]=>
  string(8) "esportes"
  ["term_group"]=>
  int(0)
  ["term_taxonomy_id"]=>
  int(3)
  ["taxonomy"]=>
  string(17) "noticiaseditorias"
  ["description"]=>
  string(0) ""
  ["parent"]=>
  int(0)
  ["count"]=>
  int(4)
  ["object_id"]=>
  int(123)
  ["filter"]=>
  string(3) "raw"
}

And you can use $parentObj to get slug, name, id, whatever. Just by using $parentObj->slug or $parentObj->name as exemple.

3

Easiest way:

$rootId = end( get_ancestors( $term_id, 'my_taxonomy' ) );
$root = get_term( $rootId, 'my_taxonomy' );
echo $root->name;
0
0

Maybe this helps: get_ancestors( $object_id, $object_type );

codex.wordpress.org

0

Try this!

function get_term_top_most_parent( $term_id, $taxonomy ) {
    $ancestors = get_ancestors( $term_id, $taxonomy );

    if(!empty($ancestors)){
        $parentID = end( $ancestors );
    }else{
        $parentID = $term_id;
    }
    return $parentID;
}
1
  • Please edit your answer, and add an explanation: why could that solve the problem?
    – fuxia
    Commented Sep 1, 2021 at 12:25

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.