Make Two Views of Post Type Archive At Two URLs

Updated approach

The first thought/suggestion I made actually – like you said – doesn’t work as I understood it. At least I tried it and couldn’t figure it out. That said, what you want is still achievable, but not by using a endpoint or at least not by making use of add_rewrite_endpoint().

However I figured it should be possible via a “ordinary” rewrite setup. Below code shows how to setup a post type, a query variable and a rewrite rule, to make a custom view for the post type archive possible. Last but not least we need to make sure to load the correct template. This it is possible to kind of emulate an endpoint. The exemplary code should get you in the right direction, so you can adapt it to your needs.

Code:

// minimal setup to register the new post type
add_action( 'init', 'wpse130664_pt_rw_ep_cpt');
function wpse130664_pt_rw_ep_cpt() { 
    register_post_type( 'rw_ep_cpt', 
        array(
            'label' => __( 'rw_ep_cpt', 'rw_ep_cpt_textdomain' ),
            'public' => true,
            // the archive slug defaults to the post type name »rw_ep_cpt«
            'has_archive' => true
        )
    );  
} 

// add a new query variable
add_filter('init', 'wpse130664_pt_archive_qv');
function wpse130664_pt_archive_qv() {
    global $wp;
    $wp->add_query_var('aview');
}

// add a new rewrite rule
add_filter('init', 'wpse130664_pt_archive_rw_rule');
function wpse130664_pt_archive_rw_rule() {
    // we're adding »aview« as a possibility to the slug 
    // of the custom post type archive we registered above
    // no need to match anything, e.g. with »$matches[1]«
    // so we're defaulting the aview query variable to 1
    // this kind of emulates a endpoint
    add_rewrite_rule( "rw_ep_cpt/aview$", "index.php?post_type=rw_ep_cpt" . '&aview=1', 'top' );
}

// load the »aview« template
add_filter( 'template_include', 'wpse130664_aview_tmpl_red' );
function wpse130664_aview_tmpl_red( $original_template ) {
    // we're loading the template conditionally, 
    // but only if we're actually at the »aview« "endpoint"
    if ( 1 == intval(get_query_var('aview')) ) {
        // you've to create the template you want to use here
        return get_template_directory().'/archive-aview.php';
    } else {
        return $original_template;
    }
}

Answer to comment

In the mean time, I’m curious why you chose to use the methods on the $wp global rather than the functions get_query_var() and add_query_var()?

To be honest I reused some code I’ve written some time ago, I only adapted it a bit to make it fit to your needs. There I used the above approach, with the $wp global. But that of course is no explanation for the why, so I try to address that too.

If I’m not totally absolutely mistaken add_query_var() is only available as function/method of the WP class. So the above way is just the way to do it.

Regarding get_query_var(), this one you could use instead, but it globalizes $wp_query and uses the get() function/method of the WP_Query class. So in a way the difference isn’t or shouldn’t be a big one.

Besides that, one more thought, the WP_Query object is likely to be bigger than the WP object, if not always. So doing it via global $wp might actually be a good thing.
But actually I didn’t thought and tested this trough, I’ve used it like this and it is working in my setup, so I was satisfied when I did that code. So there might be a drawback in another setup/use case. Or doing it another way might be more valuable/beneficial in other cases. But like I said above, this is to get you started, you have to adapt it to your needs yourself.

Update after comment

A well-timed blog post from @MarkJaquith turned me on to the template_include filter which is better-suited for including a new template file. I’ve updated my code to use that filter and I’d recommend updating the example code too.

As @mrwweb pointed out and above linked article explains it, the template_redirect filter isn’t optimal for choosing a different template. Or as @MarkJaquith simply concludes:

→ template_redirect is for redirects.
→ template_include is for includes.

He convinced me, so I changed the way the »aview« template loads to the template_include filter in above code.


First thought/approach


Disclaimer:
I’m keeping this, because of it’s informational value, but this won’t work for the custom post type archive. However using ep_mask comes in handy for creating endpoints for the single custom post type posts.


From what I understand, endpoints can be done in such cases. I recently read into that, but never actually had to approach doing it. So this is to the best of my knowledge, maybe someone with a lot more of it will come by and clear things up.

You’re right with what you said:

My understanding is that endpoints do not work for post type archives. They’re intended for posts within that post type but not the archive itself.

So making use of the ep_mask parameter like described below can be used for the posts of a custom post type, but not for the archive. Beside that, playing with this made me realize how handy a custom ep_mask can be for the single custom post type endpoint creation.

Basically what I read pinnacled into making use of the ep_mask argument you’ve available when using

and

rewrite argument.

Take a look at the related trac ticket 19275. You can find additional possibly helpful information at the register_post_type() codex page at the permalink_epmask description, especially trac ticket 12605.

As for an overview about endpoints:

Here is an answer on:

for categories there already is EP_CATEGORIES of course, but it shows that it really should be possible, if you make use of the ep_mask argument.

Leave a Comment