Create a page that lists posts by category (using the Genesis Framework)

Have you ever wanted to create a page on your WordPress site that displayed all the categories on your site and list their corresponding posts underneath? If so, today’s your lucky day.

When I first started working with WordPress, I was frustrated to find that there are no native templates that list all categories on a site with a list of posts underneath, like this:

List of posts by category

But alas, if you look at the WordPress template hierarchy, a page that automatically spits out that info doesn’t exist. It’s just not the way WordPress works. Thankfully, it’s not hard to add as a customization. Following is a quick tutorial on how to add this feature to your site.

Note that this tutorial is for sites using the Genesis Framework. (<– that’s a big ole affiliate link)

How to List Posts by Category on a Page

In order to get a page that shows a list of categories (and the posts belonging to each category), we need to do two things:

  1. Create a custom page template
  2. Assign that template to a Page

The first step takes a little work. The second step you can knock out in seconds. Now, you may think that it’s silly to even bother with this as you could simply create a Page and manually write out your categories and list your posts. But as your blog grows and you get more content, that’s a terribly inefficient way to keep up your post lists.

So, on we go…

Step 1: Create a custom page template

First things first. Open up your code editor (I like Sublime Text) and create a new file within your Genesis child theme folder. I’m calling mine categories-template.php because it’s descriptive and follows the best practice for naming a template file.

You can use the following code to create a custom page template. I’ll post the code first and then walk through what it does.

<?php
/**
* Template Name: Category Archives
*/
add_action( 'genesis_loop', 'custom_category_loop' );
/**
* Custom loop that display a list of categories with corresponding posts.
*/
function custom_category_loop() {
// Grab all the categories from the database that have posts.
$categories = get_terms( 'category', 'orderby=name&order=ASC');
// Loop through categories
foreach ( $categories as $category ) {
// Display category name
echo '<h2 class="post-title">' . $category->name . '</h2>';
echo '<div class="post-list">';
// WP_Query arguments
$args = array(
'cat' => $category->term_id,
'orderby' => 'term_order',
);
// The Query
$query = new WP_Query( $args );
// The Loop
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
?>
<p><a href="<?php the_permalink();?>"><?php the_title(); ?></a></p>
<?php
} // End while
} // End if
echo '</div>';
// Restore original Post Data
wp_reset_postdata();
} // End foreach
}
// Start the engine.
genesis();

(Are you already getting sweaty armpits? I teach a whole class dedicated to customizing Genesis child themes).

Step 1a

Let’s start with line 6. All I’m doing here is hooking a  custom function (custom_category_loop) to the genesis_loop.

add_action( 'genesis_loop', 'custom_category_loop' );

Step 1b

Now, in line 10, I’m going to create my custom function.

function custom_category_loop() {

Step 1c

Lines 11-47 contain the guts of the custom_category_loop function.

// Grab all the categories from the database that have posts.
$categories = get_terms( 'category', 'orderby=name&order=ASC');
// Loop through categories
foreach ( $categories as $category ) {
// Display category name
echo '<h2 class="post-title">' . $category->name . '</h2>';
echo '<div class="post-list">';
// WP_Query arguments
$args = array(
'cat' => $category->term_id,
'orderby' => 'term_order',
);
// The Query
$query = new WP_Query( $args );
// The Loop
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
?>
<p><a href="<?php the_permalink();?>"><?php the_title(); ?></a></p>
<?php
} // End while
} // End if
echo '</div>';
// Restore original Post Data
wp_reset_postdata();
} // End foreach

We’re doing a couple of things within the function:

  • Line 13: Grabbing all the categories on the site using WordPress’s get_terms() function and assigning those categories to a variable called $categories. I’m grabbing those categories in order by name. Check the get_terms() documentation if you want to specify other details about the categories you want.
  • Line 16: We start a loop (not the Loop) that will loop through each category and do some stuff.
  • Lines 19-20: The first thing we do is add a little HTML markup and output the name of the category. You can add whatever HTML markup you want or whatever CSS classes you want.
  • Lines 22-26: Here we’re creating an array of arguments that we’ll shortly pass to WP_Query. Those arguments basically say that we want to grab a specific category (by its ID and order it a certain way). There are a bajillion ways you can customize the WP_Query, so check the WordPress codex to learn more.
  • Line 29: We create a new instance of WP_Query with the arguments we just created and assign it to a variable called $query.
  • Lines 31-40: Here comes THE Loop, the one that loops through posts. It’s a simple if statement that says HEY, IF THERE’S A POST, GET IT! And then on line 36 we output a little HTML, the post permalink, and the post name. There are lots of post details you can return in the loop, but that’s all I wanted.
  • Line 42: We close out our markup. No dangling participles or HTML tags here! Again, you can use whatever HTML markup you want.
  • Line 45: Here we’re being good WordPress citizens and calling the wp_reset_postdata() function. Since we added a custom loop, that function basically says, WE’RE ALL DONE HERE. AS YOU WERE, PAGE!

We’re almost to the finish line.

Step 1d

The final step is to call the genesis() function in line 51, which basically says, HEY GENESIS FRAMEWORK, WE’RE READY FOR YOU TO DO YOUR THING!

genesis();

Step 1e

Save your file (remember we’re in the root child theme directory).

Step 2 Assign a custom template to a page

I told you this was the easy part and I wasn’t lying! Go create a new Page on your WordPress site. There’s a metabox on the page called Page Attributes (typically somewhere on the right-hand side of the screen when you’re in the page editor.)

Page Attributes metabox

You’ll see your custom template in the Template drop-down. Select it.

Oh yeah, that name that you see in the drop-down comes from Line 3 of your custom template file.

* Template Name: Category Archives

Save it, and that’s it!

Further customizations to this template

Does this get you 90% of the way to what you’re trying to accomplish, but you’re not sure about the last 10%? Here are a couple of common customizations.

Get rid of the page content

In the example here, any content that you enter in your Page will show first, and then your categories and posts lists will show underneath. If you don’t want ANY of your Page content to show (i.e. the Page is simply the vessel for displaying your template), then you’ll want to remove the default Loop before adding our custom loop.

Add this snippet to your categories-template.php

// Remove the standard loop
view raw remove-loop.php hosted with ❤ by GitHub

Display the posts as a bulleted list

This is pretty straightforward. All we need to do is swap out this loop markup:

// The Loop
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
?>
<p><a href="<?php the_permalink();?>"><?php the_title(); ?></a></p>
<?php
} // End while
} // End if

with this:

<ul> // Start your unordered list
// The Loop
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
?>
<li><a href="<?php the_permalink();?>"><?php the_title(); ?></a></li>
<?php
} // End while
} // End if
</ul> // End your unordered list

All that did is add the list markup <ul></ul> OUTSIDE of the Loop and then wrap each blog post in list tag <li></li>.

???

Is there another customization you’d like to see? Drop a comment and I’ll do my best to help.
Cobalt Apps

37 thoughts on “Create a page that lists posts by category (using the Genesis Framework)”

  1. I used this for a custom post type. It put the categories (custom taxonomies) in order, but did not put the posts under them. The posts appeared ABOVE the taxonomy listing in it’s usual order.

Leave a Comment

Your email address will not be published. Required fields are marked *

Carrie Dils uses Accessibility Checker to monitor our website's accessibility.