Display Posts using WP_Query

In this post, we’ll learn how to build a custom page to display posts of a specific ‘Category’. Having a category based page is a handy way to direct your visitors to a specific set of your posts without the risk of distracting them with all your other great content.

The steps will be to:

  • create a custom page template
  • understanding the ‘Loop’
  • understand how WP_Query works in this use case
  • modify the php code to pull (or filter) just the posts having the category we want
  • display the posts – in this case, posts with my WordCamp presentations
  • return control to the normal page ‘Loop’ so that the rest of the content is displayed properly

Creating a Custom Page Template

First go to your cPanel, open your child theme, create a file named page_category.php. You can put this file in the top level of your child theme folder or, if you expect to create several custom page templates, you might decide to organize them in a separate custom template folder. In this example, I have the new file ‘page_category.php’ at the top level of my child theme.

cPanel showing the files in my child theme

Now open the page_category.php file, delete the header and put the following code at the top of the file (just above the ‘get_header’ statement).

<?php /* Template Name: Display Category */?>

Here’s what the top of the page_category.php looks like:

Now create a new page and confirm that the newly created template is available. Here, I’m using the Gutenberg Block Editor and ‘page attributes is shown in the right hand pane.

As you can see the Category page template now exists.

Understanding the ‘Loop’

Here’s where we introduce WP_Query and the concept of the Loop.

You can learn more about this from the WordPress Codex at https://developer.wordpress.org/reference/classes/wp_query/ (here’s an excerpt)

…during The Loop. WP_Query provides numerous functions for common tasks within The Loop. To begin with, have_posts(), which calls $wp_query->have_posts(), is called to see if there are any posts to show. If there are, a while loop is begun, using have_posts() as the condition. This will iterate around as long as there are posts to show. In each iteration, the_post(), which calls $wp_query->the_post() is called, setting up internal variables within $wp_query and the global $post variable …

Well……

It’s really not all that bad!

The ‘Loop’ is really a while loop that searches the WordPress database of the website to find all the posts, then grabs the components of each post, one at a time, (components include; title, content, post meta data: author, date etc). Then calls template parts to display each post, then goes to the next post until there are no more posts to display.

Let’s compare the Loop for the twentyseventeen (default) and oceanwp themes. This website is built on oceanwp. You will notice that both themes contain the same have_post() and the_post() statements but handle template parts and comments differently. Here we’ll concentrate on the post functions.

while ( have_posts() ) :
the_post();

From the Twenty Seventeen default theme

<?php
                // Elementor `single` location
                if ( ! function_exists( 'elementor_theme_do_location' ) || ! elementor_theme_do_location( 'single' ) ) {
                    
                    // Start loop
                    while ( have_posts() ) : the_post();

                        get_template_part( 'partials/page/layout' );

                    endwhile;

                } ?>

From the OceanWP custom theme

    <?php
            while ( have_posts() ) :
                the_post();

                get_template_part( 'template-parts/page/content', 'page' );

                // If comments are open or we have at least one comment, load up the comment template.
                if ( comments_open() || get_comments_number() ) :
                    comments_template();
                endif;

            endwhile; // End the loop.
            ?>

What is WP_Query?

WP_Query is a class defined in WordPress. It allows developers to write custom queries and display posts using different parameters.

Simply put, WP_Query acts like a database language (think SQL or MySQL). You can think of WP_Query like a ‘filter’ in Excel which will allow you to see only those rows which meet a specific criteria (example: filter a customer table for customers first name = John).

How to use WP_Query

The following code is courtesy of Artisan Web which I modified slightly for this example.

NOTE: WordPress is licensed as open source under GNU license. This means that you can and should, use, modify, and expand on other peoples code. This is perfectly legal and is encouraged!

<?php /* Template Name: Category */ 
?>

<?php
/* ******************************** 
/* This is the WP_Query code */
$args = array(
    'post_type' => 'post',
    'post_status' => 'publish',
    'category_name' => 'wordcamp',
    'posts_per_page' => 5,
);
$arr_posts = new WP_Query( $args );


 /* ********************************
 /* The Loop and display code */
