Find posts published in a specific date range using WP_Query

Date-based post retrieval is a common requirement in WordPress development that many developers solve less elegantly than they should. Typical use cases include a “This week’s posts” sidebar widget, an “Articles from last month” archive section, a year-in-review landing page that lists everything published in a calendar year, or an events-style content type where posts represent scheduled activities with a start date stored in post meta. The most direct path to date-filtered posts is WP_Query with the date_query parameter, which was added to core in WordPress 3.7 and provides a clean, readable interface for building date range conditions without writing raw SQL. Before date_query existed, developers wrote custom JOIN or WHERE clauses by filtering posts_where with raw SQL fragments — code that was harder to maintain, easier to break across WordPress versions, and impossible to combine cleanly with other query arguments. The date_query parameter accepts an array of conditions, each specifying a column to compare against (post_date, post_date_gmt, or post_modified), a date range using after and before keys, and an inclusive flag that controls whether the boundary dates themselves are included in the result. Dates can be expressed as strings in any format PHP’s strtotime() understands — natural language like '1 month ago', ISO 8601 format, or a structured array of year, month, and day integers. Multiple date conditions within a single date_query array are combined using a top-level relation key set to either AND or OR, making complex range queries possible without any SQL. The query integrates seamlessly with all other WP_Query parameters: you can filter by post type, status, category, taxonomy term, and author alongside the date condition in a single database query. For cases where you need to query by a custom date stored in post meta rather than the publication date, use meta_query with the meta_value stored as Ymd formatted integers and the BETWEEN compare operator instead. Always call wp_reset_postdata() after any custom WP_Query loop, as described in our post on querying posts by custom taxonomy term. The example below fetches all published posts from the past 30 days, which is the most common date range request in WordPress theme and plugin development.

Problem: You need to retrieve posts published within a specific date range, such as the last 30 days or a particular calendar month.

Solution: Use WP_Query with the date_query parameter in your theme template:

<?php
// Posts published in the last 30 days
$args = array(
    'post_type'      => 'post',
    'post_status'    => 'publish',
    'posts_per_page' => 10,
    'date_query'     => array(
        array(
            'after'     => '30 days ago',
            'before'    => 'today',
            'inclusive' => true,
        ),
    ),
);

// Posts published in a specific calendar month (e.g., March 2021)
$args_month = array(
    'post_type'      => 'post',
    'post_status'    => 'publish',
    'posts_per_page' => -1,
    'date_query'     => array(
        array(
            'year'  => 2021,
            'month' => 3,
        ),
    ),
);

$query = new WP_Query( $args );

if ( $query->have_posts() ) {
    while ( $query->have_posts() ) {
        $query->the_post();
        the_title( '<h2>', '</h2>' );
        echo '<p>' . get_the_date() . '</p>';
    }
    wp_reset_postdata();
}

NOTE: The after and before keys accept any string recognized by PHP’s strtotime(), including ISO 8601 dates like '2021-03-01' and natural language expressions like 'first day of this month'. Setting inclusive to true uses <= and >= comparisons; omitting it defaults to strict < and >. When debugging a date query that returns unexpected results, add 'suppress_filters' => false and temporarily dump the SQL with echo $query->request; to see the exact WHERE clause generated.