How to Query Multiple CPTs in One Loop

January 7, 2026
How to Query Multiple CPTs in One Loop

In WordPress, it’s common to need a single loop that pulls posts from multiple Custom Post Types (CPTs).
Examples include unified search results, mixed “Latest Content” sections, or archive-like pages that combine
posts, pages, and custom content.

This article explains how to query multiple CPTs in one loop safely and correctly,
using WP_Query and related techniques—without breaking pagination, ordering, or performance.

The Core Idea: post_type Accepts an Array

At its simplest, querying multiple post types is just passing an array to post_type.

<?php
$args = array(
  'post_type'      => array( 'post', 'page', 'news' ),
  'posts_per_page' => 10,
);

$query = new WP_Query( $args );
?>

This single query returns posts from all specified post types.
WordPress handles the SQL automatically.

Basic Loop Example

<?php if ( $query->have_posts() ) : ?>
  <?php while ( $query->have_posts() ) : $query->the_post(); ?>

    <h2><a href="<?php the_permalink(); ?>">
      <?php the_title(); ?>
    </a></h2>

  <?php endwhile; ?>
  <?php wp_reset_postdata(); ?>
<?php endif; ?>

This works exactly like a normal loop.

Common Use Case: Mix Posts and a CPT

A very common pattern is combining blog posts with a CPT like news or events.

<?php
$args = array(
  'post_type'      => array( 'post', 'event' ),
  'posts_per_page' => 5,
  'orderby'        => 'date',
  'order'          => 'DESC',
);
$query = new WP_Query( $args );
?>

Because ordering is shared, all post types are sorted together by date.

Important: Public and Queryable CPTs Only

A CPT must be:

  • public => true
  • publicly_queryable => true

Otherwise, it will not appear in front-end queries—even if you include it in post_type.

Handling Pagination Correctly

Pagination is where many implementations break.
You must pass the current page number explicitly.

<?php
$paged = max( 1, get_query_var( 'paged' ) );

$args = array(
  'post_type'      => array( 'post', 'news' ),
  'posts_per_page' => 10,
  'paged'          => $paged,
);

$query = new WP_Query( $args );
?>

Then output pagination normally:

<?php
the_posts_pagination( array(
  'mid_size'  => 2,
  'prev_text' => '«',
  'next_text' => '»',
) );
?>

Filtering by Taxonomy Across CPTs

You can filter multiple CPTs by a shared taxonomy.
This is common for category-like taxonomies used across content types.

<?php
$args = array(
  'post_type' => array( 'post', 'product', 'event' ),
  'tax_query' => array(
    array(
      'taxonomy' => 'category',
      'field'    => 'slug',
      'terms'    => array( 'featured' ),
    ),
  ),
);
$query = new WP_Query( $args );
?>

All queried post types must support that taxonomy.

Query Multiple CPTs with Meta Conditions

If all CPTs share a meta key, you can filter them together.

<?php
$args = array(
  'post_type'  => array( 'service', 'product' ),
  'meta_query' => array(
    array(
      'key'     => 'is_featured',
      'value'   => '1',
      'compare' => '=',
    ),
  ),
);
$query = new WP_Query( $args );
?>

Be careful: meta queries can be expensive on large datasets.

Ordering by Post Type (Advanced)

Sometimes you want to group or prioritize one CPT over another.
WordPress does not support this directly, but you can control it with orderby.

Order by Post Type, Then Date

<?php
$args = array(
  'post_type' => array( 'event', 'post' ),
  'orderby'   => array(
    'post_type' => 'ASC',
    'date'      => 'DESC',
  ),
);
$query = new WP_Query( $args );
?>

This sorts alphabetically by post type slug first.

When NOT to Use One Query

Avoid a single combined query if:

  • Each CPT has completely different display logic
  • You need different ordering rules per CPT
  • Each CPT has heavy meta queries

In those cases, multiple queries with controlled merging may be clearer.

WP_Query vs pre_get_posts

Use WP_Query when:

  • You need a custom loop in a template or block
  • The query is localized to one section

Use pre_get_posts when:

  • You want to modify the main query (archives, search)
  • The behavior should apply site-wide

Common Mistakes

  • Forgetting paged (pagination breaks)
  • Querying non-public CPTs
  • Using heavy meta queries unnecessarily
  • Not resetting post data after a custom loop

Summary

  • Use an array in post_type to query multiple CPTs
  • Pagination requires explicit paged handling
  • Shared taxonomies and meta keys can be queried together
  • Order carefully when mixing content types
  • Choose WP_Query or pre_get_posts based on scope

Querying multiple CPTs in one loop is a powerful pattern when done deliberately.
Used correctly, it keeps templates simple and avoids unnecessary query complexity.

Avatar

Written by

satoshi

I’ve been building and customizing WordPress themes for over 10 years. In my free time, you’ll probably find me enjoying a good football match.