I am trying to hack the default categories widget from wordpress. I have the categories displaying the way I want but I am having trouble editing the output. The widget shows the number of posts in each post which is what I want, but it also displays the number in parenthesis. I don't want that. I know how to get rid of them but I can't seem to make it work. I tried like so

$cat_args['title_li'] = '';
$list = wp_list_categories(apply_filters('widget_categories_args', $cat_args));
$list .= str_replace('(', '<span class="number">', $list);
$list .= str_replace(')', '<span class="number">', $list);
echo $list;

It just continues to display the categories the same way. I don't understand why it's not echoing the list. I am using the code for the categories from the default-widgets.php file in the wp-includes folder.

2 Answers 2


wp_list_categories echoes output by default, your str_replace isn't working because nothing was assigned to $list.

  • You are right, but we can pass echo => false to get result into a variable.
    – Amit Kosti
    Aug 21, 2012 at 18:14

I've run into this situation too, and ended up duplicating the built in List Categories widget, and customized it to fit my needs. I left a couple variations of the $replacement regex commented out in the code.


// Register our tweaked Category Archives widget
function myprefix_widgets_init() {
  register_widget( 'WP_Widget_Categories_custom' );
add_action( 'widgets_init', 'myprefix_widgets_init' );

 * Duplicated and tweaked WP core Categories widget class
class WP_Widget_Categories_Custom extends WP_Widget {

  function __construct() {
    $widget_ops = array( 'classname' => 'widget_categories widget_categories_custom', 'description' => __( "A list of categories, with slightly tweaked output.", 'mytextdomain'  ) );
    parent::__construct( 'categories_custom', __( 'Categories Custom', 'mytextdomain' ), $widget_ops );

  function widget( $args, $instance ) {
    extract( $args );

    $title = apply_filters( 'widget_title', empty( $instance['title'] ) ? __( 'Categories Custom', 'mytextdomain'  ) : $instance['title'], $instance, $this->id_base);

    echo $before_widget;
    if ( $title )
      echo $before_title . $title . $after_title;

      // Get the category list, and tweak the output of the markup.
      $pattern = '#<li([^>]*)><a([^>]*)>(.*?)<\/a>\s*\(([0-9]*)\)\s*<\/li>#i';  // removed ( and )

      // $replacement = '<li$1><a$2>$3</a><span class="cat-count">$4</span>'; // no link on span
      // $replacement = '<li$1><a$2>$3</a><span class="cat-count"><a$2>$4</a></span>'; // wrap link in span
      $replacement = '<li$1><a$2><span class="cat-name">$3</span><span class="cat-count">$4</span></a>'; // give cat name and count a span, wrap it all in a link

      $subject      = wp_list_categories( 'echo=0&orderby=name&exclude=&title_li=&depth=1&show_count=1' );    
      echo preg_replace( $pattern, $replacement, $subject );
    echo $after_widget;

  function update( $new_instance, $old_instance ) {
    $instance = $old_instance;
    $instance['title'] = strip_tags( $new_instance['title'] );
    $instance['count'] = 1;
    $instance['hierarchical'] = 0;
    $instance['dropdown'] = 0;

    return $instance;

  function form( $instance ) {
    $instance = wp_parse_args( (array) $instance, array( 'title' => '') );
    $title = esc_attr( $instance['title'] );
    $count = true;
    $hierarchical = false;
    $dropdown = false;
    <p><label for="<?php echo $this->get_field_id('title', 'mytextdomain' ); ?>"><?php _e( 'Title:', 'mytextdomain'  ); ?></label>
    <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" /></p>

    <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id('count'); ?>" name="<?php echo $this->get_field_name('count'); ?>"<?php checked( $count ); ?> disabled="disabled" />
    <label for="<?php echo $this->get_field_id('count'); ?>"><?php _e( 'Show post counts', 'mytextdomain'  ); ?></label><br />


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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