Blog / Tutorials / List posts by Category Shortcode for WordPress

List posts by Category Shortcode for WordPress

Cristian Antohe
Last Updated: 11/09/24

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:

<?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”]

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

     $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

/*
 * 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 Shortcode

From the blog

Related Articles

WordPress Creation Kit – a sparkling new custom field, taxonomy and post type creator

Author: Cristian Antohe
Last Updated: December 20th, 2023

WordPress Creation Kit consists of three brand new modules that can help you with the tough task of creating and maintaining custom post types, custom taxonomies and most importantly, custom fields and metaboxes for your posts, pages or CPT's. Why another plugin for this? We've actually started working on this more then a year ago, […]

Continue Reading

Swift Templates – a straight forward alternative to WordPress templates hell

Author: Cristian Antohe
Last Updated: April 28th, 2016

I'm not a programmer... I do know some basic html and css, but I was nervous about messing with any of the templates in fear of making a bigger mess than where I started. That's a quote from one of our customers. We hear this quite a lot, not everybody is a developer. Most WordPress […]

Continue Reading

WordPress 4.4 “Clifford” explained

Author: Cristian Antohe
Last Updated: December 10th, 2015

WordPress 4.4 “Clifford” (named for jazz musician Clifford Brown) was released with over 2,000 contributions by 471 contributors. That's the largest number of contributors to a point release by far. Here's the short launch video for this version. As you can see, there are a lot of great things in this release like: REST API […]

Continue Reading

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.