1

I am building my Wordpress Widget and I ran into an issue that I am not able to find a solution for. The widget is a simple one: that displays the last 10 posts in my CPT filtered by Category.

The tricky bit for me at least is getting it to work with Multiple Categories selected ( works with single category )>

Every time I select two categories the select field reverts either to the default selection or to the last single category selected.

Here is my widget code:

public function widget( $args, $instance ) 
    {
        $cache = [];
        if ( ! $this->is_preview() ) {
            $cache = wp_cache_get( 'widget_cat_posts', 'widget' );
        }

        if ( ! is_array( $cache ) ) {
            $cache = [];
        }

        if ( ! isset( $args['widget_id'] ) ) {
            $args['widget_id'] = $this->id;
        }

        if ( isset( $cache[ $args['widget_id'] ] ) ) {
            echo $cache[ $args['widget_id'] ];
            return;
        }

        ob_start();

        $title          = ( ! empty( $instance['title'] ) ) ? $instance['title'] : __( 'Category Posts' );

        $title          = apply_filters( 'widget_title', $title, $instance, $this->id_base );
        $number         = ( ! empty( $instance['number'] ) ) ? absint( $instance['number'] ) : 5;
        if ( ! $number ) {
            $number = 5;
        }
        $cat_id         = $instance['cat_id'];



        if( true === $random ) {

            $query_args = [
                'posts_per_page'    => 10,
                'cat'               => $cat_id,
                'post_type'         => 'mycmpt',
                'orderby'           => 'rand'
            ];

        }else{  

            $query_args = [
                'posts_per_page'    => 10,
                'cat'               => $cat_id,
                'post_type'         => 'mycmpt',
            ];

        }
        $q = new WP_Query( apply_filters( 'category_posts_args', $query_args ) );

        if( $q->have_posts() ) {

            echo $args['before_widget'];
            if ( $title ) {
                echo $args['before_title'] . $title . $args['after_title'];
            }               

            while( $q->have_posts() ) {
                $q->the_post(); ?>

                <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> 

                    <header class="entry-header">
                        <?php the_title( '<h1 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h1>' ); ?>
                    </header><!-- .entry-header -->




                            <?php the_post_thumbnail(); ?>





                            <?php the_excerpt(); ?>



                    <?php } ?>

                </article><!-- #post-## -->

                <?php 



            wp_reset_postdata();
        }
            echo $args['after_widget']; 

        if ( ! $this->is_preview() ) {
            $cache[ $args['widget_id'] ] = ob_get_flush();
            wp_cache_set( 'widget_cat_posts', $cache, 'widget' );
        } else {
            ob_end_flush();
        }
    } 

Here is my update code:

public function update( $new_instance, $old_instance ) 
    {
        $instance                   = $old_instance;
        $instance['title']          = strip_tags( $new_instance['title'] );
        $instance['number']         = (int) $new_instance['number'];
        $instance['cat_id']         = (int) $new_instance['cat_id'];
        $this->flush_widget_cache();

        $alloptions = wp_cache_get( 'alloptions', 'options' );
        if ( isset($alloptions['widget_category_posts']) )
            delete_option('widget_category_posts');

        return $instance;
    } 

Here is my form code:

public function form( $instance ) 
{

    $title      = isset( $instance['title'] ) ? esc_attr( $instance['title'] ) : '';
    $number     = isset( $instance['number'] ) ? absint( $instance['number'] ) : 5;
    $cat_id     = isset( $instance['cat_id'] ) ? absint( $instance['cat_id'] ) : 1;

    ?>

    <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>
        <label for="<?php echo $this->get_field_id('cat_id'); ?>"><?php _e( 'Category Name:' )?></label>

        <select multiple="multiple" id="<?php echo $this->get_field_id('cat_id'); ?>" name="<?php echo $this->get_field_name('cat_id'); ?>">
            <?php 
            $this->categories = get_categories();
            foreach ( $this->categories as $cat ) {
                $selected = ( $cat->term_id == esc_attr( $cat_id ) ) ? ' selected = "selected" ' : '';
                $option = '<option '.$selected .'value="' . $cat->term_id;
                $option = $option .'">';
                $option = $option .$cat->name;
                $option = $option .'</option>';
                echo $option;
            }
            ?>
        </select>
    </p>



<?php
}

I tried setting $selected = in_array with no luck.

I have made it work with single select but I have no clue right now why it does not work with multiselect.

1 Answer 1

0

If someone is looking at this question, I managed to find a solution. 1. Switched to a checkbox instead of a multi-select and used "checked" instead of "selected"; 2. Used tax_query and some other query modifications.

The code is not perfect but it works for now.

