How can I customize the wp_list_categories

I have a list of categories in woo-commerce which I’m trying to customize to be displayed to look like the following image.

List of categories

Read More

I created the above image using normal HTML and css however I would like to now convert it to WordPress in order to have it dynamically created.

Here is the HTML:

<div class="col tertiary" id="filters">
        <ul class="product-categories">        

            <li id="pattern_garment_type">
                <h5>Women</h5>
                <ul>
                    <li class="selected">                
                          <a href="#">All</a>                        
                    </li>

                    <li class="">
                      <a href="#">Accessories</a>
                    </li>

                    <li class="">
                      <a href="#">Blouses</a>
                    </li>

                    .etc...

          </ul>
            </li>

            <li id="pattern_garment_type">
                <h5>Men</h5>
                <ul>
                <li class="selected">

                      <a href="#">All</a>

                </li>

                  <li class="">
                      <a href="#">Accessories</a>
                  </li>

                  <li class="">
                      <a href="#">Coats</a>
                  </li>
                  ..etc..

                </ul>
            </li>


            <li id="pattern_garment_type">
                <h5>Kids</h5>
                <ul>
                <li class="selected">

                      <a href="#">All</a>

                </li>

                  <li class="">
                      <a href="#">Babies</a>
                  </li>

                  <li class="">
                      <a href="#">Girls</a>
                  </li>

                  <li class="">
                      <a href="#">Boys</a>
                  </li>

                </ul>
            </li>

        </ul>
    </div>

Here is the current WordPress code I’m working with (not sure if I should use the walker to customize the output to be generated like the HTML above):

  <div id="content-filters" class="two columns">
<?php $args = array(
    'style'              => 'list',
    'show_count'         => 0,
    'use_desc_for_title' => 1,
    'child_of'           => 0,
    'title_li'           => __( '' ),
    'show_option_none'   => __('No Menu Items'),
    'number'             => null,
    'echo'               => 1,
    'depth'              => 2,
    'taxonomy'           => 'product_cat',
); ?>

<div class="col tertiary" id="filters">
    <ul class="product-categories">   
        <?php wp_list_categories( $args ); ?>
    </ul>
</div>

1) How can I use wp_list_categories filter to add an “All” link at the top of the sub categories which links to a page which displays all items.

2) How can I also use the wp_list_categories filter to remove the link from the parent parent category and wrap it in an to make it bold (like in the example image)?

Any help would be appreciated

Related posts

