Need help adding additional controls to a custom widget

Here’s a complete example of the projects widget based on your code. This widget will allow users to specify the number of project posts to display and will also allow a word limit to be enforced for the content.

Note that I went with using a word limit for the content instead of a character limit. This is because things get kind of dicey with character limits once HTML and shortcodes get involved.

Just as an aside, I find it greatly helpful to take a look at the core’s widgets for a reference for building my own custom widgets. The core team is really good at updating the widgets for newer versions of WordPress, so the source is a great reference.

class WPSE_Projects_Widget extends WP_Widget {

    /**
     * Register widget with WordPress.
     */
    function __construct() {
        parent::__construct(
            'wpse_projects_widget', // Base ID
            esc_html__( 'WPSE Projects Widget', 'text_domain' ), // Name
            array( 'description' => esc_html__( 'Display some projects.', 'text_domain' ), ) // Args
        );
    }

    /**
     * Outputs the content of the widget
     *
     * @param array $args
     * @param array $instance
     */
public function widget($args, $instance) {

    echo $args['before_widget'];
    if ( ! empty( $instance['title'] ) ) {
        echo $args['before_title'] . apply_filters( 'widget_title', $instance['title'] ) . $args['after_title'];
    }

    $number_of_posts = ( ! empty( $instance['number_of_posts'] ) ) ? absint( $instance['number_of_posts'] ) : 5;
    if ( ! $number_of_posts ) {
        $number_of_posts = 5;
    }


    $number_of_words = ( ! empty( $instance['number_of_words'] ) ) ? absint( $instance['number_of_words'] ) : 20;
    if ( ! $number_of_words ) {
        $number_of_words = 20;
    }

    /* Create a custom query and get the most recent 4 projects. */
    $query_args = array(
            /* Do not get posts from the Uncategorized category. */
            'cat' => '-1',
            /* Order by date. */
            'orderby' => 'date',
            /* Number of posts to get. */
            'posts_per_page' => $number_of_posts,
    );
    $query = new WP_Query( $query_args );
    if ( $query->have_posts() ) : ?>
            <ul class="unbullet unbullet-v">
            <?php while ( $query->have_posts() ) : $query->the_post(); ?>
                    <li class="snippet-box vertical">
                            <div>
                                    <!-- <img src="http://heightandweights.com/wp-content/uploads/2014/10/Beautiful-Lindsey-Vonn.jpg" alt="" class="hundred"> -->
                                    <?php the_post_thumbnail( 'medium', array( 'class' => 'hundred' ) ); ?>
                                    <div class="snippet-text">
                                            <h3><a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>"><?php the_title(); ?></a></h3>
                                            <?php echo wp_trim_words( get_the_excerpt(), $number_of_words, __( '&hellip;', 'text_domain' ) ); ?>
                                    </div>
                            </div>
                            <!-- <a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>"><?php the_post_thumbnail( 'large', array( 'class' => 'img-responsive' ) ); ?></a> -->
                    </li>
            <?php endwhile; ?>
            </ul>
    <?php endif;

    echo $args['after_widget'];
}

    /**
     * Back-end widget form.
     *
     * @see WP_Widget::form()
     *
     * @param array $instance Previously saved values from database.
     */
    public function form( $instance ) {
        $title = isset( $instance['title'] ) ? $instance['title'] : '';
        $number_of_posts = isset( $instance['number_of_posts'] ) ? absint( $instance['number_of_posts'] ) : 5;
        $number_of_words = isset( $instance['number_of_words'] ) ? absint( $instance['number_of_words'] ) : 20;
        ?>
        <p><label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:', 'text_domain' ); ?></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 esc_attr( $title ); ?>" /></p>

        <p><label for="<?php echo $this->get_field_id( 'number_of_posts' ); ?>"><?php _e( 'Number of projects to show:', 'text_domain' ); ?></label>
        <input class="tiny-text" id="<?php echo $this->get_field_id( 'number_of_posts' ); ?>" name="<?php echo $this->get_field_name( 'number_of_posts' ); ?>" type="number" step="1" min="1" value="<?php echo $number_of_posts; ?>" size="3" /></p>

        <p><label for="<?php echo $this->get_field_id( 'number_of_words' ); ?>"><?php _e( 'Set the word limit for project descriptions:', 'text_domain' ); ?></label>
        <input class="tiny-text" id="<?php echo $this->get_field_id( 'number_of_words' ); ?>" name="<?php echo $this->get_field_name( 'number_of_words' ); ?>" type="number" step="1" min="1" value="<?php echo $number_of_words; ?>" size="4" /></p>       
        <?php
    }

    /**
     * Sanitize widget form values as they are saved.
     *
     * @see WP_Widget::update()
     *
     * @param array $new_instance Values just sent to be saved.
     * @param array $old_instance Previously saved values from database.
     *
     * @return array Updated safe values to be saved.
     */
    public function update( $new_instance, $old_instance ) {
        $instance = $old_instance;
        $instance['title']           = sanitize_text_field( $new_instance['title'] );
        $instance['number_of_posts'] = absint( $new_instance['number_of_posts'] );
        $instance['number_of_words'] = absint( $new_instance['number_of_words'] );
        return $instance;
    }
}

Register the widget:

function wpse_register_widget() {
    register_widget( 'WPSE_Projects_Widget' );
}
add_action( 'widgets_init', 'wpse_register_widget' );

Leave a Comment