Saturday, June 9, 2012

Front-End Author Listing And User Search For WordPress

This article will guide you through the process of creating a front-end page in WordPress that lists your authors. We’ll discuss why you would want to do this, we’ll introduce the WP_User_Query class, and then we’ll put it it all together.

User Engagement And WordPress

At its core, WordPress is a rock-solid publishing platform. With a beautiful and easy to use interface, and support for custom post types and post formats, publishers have the flexibility to do what they do best: write content.
However, WordPress is lacking in social interaction between content authors and readers. BuddyPress is trying to solve this, but I believe it’s going in the wrong direction by trying to be a full-fledged social network.
A big phrase in the publishing world is “user engagement.” This is about getting readers to spend more time on the website, actively searching for content and even generating their own. While one could write a few books on the subject, here are a few things a WordPress publisher can do:
  • Create a daily or weekly newsletter, with top stories from selected categories;
  • Provide an editorial-driven open forum in which editors propose themes, stories and questions and readers comment on them;
  • Continue the discussion of articles on social platforms;
  • Encourage users to submit articles and images for contests;
  • Highlight your authors.

Listing Authors, And Why It’s A Good Thing

If you’re a publisher, your authors are your biggest asset. They are the content creators. Their writing gets consumed by millions of people all over the world.
Showcasing them exposes them for what they really are: authorities. Your authors will thank you for acknowledging them, and readers will get to see the human face behind the technology.

Coding The Perfect Author Listing

Here are the things we want to achieve with our page:
  • Build it as a WordPress plugin so that we can reuse it more easily;
  • Display the name, biography, number of posts and latest published post of all authors;
  • Paginate the listing if we have many authors;
  • Make the listing searchable.

Introducing WP_User_Query And get_users

