Problem (Example): I have one custom taxonomy called "portfolios". It is tied to a custom post type called "portfolio". I create a portfolios term called Animals and another called Pets. Then I create a portfolio post called Beagle that belongs to both portfolios terms. In their respective term archives, Beagle is displayed as expected.

Question: The permalink for the Beagle post is always http://example.com/portfolios/animals/beagle, irrespective of the taconomy term archive (animals or pets) in which it is being displayed. How can I make the permalink reflect the term of the current archive page?

In other words, I need http://example.com/portfolios/animals/beagle to be the permalink on the "animals" archive and http://example.com/portfolios/pets/beagle to be the permalink on the pets archive - and they both send you to the same post "Beagles".

Note: This also affects how the Prev/Next links within the post will function (more on that later).

Here is the code I have so far:

add_action( 'init', 'portfolio_post' );
function portfolio_post()
    $labels = array(
        'name'          => _x('Portfolio Items', 'post type general name'),
        /* The rest of the labels, right out of the codex */
    $args = array(
        'labels'              => $labels,
        'public'              => true,
        'exclude_from_search' => false,
        'publicly_queryable'  => true,
        'show_ui'             => true, 
        'show_in_nav_menus'   => true,
        'show_in_menu'        => true, 
        'show_in_admin_bar'   => true,
        'menu_position'       => 5,
        'menu_icon'           => get_stylesheet_directory_uri() . '/images/portfolio-icon16.png',
        'capability_type'     => 'post',
        'hierarchical'        => false,
        'supports'            => array('title','editor','page-attributes','thumbnail','revisions'),
        'taxonomies'          => array('portfolios'),
        'has_archive'         => 'portfolios', 
        'rewrite'             => array('slug' => 'portfolios/%portfolios%'),
        'query_var'           => true

/* Register the "Portfolios" Taxonomy */
add_action( 'init', 'portfolios_taxonomy', 0 );
function portfolios_taxonomy() {
    $labels = array(
        'name'                => _x('Portfolios', 'taxonomy general name'),
        /* The rest of the labels, right out of the codex */
    $args = array(
        'labels'              => $labels,
        'public'              => true,
        'show_ui'             => true,
        'show_in_nav_menus'   => true,
        'show_admin_column'   => true,
        'hierarchical'        => true,
        'query_var'           => true,
        'rewrite'             => array('slug' => 'portfolios'),
    register_taxonomy('portfolios', array('portfolio'), $args);

add_filter('post_type_link', 'portfolio_permalink_filter_function', 1, 3);
function portfolio_permalink_filter_function( $post_link, $id = 0, $leavename = FALSE ) {
    if ( strpos('%portfolios%', $post_link) === 'FALSE' ) {
        return $post_link;

    $post = get_post($id);
    if ( !is_object($post) || $post->post_type != 'portfolio' ) {
        return $post_link;

    $terms = wp_get_object_terms($post->ID, 'portfolios');
    if ( !$terms ) {
        return str_replace('portfolios/%portfolios%/', '', $post_link);
    return str_replace('%portfolios%', $terms[0]->slug, $post_link);

The following URLs do what they are supposed to do:
http://example.com/portfolios <-- portfolio archive (archive-portfolio.php)
http://example.com/portfolios/animals/ <-- term archive (taxonomy-portfolios.php)
http://example.com/portfolios/pets/ <-- term archive (taxonomy-portfolios.php)
http://example.com/portfolios/animals/beagle <-- post (single-portfolio.php)

However, making http://example.com/portfolios/animals/beagle = http://example.com/portfolios/pets/beagle continues to elude me.

Post Prev/Next Links
If you are navigating through posts in the "Pets" archive using the prev/next links at the bottom of the posts, when you get to the "Beagle" post, the prev/next links now display the previous and next links to posts in the "Animals" archive (because of the way I generate the prev/next links and because the Beagle permailnk term is "animals"). Here is the code for the prev/next links:

    /* Previous/Next Links within primary parent portfolios taxonomy term */
$post_ids = get_posts(array(
    'numberposts'   => -1, // get all posts.
    'post_type'     => 'portfolio',
    'fields'        => 'ids', // Only get post IDs
    'tax_query'     => array(array('taxonomy' => 'portfolios', 'field' => 'name', 'terms' => $portfolio_terms[0])),
    'orderby'       => 'title',
    'order'         => 'ASC'
$thisindex = array_search($post->ID, $post_ids);
$previd = $post_ids[$thisindex-1];
$nextid = $post_ids[$thisindex+1];
echo '<div class="post-prev-next"><!-- .post-prev-next -->';
if ( !empty($previd) ) {
   echo '<div class="post-prev"><a rel="prev" href="' . get_permalink($previd) . '" title="'. get_the_title($previd) .'">&laquo; '. get_the_title($previd) .'</a></div>';
if ( !empty($nextid) ) {
   echo '<div class="post-next"><a rel="next" href="' . get_permalink($nextid) . '" title="'. get_the_title($nextid) .'">'. get_the_title($nextid) .' &raquo;</a></div>';
    echo '</div><!-- end .post-prev-next -->';

The logic above will likely have to change once the first problem is solved, but I'm not sure what it should change to.

It looks like @TheDeadMedic hinted at a solution on this answer, but since the questioner was not going in that direction, it was never elaborated upon.

If you're assigning multiple categories to a single product, I can easily change how it determines which one to use in the permalink.

Thanks to reading tons of stackexchange Q/A's and some tutorial blogs over the past few days, I was able piece together what I have so far, but I've hit a wall with this problem. I appreciate any help the community can provide.

  • Take a look at: falise.com/blog/wordpress-code/… for handling the multiple category permalinks. And you should be able to manage the next/previous post links with: ambrosite.com/plugins/… Jul 2, 2013 at 14:22
  • I tried the code on that page but it didn't seem to do anything. He mentions a plugin and maybe you need that for his code to work. However, I am looking for a solution that does not rely on plugins - it needs to be built into the theme.
    – Joe
    Jul 7, 2013 at 22:18


Your Answer

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