How to display a posts 1 year ago with custom WP_Query loop?

Filters allow you to change data as it is being used by the wordpress core. This is a huge part of what gives wordpress so much flexibility.

add_filter() has 2 main parameters, the filter’s hook and the callback function. When the filter is executed, all the callbacks associated with that filter will be executed.

Naturally, the filter needs to pass out some data and then look for a response. This particular filter is on $where, so that is passed in, and then returned after the callback function has modified it.

$where contains a portion of the final query string which is used by WP_Query when the query() method is called. By modifying this, you are able to perform filtering which isn’t directly possible with WP_Query itself (like advanced date filtering).

In your case, what you’re going to want to do is something like this:

function wpse46066_filter_where( $where="" ) {
    // posts  30 to 60 days old
    $where .= " AND post_date >= '" . date('Y-m-d', strtotime('-1 year -2 days')) . "'" .
        " AND post_date <= '" . date('Y-m-d', strtotime('-1 year 2 days')) . "'";
    return $where;
}

add_filter( 'posts_where', 'wpse46066_filter_where' );
$query = new WP_Query( $post_args );
remove_filter( 'posts_where', 'wpse46066_filter_where' );

You’ll notice that you don’t actually change your query args at all, this is because the filter is operating independent of the input WP_Query is receiving from those args. You’ll also notice that the filter is added, then applied (by calling WP_Query), then removed. This prevents all of your queries from having the same time restriction as this one.

A note on strtotime(): If you use multiple values, you must negate each of them. -1 year 2 days (assuming no leap year) is turned into 363 days, not 367. If you want to play with that, you can use this utility, which does a good job of showing you exactly what you’re getting.