2

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] => 
            [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

  • There have a plugin for future post. I used it on my project. try this plugin once No Future Posts . So your single post details page will work. – Chinmoy Kumar Paul Sep 5 '14 at 13:50
  • Hey, thanks, but that's not helping. They should only appear if you look at the single post and never show up in searches or inside the loop. – Øle Bjarnstroem Sep 5 '14 at 14:00
  • Ok, you can do other way. You can use custom field for event date and when you'll show the event post you'll not display the publish date. You'll use event date custom field. Also you'll write the query based on event date. This way your problem can be solved – Chinmoy Kumar Paul Sep 5 '14 at 14:34
1

You are stepping on a query mine. It is easy to assume that:

  1. You can change query.
  2. Parameters are well defined.
  3. 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.

  1. Implement complex data as custom field data.
  2. Query it accordingly.
  • Hey, I still don't understand. In query 16 the post_name is set to 'my-life'. Which is the post I'm after. When I copy&paste this exact query into my MySQL console I retrieve the post I want. If I print out $wp_query the 'name' parameter is also set. – Øle Bjarnstroem Sep 5 '14 at 13:43
  • @ØleBjarnstroem Then you are probably hitting different edge case from the one I did. :) See, in two separate attempts we had hit at least two different edge cases here. Proving my point. :) – Rarst Sep 5 '14 at 13:46
  • Well but where do I create a new query then? I never arrive at the single.php because it immediately goes to 404... – Øle Bjarnstroem Sep 5 '14 at 14:24
  • @ØleBjarnstroem My point is primarily that you are going to have horrible issues querying non–public post status, no matter how for front display. Been there, done that, got shit from a boss for years after. :) It's just something WP doesn't do well. – Rarst Sep 5 '14 at 14:48
0

It won't let me comment because I'm not cool enough yet.

Have you considered using wordpress's WP_Query to alter the loop instead of creating a function?

$new_query = WP_Query(
    'post-status' => array (
        'future',
        'publish',
        'draft',
    ),
);

if ( $new_query->have_posts() ) :
    while ($new_query->have_posts() ) : the_post(); ?>
        <h1><?php echo the_title(); ?></h1>
    <?php endwhile;
endif;

If you need it to only be on a specific page, you can always create page-[template name].php, and then content-[template-name].php to call it.

Let me know if you're going after something completely different here, but if you're just trying to display a different post-status type on the page, I'd alter the loop.

  • The problem is, that I never arrive at the loop. I immediately hit the 404 page. But I'm also trying to fix a horrribly coded theme which is basically a giant mess of monkey-patching. So single.php consists of only one function call and from there on it means looking through dozens of files and functions... That's why I try to alter the main query. Which is successful. Except that something is just altering it again. – Øle Bjarnstroem Sep 5 '14 at 14:12
  • Try deleting that one function call from the single .php and rebuild the loop like I have it here? Or why not, instead of spending all this time trying to figure this garbage out, simply clone the theme in your own words? It really doesn't take more than 4 or so hours to build a wp theme. – Remy Sheppard Sep 5 '14 at 14:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.