Function Friday #9: create a custom widget to list blog contributors

Function Friday #9

Every Friday, I’m sharing code snippets that I use to customize WordPress. Feedback/suggestions are always welcome! For more information, check out the first post in the series.


A fairly common request I get is to have a list of my client’s blog contributors in the sidebar. It’s odd this isn’t one of the default WordPress widgets, to be honest! But it’s easy to add with a bit of code.

Here’s the custom widget as it appears on the Appearance → Widgets page:

The code

Creating a custom widget requires a few steps. At first glance I thought the Widgets API looked intimidating (so much code for such a tiny thing!) but once you dig in it’s fairly simple. First I’ve got the entire block of code, and then I’ll break it down by section.

// Create Authors widget
class authors_widget extends WP_Widget {
    // Register widget with WordPress
    public function __construct() {
        parent::__construct(
            'authors-widget', // Slug
            'Authors Widget', // Name
            array( 'description' => __( 'A list of blog contributors, linked to their articles.', 'drollic' ), ) // Args
        );
    }
    // Admin widget form
    public function form( $instance ) {
        if ( isset( $instance['title'] ) ) {
            $title = $instance['title'];
        }
        else {
            $title = __( '', 'drollic' );
        }
        ?>
        <p><strong>Note:</strong> Author names will use the field "Display name publicly as".</p>
        <p>
        <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e( 'Widget Title:', 'drollic'); ?></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>
        <?php
    }
    // Sanitize widget title on save
    public function update( $new_instance, $old_instance ) {
        $instance = array();
        $instance['title'] = strip_tags( $new_instance['title'] );
        return $instance;
    }
    // Front-end display of widget
    public function widget( $args, $instance ) {
        extract( $args );
        $title = apply_filters( 'widget_title', $instance['title'] );
        echo $before_widget;
            if ( ! empty( $title ) ) {
                echo $before_title . $title . $after_title;
            }
            echo '<ul>';
                wp_list_authors();
            echo '</ul>';
        echo $after_widget;
    }
}
function drollic_register_widgets() {
    register_widget('authors_widget');
}
add_action( 'widgets_init', 'drollic_register_widgets' );

Going one section at a time…

Register widget with WordPress

public function __construct() {
    parent::__construct(
        'authors-widget', // Slug
        'Authors Widget', // Name
        array( 'description' => __( 'A list of blog contributors, linked to their articles.', 'drollic' ), ) // Args
    );
}

All you need to fill in here is:

Admin widget form

public function form( $instance ) {
    if ( isset( $instance['title'] ) ) {
        $title = $instance['title'];
    }
    else {
        $title = __( '', 'drollic' );
    }
    ?>
    <p><strong>Note:</strong> Author names will use the field "Display name publicly as".</p>
    <p>
    <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e( 'Widget Title:', 'drollic'); ?></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>
    <?php
}

The first part checks if there’s a stored value for the Widget Title field.

Then it creates the form that appears within the widget itself, on the Widgets page. This widget just has one field (the Title) so there’s not a lot to do here.

I’ve also added a helpful note to explain which of the User’s names will actually appear when you use this widget to avoid any confusion.

Sanitize widget title on save

public function update( $new_instance, $old_instance ) {
    $instance = array();
    $instance['title'] = strip_tags( $new_instance['title'] );
    return $instance;
}

This saves what you type into the Widget Title field to the database. As a precaution, it runs it through the strip_tags function to get rid of any stray HTML before storing it.

Front-end display of widget

public function widget( $args, $instance ) {
    extract( $args );
    $title = apply_filters( 'widget_title', $instance['title'] );
    echo $before_widget;
        if ( ! empty( $title ) ) {
            echo $before_title . $title . $after_title;
        }
        echo '<ul>';
            wp_list_authors();
        echo '</ul>';
    echo $after_widget;
}

This determines what happens on the front end of your site, once someone adds this widget to a visible widget area.

The $title variable will output whatever you entered in the Widget Title field. I’m checking if this field was left blank, and if so, not displaying a title at all.

The $before_widget, $after_widget, $before_title and $after_title variables are all determined by your theme, when you set up the widget areas.

Then the wp_list_authors function outputs all Users that have public posts. This function automatically links each author’s name to their Author page. It has a handful of arguments, but here I’ve just gone with the defaults.

If you wanted to set some arguments – such as ordering authors by their number of posts, instead of alphabetically – you could do so like this (new code in bold):

$listargs = array(
    'orderby' => 'post_count'
);
echo '<ul>';
    wp_list_authors( $listargs );
echo '</ul>';

Where does it go?

This widget will work regardless of which theme you’re using, so this code should go in a functionality plugin. For more info, see the first post in this series.

Resources


Bonus tip: add more fields with Advanced Custom Fields

If you, like me, are a fan of the Advanced Custom Fields plugin, you might be interested to know that one of the Location Rules options is Widget!

Working with the custom widget from this post, you could create a field group and set the location rules to “Show this field group if [Widget] is equal to [Authors Widget]”:

Any fields you add to this field group in ACF will now appear within the Authors Widget, with no extra code required. You can then output the content of those fields in the “Front-end display of widget” section of the code above.

For example, you may want to exclude some Users from the Authors widget. Instead of having to find their user IDs and enter those in a text field, you can add a User type field to your new field group and have it appear in the widget.

Set the Field Label to “Author(s) to exclude from the list:”, Field Name to “exclude”, and allow selecting multiple values:

Add new ACF field group

Now the widget looks like this:

Improved authors widget

The new field autocompletes from your list of Users. Much easier than typing out user IDs!

Finally, you’ll need to update the “Front-end display of widget” section of code. Add an argument to exclude users if the field is filled out (new sections of code are in bold):

public function widget( $args, $instance ) {
    extract( $args );
    $title = apply_filters( 'widget_title', $instance['title'] );
    // Check ACF field for Users to exclude
    $exclude = get_field( 'exclude', 'widget_' . $widget_id );
    if ( $exclude ) {
        $exclude_ids = array();
        foreach ( $exclude as $id ) {
            $exclude_ids[] = $id[ID];
        }
        // Turn the array of user IDs into a comma-separated list
        $exclude_ids = implode( ',', $exclude_ids );
    }
    echo $before_widget;
        if ( ! empty( $title ) ) {
            echo $before_title . $title . $after_title;
        }
        $listargs = array(
            'exclude' => $exclude_ids
        );
        echo '<ul>';
        wp_list_authors( $listargs );
        echo '</ul>';
    echo $after_widget;
}

Leave a Reply

Your email address will not be published.