DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan Now×
Skip to content
World desk11 min

How to List WordPress Posts by Category (Query Loop, WP_Query, and More)

A practical guide to displaying WordPress posts by category using the Query Loop block, WP_Query, get_posts(), and archive templates—with code, filtering options, pagination, and troubleshooting.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To show posts from one category on a WordPress page, use a Query Loop block if you want a visual, no-code setup. Use a separate WP_Query when a theme or landing page needs PHP-level control, and use get_posts() for a short, non-paginated list. Do not use query_posts() for an embedded list because it replaces the page’s main query.

The right method depends on whether the category is the page’s primary content (a normal category archive) or one section among several on a page. The steps and examples below cover both cases, including category slugs versus IDs, grids, pagination, empty results, template files, and common failures.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose the method that matches the page

WordPress offers four practical ways to present posts belonging to a category. They are not interchangeable: each changes who controls the query, the layout, and navigation.

Method Best for Category control Main caution
Query Loop block Block themes and editors who want no-code control Category filter in the block settings; list or grid layouts The theme and editor determine the exact styling controls
WP_Query Custom PHP templates, home-page sections, and landing pages Slugs, IDs, AND/OR inclusion, and exclusions Call wp_reset_postdata() after the loop
get_posts() Small secondary lists such as “latest five in News” Most normal query arguments It is not the right tool for a full, paginated archive
Category archive template When the category URL is the primary destination for that topic WordPress archive routing The available template files depend on the theme

If visitors should browse an entire category with its own URL, use the standard category archive. If a page needs a News grid above a Tutorials list, embed separate Query Loop blocks or secondary queries instead.

List posts without code using the Query Loop block

The Query Loop block is the simplest way to filter posts by category and present them as a list or grid. It can also control the post type, order, item count, pagination, and what visitors see when no posts match.

1. Insert a Query Loop

  1. Open the page in the WordPress editor, or open the Site Editor when editing a template.
  2. Insert a Query Loop block. If the editor offers a pattern, choose a list or grid pattern that you can modify.
  3. Choose the post type. For ordinary blog entries, leave it set to Posts. A custom post type must be registered and selected separately.

2. Apply the category filter

  1. Select the Query Loop block and open its block settings.
  2. Find the taxonomy or category filter and select the category you want.
  3. Confirm that the selected category is the intended one; similarly named categories can be easy to confuse in a large site.

The block uses the category relationship rather than a text search, so a post must actually be assigned to that category to appear.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

3. Build the item layout

Inside Post Template, add the blocks that should repeat for every result:

  • Post Title, usually linked to the full post.
  • Featured Image, with an appropriate aspect ratio for a grid.
  • Excerpt or post content, depending on how much text belongs on the listing page.
  • Date, Author, and Categories metadata when it helps visitors evaluate the result.
  • Read More for a consistent call to action.

Choose a single-column list for text-heavy archives or a grid for visual cards. The number of columns, spacing, image dimensions, and typography are controlled by the block and theme styles, so the same Query Loop can look different across themes.

4. Set order, count, and pagination

Use the Query Loop settings to select the ordering (for example, newest first), the number of posts shown, and the relevant post filters. If the category can contain more posts than the first screen, add a Pagination block inside the Query Loop. Without pagination, visitors see only the configured first batch.

Pagination is especially important when the block is acting as the main content of a page. A small “Latest News” section may intentionally show only five posts, but a category landing page should offer a way to reach older entries.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

5. Add a No Results state

Insert a No Results section in the Query Loop and write a useful message, such as “No published posts are in this category yet.” This prevents an empty area from looking like a broken page after a category is renamed, emptied, or filtered by another condition.

Use a secondary WP_Query in PHP

A new WP_Query is the flexible choice for a custom template or a page that contains several independently filtered sections. It creates a separate query instead of replacing the page’s main query.

Basic category list by slug

category_name expects the category’s URL slug, not its display name. This example returns ten published posts in the news category and prints a title and excerpt for each one.

<?php
$category_posts = new WP_Query([
    'post_type'      => 'post',
    'category_name'  => 'news', // category slug, not the display name
    'post_status'    => 'publish',
    'posts_per_page' => 10,
]);

if ($category_posts->have_posts()) :
    while ($category_posts->have_posts()) :
        $category_posts->the_post();
        ?>
        <article>
            <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
            <?php the_excerpt(); ?>
        </article>
        <?php
    endwhile;
