Skip to main content

Displaying Posts From A Category In WordPress

It may happen that you are designing some sort of archive pages or a front page and you want to list all posts belonging to some specific category. In this case you can go for following code.

It may happen that you are designing some sort of archive page or a front page and you want to list all posts belonging to a specific category. In this case you can use WP_Query (or the simpler get_posts() helper) to pull in exactly the posts you need.

Using WP_Query to list posts from a category

The most flexible way to grab posts from a specific category is a custom WP_Query. Here’s a complete, working example:


$query = new WP_Query( array(
    'category_name'  => 'news',
    'posts_per_page' => 10,
) );

if ( $query->have_posts() ) {
    while ( $query->have_posts() ) {
        $query->the_post();

        // Do what ever you want with your posts
        echo '<article id="post-' . get_the_ID() . '">';
        echo '<h2><a href="' . esc_url( get_permalink() ) . '">' . esc_html( get_the_title() ) . '</a></h2>';
        echo '<div class="entry-summary">' . get_the_excerpt() . '</div>';
        echo '</article>';
    }

    // Always reset the query after a custom WP_Query loop
    wp_reset_postdata();
} else {
    echo '<p>No posts found in this category.</p>';
}

A couple of notes on the arguments:

  • category_name accepts the category slug (not the display name). Use a comma-separated list of slugs to match any of several categories.
  • If you’d rather reference the category by its numeric ID, use cat instead, e.g. 'cat' => 5. Prefix the ID with a minus sign ('cat' => -5) to exclude that category instead.
  • By default, WP_Query automatically includes posts from child categories of the one you specify, so you don’t need any extra logic to pull those in too.
  • Always pair a custom WP_Query loop with wp_reset_postdata() afterwards. It restores the global $post object to the main query so the rest of your template behaves correctly.

A quicker option: get_posts()

If you just need a simple list of posts (for example, in a sidebar widget or a “related posts” block) and don’t need the full WP_Query object, get_posts() is a convenient shorthand. It returns a plain array of post objects:


$posts = get_posts( array(
    'category_name' => 'news',
    'numberposts'   => 10,
) );

foreach ( $posts as $post ) {
    setup_postdata( $post );

    // Do what ever you want with your posts
    echo '<h2><a href="' . esc_url( get_permalink() ) . '">' . esc_html( get_the_title() ) . '</a></h2>';
}

wp_reset_postdata();

get_posts() accepts most of the same arguments as WP_Query (note it uses numberposts instead of posts_per_page). Because it still touches the global post data when you call setup_postdata(), remember to call wp_reset_postdata() once you’re done with the loop.

A more idiomatic alternative: pre_get_posts

If your goal is simply to change what shows up on the existing category archive page itself, rather than building a custom block somewhere in a template, you usually don’t need a separate query at all. Hook into pre_get_posts and modify the main query before it runs:


function ankurm_modify_category_query( $query ) {
    if ( ! is_admin() && $query->is_main_query() && is_category( 'news' ) ) {
        $query->set( 'posts_per_page', 10 );
    }
}
add_action( 'pre_get_posts', 'ankurm_modify_category_query' );

This approach is generally preferred over a fresh WP_Query when you’re working with an actual category archive page, since it avoids running a duplicate database query and keeps pagination, SEO plugins, and other code that relies on the main query working correctly. Reach for a custom WP_Query or get_posts() call instead when you need a category listing in a spot that isn’t the main query, such as a widget, a shortcode, or a block on the front page.

FAQs

How do I list posts from a category by ID instead of slug?

Use the cat argument with the category’s numeric ID, e.g. 'cat' => 5, instead of category_name.

Will child categories be included automatically?

Yes. Both WP_Query and get_posts() include posts from child categories of the specified category by default.

Do I need wp_reset_postdata() with get_posts()?

Only if you call setup_postdata() inside your loop (which is needed for template tags like the_title() to work). If you access post properties directly instead, you can skip both calls.

Conclusion

For most category-listing needs, a custom WP_Query loop or the simpler get_posts() helper will get the job done. But if you’re customizing an existing category archive page rather than building a new listing elsewhere, hooking into pre_get_posts is the cleaner, more idiomatic solution.

No Comments yet!

Leave a Reply

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