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;