Custom CPT-onomy Archive Pages

As of version 1.2, CPT-onomies has implemented a simple, built-in method of setting up custom CPT-onomy archive pages that’s as easy as adding a rewrite rule with a few parameters. I’ve included a few samples that should help you get your feet wet.

Just a few notes before you get started:

  • The ‘cpt_onomy_archive=1′ parameter is required to make all of this work.
  • Keep in mind that the order in which you add your rewrite rules are important because rules with similar structure could overwrite one another. Rewrite URLs with longer structure usually need to be added first.
  • Be sure to flush your rewrite rules each time you edit them. Flush your rewrite rules by visiting Settings -> Permalinks and clicking “Save Changes”.
  • If you really want to keep track of your custom rewrites, and make sure everything is working just right, I highly recommend installing the Rewrite Rules Inspector plugin.

Add this code to your functions.php file:

add_action( 'init', 'my_website_add_rewrite_rule' );
function my_website_add_rewrite_rule() {

    * The following set of rewrite rules states that if the URL matches this rule,
    * i.e., then the page
    * should display all post type 'movies' that are tagged with a specified term
    * from the 'directors' CPT-onomy
   // if you want feeds
   add_rewrite_rule( 'movies/directors/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$', 'index.php?post_type=movies&directors=$matches[1]&feed=$matches[2]&cpt_onomy_archive=1', 'top' );
   add_rewrite_rule( 'movies/directors/([^/]+)/(feed|rdf|rss|rss2|atom)/?$', 'index.php?post_type=movies&directors=$matches[1]&feed=$matches[2]&cpt_onomy_archive=1', 'top' );

   // if you want pagination
   add_rewrite_rule( 'movies/directors/([^/]+)/page/?([0-9]{1,})/?$', 'index.php?post_type=movies&directors=$matches[1]&paged=$matches[2]&cpt_onomy_archive=1', 'top' );

   // base rewrite
   add_rewrite_rule( 'movies/directors/([^/]+)/?$', 'index.php?post_type=movies&directors=$matches[1]&cpt_onomy_archive=1', 'top' );
    * The following set of rewrite rules states that if the URL matches this rule,
    * i.e., then the page
    * should display all post type 'movies' that are tagged with the first term
    * (which should be from the 'directors' CPT-onomy) and the second term
    * (which should be from the 'actors' CPT-onomy).
   // if you want feeds
   add_rewrite_rule( 'movies/([^/]+)/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$', 'index.php?post_type=movies&directors=$matches[1]&actors=$matches[2]&feed=$matches[3]&cpt_onomy_archive=1', 'top' );
   add_rewrite_rule( 'movies/([^/]+)/([^/]+)/(feed|rdf|rss|rss2|atom)/?$', 'index.php?post_type=movies&directors=$matches[1]&actors=$matches[2]&feed=$matches[3]&cpt_onomy_archive=1', 'top' );

   // if you want pagination
   add_rewrite_rule( 'movies/([^/]+)/([^/]+)/page/?([0-9]{1,})/?$', 'index.php?post_type=movies&directors=$matches[1]&actors=$matches[2]&paged=$matches[3]&cpt_onomy_archive=1', 'top' );

   // base rewrite
   add_rewrite_rule( 'movies/([^/]+)/([^/]+)/?$', 'index.php?post_type=movies&directors=$matches[1]&actors=$matches[2]&cpt_onomy_archive=1', 'top' );


How To Add Custom Templates Based On Custom Archive Pages

If you’d like to use a custom template file based on your custom archive page, the ‘template_include’ filter is your friend. Don’t forget that filters must always return a value!

add_filter( 'template_include', 'my_website_template_include' );
function my_website_template_include( $template ) {
   global $post_type;

   // only include our custom template if we're viewing an archive page
   // with 'movies' posts that are tagged by 'directors'.
   // the is_tax() function will also let you narrow it down
   // by a specific director.
   if ( is_archive() && $post_type == 'movies' && is_tax( 'directors' ) ) {

      // locate_template will first verify that the template exists
      // If it exists, it will return the template URI to be used
      if ( $custom_template = locate_template( 'archive-director-movies.php' ) )
         return $custom_template;


   // A filter must always return a value
   // If your template doesn't exist, it will return the
   // original value passed to the filter.
   return $template;

  • Jpl

    if i want to rewrite url for archive, can i use this in my function.php
    How i can add_rewrite_rule only if i want

  • Junior Godoi

    AWESOME!!! Thanks Rachel, this plugins gets even better now =)

    • rachelcarden

      You’re welcome! Glad you like it!

  • Paul

    Where does the ‘cpt_onomy_archive=1′ parameter go – for those of us new to the plugin?

    • rachelcarden

      It goes in the add_rewrite_rule() declaration. See the example code above.

      • Paul

        Ah, I see now that each add_rewrite_rule() has it. Thank you.

  • Toine Kamps

    Hi there, great plugin!

    I’m running a multilingual website using WPML and my CPT-onomy archive page is working fine in the default language using this rewrite rule:

    function publication_team_archive_add_rewrite_rule() {
    add_rewrite_rule( ‘^publications/([^/]*)/?’, ‘index.php?post_type=publication&team=$matches[1]&cpt_onomy_archive=1′, ‘top’ );

    Which results in the following working url:

    But I was wundering how I can adjust the rewrite rule, so that I can also use it with the language slug like so:

    Any ideas how to achieve this?

    • rachelcarden

      You’ll have to add a rewrite rule for each language, something like:

      $languages = array( ‘en’, ‘de’ );
      foreach( $languages as $lang ) {
      add_rewrite_rule( ‘^’ . $lang . ‘/publications/([^/]*)/?’, ‘index.php?lang=’ . $lang . ‘&post_type=publication&team=$matches[1]&cpt_onomy_archive=1′, ‘top’ );

  • Ahmed Kordy

    Hello Rachel,
    While the pagination fix you have made is working perfectly on normal post type archive slug “movies/tax/batman” but it is not working with the custom archive (ex. “list/actors/movies/batman”), Still can’t move to page 2 on custom archive pages :(

    And thank you for your efforts in this great plugin :)

    • rachelcarden

      ApproveRachel Carden

      “All our dreams can come true, if we have the courage to pursue them.” – Walt Disney

      • Ahmed Kordy

        Well … That was inspiring

        • rachelcarden

          hehehe. I’m so sorry Ahmed. I thought I was replying to “Approve” your comment but clearly that didn’t work. :) I’ll see if I can play around with custom archive slugs today to re-create your issue and find the solution. Thanks!

          • Ahmed Kordy

            Now it makes sense! :)

          • rachelcarden

            I updated the page with info on how to add pagination to your rewrites. Hope this helps!

          • Ahmed Kordy

            Works perfectly! Thank you Rachel :)

            Also to add another usability example that may be useful for others, i am using it more dynamic as:

            add_rewrite_rule( ‘^list/([^/]*)/([^/]*)/([^/]*)/feed/(feed|rdf|rss|rss2|atom)/?$’, ‘index.php?post_type=$matches[1]&taxonomy=$matches[2]&term=$matches[3]&feed=$matches[4]&cpt_onomy_archive=1′, ‘top’ );

            add_rewrite_rule( ‘^list/([^/]*)/([^/]*)/([^/]*)/(feed|rdf|rss|rss2|atom)/?$’, ‘index.php?post_type=$matches[1]&taxonomy=$matches[2]&term=$matches[3]&feed=$matches[4]&cpt_onomy_archive=1′, ‘top’ );

            add_rewrite_rule( ‘^list/([^/]*)/([^/]*)/([^/]*)/page/?([0-9]{1,})/?$’, ‘index.php?post_type=$matches[1]&taxonomy=$matches[2]&term=$matches[3]&paged=$matches[4]&cpt_onomy_archive=1′, ‘top’ );

            add_rewrite_rule( ‘^list/([^/]*)/([^/]*)/([^/]*)/?$’, ‘index.php?post_type=$matches[1]&taxonomy=$matches[2]&term=$matches[3]&cpt_onomy_archive=1′, ‘top’ );

          • Ahmed Kordy

            and that gives me an idea, what if the plugin core includes by default rules like those with a key in the first like “cpt”, so we just after the creation of our types, we can start using them without any need to write rules.
            1. Install cpt-onomy plugin
            2. Create types (ex. movies, directors, actors) and register them
            3. To list all directors in a particular movie just go to this archive link: cpt/directors/movies/batman
            or to list all actores in a movie just go to this: cpt/actors/movies/batman

          • rachelcarden

            Well, this kind of work is super custom for each user so it would be pretty difficult for me to include something like this in the plugin but if I think of a way to make stuff like this easier, I’ll definitely work it in!

  • mpmchugh

    Hi Rachel,

    Two questions on archive pages:

    1. Is it possible to have an alternative structure for these? For instance, if I wanted to have a section of a Movies site for directors, with a page listing their movies, their tv shows, etc., is there a way to have the urls for that section be in the form of /directors/director_name/movies

    2. Related to this, is there a way then to have an alternate archive template depending on the url structure used? For instance, in the “directors” section example above, I’d want the template to have sub-navigation focused on the director, whereas for a main /movies page I might want something different.

    Does that make sense?


    • rachelcarden

      Hey Michael! I answered your question in the support forum AND added the bit about the custom template to the page. Thanks for the great question!

      • mpmchugh

        Thanks Rachel. That was helpful. I did post a follow-up question in the support forums on that ticket and another question in another ticket when you have a chance to have a look. -Thanks!