2 comments

  1. Even if a wp_list_categories filter exists, it passes (and so you have to return) the html markup generated by wp_list_categories() function. This means that if you want use that filter you have to alter the DOM with php, and even if it’s possible (hopefully using external php libraries), sure it’s not the best solution for your needs.
    Alternartive are use js to alter html after it was created. It’s a possibility, but I’m a WP developer not a js one, so I’ll give you the Worpress solution.

    You have to create a custom Category Walker class and then use it inside a customuized version of wp_list_categories();

    Let’s start.

    First of all the custom Category Walker class (put it in functions.php):

    class My_Category_Walker extends Walker_Category {
    
      var $lev = -1;
      var $skip = 0;
      static $current_parent;
    
      function start_lvl( &$output, $depth = 0, $args = array() ) {
        $this->lev = 0;
        $output .= "<ul>" . PHP_EOL;
      }
    
      function end_lvl( &$output, $depth = 0, $args = array() ) {
        $output .= "</ul>" . PHP_EOL;
        $this->lev = -1;
      }
    
      function start_el( &$output, $category, $depth = 0, $args = array(), $id = 0 ) {
        extract($args);
        $cat_name = esc_attr( $category->name );
        $class_current = $current_class ? $current_class . ' ' : 'current ';
        if ( ! empty($current_category) ) {
          $_current_category = get_term( $current_category, $category->taxonomy );
          if ( $category->term_id == $current_category ) $class = $class_current;
          elseif ( $category->term_id == $_current_category->parent ) $class = rtrim($class_current) . '-parent ';
        } else {
          $class = '';
        }
        if ( ! $category->parent ) {
          if ( ! get_term_children( $category->term_id, $category->taxonomy ) ) {
              $this->skip = 1;
          } else {
            if ($class == $class_current) self::$current_parent = $category->term_id;
            $output .= "<li class='" . $class . $level_class . "'>" . PHP_EOL;
            $output .= sprintf($parent_title_format, $cat_name) . PHP_EOL;
          }
        } else { 
          if ( $this->lev == 0 && $category->parent) {
            $link = get_term_link(intval($category->parent) , $category->taxonomy);
            $stored_parent = intval(self::$current_parent);
            $now_parent = intval($category->parent);
            $all_class = ($stored_parent > 0 && ( $stored_parent === $now_parent) ) ? $class_current . ' all' : 'all';
            $output .= "<li class='" . $all_class . "'><a href='" . $link . "'>" . __('All') . "</a></li>n";
            self::$current_parent = null;
          }
          $link = '<a href="' . esc_url( get_term_link($category) ) . '" >' . $cat_name . '</a>';
          $output .= "<li";
          $class .= $category->taxonomy . '-item ' . $category->taxonomy . '-item-' . $category->term_id;
          $output .=  ' class="' . $class . '"';
          $output .= ">" . $link;
        }
      }
    
      function end_el( &$output, $page, $depth = 0, $args = array() ) {
        $this->lev++;
        if ( $this->skip == 1 ) {
          $this->skip = 0;
          return;
        }
        $output .= "</li>" . PHP_EOL;
      }
    
    }
    

    It extends the WP Walker_Category and overwrite all the 4 methods with something that fits your needs.

    After that, in the functions.php put the customized function:

    function custom_list_categories( $args = '' ) {
      $defaults = array(
        'taxonomy' => 'category',
        'show_option_none' => '',
        'echo' => 1,
        'depth' => 2,
        'wrap_class' => '',
        'level_class' => '',
        'parent_title_format' => '%s',
        'current_class' => 'current'
      );
      $r = wp_parse_args( $args, $defaults );
      if ( ! isset( $r['wrap_class'] ) ) $r['wrap_class'] = ( 'category' == $r['taxonomy'] ) ? 'categories' : $r['taxonomy'];
      extract( $r );
      if ( ! taxonomy_exists($taxonomy) ) return false;
      $categories = get_categories( $r );
      $output = "<ul class='" . esc_attr( $wrap_class ) . "'>" . PHP_EOL;
      if ( empty( $categories ) ) {
        if ( ! empty( $show_option_none ) ) $output .= "<li>" . $show_option_none . "</li>" . PHP_EOL;
      } else {
        if ( is_category() || is_tax() || is_tag() ) {
          $current_term_object = get_queried_object();
          if ( $r['taxonomy'] == $current_term_object->taxonomy ) $r['current_category'] = get_queried_object_id();
        }
        $depth = $r['depth'];
        $walker = new My_Category_Walker;
        $output .= $walker->walk($categories, $depth, $r);
      }
      $output .= "</ul>" . PHP_EOL;
      if ( $echo ) echo $output; else return $output;
    }
    

    The hard part is done. Now the template code, put it everywhere you need:

    <div id="content-filters" class="two columns">
    <div class="col tertiary" id="filters">
    <?php
    $args = array(
      'taxonomy' => 'product_cat',
      'show_option_none' => __('No Menu Items.'),
      'echo' => 1,
      'depth' => 2,
      'wrap_class' => 'product-categories',
      'level_class' => 'pattern_garment_type',
      'parent_title_format' => '<h5>%s</h5>',
      'current_class' => 'selected'
    );
    custom_list_categories( $args );
    ?>
    </div>
    </div>
    

    Customize the $args if you want, I setted them according to you answer code. Only I have changed ‘pattern_garment_type’ to be class and not an id, because you can’t have the same tag id multiple times in html (as in your markup).

    That’s all, hope it helps.

  2. Oudin,

    I will answer here the CSS part of your question:

    Use this to remove the list bullets:

    .ul.product-categories, ul.children{
        list-style-type: none;
    
    }
    

    Use this to make only the main categories bold:

    li {font-weight:normal} // you need to set the default state first of the list
    
    ul.product-categories > li{font-weight:bold;} //then you can change the top level list without affecting its children
    

    That’s how you target those elements with css without having to write your own classes.

    You can also add this to your wp_list_categories arguments

    'hide_empty' => 0
    

    To show all categories, even those who do not have a post.

    There are two approaches you can take to the second part of your question (adding the ALL link, and removing the link from the main categories)

    1. You can use Javascript/jquery to remove/add what you want once the page has loaded
    2. You can write a wp_list_categories filter, to make those changes

    Option 2, would be the clean way to do it.
    Option 1, would be the fastest way to do it.

    I have not gotten to either, becasue of lack of time. But take a look into creating filters in wordpress.

Comments are closed.