1

As there doesn't seem to be an adequate and still actively developed WordPress plug-in that allows me to display a collapsible category tree without having to use widgets (I personally dislike widgets), I decided to write one on my own.

I wrote this code:

<script type="text/javascript">
    function toggleCatDiv(id) {
        if (jQuery("#catTogglerDiv-"+id).is(":visible")) {
            jQuery("#catToggler-"+id).innerHTML="►";
        }
        else {
            jQuery("#catToggler-"+id).innerHTML="▼";
        }

        jQuery("#catTogglerDIV-"+id).slideToggle("normal");
    }
</script>
<?php
$args = array('orderby' => 'name', 'parent' => 0 );
$categories = get_categories( $args );

foreach ( $categories as $category ) {

?>
<span style="cursor:pointer" id="catToggler-<?php echo $category->cat_ID; ?>" onclick="toggleCatDiv('<?php echo $category->cat_ID; ?>')">►</span> <a href="<?php echo get_category_link( $category->term_id ); ?>"><?php echo $category->name;?></a><br />
<div id="catTogglerDIV-<?php echo $category->cat_ID; ?>" style="margin-left:3em;visibility:hidden">
    <?php
    $args = array(
      'child_of'     => $category->cat_ID
    );
    $subcats = get_categories($args);
    foreach ( $subcats as $subcat ) {
        <a href="<?php echo get_category_link( $subcat->term_id ); ?>"><?php echo $subcat->name;?></a>
    }
    ?>
</div>
<?php

}
?>

As you might see, it's intended to grab the list of "main categories" and display a list of subcategories when clicking the arrow on each of them.

Now clicking the arrow does nothing (not even a JS error), and only 2 of 4 main categories are actually shown. Why?

brasofilo
  • 25,496
  • 15
  • 91
  • 179
r4ndom n00b
  • 89
  • 2
  • 8
  • if you have no event listeners for click event how do you want something to happen when you click on it? – lukaleli Oct 09 '13 at 00:08

1 Answers1

1

Problems with your code:

  • You have catTogglerDIV and catTogglerDiv. Give meaningful and consistent names to your functions and variables, it's very easy to get lost when many of them have similar names.

  • Some categories are not showing up because show_empty is true by default: Function_Reference/get_categories.

  • You are running the sub-categories foreach even if there are no sub-cats.

  • InnerHTML was not working for me, changed for html().

The widget I like the most is the Text Widget. Why? Because we can put Shortcodes there and execute any kind of output through our functions. Normally, I don't do Widgets, I do Shortcodes and use this technique.

The following filter is needed to enable this feature:

add_filter( 'widget_text', 'do_shortcode', 11 );

And a working example:

add_shortcode( 'cat_toggle', 'shortcode_so_19260684' );

function shortcode_so_19260684()
{
    wp_enqueue_script('jquery'); // Load jQuery only when shortcode present.

    # Start the output string
    $return = '
    <script type="text/javascript">
        function doToggle( id ) 
        {
            if ( jQuery( "#subCategories-" + id ).is( ":visible" ) )
                jQuery( "#catToggler-" + id ).html( "‣" );
            else
                jQuery( "#catToggler-" + id ).html( "▾" );

            jQuery( "#subCategories-" + id ).slideToggle( "normal" );
        }
    </script>';

    $categories = get_categories( array(
        'orderby'    => 'name', 
        'parent'     => 0, 
        'hide_empty' => false 
    ));

    foreach ( $categories as $category ) 
    {
        $subcats = get_categories( array(
            'child_of'   => $category->cat_ID, 
            'hide_empty' => false
        ));
        # Maybe useful
        if( !$subcats )
            $change_the_folding_indicator = 'ø';

        $return .= sprintf(
            '<span style="cursor:pointer" id="catToggler-%1$s" onclick="doToggle(\'%1$s\')">‣</span> <a href="%2$s">%3$s</a><br />
            <div id="subCategories-%1$s" style="margin-left:3em;display:none">',
            $category->cat_ID,
            get_category_link( $category->term_id ),
            $category->name
        );

        # Add this level only if subcats not empty
        if( $subcats ) 
        {
            foreach ( $subcats as $subcat ) 
            {
                $return .= sprintf(
                    '<a href="%s">%s</a>',
                    get_category_link( $subcat->term_id ),
                    $subcat->name
                );
            }
        }       
        $return .= '</div>';
    }
    return $return;
}
Community
  • 1
  • 1
brasofilo
  • 25,496
  • 15
  • 91
  • 179
  • Thanks, that did the trick! :-) (And thanks for the reference to the shortcode thing. Having used a static sidebar for years now due to its flexibility, I might have been wrong here...) – r4ndom n00b Oct 09 '13 at 10:37
  • Yes, TextWidget+Shortcode is bloody simple and has no limits ;o) I liked this exercise a lot, and if you develop and style this further, ping me with a link. – brasofilo Oct 09 '13 at 10:42