Some background:
- I’m trying to replace the default main query for archive templates, and to return a subset of a custom post type (‘days’) where meta values against the key ‘dates’ is between a certain value
- The ‘days’ custom post type has a custom variable field of ‘dates’ which stores individual database rows in the standard wp_postmeta table for each date associated with that post, stored in Epoch format (‘U’)
- I’m fairly confident that the SQL query is functioning correctly; the post IDs it returns appear to be correct in each case for the date range queried.
I’m running the following query in my functions file:
function modify_queries( $query ) {
global $wpdb;
if ( $query->is_post_type_archive('days') && $query->is_main_query() ) {
// Get Days with a date within the archive range
$year = substr($query->query_vars['m'],0,4);
$month = substr($query->query_vars['m'],4,2);
$day = substr($query->query_vars['m'],6,2);
if (is_year()) {
$startDate = date('U', mktime(0, 0, 0, 1, 1, $year));
$endDate = date('U', mktime(0, 0, 0, 12, 31, $year));
}
if (is_month()) {
$startDate = date('U', mktime(0, 0, 0, $month, 1, $year));
$endDate = date('U', mktime(0, 0, 0, $month, cal_days_in_month(CAL_GREGORIAN, $month, $year), $year));
}
if (is_day()) {
$startDate = date('U', mktime(0, 0, 0, $month, $day, $year));
$endDate = date('U', mktime(0, 0, 0, $month, $day, $year));
}
$request = "SELECT ID FROM $wpdb->posts, $wpdb->postmeta";
$request .= " WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id";
$request .= " AND post_status='publish' AND post_type='days'";
$request .= " AND $wpdb->postmeta.meta_key = 'dates' AND $wpdb->postmeta.meta_value >= $startDate AND $wpdb->postmeta.meta_value <= $endDate LIMIT 0 , 30";
$postsList = $wpdb->get_results($request,ARRAY_N);
if ($postsList) {
foreach ($postsList as $thePost) {
$thePostList[] = $thePost[0];
}
$query->set( 'post__in', $thePostList);
$query->set( 'post_type', 'days');
return;
} else {
return false;
}
}
add_action( 'pre_get_posts', 'modify_queries',1 );
My understanding is that this should take the output of the query and simply replace the normal query with one using the IDs returned from the SQL query – however, it’s just returning the 5 most recent ‘days’ posts.
At present, the archive.php file consists purely of the following, so we can rule out any interference:
<?
while ( have_posts() ) : the_post();
global $post;
the_title();
endwhile;
?>
I get the 5 most recently published ‘days’ posts, and it seems to ignore the IDs that the pre_get_posts filter should have passed it.
I have a sneaky suspicion that part of the problem relates to setting ‘post_id’ on the main query, rather than ‘p’, but I don’t seem to get any results at all with the latter.
I’ve hunted around, but can’t find much documentation about pre_get_posts other than how useful and beneficial it is as a replacement to query_posts.
Live debug output at: http://dev.daysoftheyear.com/days/2012/10
You can find the documentation on the
pre_get_post
filter here http://codex.wordpress.org/Plugin_API/Action_Reference/pre_get_postsIt looks to me like the problem is in fact how you are setting the post_ids that you want to retrive. If you refer to the link above, you can see the different values that can be set on the
$query
object that is passed to the filter, andpost_id
isn’t one of them, which is why it “works” when you set it, and “doesn’t work” when you setp
. The latter is for a single post ID, so if you just wanted 100, you would use$query->set('p', 100)
. If you want to return results where the post ID is in an array, you use$query->set('post__in', array(100, 120))
. Your SQL code is just returning the ID, so rather than returning objects, you can just get an array directly – I’m assuming that echoing the title andprint_r
lines are just debugging:You may also not get results if there are existing conflicting parameters set on the
$query
. You can check these values withvar_dump($query->query_vars)
and set any that may be in conflict to an empty string – in your case$query->set( 'm', '' );
Think I’ve nailed it; gave ‘m’ a blank value to stop it thinking it was a date-based query. Thanks! 🙂