if ( $arr_posts->have_posts() ) :
 
    while ( $arr_posts->have_posts() ) :
        $arr_posts->the_post();
        ?>
        <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
            <?php
            if ( has_post_thumbnail() ) :
                the_post_thumbnail();
            endif;
            ?>
            <header class="entry-header">
                <h1 class="entry-title"><?php the_title(); ?></h1>
            </header>
            <div class="entry-content">
                <?php the_excerpt(); ?>
                <a href="<?php the_permalink(); ?>">Read More</a>
            </div>
        </article>
        <?php
    endwhile;
endif;
?>

While this may look complicated, most of the code is used to display the post excerpts as ‘articles’. The top block is the WP_Query ‘filter’.

/* ****
/* This is the WP_Query code */
$args = array(
‘post_type’ => ‘post’,
‘post_status’ => ‘publish’,
‘category_name’ => ‘wordcamp’,
‘posts_per_page’ => 5,
);
$arr_posts = new WP_Query( $args );

First, the variable ‘$args’ is defined as an array which defines the parameters of the database query as; published posts whose category is ‘wordamp’. Then we’ll set a limit of 5 posts to be displayed per page.

Finally, we’ll do a ‘new WP_query’ using the parameters in $args and put the post data for each post found into the array named ‘$arr_posts’

That’s it!

Now let’s see if it worked…

We’ll we can see this code worked because it displays excerpts of both posts whose category is ‘WordCamp’. But it has no styling. No header, footer, navbar, or sidebar.

More work needs to be done.

Adding essential page components

Open the page.php file from the parent theme. Copy and paste the commands get_header(), and get_footer() and place them in the appropriate places near the top and bottom of the page code. Test. Add in the theme’s (oceanwp) ocean_before and ocean_after sections. Heree’s the completed custom code for the category page template.

<?php /* Template Name: Category */ 
?>

<?php get_header(); ?>

<?php
// ******************  copy before objects from parent theme page.php  ******** 
?>

    <?php do_action( 'ocean_before_content_wrap' ); ?>

    <div id="content-wrap" class="container clr">

        <?php do_action( 'ocean_before_primary' ); ?>

        <div id="primary" class="content-area clr">

            <?php do_action( 'ocean_before_content' ); ?>

            <div id="content" class="site-content clr">

                <?php do_action( 'ocean_before_content_inner' ); ?>

<?php
// **************** replace the normal while loop with WP_Query ****************
$args = array(
    'post_type' => 'post',
    'post_status' => 'publish',
    'category_name' => 'wordcamp',
    'posts_per_page' => 5,
);
$arr_posts = new WP_Query( $args );
 
if ( $arr_posts->have_posts() ) :
 
    while ( $arr_posts->have_posts() ) :
        $arr_posts->the_post();
        ?>
        <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
            <?php
            if ( has_post_thumbnail() ) :
                the_post_thumbnail();
            endif;
            ?>
            <header class="entry-header">
                <h1 class="entry-title"><?php the_title(); ?></h1>
            </header>
            <div class="entry-content">
                <?php the_excerpt(); ?>
                <a href="<?php the_permalink(); ?>">Read More</a>
            </div>
        </article>
        <?php
    endwhile;
endif;
?>

<?php
// ***************** add the after section ********************
?>

<?php do_action( 'ocean_after_content_inner' ); ?>

            </div><!-- #content -->

            <?php do_action( 'ocean_after_content' ); ?>

        </div><!-- #primary -->

        <?php do_action( 'ocean_after_primary' ); ?>

        <?php do_action( 'ocean_display_sidebar' ); ?>

    </div><!-- #content-wrap -->

    <?php do_action( 'ocean_after_content_wrap' ); ?>


<?php get_footer(); ?>

Go To The Finished Page

OK- so now the Category page has a header, navbar, footer and sidebar.

Now we need to return control to the normal page loop so I added this just after the endif statement:

endif;

// add return control to normal page loop after this WP_Query
wp_reset_postdata();
?>

This is a good practice even though in this case it didn’t make any difference in how the page displays.

Leave a Reply

Close Menu