6

Lets use the classic example of a custom post type called "movies", with its own taxonomy called "genre".

By registering the custom post type (with a "movie" slug), the permalinks are already set up for

<domain>/movie/action/ 

...to see all movies in the action genre.

But, archives by date, like

<domain>/2010/09/

...don't know about the custom post type.

The closest date-based archive I'm able to get working is:

<domain>/2010/?post_type=movies

...which lists all the custom post types posted during the current year (2010). For some reason, the month, taxonomy and a term cannot be added to the URL to get the expected result.

What must be done to enable url's like these...

<domain>/2010/09/movie/action/

...to work as expected, thus to list all action movies posted during September 2010?

3 Answers 3

6

Yes, there isn't currently built-in support for CPT archives, but that doesn't mean you can't extend WP to provide it. I just did this myself the other day...

This won't create the date-based archives you're looking for, but it will give you virtual archive behavior for custom post types. Adding the date should just be a matter of tweaking the rewrite rules (actually, date-based permalinks might just work as-is)...

EXAMPLE: you have a custom type of "movies" and single movie post called "gone with the wind". This code will give you a URL structure of website.com/movies/gone-with-the-wind. Also, going to website.com/movies will list just the movies (just like a category archive, though it will not call the archive.php template for output, but will format the output just like the standard index.php loop template).

function register_post_type_archives( $post_type, $base_path = '' ) {
    global $wp_rewrite;
    if ( !$base_path ) {
        $base_path = $post_type;
    }
    $rules = $wp_rewrite->generate_rewrite_rules($base_path);
    $rules[$base_path.'/?$'] = 'index.php?paged=1';
    foreach ( $rules as $regex=>$redirect ) {
        if ( strpos($redirect, 'attachment=') == FALSE ) {
            $redirect .= '&post_type='.$post_type;
            if (  0 < preg_match_all('@\$([0-9])@', $redirect, $matches) ) {
                for ( $i=0 ; $i < count($matches[0]) ; $i++ ) {
                    $redirect = str_replace($matches[0][$i], '$matches['.$matches[1][$i].']', $redirect);
                }
            }
        }
        add_rewrite_rule($regex, $redirect, 'top');
    }
}

call this function right after having generated your custom post type:

register_post_type('movies', $args);
register_post_type_archives('movies');

Then, if you would like to be able to use custom templates to control the output of these quasi-archive listings, you can use this:

add_action('template_redirect', 'post_type_templates');
function post_type_templates() {
    $post_type = get_query_var('post_type');
    if (!empty($post_type)) {
        locate_template(array("{$post_type}.php","index.php"), true);
        die;
    }
}

Now you can create a "movies.php" template in your theme and customize the loop output to your liking..

UPDATE: having the archive functionality for custom types is great, but I realized I needed a way to access them. You can obviously hard-code buttons somewhere that point to the slugs, but I made a function to generate a wp3.0 navbar with all my custom types in it. Right now it spawns a new navbar and makes it the primary, but you could change it to be the secondary, or to just add the items to an existing navbar. Note: the nav links will only work if you're using the rewrite rules from above.

function register_typenav() {
    $mainnav = wp_get_nav_menu_object('Types Nav');
    if (!$mainnav) {
        $menu_id = wp_create_nav_menu( 'Types Nav' );
        // vav item for each post type
        $types = get_post_types( array( 'exclude_from_search' => false ), 'objects' );
        foreach ($types as $type) {
            if (!$type->_builtin) {
                wp_update_nav_menu_item( $menu_id, 0, array(
                    'menu-item-type' => 'custom',
                    'menu-item-title' => $type->labels->name,
                    'menu-item-url' => get_bloginfo('url') . '/' . $type->rewrite['slug'] . '/',
                    'menu-item-status' => 'publish'
                    )
                );
            }
        }
    if ($mainnav && !has_nav_menu( 'primary-menu' ) ) {
        $theme = get_current_theme();
        $mods = get_option("mods_$theme");
        $key = key($mods['nav_menu_locations']);
        $mods['nav_menu_locations'][$key] = $mainnav->term_id;
        update_option("mods_$theme", $mods);
    }
}
add_action('init', 'register_typenav');
4
  • Thanks for this, I'll try it out and accept your answer / propose changes if I can make it work...
    – Werner
    Sep 22, 2010 at 14:00
  • This is GREAT! One quick question, how would I add custom taxonomy names as sub items on a menu.
    – Brad
    Sep 26, 2010 at 23:23
  • Brad, I guess posting a new question for that is the best way forward, unless somatic edits his post?
    – Werner
    Sep 27, 2010 at 11:25
  • that would require a whole new set of code, and would be best as a separate question... which I'd be happy to answer ;-) Werner- have I answered the original question? I would appreciate you choosing my answer as "accepted".
    – somatic
    Oct 10, 2010 at 23:58
2

Custom Post Types are not designed to provide archive as the common blog post post type does. This might be something that will be changed in the future.

This is the missing link: Custom Post Types (CPT) enhancements that deserve consideration in 3.1.

1

This plugin provides the exactly what you want. It works well with Wordpress 3.3.1.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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