Tag Archives: sample code

How to display a WordPress archive with every author and their posts

A few days ago, at the March Seattle WordPress meetup with guest speaker John Chow, who gave an excellent presentation on how to make money online, Leslie Ström asked me about WordPress archive pages. She had an interesting question: How could she make an archive page that had all of the authors on her blog who have penned a post, and all of their posts? She wanted this page to be sorted by authors, but for each other to have a listing of their posts. While I’m not accepting any freelance work currently, it was a fun enough challenge to go ahead and try to do. Granted it ended up being pretty easy after a few visits to the Codex and browsing through some of the code, and below I list the actual code that will make this possible, explaining it step-by-step.

Let me preface the rest of this post by mentioning that what follows is going to get relatively technical, and it would be helpful to have some background in coding for WordPress, particularly making themes, before diving into what follows.

For a preview of what this will output on my lame, single-author blog, check out this page. Keep in mind that this will generate a relatively large page for a blog with any sizable number of authors and/or posts, and moreover, generating the page is expensive, requiring a lot of database queries, so you should definitely have a caching solution in place.

Let’s dive right in: The two important functions that I use are get_users and query_posts (I could have used get_posts instead, but query_posts sets up a Loop in the correct way, whereas get_posts didn’t seem to quite as well. Know the reason why this is so? Let me know in the comments). First I get all the authors and above of the blog, like so:

$args = array( 'orderby' => 'display_name', 'order' => 'ASC', 'who' => 'authors' );
$authors = get_users( $args );

This explicitly leaves out any subscribers to the blog. Now, since this archive page might be relatively large, direct links (anchors) to a particular author’s section of the archive might be useful. So let’s loop through the authors to print this “header” out, using the pipe character as a separator between each author:

// Loop through all the users, printing their names, with links to their section of the
// archives. We can't use a foreach loop because we don't want to print the separator
// for the last author
for ( $i = 0; $i < count( $authors ); ++$i ) {
	$author = $authors[$i];
	echo "<a href='#{$author->user_nicename}'>$author->display_name</a>";
	if ( $i < count( $authors ) - 1 ) {
		echo ' | ';
	}
}

Now that we’ve displayed this “header,” let’s loop through all the authors again, this time printing out their posts, if they have any:

foreach ( $authors as $author ) {
	// Add the anchor for this author, as linked from the "header section"
	echo "<a name='{$author->user_nicename}'></a>";
	// Set up a Loop, querying only for the current user's posts
	$args = array( 'author' => $author->ID );
	$posts = query_posts( $args );
	// Now that we have the posts, simulate a Loop here or use get_template_part
	// if we already have the output in another template
	if ( have_posts() ) : while ( have_posts() ) : the_post();
		// Let's just print the title of each post
		echo '<p>' . the_title() . '</p>';
	endwhile; else:
		echo '<p>This author has not yet published any posts</p>';
	endif;
}

Now of course we could have made the output of each post a bit fancier, maybe printing the publication date, an excerpt, etc., as well as adding some styling to it. As I mentioned in the comment above, we could have even used get_template_part to print out all the posts for us, since we set up a Loop. However, for the sake of this example, I wanted to keep things simple, and you know how you want to style your archive page better than I do, anyway. But just for fun, I include some nicer-looking output in the full code listing at the bottom of this post.

Okay, so now that you have the code, how would you use this all? Well, the easiest way would be to wrap it up into a plugin that “listens” for a shortcode, which you would then put into a Page on your site on which you actually want to display the archives. However, I’m not going to make it quite that easy for you, mainly because it seems excessive to make a plugin just for this archive page.

So how else? Well, those who have built themes probably already know how. But I’ll give a run-down for those lucky enough to have never had to build a theme. I’d recommend that you still output these archives using a WordPress Page. You simply upload a file called all-author-archives.php to your theme (or a child theme!) on your server with the full code (handily available below). Once you’ve done that, make a new Page. On the right side of this new page, under Page Attributes, you should now be able to select a Template of “All Author Archives.” (If you don’t see a Template section under Page Attributes, or don’t see “All Author Archives” in the template drop-down, then something else went wrong. Make sure the file is actually in your current theme’s folder.) Once you select this new template, you can give your Page a title, which will display above the archives. You can preview your archives, and publish when ready.

Alternatively, rather than creating a page template, you could simply put the code for these archives in your theme’s folder with a filename of page-archives.php, and give your Page, as created above, the slug “archives” (that means changing the part of the permalink that is editable). As long as the slug matches the part of the filename after “page-” and before “.php”, this new Page will be displayed with the file you uploaded because of WordPress template hierarchy magic. This makes the archives a bit more one-off.

