Creating a custom categories widget

The code below is an attempt to take the WP_Widget_Categories class and use it as the basis for a custom categories widget based on the default categories widget.

I’m getting no output however and the widget is not showing up in the “Available Widgets” listing. What am I doing wrong?

<?php
/*
Plugin Name: My Categories Widget
Version: 1.0
*/


class MY_Widget_Categories extends WP_Widget {

    function MY_Widget_Categories() {
        $widget_ops = array( 'classname' => 'widget_categories', 'description' => __( "A list or dropdown of categories" ) );
        $this->WP_Widget('categories', __('Categories'), $widget_ops);
    }

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

        $title = apply_filters('widget_title', empty( $instance['title'] ) ? __( 'Categories' ) : $instance['title']);
        $c = $instance['count'] ? '1' : '0';
        $h = $instance['hierarchical'] ? '1' : '0';
        $d = $instance['dropdown'] ? '1' : '0';

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

        $cat_args = array('orderby' => 'name', 'show_count' => $c, 'hierarchical' => $h);

        if ( $d ) {
            $cat_args['show_option_none'] = __('Select Category');
            wp_dropdown_categories(apply_filters('widget_categories_dropdown_args', $cat_args));
?>

<script type='text/javascript'>
/* <![CDATA[ */
    var dropdown = document.getElementById("cat");
    function onCatChange() {
        if ( dropdown.options[dropdown.selectedIndex].value > 0 ) {
            location.href = "<?php echo get_option('home'); ?>/?cat="+dropdown.options[dropdown.selectedIndex].value;
        }
    }
    dropdown.onchange = onCatChange;
/* ]]> */
</script>

<?php
        } else {
?>
        <ul>
<?php
        $cat_args['title_li'] = '';
        wp_list_categories(apply_filters('widget_categories_args', $cat_args));
?>
        </ul>
<?php
        }

        echo $after_widget;
    }

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

        return $instance;
    }

    function form( $instance ) {
        //Defaults
        $instance = wp_parse_args( (array) $instance, array( 'title' => '') );
        $title = esc_attr( $instance['title'] );
        $count = isset($instance['count']) ? (bool) $instance['count'] :false;
        $hierarchical = isset( $instance['hierarchical'] ) ? (bool) $instance['hierarchical'] : false;
        $dropdown = isset( $instance['dropdown'] ) ? (bool) $instance['dropdown'] : false;
?>
        <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e( 'Title:' ); ?></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>

        <p><input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id('dropdown'); ?>" name="<?php echo $this->get_field_name('dropdown'); ?>"<?php checked( $dropdown ); ?> />
        <label for="<?php echo $this->get_field_id('dropdown'); ?>"><?php _e( 'Show as dropdown' ); ?></label><br />

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

        <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id('hierarchical'); ?>" name="<?php echo $this->get_field_name('hierarchical'); ?>"<?php checked( $hierarchical ); ?> />
        <label for="<?php echo $this->get_field_id('hierarchical'); ?>"><?php _e( 'Show hierarchy' ); ?></label></p>
<?php
    }

}

function my_categories_init()
{
  register_sidebar_widget(__('My Categories Widget'), 'MY_Widget_Categories');
}

add_action("plugins_loaded", "my_categories_init");
?>

Related posts

Leave a Reply