else :
    echo '<p>No published posts found in this category.</p>';
endif;

wp_reset_postdata();
?>

The final wp_reset_postdata() is essential. Calling the_post() changes the global post context used by template tags such as the_title() and the_permalink(). Resetting it lets the surrounding page continue with the correct page or post after the custom loop.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Filter by a category ID

When an ID is easier to obtain than a slug, use cat:

<?php
$category_posts = new WP_Query([
    'post_type'      => 'post',
    'cat'             => 42,
    'posts_per_page' => 10,
]);
?>

The value is an integer category ID. Verify the ID in the category management screen rather than assuming that a category’s position in a list is its ID.

Include any of several categories

category__in accepts an array of category IDs and matches posts assigned to at least one of them:

<?php
$posts = new WP_Query([
    'post_type'      => 'post',
    'category__in'   => [12, 18, 27],
    'posts_per_page' => 12,
]);
?>

Use this for a combined feed such as News, Announcements, or Events. The documented behavior for category__in does not automatically include child categories, so add the relevant child IDs explicitly when that is required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Require every listed category

category__and returns posts assigned to all of the supplied category IDs:

<?php
$posts = new WP_Query([
    'post_type'    => 'post',
    'category__and' => [12, 18],
]);
?>

This is useful for a narrow intersection, such as posts tagged in both a product category and a region category. It can legitimately return no results even when each category contains many posts.

Exclude categories

Use category__not_in to omit posts assigned to specified category IDs:

<?php
$posts = new WP_Query([
    'post_type'       => 'post',
    'category__not_in' => [31, 32],
    'posts_per_page'  => 10,
]);
?>

Combine inclusion and exclusion deliberately. For example, an “All News except internal” feed can include the News category and exclude an internal-only category, provided your content model assigns those categories consistently.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Render a grid with your own markup

The query does not impose a visual design. You can output a class on the wrapper and let the theme’s CSS create columns:

<div class="category-grid">
    <?php if ($category_posts->have_posts()) : ?>
        <?php while ($category_posts->have_posts()) : $category_posts->the_post(); ?>
            <article class="category-card">
                <?php if (has_post_thumbnail()) : ?>
                    <a href="<?php the_permalink(); ?>">
                        <?php the_post_thumbnail('medium'); ?>
                    </a>
                <?php endif; ?>
                <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
                <?php the_excerpt(); ?>
            </article>
        <?php endwhile; ?>
    <?php endif; ?>
</div>
<?php wp_reset_postdata(); ?>

Keep the query and markup separate: the query decides which posts qualify, while CSS decides whether those posts appear as one column, multiple columns, or a responsive layout.

Use get_posts() for a small isolated list

get_posts() is convenient when you need a few links in a sidebar, footer, or landing-page panel and do not need archive-style pagination. It performs a separate query and does not replace the global main loop.

<?php
$category_posts = get_posts([
    'category_name' => 'news',
    'numberposts'   => 5,
    'post_status'   => 'publish',
]);

foreach ($category_posts as $post) :
    setup_postdata($post);
    ?>
    <article>
        <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
    </article>
    <?php
endforeach;

wp_reset_postdata();
?>

Although get_posts() does not alter the main query, setup_postdata() still changes the context used by template tags during the loop, so reset it afterward. For a complete archive with navigation, use a category archive or a paginated WP_Query instead.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When the category archive is the better answer

A category archive is the canonical destination when the category itself is the page’s subject. Visitors get a stable category URL, and WordPress can provide archive navigation rather than embedding a subset inside unrelated landing-page content.

Classic themes

Classic themes commonly render category archives through archive.php. A theme may also provide more specific category templates, which take precedence according to WordPress’s template hierarchy. Check the active theme before creating a new file so you do not edit a file that is never used.

Custom post types

For a custom post type archive, the conventional template name is archive-{post_type}.php, where {post_type} is the registered post-type key. A normal post category and a custom taxonomy are different systems; a custom post type may need its own taxonomy archive rather than the built-in category archive.

Block themes

In a block theme, edit the category archive template in the Site Editor and place a Query Loop configured to use the current archive query. This keeps the archive’s URL and query behavior while allowing a visual list or grid design.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Do not use query_posts() for an embedded category list

