List posts by Category Shortcode for WordPress

Cristian Antohe
Last Updated: 15/05/19

Usually the archive pages in WordPress leave a lot to be desired and sometimes you want to list posts by category so users have a much nicer way of interacting with your content so it can be useful to have access to a list posts by category shortcode.

What we’re aiming for is a post listing by category similar to:

list posts by category shortcode

While you can modify the archive page template in your theme to have this listing, it would be a lot simpler to just have a list posts by category shortcode that you can use anywhere you want. And that’s what we’re going to build.

Create a new plugin

Creating a new plugin is really straight forward, we just need to create a new file and add these php commets to the top of the file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
/**
 * Plugin Name: Taxonomy Archive Shortcode
 * Plugin URI: https://www.cozmoslabs.com
 * Description: A simple shortcode to list a taxonomy archive and the posts for each term ex: [list_taxonomy_archive cpt="book" tax="genre"]
 * Version: 1.0
 * Author: Cristian Antohe
 * Author URI: https://www.cozmoslabs.com
 * License: GPL2
 */
 
/*  Copyright 2016 Cristian Antohe
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License, version 2, as 
    published by the Free Software Foundation.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
// Start writing code after this line!

Create a new shortcode

We’ll need code to register a new shortcode: [list_taxonomy_archive]

By default this shortcode will create a listing with all the categories and the posts found inside those categories. However, you can also define a custom taxonomy or custom post type like so: [list_taxonomy_archive cpt=”book” tax=”genre”]

1
2
3
4
5
6
7
add_shortcode('list_taxonomy_archive', 'wckc_list_taxonomy_archive');
function wckc_list_taxonomy_archive($atts){
    $a = shortcode_atts( array(
        'cpt' => 'post',
        'tax' => 'category',
    ), $atts );
}

So far our shortcode doesn’t do anything. Next we’ll need to look into querying all the taxonomy terms and the posts that have them assigned.

Query all taxonomy terms and the posts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    $terms = get_terms( array('taxonomy' => $a['tax'], 'hide_empty' => false) );
 
    if( $terms ){
        $output .= '<div class="list_tax_archive">';
        foreach ($terms as $term) {
            if ( is_array($term) && isset($term['invalid_taxonomy']) )
                return;
 
            $args = array (
                'post_type'         => $a['cpt'],
                $a['tax']           => $term->slug,
                'posts_per_page'    => '-1',
            );
 
            // The Query
            $posts = get_posts($args);
 
            if( empty($posts)){
                return;
            }
            $output .= "<h4> {$term->name} </h4>";
            $output .= '<ul class="term_archive">';
            foreach($posts as $post){
                $output .= '<li><a href="'.get_permalink( $post ).'">'.get_the_title( $post ).'</a></li>';
            }
            $output .= '</ul>';
 
        }
        $output .= '</div>';
    }

What we’re doing is:

  • Get all the terms of our taxonomy using get_terms
  • For each term that is assigned to at least 1 post, query for those particular posts using get_posts

The code for the list posts by category shortcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
 * Create a shortcode that lists all cpt's ordered by taxonomy term
 */
 
add_shortcode('list_taxonomy_archive', 'wckc_list_taxonomy_archive');
function wckc_list_taxonomy_archive($atts){
    $a = shortcode_atts( array(
        'cpt' => 'post',
        'tax' => 'category',
    ), $atts );
 
    $output = '';
 
    $terms = get_terms( array('taxonomy' => $a['tax'], 'hide_empty' => false) );
 
    if( $terms ){
        $output .= '<div class="list_tax_archive">';
        foreach ($terms as $term) {
            if ( is_array($term) && isset($term['invalid_taxonomy']) )
                return;
 
            $args = array (
                'post_type'         => $a['cpt'],
                $a['tax']           => $term->slug,
                'posts_per_page'    => '-1',
            );
 
            // The Query
            $posts = get_posts($args);
 
            if( empty($posts)){
                return;
            }
            $output .= "<h4> {$term->name} </h4>";
            $output .= '<ul class="term_archive">';
            foreach($posts as $post){
                $output .= '<li><a href="'.get_permalink( $post ).'">'.get_the_title( $post ).'</a></li>';
            }
            $output .= '</ul>';
 
        }
        $output .= '</div>';
    }
    return $output;
 
}

You can also download the List Posts by Category Shortcode plugin below:

Get List posts by category

7 thoughts on “List posts by Category Shortcode for WordPress

    Just what I was looking for! Except, using the default shortcode ([list_taxonomy_archive]) I get all posts under each category. Or, when I try the other option ([list_taxonomy_archive cpt=”book” tax=”genre”]) using a category slug I get nothing. Any thoughts? Thank you!

    Reply

    Hi – is it possible to create this code to pick up a particular tag as opposed to catagories?
    Thank you!

    Reply

    It already does that. For example, you use the shortcode like so: [list_taxonomy_archive cpt=”book” tax=”genre”]

    you can then replace it with

    [list_taxonomy_archive cpt=”post” tax=”tag”]

    Reply

    Hi!

    Would appreciate any help with this question.
    How do I display only specific terms like [list_taxonomy_archive cpt=”book” tax=”genre” myterms=”romance,science-fiction”] ?
    Now it loops through all the terms of genre. How do I make it loop only through the terms specified in $a[‘myterms’]?

    Reply

    If anyone needs to do the same:
    Managed to do it by using the value from $a[‘myterms’] in
    foreach ($a[‘myterms’] as $term)
    and extending the post query with
    ‘tax_query’ => array(
    array(
    ‘taxonomy’ => $a[‘tax’],
    ‘field’ => ‘slug’,
    ‘terms’ => $term,
    ‘operator’ => ‘IN’,
    )
    )
    Thank you for the code. Really helped me in my project!

    Reply

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.