And now, without further ado, a listing of the full code that you’ll need to make this happen. Of course, you’ll probably want to edit the display of the individual posts to your needs (though the version included below adds users’ Gravatars to the left of their posts listing). And you might not need the “container” or “content” div elements, nor might you want to display a sidebar.

<?php
/**
 * Template Name: All Author Archives
 * Code: Scott Bressler (http://www.scottbressler.com/blog)
 * Explanation: http://www.scottbressler.com/blog/2011/03/wordpress-archive-page-with-all-authors-and-all-posts
 */
get_header(); ?>
<div id="container">
	<div id="content">
		<div id="all-authors-archive">
			<h1><?php the_title(); ?></h1>
<?php
// Arguments to pass to get_users
$args = array( 'orderby' => 'display_name', 'order' => 'ASC', 'who' => 'authors' );
// Query for the users
$authors = get_users( $args ); ?>

			<div id="authors-listing"><p><strong>Authors: </strong>
<?php
// Loop through all the users, printing their names, with links to their section of the archives
for ( $i = 0; $i < count( $authors ); ++$i ) {
	$author = $authors[$i];
	echo "<a href='#{$author->user_nicename}'>$author->display_name</a>";
	if ( $i < count( $authors ) - 1 ) {
		echo ' | ';
	}
} ?>
			</p></div>

<?php
// Loop through all the users, printing all of their posts as we go
foreach ( $authors as $author ) { ?>
			<a name="<?php echo $author->user_nicename; ?>"></a>
			<div class="author-posts-wrapper" id="author-<?php echo $author->ID; ?>-posts-wrapper">
				<div class="author-avatar" id="author-<?php echo $author->ID; ?>-avatar">
					<?php echo get_avatar( $author->ID, 96 ); ?>
				</div>
				<div class="author-posts" id="author-<?php echo $author->ID; ?>-posts">
					<h2><a href="<?php echo get_author_posts_url( $author->ID ); ?>"><?php echo $author->display_name; ?></a></h2>
	<?php
	// Set up a Loop, querying for all of the current user's posts
	$args = array( 'author' => $author->ID, 'posts_per_page' => -1 );
	$posts = query_posts($args);
	// Now that we have the posts, simulate a Loop here or use get_template_part
	// if we already have the output in another template, like:
	// get_template_part( 'loop', 'all-authors' ); // Pulls in loop-all-authors.php from theme
	if ( have_posts() ) : ?>
				<ul class="author-post-list" id="author-<?php echo $author->ID; ?>-post-list">
		<?php while ( have_posts() ) : the_post(); // Print whatever we want for each post - for now the title and date ?>
					<li><a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>"><?php the_title(); ?></a> &mdash; <?php echo get_the_date(); ?></li>
		<?php endwhile; ?>
				</ul><!-- #author-post-list -->
	<?php else: ?>
					<p>This author has not yet published any posts</p>
	<?php endif; ?>
				</div><!-- #author-posts -->
			</div><!-- #author-posts-wrapper -->
<?php } // End looping over all users ?>

			<p>See <a href="http://www.scottbressler.com/blog/2011/03/wordpress-archive-page-with-all-authors-and-all-posts">this post</a> for an explanation of the motivation behind this page</p>
		</div><!-- #all-authors-archive -->
	</div><!-- #content -->
</div><!-- #container -->
<style type="text/css">
/* We would certainly put this in a separate file for production use */
#all-authors-archive h1 {
	margin-bottom: 15px;
}
#all-authors-archive h2,
#all-authors-archive .author-posts-wrapper {
	margin-bottom: 10px;
}
#all-authors-archive .author-posts-wrapper {
	position: relative;
	padding-left: 111px;
	min-height: 106px;
}
#all-authors-archive .author-avatar {
	position: absolute;
	left: 0;
}
#all-authors-archive .author-post-list li {
	word-wrap: break-word;
	font-size: 14px;
}
</style>
<?php
get_sidebar();
get_footer();
?>

You can alternatively download the code directly. Make sure the file is named all-author-archives.php before uploading to your server. And consider moving the CSS to your theme’s (or child theme’s) style.css file. And just as a head’s up regarding browser compatibility, I tested this code (mostly the individual article display with avatars, since that’s where the CSS really comes into play) in Firefox 3.6, Internet Explorer 7-9, Chrome 10, and Safari 5 (all on Windows). Things don’t work as well in IE6, so if you’re targeting IE6 users, you’ll probably want to fix things up just a wee bit.

I hope that this code helps you. Sound off in the comments below with your thoughts, feedback, or experience using it!