1
public function widget($args, $instance) {
    extract( $args );
    $title = apply_filters( 'widget_title', $instance['title'] );

    /* Display the markup before the widget. */
    echo $before_widget;
    if ( $title ) {
        echo $before_title . $title . $after_title;
    }
    /* Create a custom query and get the most recent 4 projects. */
    $queryArgs = array(
        /* Do not get posts from the Uncategorized category. */
        'cat' => '-1',
        /* Order by date. */
        'orderby' => 'date',
        /* Show all posts. */
        'posts_per_page' => '4'
    );
    $query = new WP_Query( $queryArgs );
    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>
                        <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>
                    </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;
    /* Display the markup after the widget. */
    echo $after_widget;
}

The above is my widget function. I need some assistance.

Issue #1 →

            'posts_per_page' => '4'

I want this to be dynamic that means there should be an input box in the backend widget form where the admin should have the capability to input the number of posts to be displayed.

I tried this way→ This is the Form method in the backend →`

public function form( $instance ) {
    /* Defaults. */
    $defaults = array(
        'title' => 'Recent Projects',
    );

    $instance = wp_parse_args( (array) $instance, $defaults ); ?>
    <p>
        <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:', 'tuts' ); ?></label>
        <input type="text" class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo esc_attr( $instance['title'] ); ?>">
    </p>

    <?php
}

I manipulated this form this way → (But it didn't work and it generated error)

public function form( $instance ) {
    /* Defaults. */
    $defaults = array(
        'title' => 'Recent Projects',
        'post-number'  =>'4';
    );

    $instance = wp_parse_args( (array) $instance, $defaults ); ?>
    <p>
        <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:', 'tuts' ); ?></label>
        <input type="text" class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo esc_attr( $instance['title'] ); ?>">
    </p>

    <p>
        <label for="<?php echo $this->get_field_id( 'post-number' ); ?>"><?php _e( 'Post :', 'tuts' ); ?></label>
        <input type="text" class="widefat" id="<?php echo $this->get_field_id( 'post-number' ); ?>" name="<?php echo $this->get_field_name( 'post-number' ); ?>" value="<?php echo esc_attr( $instance['post-number'] ); ?>">
    </p>

    <?php
}

Summary: I want a backend form input for the number of posts to be displayed in the widget and then reflect the same number of posts in the widget method so that the selected # of posts can be displayed on the front-end.

Issue #2 → in the widget form method, you can see this → <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>

I want this to be dynamic, and that is possible like this →

<p><?php the_content(); ?></p>

But this will publish the whole post content, which is not desirable. I want just like there should be an input form method the # of character to be pulled from the post content should be decided by the numerical value entered into the input box of the form and the same number of characters should be displayed in the widget front-end.

THE PART 2 OF THIS QUESTION IS HERE

1 Answer 1

3

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' );
8
  • I think that this piece of code still has a hard-coded number "20" → '<?php echo wp_trim_words( get_the_excerpt(), 20, __( '&hellip;', 'text_domain' ) ); ?> </div>'
    – WordCent
    May 4, 2017 at 2:24
  • 1
    Your'e right; sorry about that! Fixed! May 4, 2017 at 2:41
  • Hello there, Thanks. There seems to be something not in harmony. As I used the $number_of_words nothing is printed on the front page. I have done a short video for this → screencast.com/t/dNS2DkTg
    – WordCent
    May 4, 2017 at 2:53
  • 1
    Thank you for the video. I've double checked though, and it's definitely working for me: number of posts and words are correctly reflected on the front end based on the back end's widget settings. Would you please copy the code directly from the post and use that? If that does not work, please edit your question and include all of the code for the widget. Keep me posted! May 4, 2017 at 3:11
  • 1
    Whew! Glad to hear! May 4, 2017 at 3:18

Your Answer

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

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