Add a Custom Post Type Shortcode With Pagination

Quick Summary

  • A snowreports shortcode lists custom post type entries, 10 per page unless count is set, with linked titles, excerpts and numbered pages.
  • The paged query var tells WP_Query which page to load, and links only print when max_num_pages is greater than one.
  • On a static front page WordPress uses the page query var instead of paged, so the list would stay on its first page.

This shortcode lists entries from a custom post type with numbered pagination underneath, so you can place a paged list on any WordPress page. Each item shows the title, linked to the entry, and its excerpt. Add the code to your child theme’s functions.php or a custom plugin.

PHP
function snowreports_shortcode($atts){
    extract( shortcode_atts( array(
        'count' => 10,
    ), $atts) );
    $i = 0;
    $q = new WP_Query(
        array(
            'posts_per_page' => $count, 
            'post_type' => 'posttype', 
            'paged'     => get_query_var('paged'),
        )
    );      
         
    $list = '<div class="custom-post-list">';
    while($q->have_posts()) : $q->the_post();
        $idd = get_the_ID();
        $i++;
        $custom_field = get_post_meta($idd, 'custom_field', true);
        $post_content = get_the_excerpt();
        $list .= '
        <div class="single-post-item">
            <h2><a href="'.get_permalink().'">' .do_shortcode( get_the_title() ). '</a></h2>
            '.wpautop( $post_content ).'
        </div>
        ';        
    endwhile;
    
    $total_pages = $q->max_num_pages;
    $big = 999999999;
    if ($total_pages > 1){  
        $current_page = max(1, get_query_var('paged'));  
        $list.= '<nav class="page-nav">';  
        $list.= paginate_links(array(  
            'base'      => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
            'format'    => '?paged=%#%',  
            'current'   => $current_page,  
            'total'     => $total_pages,  
            'prev_text' => 'Prev',  
            'next_text' => 'Next'  
        ));  
        $list.= '</nav>';  
    }     
    
    
    $list.= '</div>';
    wp_reset_query();
    return $list;
}
add_shortcode('snowreports', 'snowreports_shortcode');

How to use it

Add [snowreports count="5"] to a page to show five entries per page. Without count, it shows 10. Then adjust the code for your site:

  • Replace 'posttype' with your custom post type’s slug (the key from registering a custom post type).
  • Rename the shortcode (snowreports) and its function if you like; the name comes from the project it was written for.
  • Change 'Prev' and 'Next' to the link text you want.
  • $i and $custom_field are set in the loop but never printed. Use them in the markup or remove them.

How the pagination works

  • 'paged' => get_query_var('paged') tells the query which page of results to load, based on the current URL.
  • $q->max_num_pages holds the total number of pages, and the links are only printed when there is more than one.
  • $big is a placeholder number. get_pagenum_link( $big ) builds the URL of that page in your permalink format, and str_replace() swaps the number for %#%, which paginate_links() replaces with each page number.
  • On a static front page, WordPress passes the page number in the page query var instead of paged, so there the list would stay on its first page.

The shortcode builds all its HTML in $list and returns it, which is what WordPress expects from a shortcode, and wp_reset_query() restores the page’s own post data afterward.

Share on X (opens in a new tab) Share on LinkedIn (opens in a new tab) Share on Facebook (opens in a new tab)

ChatGPT (opens in a new tab) Claude (opens in a new tab) Gemini (opens in a new tab) Perplexity (opens in a new tab) Grok (opens in a new tab)

More Insights

See More