Taxonomies in URL

I have a custom post type and two custom taxonomies associated with it. One is locations and the other is activities. How can I form the permalinks in the following format?

http://mysite.com/usa/diving

Therefore the first one would be the location taxonomy and second would be the activity taxonomy?

Solutions Collecting From Web of "Taxonomies in URL"

I recently talked about this at a couple of WordCamps. Here’s my talk from WC Portland, and the slides, source code, etc. Check out Recipe #2 specifically.

First off, you should probably have a static prefix to start the URLs. It’s not 100% necessary, but without it your rewrite will conflict with page permalinks. If you decide to use the static prefix, you might want to make it about the post type, since that’s what your taxonomies organize. I don’t know what that is, so I’m making a guess that it’s about “guides.” In that case, your URIs would be something like /guides/usa/diving/.

Here’s some code to get you started. If anything doesn’t make sense to you, you should watch the presentation and follow along with the slides.

<?php

/**
 * Setup custom permalinks with multiple taxonomies
 */

if ( !class_exists( 'WPSE_110508' ) ) :

class WPSE_110508 {

    private static $instance;

    public static function instance() {
        if ( ! isset( self::$instance ) ) {
            self::$instance = new WPSE_110508;
            self::$instance->setup();
        }
        return self::$instance;
    }

    public function setup() {
        add_action( 'init', array( $this, 'structures' ) );
        add_filter( 'post_type_link', array( $this, 'post_type_link' ), 10, 2 );
        add_filter( 'term_link', array( $this, 'term_link' ), 10, 3 );
    }

    /**
     * Register our data structures
     *
     * @return void
     */
    function structures() {
        register_taxonomy( 'location', 'guide', array(
            'label' => 'Body Types',
            'rewrite' => array( 'slug' => 'guides' )
        ) );

        add_permastruct( "all_activities", "guides/all/%activity%" );
        register_taxonomy( 'activity', 'guide', array(
            'label' => 'Activities',
            'rewrite' => array( 'slug' => 'guides/%location%' )
        ) );

        register_post_type( 'guide', array(
            'public' => true,
            'label' => 'Guides',
            'rewrite' => array( 'slug' => 'guides/%location%/%activity%' )
        ) );
    }


    /**
     * Filter post type links for guides to replace %location% & %activity% if present
     *
     * @param string $link
     * @param object $post
     * @return string
     */
    function post_type_link( $link, $post ) {
        if ( 'guide' == $post->post_type ) {
            if ( $locations = get_the_terms( $post->ID, 'location' ) ) {
                $link = str_replace( '%location%', array_pop( $locations )->slug, $link );
            }
            if ( $activities = get_the_terms( $post->ID, 'activity' ) ) {
                $link = str_replace( '%activity%', array_pop( $activities )->slug, $link );
            }
        }
        return $link;
    }


    /**
     * Filter term links for activities to replace %location% with "all"
     *
     * @param string $termlink
     * @param object $term
     * @param string $taxonomy
     * @return string
     */
    function term_link( $termlink, $term, $taxonomy ) {
        if ( 'activity' == $taxonomy ) {
            return str_replace( '%location%', 'all', $termlink );
        }
        return $termlink;
    }

}

function WPSE_110508() {
    return WPSE_110508::instance();
}
add_action( 'after_setup_theme', 'WPSE_110508' );

endif;

It seems you’re using two non-hierarchical custom taxonomies. Try using a single hierarchical custom taxonomy (imagine how categories work). That way your URLs would be able to look like “usa/diving”.

When you register your custom taxonomy via your theme’s functions.php, do something like this:

'hierarchical' => true,

The .php function is this <?php get_term_link( $term, $taxonomy ); ?> and here you have an example of how you can use this into your code:
$terms = get_terms(‘species’);

echo '<ul>';
foreach ($terms as $term) {
    //Always check if it's an error before continuing. get_term_link() can be finicky sometimes
    $term_link = get_term_link( $term, 'species' );
    if( is_wp_error( $term_link ) )
        continue;
    //We successfully got a link. Print it out.
    echo '<li><a href="' . $term_link . '">' . $term->name . '</a></li>';
}
echo '</ul>';

It seems as though you actually have multiple options here.

  • Custom permalinks for custom post types
  • GD Custom Post and Taxonomies Tool
  • WordPress Forum
  • Smashing Magazine – Custom Taxonomies

Good luck!