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 says:

    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 says:

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

  • Paul says:

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

  • Toine Kamps says:

    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 says:

      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 says:

    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 says:

      ApproveRachel Carden

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

      • Ahmed Kordy says:

        Well … That was inspiring

        • rachelcarden says:

          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 says:

            Now it makes sense! :)

          • rachelcarden says:

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

          • Ahmed Kordy says:

            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 says:

            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 says:

            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 says:

    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?


  • Jen Mak says:

    Hi Rachel,

    How can I display the title for my custom archive page?
    For example, if my page is I want to be able to show the title of the page as “Steven Spielburg Movies”


    • rachelcarden says:

      Are you using a theme where you can’t just manually type that in the template?

      • Jen Mak says:

        The template (ie archive-director-movies.php) is for all directors– not only Stephen Spielburg so I can’t manually type it in (wordpress authors are dynamically uploading movies to the theme and adding more directors so creating a template for each director would require me to check back and see if new directors have been added often.)

        • rachelcarden says:

          Ah. Gotcha. Try the following logic: if ( is_archive() && ‘movies’ == $post_type && is_tax( ‘directors’ ) && ( $director = $cpt_onomy->get_term_by( ‘slug’, get_query_var( ‘directors’ ), ‘directors’ ) ) ) { echo “{$director->name} Movies”; }

Leave a Reply