URL Rewriting for Custom Post Types Date Archive

Date based archives by default, work only with the default post types, today I am going to show you how to implement date based archives on custom post types.

Year archive: http://www.test.com/2014/
Month archive: http://www.test.com/2014/11/
Day archive: http://www.test.com/2014/30/14/
Month archive, feed: http://www.test.com/2014/10/feed/
Year archive, page 2: http://www.test.com/2014/page/3/

What we would like to achieve are link structures similar to bellow:

Year archive: http://www.test.com/blog/2014/
Month archive: http://www.test.com/blog/2014/11/
Day archive, feed: http://www.test.com/blog/2014/30/14/feed/
Year archive, page 5: http://www.test.com/blog/2014/page/3/

The idea behind the code bellow is: we are simply rewriting URL’s to read as

1
http://www.test.com/blog/2014/

instead of

1
http://www.test.com/2014/?post-type=blog

Copy this block of code into your functions.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
add_action('generate_rewrite_rules', array('NGP_Posts', 'cvf_ngp_blog_datearchives_rewrite_rules') );

class NGP_Posts {

    public static function cvf_ngp_blog_datearchives_rewrite_rules($wp_rewrite) {

        $rules = self::cvf_ngp_generate_blog_date_archives('blog', $wp_rewrite);
        $wp_rewrite->rules = $rules + $wp_rewrite->rules;
        return $wp_rewrite;
       
    }

    public static function cvf_ngp_generate_blog_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(
            array(
                'rule' => "([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})",
                'vars' => array('year', 'monthnum', 'day')),
            array(
                'rule' => "([0-9]{4})/([0-9]{1,2})",
                'vars' => array('year', 'monthnum')),
            array(
                '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);
                $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;
       
    }
}

Don’t forget to refresh your permalinks by setting it to default then back to Post Name.