Controlling Taxonomy Category listings to hide and unhide specifics

I have a vertical menu using the superfish script that shows categories in a custom ‘productcategory’ taxonomy. This menu has multiple levels, and is hierarchical.At the bottom of each branch of the tree we have the end category which represents a range of products, which the client does not want to show in this menu.

I am using this code to display it:

Read More
<ul class="frontcatlist sf-menu">
<?php
    $a = array(
        'title_li'  =>  '',
        'taxonomy'  =>  'productcategory',
        'depth'     =>  2
    );
    wp_list_categories( $a );
?>
</ul>

This is what I currently have in terms of what is showing and what isnt. left being the main categories, and each line being 1 step down to its children:

alt text

Those in the red are the categories that are not shown in the menu,

This is not what my client needs however. While I could produce a menu that fits the requirements using the native WordPress 3 menus, that would require manual intervention, intervention that is undesirable, both from a usability perspective, and from the clients wishes.

Since some main categories have subcategories that should be shown and some dont, the depth parameter will not suffice. Instead this is what I need, with the top level categories always showing:

alt text

Im not sure how to do this, and the only clue I have is a custom walker class to output custom html, during which I might be able to filter out the ones I dont want ( any categories with a parent that has no children). But I could not see any sufficient examples or articles on the subject, and I’d rather not loose the classes and markup wordpress provides

If anybody has any thoughts, or knows of tutorials forum posts or articles of use, I’d much appreciate it =)

Related posts

Leave a Reply

1 comment

  1. I’ve made some progress based on walker classes but havent gotten ti working quite as needed because wordpress doesnt appear to handle the root nodes of the taxonomy tree in the same way as the child ones.

    As a result, it prunes the end menu items, but if the parent of that node is a root level node, it prunes the node and leaves an empty ul element behind, <ul></ul>. The code that fixes this issue on child nodes does not work for a root node, resulting in the whole structure flattening with no submenus

    class Post_Category_Walker extends Walker_Category {
    
        private $term_ids = array();
        function __construct( /*$post_id,*/ $taxonomy )  {
            // fetch the list of term ids for the given post
            $this->taxterms = get_terms( $taxonomy);
            $this->noshow = array();
        }
        function isdisplayable( $element, &$children_elements, $args ){
            $id = $element->term_id;
            if(in_array($element->term_id, $this->noshow)){
                return false;
            }
            $display = true;
            if($element->parent != 0){
                $display = false;
                if ( isset( $children_elements[ $id ] ) ) {
                    $display = true;
                }
            }
            if($depth == 0){
                $display = true;
            }
            return $display;
        }
        function hasChildren( $element/*, &$children_elements*/){
            foreach($this->taxterms as $term){
                if($term->parent == $element->term_id){
                    return true;
                }
            }
            return false;//(isset($children_elements[$element->term_id]));
        }
        function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
            $display = $this->isdisplayable( $element, $children_elements, $args );
            $id = $element->term_id;
            if($element->parent != 0){
    
                if($this->hasChildren($element)){ //isset( $children_elements[ $id ] ) ) {
                    $endnode = true;
                    //print_r($children_elements[ $id ]);
                    foreach($this->taxterms as $child){
                        if($child->parent == $element->term_id){
                            if($this->hasChildren($child)){
                                $endnode = false;
                                break;
                            }
                        }
                    }
                    if($endnode == true){
                        //$children_elements = NULL;
                        unset( $children_elements[ $id ] );
                        $newlevel = false;
                        $args[0]['has_children'] = 0;
                    }
                }
            }else{
                // WordPress separates out the terms into top level and child terms,
                // making the top level terms very costly as it passes in an empty 
                // array as the children_elements unlike the other terms
                //if($this->hasChildren($element)){
                    foreach($this->taxterms as $term){
                        if($term->parent == $element->term_id){
                            if(!$this->hasChildren($term)){
                                $this->noshow[] = $term->term_id;
                                unset($newlevel);
                                $args[0]['has_children'] = 0;
                            }
                        }
                    }
                //}
            }
    
            if ( $display )
                parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
        }
    }
    $a = array(
        'title_li'  =>  '',
        'taxonomy'  =>  'productcategory',
        'walker'    =>  new Post_Category_Walker('productcategory')
    );
    wp_list_categories( $a );
    

    A temporary workaround is to remove them via the following jquery snippet:

    $("ul").each(
      function() {
        var elem = $(this);
        if (elem.children().length == 0) {
          elem.remove();
        }
      }
    );