How to set a custom post type to have viewable future posts

The question:

I’ve setup a CPT to act the same ways as posts but used to post event details.

Thing is that some of the posts are in the future and such have a future date set on them. Problem is that normal users cannot see these posts.

So:

  • How do I alter archive-events.php to list future posts too? Showing far future posts first and oldest posts last while maintaining pagination.
  • How do I make it so that when a user clicks a future post they don’t get a 404 page not found as the post is not technically published yet?

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

I’ve been able to solve this myself. My entire code for registering the CPT:

<?php
add_action( 'init', 'events_post_type_register' );
function events_post_type_register() {

    $post_type = "events";

    $labels = array(
        'name' => _x('Events', 'post type general name', 'project_X'),
        'singular_name' => _x('Event', 'post type singular name', 'project_X'),
        'add_new' => _x('Add New', 'event', 'project_X'),
        'add_new_item' => __('Add New Event', 'project_X'),
        'edit_item' => __('Edit Event', 'project_X'),
        'new_item' => __('New Event', 'project_X'),
        'all_items' => __('All Events', 'project_X'),
        'view_item' => __('View Event', 'project_X'),
        'search_items' => __('Search Events', 'project_X'),
        'not_found' =>  __('No events found', 'project_X'),
        'not_found_in_trash' => __('No events found in trash', 'project_X'),
        'parent_item_colon' => '',
        'menu_name' => 'Events'
    );

    $args = array(
        'labels' => $labels,
        'public' => true,
        'hierarchical' => false,
        'has_archive' => true,
        'rewrite' => array(
            'with_front' => false,
            'slug' => "news/{$post_type}"
        ),
        'supports' => array( 'title', 'editor', 'thumbnail' )
    );
    register_post_type($post_type, $args);

    remove_action("future_{$post_type}", '_future_post_hook');
    add_action("future_{$post_type}", 'sc_ps_publish_future_events_now', 2, 10);
}

function sc_ps_publish_future_events_now($depreciated, $post) {
    wp_publish_post($post);
}

add_filter('posts_where', 'sc_ps_show_future_events_where', 2, 10);
function sc_ps_show_future_events_where($where, $that) {
    global $wpdb;
    if("events" == $that->query_vars['post_type'] && is_archive())
        $where = str_replace( "{$wpdb->posts}.post_status = 'publish'", "{$wpdb->posts}.post_status = 'publish' OR $wpdb->posts.post_status = 'future'", $where);
    return $where;
}
?>

So to allow posts to be visable to all users even if they are set in the future you need to do the following:

remove_action("future_{$post_type}", '_future_post_hook');
add_action("future_{$post_type}", 'sc_ps_publish_future_events_now', 2, 10);

We remove the action that deals with posting later and apply our own action to force it to be published despite it having a future date with:

wp_publish_post($post);

Then all we now need to do is show future posts on the archive page by filtering posts_where:

function sc_ps_show_future_events_where($where, $that) {
    global $wpdb;
    if("events" == $that->query_vars['post_type'] && is_archive())
        $where = str_replace( "{$wpdb->posts}.post_status = 'publish'", "{$wpdb->posts}.post_status = 'publish' OR $wpdb->posts.post_status = 'future'", $where);
    return $where;
}

Method 2

Brady, I can’t thank you enough for leading me to this solution. My client had already set all of the event dates without a custom field, and I wasn’t about to go back and change everything. Your code initially threw an error when trying to post, but it worked with the following slight modifications (made to match the format used in wp-includes/post.php):

remove_action( 'future_' . $post_type, '_future_post_hook', 5, 2 );
add_action( 'future_' . $post_type, 'my_future_post_hook', 5, 2);

and

function my_future_post_hook( $deprecated = '', $post ) {
    wp_publish_post( $post->ID );
}

I spent awhile trying to figure this out. Hope it helps someone else!

Method 3

Without change the post status you can display future posts single and archive with pre_get_posts too:

add_action( 'pre_get_posts', 'joesz_include_future_posts' );
function joesz_include_future_posts( $query ) {

    if ( $query->is_main_query() && 
           ( $query->query_vars['post_type'] == 'your-post-type' || // for single
         is_post_type_archive( 'your-post-type' ) ) ) {         // for archive

        $query->set( 'post_status', array( 'future', 'publish' ) );

    }

}


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment