Please read the whole question before assuming this question is repeated. After one day of trying plugins and tutorials, I am convinced that there is no straightforward method of achieving what I am trying.

Basically I am building a site that has different components: Blog, News and Gallery, they are all items in the menu. I am trying to have different archive widgets for all of them. So, when I go to News I can see my Archive Widget that just organizes information for News. The same for Blog or Gallery.

What have I tried?

  1. get_archives: there is no category parameter for get_archive

  2. Categories::

    2.1 getarchives_join and getarchives_where filters: They work well when is just one archive. Then you can modify the query one archive. Problem: I need more than one archive

    2.2 adding templates, template_include filter and global variable: this allowed me to have a global variable with the corresponding template name (category-blog.php, category-news.php and category-archive.php). With those names I could change the getarchives_where accordingly. Problem: This almost work until I realized that the widget links for the archive point to something like mysite.com/2012/02 and use a different common template 'archive.php' (see 3 for using custom post type).

    2.3 category in permalink and ($_SERVER['REQUEST_URI']): this is more elegant than grabbing the permalink mysite.com/2012/02 to something like mysite.com/news/2012/02. Then I can use $_SERVER['REQUEST_URI'] in the getarchives_where. Problem: I have no idea how to modify the mysite.com/2012/02. I research, get_month_link and get_year_link. There is no category parameter.

  3. Using custom post type:: Obviously I needed archive-news.php, archive-blog.php and archive-gallery.php and add to my getarchives_where of 2.2. I crashed into Custom Post Type. I created and register the three custom post types: Blog, News and Gallery.

    3.1 The has_archive delusion: The parameter was there and I was convinced I got it. So I went to the news archive (mysite.com/news) and the archive was there. It worked on the right side displaying the news. The problem: The archive widget was still displaying the normal posts.

    3.2 adding the archive templates to the template_include filter and global variable: This is similar to 2.2 but with archive-blog.php and archive-gallery.php. Problem: Exactly the same as 2.2. The widget links for the archive point to something like mysite.com/2012/02 and again using the the default common template 'archive.php' instead of the ones I created.

  4. Plugins: I don't want to use a plugin for this but I did and didn't work.

    4.1. jquery-archive-list-widget: almost work except it works with exclude categories instead of include them. Problem: The link is still mysite/2012/20/. I am about to modify this plugin but I am still

    4.2. I tried a few others with less success.

How do I have different archive widgets according to category/post_type that appears according to the page I am?

1 Answer 1


I finally found an answer using Wordpress rewrites. The whole code is at the end and can be pasted in functions.php. There is just one parameter that you have to change $rules = cpt_generate_date_archives('news', $wp_rewrite); news is the name of the post_type. So I added a second line to show how to have two archives.

The code also includes the function get_cpt_archives( 'news', true ) that prints (second parameter) a list (<li> based) to add as a sidebar.

 * Custom post type date archives

 * Custom post type specific rewrite rules
 * @return wp_rewrite             Rewrite rules handled by Wordpress
function cpt_rewrite_rules($wp_rewrite) {
    $rules = cpt_generate_date_archives('news', $wp_rewrite);
    $rules = cpt_generate_date_archives('gallery', $wp_rewrite);
    $wp_rewrite->rules = $rules + $wp_rewrite->rules;
    return $wp_rewrite;
add_action('generate_rewrite_rules', 'cpt_rewrite_rules');

 * Generate date archive rewrite rules for a given custom post type
 * @param  string $cpt        slug of the custom post type
 * @return rules              returns a set of rewrite rules for Wordpress to handle
function cpt_generate_date_archives($cpt, $wp_rewrite) {
    $rules = array();

    $post_type = get_post_type_object($cpt);
    $slug_archive = $post_type->has_archive;
    if ($slug_archive === false) return $rules;
    if ($slug_archive === true) {
        $slug_archive = $post_type->name;

    $dates = array(
            'rule' => "([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})",
            'vars' => array('year', 'monthnum', 'day')),
            'rule' => "([0-9]{4})/([0-9]{1,2})",
            'vars' => array('year', 'monthnum')),
            'rule' => "([0-9]{4})",
            'vars' => array('year'))

    foreach ($dates as $data) {
        $query = 'index.php?post_type='.$cpt;
        $rule = $slug_archive.'/'.$data['rule'];

        $i = 1;
        foreach ($data['vars'] as $var) {
            $query.= '&'.$var.'='.$wp_rewrite->preg_index($i);

        $rules[$rule."/?$"] = $query;
        $rules[$rule."/feed/(feed|rdf|rss|rss2|atom)/?$"] = $query."&feed=".$wp_rewrite->preg_index($i);
        $rules[$rule."/(feed|rdf|rss|rss2|atom)/?$"] = $query."&feed=".$wp_rewrite->preg_index($i);
        $rules[$rule."/page/([0-9]{1,})/?$"] = $query."&paged=".$wp_rewrite->preg_index($i);
    return $rules;

 * Get a montlhy archive list for a custom post type
 * @param  string  $cpt  Slug of the custom post type
 * @param  boolean $echo Whether to echo the output
 * @return array         Return the output as an array to be parsed on the template level
function get_cpt_archives( $cpt, $echo = false )
    global $wpdb; 
    $sql = $wpdb->prepare("SELECT * FROM $wpdb->posts WHERE post_type = %s AND post_status = 'publish' GROUP BY YEAR(wp_posts.post_date), MONTH(wp_posts.post_date) ORDER BY wp_posts.post_date DESC", $cpt);
    $results = $wpdb->get_results($sql);

    if ( $results )
        $archive = array();
        foreach ($results as $r)
            $year = date('Y', strtotime( $r->post_date ) );
            $month = date('F', strtotime( $r->post_date ) );
            $month_num = date('m', strtotime( $r->post_date ) );
            $link = get_bloginfo('siteurl') . '/' . $cpt . '/' . $year . '/' . $month_num;
            $this_archive = array( 'month' => $month, 'year' => $year, 'link' => $link );
            array_push( $archive, $this_archive );

        if( !$echo )
            return $archive;
        foreach( $archive as $a )
            echo '<li><a href="' . $a['link'] . '">' . $a['month'] . ' ' . $a['year'] . '</a></li>';
    return false;

Your Answer

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

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