Working Widget Code for Displaying the last 10 entries in a CPT sorted by single or multiple categories:

class CPT_Widget extends WP_Widget 
{

    public function __construct() 
    {
        parent::__construct(
            'widget_category_posts', 
            _x( 'CPT Widget', 'CPT Widget' ), 
            [ 'description' => __( 'Display the latest entries in your custom post type sorted by single or multiple categories.' ) ] 
        );
        $this->alt_option_name = 'widget_category_posts';

        add_action( 'save_post', [$this, 'flush_widget_cache'] );
        add_action( 'deleted_post', [$this, 'flush_widget_cache'] );
        add_action( 'switch_theme', [$this, 'flush_widget_cache'] );
    }

    public function widget( $args, $instance ) {
        $cache = [];
        if ( ! $this->is_preview() ) {
            $cache = wp_cache_get( 'widget_cat_posts', 'widget' );
        }

        if ( ! is_array( $cache ) ) {
            $cache = [];
        }
        if ( ! isset( $args['widget_id'] ) ) {
            $args['widget_id'] = $this->id;
        }
        if ( isset( $cache[ $args['widget_id'] ] ) ) {
            echo $cache[ $args['widget_id'] ];
            return;
        }
        ob_start();
        $title          = ( ! empty( $instance['title'] ) ) ? $instance['title'] : __( 'Category Posts' );
        $title          = apply_filters( 'widget_title', $title, $instance, $this->id_base );
        $number         = ( ! empty( $instance['number'] ) ) ? absint( $instance['number'] ) : 5;
        if ( ! $number ) {
            $number = 5;
        }
        $cat_id         = $instance['categories'];
        if( true === $random ) {
            $query_args = [
                'posts_per_page'    => 10,
                'post_type'         => 'yourcustomposttype',
                'orderby'           => 'rand',
                'tax_query' => array(
                            array(
                            'taxonomy' => 'category',
                            'field' => 'term_id',
                            'terms' => $cat_id,
                             ),
                          ),
            ];
        }else{  
            $query_args = [
                'posts_per_page'    => 10,
                'post_type'         => 'yourcustomposttype',
                'orderby'           => 'rand',
                'tax_query' => array(
                            array(
                            'taxonomy' => 'category',
                            'field' => 'term_id',
                            'terms' => $cat_id,
                             ),
                          ),
            ];

        }
        $q = new WP_Query( $query_args );

        if( $q->have_posts() ) {
            echo $args['before_widget'];
            if ( $title ) {
                echo $args['before_title'] . $title . $args['after_title'];
            }               
            while( $q->have_posts() ) {
                $q->the_post(); ?>

                <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> 

                    <header class="entry-header">
                        <?php the_title( '<h1 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h1>' ); ?>
                    </header><!-- .entry-header -->
                        <div class="post-thumbnail">
                            <?php the_post_thumbnail(); ?>
                        </div><!--/.post-thumbnail-->
                        <div class="entry-summary">
                            <?php the_excerpt(); ?>
                        </div><!-- .entry-summary -->
                    <?php } ?>
                </article><!-- #post-## -->
                <?php 
            wp_reset_postdata();
        }
            echo $args['after_widget']; 

        if ( ! $this->is_preview() ) {
            $cache[ $args['widget_id'] ] = ob_get_flush();
            wp_cache_set( 'widget_cat_posts', $cache, 'widget' );
        } else {
            ob_end_flush();
        }
    }


public function update($a, $b) {
  return array(
    'title'      => isset($a['title']) ? strip_tags($a['title']) : $b['title'],
    'categories' => isset($a['categories']) ? array_filter(array_map(function($id) { return intval($id); }, (array) $a['categories'])) : (array) $b['title']
  );
}

    public function flush_widget_cache() 
    {
        wp_cache_delete('widget_cat_posts', 'widget');
    }

    public function form($instance) {
  $title = isset($instance['title']) ? $instance['title'] : '';
  $categories = isset($instance['categories']) ? $instance['categories'] : array();
  ?>

  <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') ?>"
           value="<?php echo $title ?>" />
  </p>

  <p>Categories</p>
  <ul>
  <?php foreach (\get_categories() as $category): ?>
    <li>
      <label>
        <input type="checkbox"
             class="checkbox"
             name="<?php echo $this->get_field_name('categories') ?>[]"
             value="<?php echo $category->cat_ID ?>"
             <?php checked(in_array($category->cat_ID, $categories)) ?> />
        <?php echo $category->name ?>
      </label>
    </li>
  <?php endforeach ?>
  </ul>
  <?php
}
}


add_action( 'widgets_init', function () 
{
    register_widget( 'CPT_Widget' );
}); 

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.