The WP_User_Query class allows us to query the user database.
Besides returning an array of users, WP_User_Query returns general information about the query and, most importantly, the total number of users (for pagination).
One can use WP_User_Query by passing a series of arguments and listing the output.
01$my_authors = new WP_User_Query(
02    array(
03        'blog_id' => $GLOBALS['blog_id'],
04        'role' => '',
05        'meta_key' => '',
06        'meta_value' => '',
07        'meta_compare' => '',
08        'include' => array(),
09        'exclude' => array(),
10        'search' => '',
11        'orderby' => 'login',
12        'order' => 'ASC',
13        'offset' => '',
14        'number' => '',
15        'count_total' => true,
16        'fields' => 'all',
17        'who' => ''
We’ll focus on only a few arguments, rather than go through all of them:
  • role
    This is the user’s role. In our example, we’ll query for author.
  • offset
    The first n users to be skipped in the returned array.
  • number
    Limit the total number of users returned.
We also have the get_users class, which (like WP_User_Query) returns a number of users based on the parameters set.
The important difference between the two is that get_users only returns an array of users and their meta data, whereas WP_User_Query returns extra information such as the total number of users (which is useful when it comes time to paginate).

Simple User Listing Using get_users()

Before moving on with the full user listing, including pagination and search, let’s see get_users in action.
If all you need is a simple list of authors, then you could just use wp_list_authors, like so:

Creating A Plugin And Shortcode With A Bit More Functionality

A simple and straightforward way to build our user listing would be to create a shortcode that we could include on any page we like. Housing this type of functionality in a plugin is ideal, so that we don’t have to worry about migrating it when we change the theme.
Let’s keep it simple. Our entire plugin will consist of just one file: simple-user-listing.php.
003Plugin Name: Simple User Listing
004Plugin URI:
005Description: Create a simple shortcode to list our WordPress users.
006Author: Cristian Antohe
007Version: 0.1
008Author URI:
011function sul_user_listing($atts, $content = null) {
012    global $post;
014    extract(shortcode_atts(array(
015        "role" => '',
016        "number" => '10'
017    ), $atts));
019    $role = sanitize_text_field($role);
020    $number = sanitize_text_field($number);
022    // We're outputting a lot of HTML, and the easiest way
023    // to do it is with output buffering from PHP.
024    ob_start();
026    // Get the Search Term
027    $search = ( isset($_GET["as"]) ) ? sanitize_text_field($_GET["as"]) : false ;
029    // Get Query Var for pagination. This already exists in WordPress
030    $page = (get_query_var('paged')) ? get_query_var('paged') : 1;
032    // Calculate the offset (i.e. how many users we should skip)
033    $offset = ($page - 1) * $number;
035    if ($search){
036        // Generate the query based on search field
037        $my_users = new WP_User_Query(
038            array(
039                'role' => $role,
040                'search' => '*' . $search . '*'
041            ));
042    } else {
043        // Generate the query
044        $my_users = new WP_User_Query(
045            array(
046                'role' => 'author',
047                'offset' => $offset ,
048                'number' => $number
049            ));
050    }
052    // Get the total number of authors. Based on this, offset and number
053    // per page, we'll generate our pagination.
054    $total_authors = $my_users->total_users;
056    // Calculate the total number of pages for the pagination
057    $total_pages = intval($total_authors / $number) + 1;
059    // The authors object.
060    $authors = $my_users->get_results();
063    <div class="author-search">
064    <h2>Search authors by name</h2>
065        <form method="get" id="sul-searchform" action="<?php the_permalink() ?>">
066            <label for="as" class="assistive-text">Search</label>
067            <input type="text" class="field" name="as" id="sul-s" placeholder="Search Authors" />
068            <input type="submit" class="submit" name="submit" id="sul-searchsubmit" value="Search Authors" />
069        </form>
070    <?php
071    if($search){ ?>
072        <h2 >Search Results for: <em><?php echo $search; ?></em></h2>
073        <a href="<?php the_permalink(); ?>">Back To Author Listing</a>
074    <?php } ?>
076    </div><!-- .author-search -->
078<?php if (!empty($authors))   { ?>
079    <ul class="author-list">
081    // loop through each author
082    foreach($authors as $author){
083        $author_info = get_userdata($author->ID);
084        ?>
085        <li>
086            <?php echo get_avatar( $author->ID, 90 ); ?>
087            <h2><a href="<?php echo get_author_posts_url($author->ID); ?>"><?php echo $author_info->display_name; ?></a> - <?php echo count_user_posts( $author->ID ); ?> posts</h2>
088            <p><?php echo $author_info->description; ?></p>
089            <?php $latest_post = new WP_Query( "author=$author->ID&post_count=1" );
090            if (!empty($latest_post->post)){ ?>
091            <p><strong>Latest Article:</strong>
092            <a href="<?php echo get_permalink($latest_post->post->ID) ?>">
093                <?php echo get_the_title($latest_post->post->ID) ;?>
094            </a></p>
095            <?php } //endif ?>
096            <p><a href="<?php echo get_author_posts_url($author->ID); ?> ">Read <?php echo $author_info->display_name; ?> posts</a></p>
097        </li>
098        <?php
099    }
101    </ul> <!-- .author-list -->
102<?php } else { ?>
103    <h2>No authors found</h2>
104<? } //endif ?>
106    <nav id="nav-single" style="clear:both; float:none; margin-top:20px;">
107        <h3 class="assistive-text">Post navigation</h3>
108        <?php if ($page != 1) { ?>
109            <span class="nav-previous"><a rel="prev" href="<?php the_permalink() ?>page/<?php echo $page - 1; ?>/"><span class="meta-nav">←</span> Previous</a></span>
110        <?php } ?>
112        <?php if ($page < $total_pages ) { ?>
113            <span class="nav-next"><a rel="next" href="<?php the_permalink() ?>page/<?php echo $page + 1; ?>/">Next <span class="meta-nav">→</span></a></span>
114        <?php } ?>
115    </nav>
117    <?php
118    // Output the content.
119    $output = ob_get_contents();
120    ob_end_clean();
122    // Return only if we're inside a page. This won't list anything on a post or archive page.
123    if (is_page()) return  $output;
127// Add the shortcode to WordPress.
128add_shortcode('userlisting', 'sul_user_listing');

Breaking Down The Code

The top of our plugin’s main PHP file must contain the standard header of information. This header tells WordPress that our plugin exists, and it adds it to the plugin management screen so that it can be activated, loaded and run.
2Plugin Name: Simple User Listing
3Plugin URI:
4Description: Create a simple shortcode to list our WordPress users.
5Author: Cristian Antohe
6Version: 0.1
7Author URI:

Creating a Shortcode

Adding a new shortcode in WordPress is rather easy. We find the function that returns the desired output (in our case, sul_user_listing), and then we add it using the add_shortcode WordPress function.
1function sul_user_listing($atts, $content = null) {
2// return our output
4add_shortcode('userlisting', 'sul_user_listing');

Extracting Our Shortcode Arguments

We want to be able to list users based on their roles and to control how many users are displayed on the page. We do this through shortcode arguments. We’ll add the shortcode to our theme in this way: [userlisting role="author" number="15"]. This will allow us to reuse the plugin to list our subscribers as well.
To do this, we need to use shortcode arguments:
2    "role" => '',
3    "number" => '10'
4), $atts));
The extract function imports variables into our function from an array. The WordPress function shortcode_atts basically returns an array with our arguments; and we’ll set up some defaults in case none are found.
Note that the role default is an empty string, which would list all users regardless of their role.

Shortcodes Should Never Echo Stuff Out

The return value of a shortcode handler function gets inserted into the post content’s output in place of the shortcode. You should use return and not echo; anything that is echoed will be outputted to the browser but will probably appear above everything else. You would also probably get “headers already sent” type of errors.
For simplicity, we’re buffering the output through ob_start(), so we put everything into an object and return it once we’re done.

Setting Up Our Variables

Now we can start building our listing of authors. First, we need to set up a few variables:
  • $search
    This takes the GET parameter as if it exists.
  • $page
    The get_query_var for the pagination. This already exists in WordPress.
  • $offset
    Calculate the offset (i.e. how many users to skip when paginating).
  • $total_authors
    Get the total number of authors.
  • $total_pages
    Calculate the total number of pages for the pagination.

The Query

We actually have two queries: the default listing and the search results.
01if ($search){
02    // Generate the query based on search field
03    $my_users = new WP_User_Query(
04        array(
05            'role' => $role,
06            'search' => '*' . $search . '*'
07        ));
08} else {
09    // Generate the query
10    $my_users = new WP_User_Query(
11        array(
12            'role' => 'author',
13            'offset' => $offset ,
14            'number' => $number
15        ));

WP_User_Query->total_users and WP_User_Query->get_results

WP_User_Query provides us with two useful functions, among others:
  • total_users
    Returns the total number of authors. This, the offset and the number of users per page will generate our pagination.
  • get_results
    Returns an object with the authors alone. This is similar to what get_users() returns.

The Search Form

For the search, we’re using a simple form. There’s nothing complex here.
01<div class="author-search">
02<h2>Search authors by name</h2>
03    <form method="get" id="sul-searchform" action="<?php the_permalink() ?>">
04        <label for="as" class="assistive-text">Search</label>
05        <input type="text" class="field" name="as" id="s" placeholder="Search Authors" />
06        <input type="submit" class="submit" name="submit" id="searchsubmit" value="Search Authors" />
07    </form>
09if($search){ ?>
10    <h2 >Search Results for: <em><?php echo $search; ?></em></h2>
11    <a href="<?php the_permalink(); ?>">Back To Author Listing</a>
12<?php } ?>
14</div><!-- .author-search -->

User Data and Listing the Authors

Looping through our results is fairly simple. However, getting information about users is a bit confusing in WordPress. You see, there are a lot of ways to get user data. We could get it directly from the returned query; we could use general functions such as get_userdata, get_user_meta, the_author_meta and get_the_author_meta; or we could even use dedicated functions such as the_author_link and the_author_posts.
We’ll just use get_userdata plus two other functions: get_author_posts_url and get_avatar.
01<?php if (!empty($authors))   { ?>
02    <ul class="author-list">
04    // loop through each author
05    foreach($authors as $author){
06        $author_info = get_userdata($author->ID);
07        ?>
08        <li>
09            <?php echo get_avatar( $author->ID, 90 ); ?>
10            <h2><a href="<?php echo get_author_posts_url($author->ID); ?>"><?php echo $author_info->display_name; ?></a> - <?php echo count_user_posts( $author->ID ); ?> posts</h2>
11            <p><?php echo $author_info->description; ?></p>
12            <?php $latest_post = new WP_Query( "author=$author->ID&post_count=1" );
13            if (!empty($latest_post->post)){ ?>
14            <p><strong>Latest Article:</strong>
15            <a href="<?php echo get_permalink($latest_post->post->ID) ?>">
16                <?php echo get_the_title($latest_post->post->ID) ;?>
17            </a></p>
18            <?php } //endif ?>
19            <p><a href="<?php echo get_author_posts_url($author->ID); ?> ">Read <?php echo $author_info->display_name; ?> posts</a></p>
20        </li>
21        <?php
22    }
24    </ul> <!-- .author-list -->
25<?php } else { ?>
26    <h2>No authors found</h2>
27<? } //endif ?>


We need pagination because each listing will generate two extra queries. So, if we were listing 100 people, we would end up with 200 extra queries per page. That’s a bit much, so pagination is really needed. Otherwise, for websites with many authors, the load could get so heavy that it brings down the website.
01<nav id="nav-single" style="clear:both; float:none; margin-top:20px;">
02    <h3 class="assistive-text">Post navigation</h3>
03    <?php if ($page != 1) { ?>
04        <span class="nav-previous"><a rel="prev" href="<?php the_permalink() ?>page/<?php echo $page - 1; ?>/"><span class="meta-nav">←</span> Previous</a></span>
05    <?php } ?>
07    <?php if ($page < $total_pages ) { ?>
08        <span class="nav-next"><a rel="next" href="<?php the_permalink() ?>page/<?php echo $page + 1; ?>/">Next <span class="meta-nav">→</span></a></span>
09    <?php } ?>

Final Thoughts

We’ve discussed the code for an authors listing, but it has so many more uses:
  • List your company’s employees;
  • Showcase users who have won a competition (by listing users with the role of “winners”);
  • Present your company’s departments, each with its respective team (based on user roles).
If you allow users to register on your website, you could use more or less the same code to generate any listing of users based on your needs. If you require users to log in in order to comment (an effective way to stop automated spam), then listing users and their number of comments could increase engagement.
Have you used something similar for a project? If so, let us know in the comments!


No comments:

Post a Comment