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 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:

<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 =)

share|improve this question
    
You'll need a custom walker, as WP's walker doesn't give you any control over the HTML it generates. Or you could use the get_categories() function to get a array of all categories, and build the entire menu yourself (but you'll still end up creating something like a walker) –  onetrickpony Dec 17 '10 at 11:00
add comment

1 Answer

up vote 1 down vote accepted

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();
    }
  }
);
share|improve this answer
    
why extend walker_category and not walker? –  onetrickpony Dec 17 '10 at 16:22
    
1: Because Walker_Category is what I would be using if I did not use a custom walker –  Tom J Nowell Dec 17 '10 at 16:25
    
2: Because changing it to inherit from Walker results in the following error Fatal error: Cannot access empty property in /*******************/public_html/wp-includes/classes.php on line 932 –  Tom J Nowell Dec 17 '10 at 16:25
add comment

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.