I have a very strange problem and I am stuck. I want the single page to display posts with the post_status of publish and future. So I added this code to my functions.php in my theme:
function display_future_posts() {
global $wp_query;
if( !is_admin() && $wp_query->is_main_query() && $wp_query->is_single()) {
$wp_query->set( 'post_status', array('future', 'publish', 'draft') );
}
}
add_action('pre_get_posts', 'display_future_posts');
This successfully changes the query. But I still see a 404 page when I’m not logged in as admin. So I traced the db queries. Here is what I found when calling print_r($wpdb->queries); :
[16] => Array
(
[0] => SELECT wp_posts.* FROM wp_posts WHERE 1=1 AND ( ( YEAR( post_date ) = 2014 AND MONTH( post_date ) = 9 ) ) AND wp_posts.post_name="my-life" AND wp_posts.post_type="post" AND (wp_posts.post_status="publish" OR wp_posts.post_status="future") ORDER BY wp_posts.post_date DESC
[1] => 0.000303030014038
[2] => require('wp-blog-header.php'), wp, WP->main, WP->query_posts, WP_Query->query, WP_Query->get_posts
)
[17] => Array
(
[0] => SELECT post_id FROM wp_postmeta, wp_posts WHERE ID = post_id AND post_type="post" AND meta_key = '_wp_old_slug' AND meta_value="my-life" AND YEAR(post_date) = 2014 AND MONTH(post_date) = 9
[1] => 0.000878095626831
[2] => require('wp-blog-header.php'), require_once('wp-includes/template-loader.php'), do_action('template_redirect'), call_user_func_array, wp_old_slug_redirect
)
[18] => Array
(
[0] => SELECT ID FROM wp_posts WHERE post_name LIKE 'my-life%' AND post_type IN ('post', 'page', 'attachment') AND YEAR(post_date) = 2014 AND MONTH(post_date) = 9 AND post_status="publish"
[1] => 0.00031304359436
[2] => require('wp-blog-header.php'), require_once('wp-includes/template-loader.php'), do_action('template_redirect'), call_user_func_array, redirect_canonical, redirect_guess_404_permalink
)
So my query is executed, but then the function wp_old_slug_redirect() in wp-includes/query.php is called and there the function is_404() returns true. So WordPress tries to find an old slug (which of course doesn’t exist), fails and then redirects to 404.
When I call print_r($wp_query); in the header.php of my theme it seems like the query was successfully modified, but strangely doesn’t return any results. At least [posts] is empty. When I run [request] directly on my MySQL server I get exactly the result I’m looking for.
WP_Query Object
(
[query] => Array
(
[page] =>
[year] => 2014
[monthnum] => 09
[name] => my-life
)
[query_vars] => Array
(
[page] => 0
[year] => 2014
[monthnum] => 9
[name] => my-life
[error] =>
[m] =>
[p] => 0
[post_parent] =>
[subpost] =>
[subpost_id] =>
[attachment] =>
[attachment_id] => 0
[static] =>
[pagename] =>
[page_id] => 0
[second] =>
[minute] =>
[hour] =>
[day] => 0
[w] => 0
[category_name] =>
[tag] =>
[cat] =>
[tag_id] =>
=>
[author_name] =>
[feed] =>
[tb] =>
[paged] => 0
[comments_popup] =>
[meta_key] =>
[meta_value] =>
[preview] =>
[s] =>
[sentence] =>
[fields] =>
[menu_order] =>
[category__in] => Array
(
)
[category__not_in] => Array
(
)
[category__and] => Array
(
)
[post__in] => Array
(
)
[post__not_in] => Array
(
)
[tag__in] => Array
(
)
[tag__not_in] => Array
(
)
[tag__and] => Array
(
)
[tag_slug__in] => Array
(
)
[tag_slug__and] => Array
(
)
[post_parent__in] => Array
(
)
[post_parent__not_in] => Array
(
)
[author__in] => Array
(
)
[author__not_in] => Array
(
)
[meta_query] => Array
(
)
[post_status] => Array
(
[0] => future
[1] => publish
)
[ignore_sticky_posts] =>
[suppress_filters] =>
[cache_results] => 1
[update_post_term_cache] => 1
[update_post_meta_cache] => 1
[post_type] =>
[posts_per_page] => 7
[nopaging] =>
[comments_per_page] => 50
[no_found_rows] =>
[order] => DESC
)
[tax_query] =>
[meta_query] => WP_Meta_Query Object
(
[queries] => Array
(
)
[relation] =>
)
[date_query] =>
[request] => SELECT wp_posts.* FROM wp_posts WHERE 1=1 AND ( ( YEAR( post_date ) = 2014 AND MONTH( post_date ) = 9 ) ) AND wp_posts.post_name="my-life" AND wp_posts.post_type="post" AND (wp_posts.post_status="publish" OR wp_posts.post_status="future") ORDER BY wp_posts.post_date DESC
[posts] => Array
(
)
[post_count] => 0
[current_post] => -1
[in_the_loop] =>
[comment_count] => 0
[current_comment] => -1
[found_posts] => 1
[max_num_pages] => 0
[max_num_comment_pages] => 0
[is_single] =>
[is_preview] =>
[is_page] =>
[is_archive] =>
[is_date] =>
[is_year] =>
[is_month] =>
[is_day] =>
[is_time] =>
[is_author] =>
[is_category] =>
[is_tag] =>
[is_tax] =>
[is_search] =>
[is_feed] =>
[is_comment_feed] =>
[is_trackback] =>
[is_home] =>
[is_404] => 1
[is_comments_popup] =>
[is_paged] =>
[is_admin] =>
[is_attachment] =>
[is_singular] =>
[is_robots] =>
[is_posts_page] =>
[is_post_type_archive] =>
[query_vars_hash] => 7ce0208af83c782976286abc2d021484
[query_vars_changed] => 1
[thumbnails_cached] =>
[stopwords:WP_Query:private] =>
)
I’m out of wit. What am I doing wrong? What am I missing.
I hope this question isn’t too specific and it is helpful for someone else out there.
Thanks!
Ole
2 Answers
You are stepping on a query mine. It is easy to assume that:
- You can change query.
- Parameters are well defined.
- So by changing of parameters you can achieve desired results.
In reality there are plenty of query parameters, touching which leads into horrible dead ends. WordPress is engineered to query and show posts which are public. Any attempt to circumvent it comes with serious grief.
In your specific case this is what generated SQL query looks like (for draft post):
SELECT wp_posts.*
FROM wp_posts
WHERE 1=1 AND wp_posts.post_name="draft"
AND wp_posts.post_type="post"
AND ((
wp_posts.post_status="publish"
OR wp_posts.post_status="future"
OR wp_posts.post_status="draft"
))
ORDER BY wp_posts.post_date DESC
Looks perfectly sane, doesn’t it? Well, except that post titled “Draft” doesn’t have post_name
field set to anything.
It’s not “post is always a post” situation. It’s “posts are going to be subtly different and full of edge cases” situation.
Whenever you need more complex concept, such as “future” post, do not trust WP core to do it. It will have a hearty laugh, then ruin next three days of your life.
- Implement complex data as custom field data.
- Query it accordingly.