3 comments

  1. You’ll need to use register_widget rather than register_sidebar_widget, as that function is for the old style widgets (that didn’t extend WP_Widget or were just functions). You should to do this from a function hooked into the widgets_init action. See the WordPress widgets API documentation for more info: http://codex.wordpress.org/Widgets_API


    The following plugin works for me in WP 2.9.

    /*
    Plugin Name: My Categories Widget
    Version: 0.1
    */
    
    class My_Widget_Categories extends WP_Widget {
    
        function My_Widget_Categories() {
            $widget_ops = array( 'classname' => 'widget_categories', 'description' => __( "My list or dropdown of categories" ) );
            $this->WP_Widget('my_categories', __('My Categories'), $widget_ops);
        }
    
        function widget( $args, $instance ) {
            extract( $args );
    
            $title = apply_filters('widget_title', empty( $instance['title'] ) ? __( 'Categories' ) : $instance['title']);
            $c = $instance['count'] ? '1' : '0';
            $h = $instance['hierarchical'] ? '1' : '0';
            $d = $instance['dropdown'] ? '1' : '0';
    
            echo $before_widget;
            if ( $title )
                echo $before_title . $title . $after_title;
    
            $cat_args = array('orderby' => 'name', 'show_count' => $c, 'hierarchical' => $h);
    
            if ( $d ) {
                $cat_args['show_option_none'] = __('Select Category');
                wp_dropdown_categories(apply_filters('widget_categories_dropdown_args', $cat_args));
    ?>
    
    <script type='text/javascript'>
    /* <![CDATA[ */
        var dropdown = document.getElementById("cat");
        function onCatChange() {
            if ( dropdown.options[dropdown.selectedIndex].value > 0 ) {
                location.href = "<?php echo get_option('home'); ?>/?cat="+dropdown.options[dropdown.selectedIndex].value;
            }
        }
        dropdown.onchange = onCatChange;
    /* ]]> */
    </script>
    
    <?php
            } else {
    ?>
            <ul>
    <?php
            $cat_args['title_li'] = '';
            wp_list_categories(apply_filters('widget_categories_args', $cat_args));
    ?>
            </ul>
    <?php
            }
    
            echo $after_widget;
        }
    
        function update( $new_instance, $old_instance ) {
            $instance = $old_instance;
            $instance['title'] = strip_tags($new_instance['title']);
            $instance['count'] = $new_instance['count'] ? 1 : 0;
            $instance['hierarchical'] = $new_instance['hierarchical'] ? 1 : 0;
            $instance['dropdown'] = $new_instance['dropdown'] ? 1 : 0;
    
            return $instance;
        }
    
        function form( $instance ) {
            //Defaults
            $instance = wp_parse_args( (array) $instance, array( 'title' => '') );
            $title = esc_attr( $instance['title'] );
            $count = isset($instance['count']) ? (bool) $instance['count'] :false;
            $hierarchical = isset( $instance['hierarchical'] ) ? (bool) $instance['hierarchical'] : false;
            $dropdown = isset( $instance['dropdown'] ) ? (bool) $instance['dropdown'] : false;
    ?>
            <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e( 'Title:' ); ?></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>
    
            <p><input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id('dropdown'); ?>" name="<?php echo $this->get_field_name('dropdown'); ?>"<?php checked( $dropdown ); ?> />
            <label for="<?php echo $this->get_field_id('dropdown'); ?>"><?php _e( 'Show as dropdown' ); ?></label><br />
    
            <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id('count'); ?>" name="<?php echo $this->get_field_name('count'); ?>"<?php checked( $count ); ?> />
            <label for="<?php echo $this->get_field_id('count'); ?>"><?php _e( 'Show post counts' ); ?></label><br />
    
            <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id('hierarchical'); ?>" name="<?php echo $this->get_field_name('hierarchical'); ?>"<?php checked( $hierarchical ); ?> />
            <label for="<?php echo $this->get_field_id('hierarchical'); ?>"><?php _e( 'Show hierarchy' ); ?></label></p>
    <?php
        }
    
    }
    
    add_action('widgets_init', create_function('', "register_widget('My_Widget_Categories');"));
    
  2. Categories widget with taxonomy/category select dropdown.

    enter image description here

    <?php 
    /**
    * Custom Post Type Categories widget class
    *
    * @since 1.0.0
    * @package Custom Post Type Widgets
    */
    class Custom_Post_Type_Widgets {
    
      /**
      * Sets up a new widget instance
      */
      public function __construct() {
        add_action( 'widgets_init', array( $this, 'init' ) );
      }
    
      /**
      * Register widget
      */
      public function init() {
          if ( ! is_blog_installed() ) {
            return;
          }
          register_widget( 'WP_Custom_Post_Type_Widgets_Categories' );
        }
      }
    
     if ( ! defined( 'ABSPATH' ) ) {
     exit;
    }
    $custom_post_type_widgets = new Custom_Post_Type_Widgets();
    
    
    /**
     * Core class WP_Custom_Post_Type_Widgets_Categories
     *
     * @since 1.0.0
     */
    class WP_Custom_Post_Type_Widgets_Categories extends WP_Widget {
    
        /**
         * Sets up a new widget instance.
         *
         * @since 1.0.0
         *
         * @access public
         */
        public function __construct() {
            $widget_ops = array(
                'classname'                   => 'widget_categories',
                'description'                 => __( 'A list or dropdown of categories.', 'custom-post-type-widgets' ),
                'customize_selective_refresh' => true,
            );
            parent::__construct( 'custom-post-type-categories', __( 'Categories (Custom Post Type)', 'custom-post-type-widgets' ), $widget_ops );
        }
    
        /**
         * Outputs the content for the widget instance.
         *
         * @since 1.0.0
         *
         * @access public
         *
         * @param array $args     Display arguments including 'before_title', 'after_title',
         *                        'before_widget', and 'after_widget'.
         * @param array $instance Settings for the current widget instance.
         */
        public function widget( $args, $instance ) {
            $title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Categories', 'custom-post-type-widgets' );
    
            /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
            $title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
    
            $taxonomy = ! empty( $instance['taxonomy'] ) ? $instance['taxonomy'] : 'category';
            $c        = ! empty( $instance['count'] ) ? (bool) $instance['count'] : false;
            $h        = ! empty( $instance['hierarchical'] ) ? (bool) $instance['hierarchical'] : false;
            $d        = ! empty( $instance['dropdown'] ) ? (bool) $instance['dropdown'] : false;
    
            echo $args['before_widget']; // WPCS: XSS ok.
            if ( $title ) {
                echo $args['before_title'] . $title . $args['after_title']; // WPCS: XSS ok.
            }
    
            $cat_args = array(
                'orderby'      => 'name',
                'taxonomy'     => $taxonomy,
                'show_count'   => $c,
                'hierarchical' => $h,
            );
    
            if ( $d ) {
                $dropdown_id = "{$this->id_base}-dropdown-{$this->number}";
    
                echo '<label class="screen-reader-text" for="' . esc_attr( $dropdown_id ) . '">' . $title . '</label>'; // WPCS: XSS ok.
    
                $cat_args['show_option_none'] = __( 'Select Category', 'custom-post-type-widgets' );
                $cat_args['name']             = 'category' === $taxonomy ? 'category_name' : $taxonomy;
                $cat_args['id']               = $dropdown_id;
                $cat_args['value_field']      = 'slug';
                ?>
    
    <form action="<?php echo esc_url( home_url() ); ?>" method="get">
                <?php
                /**
                 * Filters the arguments for the Categories widget drop-down.
                 *
                 * Filter hook: custom_post_type_widgets/categories/widget_categories_dropdown_args
                 *
                 * @since 2.8.0
                 * @since 4.9.0 Added the `$instance` parameter.
                 *
                 * @see wp_dropdown_categories()
                 *
                 * @param array  $cat_args An array of Categories widget drop-down arguments.
                 * @param array  $instance Array of settings for the current widget.
                 * @param string $this->id Widget id.
                 * @param string $taxonomy Taxonomy.
                 */
                wp_dropdown_categories(
                    apply_filters(
                        'custom_post_type_widgets/categories/widget_categories_dropdown_args',
                        $cat_args,
                        $instance,
                        $this->id,
                        $taxonomy
                    )
                );
                ?>
    </form>
    <script>
    /* <![CDATA[ */
    (function() {
        var dropdown = document.getElementById( "<?php echo esc_js( $dropdown_id ); ?>" );
        function onCatChange() {
            if ( dropdown.options[dropdown.selectedIndex].value ) {
                return dropdown.form.submit();
            }
        }
        dropdown.onchange = onCatChange;
    })();
    /* ]]> */
    </script>
                <?php
            }
            else {
                ?>
                <ul>
                <?php
                $cat_args['title_li'] = '';
                /**
                 * Filters the arguments for the Categories widget.
                 *
                 * Filter hook: custom_post_type_widgets/categories/widget_categories_args
                 *
                 * @see wp_list_categories()
                 *
                 * @param array  $cat_args An array of Categories widget arguments.
                 * @param array  $instance Array of settings for the current widget.
                 * @param string $this->id Widget id.
                 * @param string $taxonomy Taxonomy.
                 */
                wp_list_categories(
                    apply_filters(
                        'custom_post_type_widgets/categories/widget_categories_args',
                        $cat_args,
                        $instance,
                        $this->id,
                        $taxonomy
                    )
                );
                ?>
                </ul>
                <?php
            }
    
            echo $args['after_widget']; // WPCS: XSS ok.
        }
    
        /**
         * Handles updating settings for the current Archives widget instance.
         *
         * @since 1.0.0
         *
         * @access public
         *
         * @param array $new_instance New settings for this instance as input by the user via form() method.
         * @param array $old_instance Old settings for this instance.
         *
         * @return array Updated settings to save.
         */
        public function update( $new_instance, $old_instance ) {
            $instance                 = $old_instance;
            $instance['title']        = sanitize_text_field( $new_instance['title'] );
            $instance['taxonomy']     = stripslashes( $new_instance['taxonomy'] );
            $instance['count']        = ! empty( $new_instance['count'] ) ? (bool) $new_instance['count'] : false;
            $instance['hierarchical'] = ! empty( $new_instance['hierarchical'] ) ? (bool) $new_instance['hierarchical'] : false;
            $instance['dropdown']     = ! empty( $new_instance['dropdown'] ) ? (bool) $new_instance['dropdown'] : false;
    
            return $instance;
        }
    
        /**
         * Outputs the settings form for the widget.
         *
         * @since 1.0.0
         *
         * @access public
         *
         * @param array $instance Current settings.
         */
        public function form( $instance ) {
            $title        = isset( $instance['title'] ) ? $instance['title'] : '';
            $taxonomy     = isset( $instance['taxonomy'] ) ? $instance['taxonomy'] : '';
            $count        = isset( $instance['count'] ) ? (bool) $instance['count'] : false;
            $hierarchical = isset( $instance['hierarchical'] ) ? (bool) $instance['hierarchical'] : false;
            $dropdown     = isset( $instance['dropdown'] ) ? (bool) $instance['dropdown'] : false;
            ?>
            <p><label for="<?php echo $this->get_field_id( 'title' ); // WPCS: XSS ok. ?>"><?php esc_html_e( 'Title:', 'custom-post-type-widgets' ); ?></label>
            <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); // WPCS: XSS ok. ?>" name="<?php echo $this->get_field_name( 'title' ); // WPCS: XSS ok. ?>" type="text" value="<?php echo esc_attr( $title ); ?>" /></p>
    
            <?php
            $taxonomies = get_taxonomies( array(), 'objects' );
    
            if ( $taxonomies ) {
                printf(
                    '<p><label for="%1$s">%2$s</label>' .
                    '<select class="widefat" id="%1$s" name="%3$s">',
                    $this->get_field_id( 'taxonomy' ),
                    __( 'Taxonomy:', 'custom-post-type-widgets' ),
                    $this->get_field_name( 'taxonomy' )
                ); // WPCS: XSS ok.
    
                foreach ( $taxonomies as $taxobjects => $value ) {
                    if ( ! $value->hierarchical ) {
                        continue;
                    }
                    if ( 'nav_menu' === $taxobjects || 'link_category' === $taxobjects || 'post_format' === $taxobjects ) {
                        continue;
                    }
    
                    printf(
                        '<option value="%s"%s>%s</option>',
                        esc_attr( $taxobjects ),
                        selected( $taxobjects, $taxonomy, false ),
                        esc_html__( $value->label, 'custom-post-type-widgets' ) . ' ' . esc_html( $taxobjects )
                    );
                }
                echo '</select></p>';
            }
            ?>
    
            <p><input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id( 'dropdown' ); // WPCS: XSS ok. ?>" name="<?php echo $this->get_field_name( 'dropdown' ); // WPCS: XSS ok. ?>"<?php checked( $dropdown ); ?> />
            <label for="<?php echo $this->get_field_id( 'dropdown' ); // WPCS: XSS ok. ?>"><?php esc_html_e( 'Display as dropdown', 'custom-post-type-widgets' ); ?></label><br />
    
            <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id( 'count' ); // WPCS: XSS ok. ?>" name="<?php echo $this->get_field_name( 'count' ); // WPCS: XSS ok. ?>"<?php checked( $count ); ?> />
            <label for="<?php echo $this->get_field_id( 'count' ); // WPCS: XSS ok. ?>"><?php esc_html_e( 'Show post counts', 'custom-post-type-widgets' ); ?></label><br />
    
            <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id( 'hierarchical' ); // WPCS: XSS ok. ?>" name="<?php echo $this->get_field_name( 'hierarchical' ); // WPCS: XSS ok. ?>"<?php checked( $hierarchical ); ?> />
            <label for="<?php echo $this->get_field_id( 'hierarchical' ); // WPCS: XSS ok. ?>"><?php esc_html_e( 'Show hierarchy', 'custom-post-type-widgets' ); ?></label></p>
            <?php
        }
    }
    
  3. I think you can use built-in wp function using this.

     <?php 
        $args = array(
                        'name'             => $this->get_field_name('category'),
            'show_option_none' => __( 'Select category' ),
            'show_count'       => 1,
            'orderby'          => 'name',
            'echo'             => 0,
                        'selected'         => $category,
                        'class'            => 'widefat'
        );
                echo wp_dropdown_categories($args);
            ?>