WP_Query & The Loop

45-60 minIntermediate

WP_Query is the class WordPress uses to retrieve posts from the database. Understanding The Loop and custom queries is essential for displaying content anywhere on your site. The main query runs automatically on every page; custom queries let you display additional content like related posts, testimonials, or featured products.

Prerequisites

  • Basic PHP understanding (variables, arrays, loops)
  • Access to theme files or functions.php
  • Understanding of WordPress posts/pages concept

Step-by-Step Guide

1

Understand the Main Query vs Custom Queries

1

The Main Query: Runs automatically on every page load based on the URL

2

On a blog page: retrieves latest posts. On a category page: retrieves posts in that category

3

Custom Query: A new WP_Query instance you create to display separate content

4

Use custom queries for: related posts, sidebars, testimonials, featured products

5

DO NOT use custom queries to modify the main content - use pre_get_posts instead

Custom queries run additional database calls, so use them wisely
2

Learn When to Use Custom Queries

1

YES - Display related posts in a sidebar

2

YES - Show 3 recent testimonials on a homepage

3

YES - Display featured products in a widget

4

NO - Filter the main blog archive results (use pre_get_posts filter instead)

5

NO - Change the order of posts on category pages (use pre_get_posts)

6

The rule: If modifying what the page naturally shows, use pre_get_posts. If adding extra content, use WP_Query

3

Build Your First Custom Loop

1

Step 1 - Define Arguments: Specify what posts you want

2

Step 2 - Create Query: Instantiate WP_Query with arguments

3

Step 3 - Check for Posts: Use $the_query->have_posts()

4

Step 4 - Start The Loop: Use while ($the_query->have_posts()) : $the_query->the_post();

5

Step 5 - Display Data: Use template tags like the_title(), the_content()

6

Step 6 - End The Loop: Use endwhile;

7

Step 7 - Reset Post Data: CRITICAL - use wp_reset_postdata();

Example
// 1. Define Arguments
$args = array(
    'post_type' => 'product',  // Query the 'product' CPT
    'posts_per_page' => 4,     // Limit to 4 posts
    'orderby' => 'rand'        // Get random products
);

// 2. Create Query
$the_query = new WP_Query( $args );

// 3. Check for Posts & 4. Start The Loop
if ( $the_query->have_posts() ) :
    echo '<ul>';
    while ( $the_query->have_posts() ) : $the_query->the_post();
        // 5. Display Data
        echo '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>';
    // 6. End The Loop
    endwhile;
    echo '</ul>';
endif;

// 7. Reset Post Data (CRITICAL!)
wp_reset_postdata();
Always call wp_reset_postdata() after custom loops or you will break other queries on the page
4

Master Template Tags vs Global Functions

1

Template Tags echo output directly: the_title(), the_permalink(), the_content()

2

Global Functions return values for custom use: get_the_title(), get_permalink(), get_the_content()

3

Use echo functions when outputting directly in templates

4

Use get_ functions when you need to manipulate the value first

5

Example: the_title() outputs the title; get_the_title() returns it for storage/manipulation

5

Modify Main Query with pre_get_posts

1

Use pre_get_posts action hook to modify the main query before it runs

2

This runs before the database query - no extra database calls

3

Always check: is this the main query? is this the front-end (not admin)?

4

Add this code to your theme functions.php or a custom plugin

Example
// Change posts per page on the blog archive
add_action( 'pre_get_posts', 'modify_main_query' );
function modify_main_query( $query ) {
    // Safety checks: main query and front-end only
    if ( $query->is_main_query() && ! is_admin() ) {
        
        // Change posts per page on blog archive
        if ( $query->is_home() ) {
            $query->set( 'posts_per_page', 12 );
        }
        
        // Exclude a category from blog
        if ( $query->is_home() ) {
            $query->set( 'category__not_in', array( 5 ) );
        }
    }
}
pre_get_posts is the efficient way to modify archive queries

Verification Checklist

  • Understand difference between Main Query and Custom Query
  • Can write a custom WP_Query loop with proper arguments
  • Always call wp_reset_postdata() after custom loops
  • Know when to use WP_Query vs pre_get_posts
  • Can use both template tags (echo) and global functions (return)

Pro Tips

  • Use WP_Query with post__in to display specific posts by ID
  • The meta_query parameter lets you filter by custom fields
  • Use posts_per_page => -1 to get all posts (careful with large datasets)
  • Check the WordPress Codex for all available WP_Query parameters
  • pre_get_posts runs on admin queries too - always check !is_admin()