The WordPress custom taxonomy system allows you to create your own grouping of WordPress objects (e.g. posts, pages, and custom post types). Tags and categories, for example, are taxonomy objects that are native to the WordPress system. With the custom taxonomy framework, you can create your own tags and categories.
In the article Custom Post Type Permalinks (Part 2), Lane and Andrew asked the very good question of how we can add custom taxonomy tags to WordPress permalinks.
For example, if we have a custom taxonomy called rating we might want to set our WordPress permalink structure to -
/%rating%/%postname%
Here we consider how to insert custom taxonomy tags into the WordPress permalink structure.
1. Create a Custom Taxonomy
First, we create a custom taxonomy object called rating with the register_taxonomy WordPress function.
1 2 3 4 5 6 7 8 9 10 11 | add_action('init', 'my_rating_init'); function my_rating_init() { if (!is_taxonomy('rating')) { register_taxonomy( 'rating', 'post', array( 'hierarchical' => FALSE, 'label' => __('Rating'), 'public' => TRUE, 'show_ui' => TRUE, 'query_var' => 'rating', 'rewrite' => true ) ); } } |
Setting the rewrite argument to true (Line 10) will automatically add the tag %rating% to our WordPress system.
However, if we try to set our blog permalink structure to -
/%rating%/%postname%
Our new post permalinks will look like this
http://shibashake.com/wordpress-theme/%rating%/test-1
As a result we will get a 404 file not found error. This is because our %rating% tag was not properly translated.
2. Translate Our Custom Taxonomy Tag
To translate our new %rating% tag, we must hook into the permalink generation function – get_permalink.
The post_link hook allows us to translate tags for regular post objects and the post_type_link hook allows us to translate tags for custom post type objects.
Note that both filter hooks accept exactly the same arguments, so we can tie both hooks to the same function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | add_filter('post_link', 'rating_permalink', 10, 3); add_filter('post_type_link', 'rating_permalink', 10, 3); function rating_permalink($permalink, $post_id, $leavename) { if (strpos($permalink, '%rating%') === FALSE) return $permalink; // Get post $post = get_post($post_id); if (!$post) return $permalink; // Get taxonomy terms $terms = wp_get_object_terms($post->ID, 'rating'); if (!is_wp_error($terms) && !empty($terms) && is_object($terms[0])) $taxonomy_slug = $terms[0]->slug; else $taxonomy_slug = 'not-rated'; return str_replace('%rating%', $taxonomy_slug, $permalink); } |
Line 5 – If the permalink does not contain the %rating% tag, then we don’t need to translate anything.
Line 12 – Get the rating terms related to the current post object.
Line 13 – Retrieve the slug value of the first rating custom taxonomy object linked to the current post.
Line 14 – If no rating terms are retrieved, then replace our rating tag with the value not-rated.
Line 16 – Replace the %rating% tag with our custom taxonomy slug.
Our new post permalinks will look like this -
http://shibashake.com/wordpress-theme/rated-a/test-1
I’ve tried it, it works perfectly, except for one thing: if the taxonomy is hierarchical, it only puts the first level in the URL. Can you tell me how to change the PHP so that it works on hierarchical taxonomies by having the path /parent/child/child/postname?
Thx!
You may need to traverse the parent relationship manually by using a loop.
First… thanks for your informative article.
I tried your suggestion but i get always an 404.
http://example.com/my-custom-post-type/taxo/child-of-taxo/post-title -> 404
If i delete the slug ‘child-of-taxo’ manually from the adressbar everything works fine.
http://example.com/my-custom-post-type/taxo/post-title -> 404
This the code i’m using:
add_filter('post_link', 'taxo_permalink', 10, 3);
add_filter('post_type_link', 'taxo_permalink', 10, 3);
function taxo_permalink($permalink, $post_id, $leavename) {
if (strpos($permalink, '%taxo%') === FALSE) return $permalink;
// Get post
$post = get_post($post_id);
if (!$post) return $permalink;
// Get taxonomy terms
$terms = wp_get_object_terms($post->ID, 'taxonomie');
if (!is_wp_error($terms) && !empty($terms) && is_object($terms[0])) {
$slug1 = $terms[0]->slug;
$slug2 = $terms[1]->slug;
$taxonomy_slug = $slug1 . '/' . $slug2;
} else {
$taxonomy_slug = 'other';
}
return str_replace('%taxo%', $taxonomy_slug, $permalink);
}
I’m sure you are a busy man but i would appreciate a suggestion how to fix this problem. Do you have an idea?
I would try doing it with two separate tags – %taxo% and %childtaxo%
As before, Shibashake, I very much appreciate all your help and patience!
1) While that didn’t result in an error, the links did not function properly. Posts within a Taxonomy, and their URLs, worked perfectly. Posts within a Category worked perfectly, but their URLs removed the category entirely, leaving two slashes in the title (e.g.; site.com//postname/
2) I’ll have to dig further into this fix — or hire someone smarter than myself to help
[I feel bad for hijacking your thread with my many comments, but if interested / available / affordable, I'd be honored if you took a stab! I sent you an email through your site with the same]
Hello Rob,
Sorry for the late reply. Have been busy with dog matters lately.
I am currently not working on external projects, but will be happy to answer whatever questions that I can. Good luck with your site.
no worries, shibashake – hope the dogs are well!! regarding my permalinks, i can’t thank you enough for getting me this far!! unfortunately, heading through the next steps is just a bit (a lot!) beyond my brain. i can’t quite get the “no taxonomy, then category” part working, and hooking into the request filter is an entirely foreign concept to me. if you had anything easy to further suggest, i’m happy to give it a try! but i don’t want to completely hijack your post with my dumbness
Hi Rob,
Your site looks very awesome!
If you send me the file you use to modify your permalinks, I can probably play around with it some to get the category thing working. I will send you an e-mail.
i recently created a “cartoons” taxonomy, with all different cartoon names as part of the group: pokemon, smurfs, thundercats, etc. most of my posts have a “cartoon” that they are associated with. however, there are some posts that are not part of a cartoon taxonomy.
without knowing the proper nerd speak (i’m only an unproper nerd), i’d love the permalink logic to act something like this:
if this post has a taxonmy, make the url:
/%cartoons%/%postname%/
else this post does NOT have a taxonomy, make the url:
/%category%/%postname%/
is that feasible using your code, above…? and if so, what would i enter in SETTINGS > PERMALINK ?
Hmmm, you could try using /%cartoons%/%postname%/ as your main permalink and then in the rating_permalink/cartooon_permalink function, insert in the post category instead of ‘not-rated’.
hi shibashake – first off, you’re the best
with that out of the way, i implemented as you detailed above, and it worked VERY well, but not perfectly. all of the posts within a cartoon taxonomy moved to their new URL without issue, which was awesome.
however, i hit two issues with the rest:
1) how do i change “else $taxonomy_slug = ‘no-rating’;” to force it to pull up the respective category slug? (as a quick fix, i’ve changed it to just the general term “cartoon”, which isn’t so bad!)
2) i’ve run into the 404 issue with pages. reading through the comments, i saw that you link people to: http://shibashake.com/wordpress-theme/custom-post-type-permalinks-part-2#conflict however, im hoping to avoid adding the extra portion of the slug (that’s the whole purpose of this change, for me, anyway). one page i have, for example, is “toonbarn.com/games” which results in the 404. even if i change the slug of that page to “toonbarn.com/gamessuperface” – which i did!
– i still get the 404 upon entry. is that still part of the same issue…?
[also, thanks for making me a hot girl!
]
LOL! You are welcome.
Hello Rob -
1. Try using get_the_category
http://codex.wordpress.org/Function_Reference/get_the_category
2. The 404 error occurs because 2 different objects share the same regular expression structure. Changing the actual name of the page or even changing the permalink tag names %my_taxonomy% will not solve the issue because the regular expression structure is still similar.
You can quickly identify if it is a regular expression structure issue by adding in the slug and seeing if that solves the problem. Alternatively, you can hook into the ‘request’ filter and see what arguments are being passed into the query. There is an example of the request filter here -
http://shibashake.com/wordpress-theme/mastering-the-wordpress-loop
thanks again for the help, shibashake
1) unfortunately, i couldn’t get this to work. i’m likely just not smart enough to get the proper php phrasing when replacing the “else $taxonomy_slug” with something like “get_the_category”. The closest I could get was the URL coming up with the term “Array” as that portion of the slug. In the meantime, seems like it’s just easiest for me to keep the “fake taxonomy” of just the simple “cartoon”
2) as you said, I tried adding another term to the front of the permalink structure, and it had everything working again! the pages AND the posts with the new custom URL. Now that it is identified as an expression structure issue… does that mean its possible to bypass? I really only have three or four pages, so I’d love to be able to get to everything without the extra slug piece (though it wouldn’t be the end of the world if it had to be)
Hello Rob,
1. Try something like -
instead of else $taxonomy_slug = ‘not-rated’;
2. You could solve the 404 issue by making the regular expression structure unique. For example we could add unique characters into the taxonomy name. Another possibility is to hook into the request filter and resolve it manually there. Both are fairly complex though.