I am currently looking at creating a new type of site archive within WordPress that allows users to filter by category AND by year rather than the default category OR year.

I am hoping to build a sidebar widget that creates the interface but I am looking for ideas and advice on creating the custom permalink setup. Ideally the archive will work with URLs along the lines of:




I have no requirement to filter any deeper than year. I have discovered this snippet of code but it does not work as expected.



What you're looking for is an endpoint. There are already several of these built in: /feed/some-feed/ for feeds or /trackback/ on posts. Those are both endpoints.

Fortunately, WordPress provides a handy function makes adding your own endpionts really easy. add_rewrite_endpoint

This is all the code you need to make your yearly category archives work:

add_action( 'init', 'wpse31422_init' );
function wpse31422_init()
    add_rewrite_endpoint( 'year', EP_CATEGORIES );

As a plugin: https://gist.github.com/1296860

It works exactly like Stephen Harris' answer, and you can reach a yearly, category archive by visiting yoursite.com/category/some-cat-slug/year/2011/.

Adding an endpoint creates a query variable with the same name as the first argument of the add_rewrite_endpoint function. In this case, year. Because this query var already exists in WP (to take care of the data-based archives), we don't really have to do anything special here.

| improve this answer | |
  • I have attempted to implement this solution but unfortunately it does not work. The rewrite rules seems to be more flexible and supports page numbering. – Scott Oct 19 '11 at 16:50
  • Did you flush your rewrite rules after putting the code in place? – chrisguitarguy Oct 19 '11 at 17:03
  • Yup. I flushed them each time I made a change. – Scott Oct 20 '11 at 9:03
  • 2
    Contrary to the comments above, I managed to get this to work using the answer above. +1 – Howdy_McGee Apr 16 '15 at 3:02

This isn't tested, but try (after you added the code you'll need to go to settings> Permalinks and click save for it to take effect):

add_action('generate_rewrite_rules', 'my_rewrite_rules');
function my_rewrite_rules( $wp_rewrite ) {
  $new_rules = array(
     '(.+)/year/(.+)' => '?category_name='.$wp_rewrite->preg_index(1).'&year='.$wp_rewrite->preg_index(2),

  // Add the new rewrite rule into the top of the global rules array
  $wp_rewrite->rules = $new_rules + $wp_rewrite->rules;

That should take: http://yourwebsite.com/foobar/year/2011 and return results in category foobar, in 2011.

I'm not sure that structure is the the best way to go about it. To avoid unwanted issues, I would suggest using: http://yourwebsite.com/category/foobar/year/2011 and use instead:

'category/(.+)/year/(.+)' => '?category_name='.$wp_rewrite->preg_index(1).'&year='.$wp_rewrite->preg_index(2)

Hope this helps!

| improve this answer | |
  • Is there an advantage of altering the rules directly that way? It's generally bad practice to alter properties directly, I would use the add_rewrite_rule() wrapper, and flush_rewrite_rules() may also be required. – soulseekah Oct 18 '11 at 19:15
  • No particular advantage, or disadvantage for that matter. You could use add_rewrite_rules if you wanted to. There are generally several ways to achieve anything in WordPress. I wouldn't describe this as bad practise though. And you can flush or you can 'save permalinks' both do the job - but it's a waste to flush every time WordPress loads... – Stephen Harris Oct 18 '11 at 19:38
  • Thanks for your reply Stephen. I gave it a try and whilst it does not break the site it does not return the expected results. It looks like the category request is being ignored. I will do some more testing and see what I can work out. – Scott Oct 18 '11 at 20:41
  • @Scott - This maybe a silly error on my part. cat takes the id, so try category_name instead (this takes the category slug, rather than name though) – Stephen Harris Oct 18 '11 at 21:02
  • @StephenHarris You are absolutely right. Just spotted that myself. Just about to post updated code. – Scott Oct 18 '11 at 22:01

Following the suggestions of @StephenHarris I have developed the code a little further and come up with the following:

add_action('generate_rewrite_rules', 'my_rewrite_rules');
function my_rewrite_rules( $wp_rewrite ) {

    // handles paged/pagination requests
    $new_rules = array('news/(.+)/year/(.+)/page/?([2-9][0-9]*)' => '?category_name='.$wp_rewrite->preg_index(1).'&year='.$wp_rewrite->preg_index(2).'&paged='.$wp_rewrite->preg_index(3));

    // handles standard requests
    $new_rules1 = array('news/(.+)/year/(.+)' => '?category_name='.$wp_rewrite->preg_index(1).'&year='.$wp_rewrite->preg_index(2));

    // Add the new rewrite rule into the top of the global rules array
    $wp_rewrite->rules = $new_rules + $new_rules1 + $wp_rewrite->rules;

This allows a site to support URLS that look like:


as well as


The posts/blog part of my site is prefixed by "news" so you may wish to tweak the first part of the regular expressions and remove the word "news".

If your going to use it make sure you flush your rewrite rules by visiting the permalinks settings page.

| improve this answer | |

I managed to make it work by using the solution by StephenHarris and Scott with a little modification:

function add_events_by_year_rewrite_rules($wp_rewrite){
    // handles paged/pagination requests
    $new_rules_with_pagination = array('c/(.+)/year/(.+)/page/?([2-9][0-9]*)' => 'index.php?category_name='.$wp_rewrite->preg_index(1).'&year='.$wp_rewrite->preg_index(2).'&paged='.$wp_rewrite->preg_index(3));

    // handles standard requests
    $new_rules_without_pagination = array('c/(.+)/year/(.+)' => 'index.php?category_name='.$wp_rewrite->preg_index(1).'&year='.$wp_rewrite->preg_index(2));

    // Add the new rewrite rule into the top of the global rules array
    $wp_rewrite->rules = $new_rules_with_pagination + $new_rules_without_pagination + $wp_rewrite->rules;

    return $wp_rewrite->rules;

add_filter('generate_rewrite_rules', 'add_events_by_year_rewrite_rules');

Notice the index.php added in the rewrite rules definition.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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