Pretty URLs for Custom Post Type & Custom Taxonomy with Duplicate Slugs on WPML

I’m interested getting some help for a rather complex setup.

I’m working on a publication and interested in creating a special subsection with a custom taxonomy. Think of this as an editorial subsection with different categories – travel, food, fashion, etc. I want to create a setup like this:

  1. home.com/subsection (archive for all articles)
  2. home.com/subsection/travel (archive for travel sub_category articles)
  3. home.com/subsection/travel/post-name (the post)
  4. BONUS home.com/subsection/travel/hotels/post-name (post in subcategory of heirarchical taxonomy)

BONUS

*numbered for later reference

The Setup So Far…

This is a multi-lingual site on WPML. I’m using a custom post type (subsection) and taxonomy (sub_category) to create the subsection because I want the articles to be searchable on the same blog, yet filterable by a custom taxonomy on archive pages (I don’t want travel from the main site and the subsection to be on the same archive page). A custom taxonomy also keeps the division between the subsection’s taxonomy and the main site clean.

Problems – duplicate slugs and ugly urls

However, this means that I have some new and some duplicate categories between the main site and this subsection. This has meant I’ve had to create new slugs such as travel-sub to make them distinct. So, instead of home.com/subsection/travel, I’d have home.com/subsection/travel-sub.

Using Custom Post Type Permalinks I’ve been able to get 1 and 3 with the modified slug (travel-sub). However, the taxonomy archive is home.com/subsection/sub_category/travel-sub and not home.com/subsection/travel as I wanted to have it.

I understand the basics of why wordpress does this. Slugs must be unique, otherwise home.com/subsection/travel with a duplicate travel category could refer to the travel category of the main site or the subsection. However, the context in the url string makes me think there is a way to make rewrite rules to route the request to wordpress as I’ve outlined. Effectively I’d want to have /subsection/travel parsed to a query for all subsection custom posts of sub_category equal to travel.

Does anyone know a way that I can achieve the URL structure I outlined above?

UPDATE: Hacky Partial Solution

The best solution for getting the urls in 1, 2, and 3 comes from this response: Custom Taxonomy specific to a Custom Post type

However, it doesn’t help avoid running into duplicate slugs between the main site and subsection. Getting clean urls with duplicate slugs has a different solution that involves writing custom rewrite rules for every slug.

As I alluded to in my question, I thought there would be a way to use rewrites to translate between the urls I want and the querystring wordpress needs. While I’m not satisfied, this process works. Code is mostly from http://someweblog.com/wordpress-custom-taxonomy-with-same-slug-as-custom-post-type/

This function (placed in functions.php) iterates though all custom taxonomies associated with custom posts types and generates a rewrite rule (commented // make rules). I modified the code to support duplicate slugs for the custom taxonomy by stripping “-sub” string from the custom taxonomy slug. So, the “travel-sub” slug for “Travel” in my custom taxonomy linked to the subsection becomes “travel” in the url, but remains “travel-sub” in the wordpress querystring. Finally these new rules are merged with the existing rules. Flush the rewrite rules by resaving your permalink structure and you should be good to go.

However, this is not satisfying because functions like get_category_link won’t return the pretty url structure, and without adding a 301 redirect, there will be two urls pointing to the same content. Additionally, it doesn’t achieve the nested custom_post_type/tax_term/post_name structure I wanted from point 3 or the hierarchical structure.

function taxonomy_slug_rewrite($wp_rewrite) {
    $rules = array();
    // get all custom taxonomies
    $taxonomies = get_taxonomies(array('_builtin' => false), 'objects');
    // get all custom post types
    $post_types = get_post_types(array('public' => true, '_builtin' => false), 'objects');

    foreach ($post_types as $post_type) {
        foreach ($taxonomies as $taxonomy) {

            // go through all post types which this taxonomy is assigned to
            foreach ($taxonomy->object_type as $object_type) {

                // check if taxonomy is registered for this custom type
                if ($object_type == $post_type->rewrite['slug']) {

                    // get category objects
                    $terms = get_categories(array('type' => $object_type, 'taxonomy' => $taxonomy->name, 'hide_empty' => 0));

                    // make rules
                    foreach ($terms as $term) {
                        $rules[$object_type . "https://wordpress.stackexchange.com/" . str_replace('-sub', "", $term->slug) . '/?$'] = 'index.php?' . $term->taxonomy . '=' . $term->slug;
                    }
                }
            }
        }
    }
    // merge with global rules
    $wp_rewrite->rules = $rules + $wp_rewrite->rules;
}
add_filter('generate_rewrite_rules', 'taxonomy_slug_rewrite');

0

Leave a Comment