query_posts() also uses WP_Query, but it directly alters the main loop. Replacing the main query can break pagination, conditional tags, page metadata, and other template behavior. It is therefore a poor choice for adding a category section to an existing page.

Use a new WP_Query or get_posts() for secondary content. If your real requirement is to change the main category archive query itself, modify that main query with the pre_get_posts hook and target it conditionally rather than replacing it inside the template.

Example: adjust the main archive query with pre_get_posts

<?php
function adjust_news_archive_query($query) {
    if (is_admin() || ! $query->is_main_query()) {
        return;
    }

    if ($query->is_category('news')) {
        $query->set('posts_per_page', 20);
        $query->set('orderby', 'date');
        $query->set('order', 'DESC');
    }
}
add_action('pre_get_posts', 'adjust_news_archive_query');
?>

The conditional checks matter: without is_admin() and is_main_query(), the adjustment could affect dashboard queries or unrelated loops.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Pagination, ordering, and performance decisions

Choose a realistic item count

More cards mean more database work, image requests, and page weight. A small embedded panel should usually request only the number of items it displays. A full archive can use a larger page size, but it should still provide pagination rather than loading an unbounded category.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep pagination tied to the right query

A Query Loop’s Pagination block is designed to work with that loop. In custom PHP, pagination requires passing the current page value and generating links for the custom query; a secondary query should not silently hijack the main page’s pagination. If you need independent paginated sections on one page, plan distinct query variables and pagination links so one section does not change the other.

Use published content intentionally

Set post_status to publish for public lists when the surrounding context could otherwise inherit a different status. WordPress normally limits front-end visitors to published posts, but being explicit makes a reusable query safer.

Request only the data the layout needs

For a text-only list, omit thumbnails and avoid loading large image sizes. For a visual grid, use an appropriate registered image size rather than the original upload. Keep the loop markup lean and let the theme provide shared styles.

Troubleshoot an empty or incorrect category list

  • Slug versus name: If category_name returns nothing, check the category’s slug. It is usually lowercase and hyphenated, and it may differ from the visible name.
  • Wrong ID: When using cat, category__in, category__and, or category__not_in, verify each numeric ID.
  • Child-category expectations: Confirm whether your chosen argument includes child categories. Do not assume that an ID list behaves like a parent archive.
  • Post type mismatch: A query for post will not return a custom post type. Set post_type to the registered key when appropriate.
  • Status and visibility: Check that the posts are published and not scheduled, private, or protected.
  • Pagination missing: If only the first items appear, add Pagination in the Query Loop or implement pagination for the custom query.
  • Context not restored: If the page title or later template output suddenly shows a post from the category list, add wp_reset_postdata() after the loop.
  • Empty category: Add a Query Loop No Results section or an equivalent PHP fallback message.
  • Cache or stale markup: Clear the page cache after changing filters, templates, or category assignments, then test while logged out.

Security and maintenance checklist for PHP templates

  • Use WordPress template tags such as the_permalink() and the_title() rather than printing unescaped database values directly.
  • Keep query arguments explicit, especially post_type, post_status, and posts_per_page.
  • Place custom code in a child theme or a site-specific plugin so a theme update does not erase it.
  • Use a meaningful function name for hooks such as pre_get_posts to avoid collisions with other code.
  • Test logged-out behavior, an empty category, a category with more than one page, and a post assigned to multiple categories.
  • After changing a category slug, update any hard-coded category_name values and check links that rely on the old slug.

A practical decision guide

Use Query Loop when

  • You are comfortable editing blocks but do not need custom PHP.
  • You want a list or grid that editors can rearrange.
  • You need built-in controls for filtering, ordering, count, pagination, and no-results content.

Use WP_Query when

  • The list belongs in a PHP template or a custom landing-page component.
  • You need multiple category combinations, exclusions, or custom markup.
  • You can reliably reset post data after the loop.

Use get_posts() when

  • The result is a small, separate list.
  • You do not need archive-style pagination.
  • You want a straightforward array of posts for a compact component.

Use the category archive when

  • The category is the primary subject of the URL.
  • Visitors need to browse the complete category over multiple pages.
  • You want WordPress’s archive routing and template hierarchy to handle the page.

For most editors, start with Query Loop. Move to a secondary WP_Query when the layout or filtering exceeds the block controls, reserve get_posts() for genuinely small lists, and keep the normal category archive for category-first navigation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

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

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.