Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I have a number of top-level categories including "News" and "Sport". They each have multiple levels of child categories as shown below.

  • News

    • Australia
      • NSW
        • Sydney
  • Sports

    • Cycling
      • Road Cycling
      • BMX
    • Triathlon

In my loop I want to display a single category - what ever is the deepest child category of "Sport".

I have found some code on StackOverflow that does returns the deepest child category, but not from a specific category. It returns the the deepest child category from all top-level categories. So if a post is in two categories (Sydney and Triathlon) the code shows Sydney as the deepest child category. I somehow need to specify that which top-level category I want the deepest child to come from. In this case that would be "Sport" and the deepest child cat would therefore be "Triathlon".

share|improve this question
    
How would the code know that you specifically want 'Sport' and not 'News'? If you instead gave this task to a set of people, how would they know that you specifically wanted 'Sport' and not 'News' without resorting to crystal balls? It seems somewhat arbitrary and suggests you intend to hardcode things somewhere –  Tom J Nowell Jul 7 at 21:53

3 Answers 3

OK - I originally misunderstood your question.

function getLowestCategory()
{
    $postCategories = get_the_category();
    for ($I = 0;$I<sizeof($postCategories);$I++)
    {
        //this is a top level category
        if ($postCategories[$I])
        {
            continue;
        }
        for ($J=0;J<sizeof($postCategories);$J++)
        {
            //if another category lists it as its parent, it cannot be the lowest category 
            if (strcmp($postCategories[$I]->name,$postCategories[$J]->category_parent)==0)
            break;
        }
        //at this point, no other cateogry says it's its parent, therefore it must be the lowest one
        return $postCategories[$I]->name;
    }
}
share|improve this answer
    
Thanks for the help @fdsa. Your solution did indeed target the correct top-level category, but it pulls out the last child category (not necessarily the deepest). In the instance of my demo categories, "Sports" is category 2. And if I use your code of get_categories('child_of=2') I might have been wrong path when I said the code from StackOverflow was close, because –  TheLoneCuber Jun 8 '12 at 6:52
    
(I always hit the "Enter" key by habit which send my reply before I've finished it). In the instance of my demo categories, "Sports" is category 2. And if I use your code of get_categories('child_of=2'), then the "Triathlon" child category is shown for all posts (even posts that aren't in that category). I think that's the difference between get_the_category and get_categories isn't it? That get_categories returns objects for each category assigned to the post. –  TheLoneCuber Jun 8 '12 at 6:59
    
@Thao does the edit work for you? –  fdsa Jun 12 '12 at 5:30
    
This answer makes no attempt to explain how it answers the question. Can you explain the code and how it solves the problem, and what you did? –  Tom J Nowell Jul 7 at 21:51

The code you referenced in your question is flawed. In most cases it will work but it relies on an assumption that newer child terms are created after their parents, and as a result, have higher IDs.

To fool the code you posted, do this:

  • Create a new category
  • Edit an older child term
  • Change its parent to the new category
  • Make sure it has a different depth

You also have the other problem of specificity. In your example, you specify that it should look inside sport, not all, but how would the code know to look specifically in sport? This sounds like you plan to hardcode the Sport category name or ID into your code, which I STRONGLY advise against. Instead a post meta value or metabox UI would be better but not ideal.

Your question can be distilled to this:

Given a post A, and a term B, what is the deepest child term of B on post A? Where B is of taxonomy 'category'.

This gives us 2 new questions:

  1. How do you determine if term A contains term B?
  2. How do you find out how many ancestors/parents a term has?

The answers to those questions would implement these 2 functions:

  • get_term_depth( $term ) - returns the depth or number of parents a term has
  • is_term_ancestor( $term, $ancestor ) - is this term an ancestor of another term? Returns true or false

These functions are not a part of WordPress core, and will need to be written.

But if using these 2 functions we could then do this:

function get_deepest_child_term( $terms, $specific_term ) {
    $deepest_term = $specific_term;
    $deepest_depth = get_term_depth( $specific_term );
    foreach ( $terms as $term ) {
        if ( is_term_ancestor( $term, $specific_term ) ) {
            $depth = get_term_depth( $term );
            if ( $depth > $deepest_depth ) {
                $deepest_term = $term;
                $deepest_depth = $depth;
            }
        }
    }
    return $deepest_depth;
}

Which you could then use like this:

$terms = wp_get_object_terms( $post_id, 'category' );
$sport_term = get_term_by( 'slug', 'sport', 'category' );
$deepest_term = get_deepest_child_term( $terms, $sport_term );
echo $deepest_term->name;

You'll note I went directly to the taxonomy term API rather than using the higher level middle men such as get_the_category. This way the code is just as valid for custom taxonomies. E.g. a product category.

The implementation of get_term_depth and the implementation of is_term_ancestor I leave as a task to the reader, and encourage 2 new questions be asked, as they are each useful and interesting questions in their own right. It's important to break down a task into smaller parts, repeating the process until each part is solvable or bite sized. Both functions would require an understanding of recursion to implement.

share|improve this answer

I have found some code on StackOverflow that does returns the deepest child category, but not from a specific category

So what you are missing is, to specify a category. Why dont you do it? It's simple

$catID = get_cat_ID( 'Sports' );
$categories = get_the_category( $catID );
if ( $categories ) {
    $deepChild = get_deep_child_category( $categories );
    ?>
        <a href="<?php echo get_category_link( $deepChild->term_id ); ?>" title="<?php echo sprintf( __( "View all posts in %s" ), $deepChild->name ); ?>"><?php echo $deepChild->name; ?></a>
    <?php 
}

function get_deep_child_category( $categories )
{
    $maxId = 0;
    $maxKey = 0;
    foreach ( $categories as $key => $value )
    {
        if ( $value->parent > $maxId )
        {
            $maxId = $value->term_id;
            $maxKey = $key;
        }
    }
    return $categories[$maxKey];
}
share|improve this answer
    
get_the_category takes a post ID not a term ID –  Tom J Nowell Jul 7 at 22:19

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.