How do I create a custom query for displaying posts from multiple categories in WordPress?

Sarah J Dec 20, 2024 Custom Queries
How can I show blog posts from different categories on my website?
What is the best way to implement a custom WP_Query to retrieve and display posts from multiple categories in WordPress?
Andy answered Dec 20, 2024

Creating Custom Queries for Multiple Categories

Basic Approach

To display posts from multiple categories, you can use WordPress's WP_Query class or modify the main query using pre_get_posts. Here are the most effective methods:

Method 1: Using WP_Query

Basic example to fetch posts from multiple categories:

$args = array(
    'category__in' => array(4, 7, 12), // Add your category IDs
    'posts_per_page' => 6,
    'orderby' => 'date',
    'order' => 'DESC'
);

$category_query = new WP_Query($args);

if ($category_query->have_posts()) :
    while ($category_query->have_posts()) : $category_query->the_post();
        get_template_part('template-parts/content');
    endwhile;
    wp_reset_postdata();
endif;

Method 2: Using Category Slugs

If you prefer using category slugs instead of IDs:

$args = array(
    'category_name' => 'news,events,updates', // Comma-separated category slugs
    'posts_per_page' => 6
);

$category_query = new WP_Query($args);

Advanced Implementation

For more complex filtering with pagination:

function get_multi_category_posts() {
    $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
    
    $args = array(
        'category__in' => array(4, 7, 12),
        'posts_per_page' => 9,
        'paged' => $paged,
        'orderby' => 'date',
        'order' => 'DESC',
        'post_status' => 'publish'
    );
    
    return new WP_Query($args);
}

// Usage
$multi_cat_query = get_multi_category_posts();

Security Best Practices

  1. Always sanitize input data if category IDs come from user input
  2. Use wp_reset_postdata() after your custom query
  3. Check user capabilities when necessary
  4. Validate category IDs before querying

Example with security measures:

function get_safe_category_posts($category_ids) {
    // Sanitize input
    $safe_ids = array_map('absint', (array) $category_ids);
    
    // Verify categories exist
    $safe_ids = array_filter($safe_ids, 'term_exists');
    
    if (empty($safe_ids)) {
        return false;
    }
    
    $args = array(
        'category__in' => $safe_ids,
        'posts_per_page' => 6,
        'no_found_rows' => true, // Performance optimization
        'post_status' => 'publish'
    );
    
    return new WP_Query($args);
}

Common Pitfalls to Avoid

  1. Not resetting post data after the query
  2. Using too many queries on one page
  3. Not implementing proper pagination
  4. Forgetting to check if posts exist

Performance Optimization

For better performance when you don't need pagination:

$args = array(
    'category__in' => array(4, 7),
    'posts_per_page' => 6,
    'no_found_rows' => true,
    'fields' => 'ids', // Only get post IDs if that's all you need
    'cache_results' => true
);

Helpful Plugins

  1. Query Monitor (link) - Debug and optimize your queries
  2. Posts in Page (link) - Embed custom post queries using shortcodes

Alternative Approaches

  1. Using pre_get_posts for modifying main query
  2. Using tax_query for more complex taxonomy relationships
  3. Using category parameters in REST API calls

Template Integration

Example of how to integrate the query into a template:

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

get_header();

$multi_cat_query = get_multi_category_posts();

if ($multi_cat_query->have_posts()) :
    echo '<div class="post-grid">';
    while ($multi_cat_query->have_posts()) : $multi_cat_query->the_post();
        get_template_part('template-parts/content', 'category');
    endwhile;
    echo '</div>';
    
    // Pagination
    echo paginate_links(array(
        'total' => $multi_cat_query->max_num_pages
    ));
    
    wp_reset_postdata();
else :
    get_template_part('template-parts/content', 'none');
endif;

get_footer();

Remember to test your queries thoroughly and monitor their performance impact on your site.