Shiba

Adventures in WordPress

  • Home
  • Dog
  • Art
  • Contact
  • WordPress Articles
    • WP Plugins
    • WP Programming
    • WP Admin Panels
    • WP Theme Design
    • WP How-To
    • WP Theme Images
You are here: Home / WordPress Admin / Custom Taxonomy / Add Custom Taxonomy Tags to Your WordPress Permalinks

Add Custom Taxonomy Tags to Your WordPress Permalinks

by ShibaShake 125 Comments

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.

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.

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

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Comments

1 2 3 … 6 Next »
  1. Paul says

    November 19, 2010 at 12:45 am

    Brilliant! Just what I was looking for. Nice work on all the wordpress customizations, much appreciated.

    Reply
  2. robert felty says

    November 17, 2010 at 3:31 pm

    Thanks for the great article. I was wondering if there is some way to do this for categories too. I am building a site which has the same categories for several different cities. I have created a custom taxonomy called city, and have successfully gotten posts to use the structure:
    %city%/%postname%

    I would also like this for categories, so I could have
    %city%/%category%
    For example,
    domain.com/new-york/food/fine-dining
    would return all posts categorized as ‘fine-dining’ that also have the city term=’new-york’ (and fine-dining is a subcategory of food).

    Thanks in advance for any advice.

    Reply
    • ShibaShake says

      November 19, 2010 at 8:22 am

      Hello Robert,
      I haven’t done this before with categories, but it should definitely be very doable.

      You can probably replace the existing permalink structure of categories with $wp_rewrite->add_permastruct. Something like this –
      $wp_rewrite->add_permastruct(‘category’, $category_structure, false);

      Here is where taxonomy permalink rules get added in the WordPress source –
      http://phpxref.ftwr.co.uk/wordpress/nav.html?wp-includes/taxonomy.php.source.html#l325

      Reply
  3. Dave says

    November 7, 2010 at 10:56 am

    Great article! In fact, you have lots of great articles on WordPress.

    I followed your method and my custom permalinks for several custom post types are working great. they replace %artist% in my URL with an artist name. However, whenever I try to view a page I get a ‘page not found’ error.

    Also, same thing happens for normal posts. I can get posts working if I set my permalink settings to /%artist%/%postname% but if I leave out %artist% I get a ‘post not found’ error.

    Any ideas where the conflict is occurring for pages and posts?

    Cheers

    Reply
    • ShibaShake says

      November 8, 2010 at 1:51 pm

      Hello Dave,
      What you describe sounds like the dreaded permalink conflict issue. I have added a section to the main permalink article that explains this problem –
      http://shibashake.com/wordpress-theme/custom-post-type-permalinks-part-2#conflict

      Reply
      • Dave says

        November 9, 2010 at 5:50 am

        It seems that permalink conflict issue was the culprit.

        I added a unique name to the beginning of each custom post type permalink structure (as advised by your article) and I can now view posts (normal and custom) and pages without any problems.

        Cheers for the help.

        Keep up the good work, your site is the best resource for tricky WordPress issues!

  4. Frederic says

    October 14, 2010 at 4:01 am

    Hi there,
    There is a small typo in the following code:

    `add_filter(‘post_type_link’, ‘rating_permalink’), 10, 3);`

    Should be:

    `add_filter(‘post_type_link’, ‘rating_permalink’, 10, 3);`

    I removed a parenthesis.

    Reply
    • ShibaShake says

      October 14, 2010 at 8:03 am

      I have corrected it. Thanks for letting me know. 😀

      Reply
  5. Mauko Quiroga says

    October 4, 2010 at 10:02 pm

    I’m having an issue here too. I have adapted your code for my two taxonomies: ‘artist’ and ‘writer’. Also, I use a custom post type ‘story’.

    When I define the rules to /%artist%/%writer%/%postname% or /%artist%/%writer%/%story% I get a not found.

    Reply
    • ShibaShake says

      October 5, 2010 at 8:36 am

      In general, I find that it is best to go slowly –
      1. First, make sure the custom post type permalink is working, i.e. don’t include a taxonomy tag yet.
      2. Then only include one taxonomy tag.
      3. Once that works, add another one and so on.

      At this point, it is difficult to tell whether the issue is with the custom post type or with the taxonomy. To debug, you can also hook into the ‘request’ filter and see what the query arguments are.

      Reply
  6. Homem Robô says

    September 19, 2010 at 11:27 am

    Hi there, first, nice work! I learn some cool tricks with your tutorials. But can you help me? I try almost 2 days to get this structure to working:

    For custom post types:
    /%category%/%child_category/%post_type%/%postname%/
    /%category%/%post_type%/%postname%/

    For normal posts:
    /%category%/%child_category/%postname%/
    /%category%/%postname%/

    But no lucky. I’m using the default wordpres “categories” as taxonomies for posts and other post_types. But when I got the permalink right on admin, my template get 404.

    Thanks,

    homem robo

    Reply
    • ShibaShake says

      September 21, 2010 at 7:56 am

      For custom post types you need to use the custom post type tag. For example, if my custom post type = gallery, then I do
      /%category%/gallery/%gallery%/

      If you want to use your own tags, e.g. %child_category% or %post_type% you must first define them. Permalink tags can get created during taxonomy or custom post type creation, or you can create them yourself using add_rewrite_tag.

      Here is an article specific to setting the permalinks for custom post types –
      http://shibashake.com/wordpress-theme/custom-post-type-permalinks-part-2

      Reply
  7. Zak says

    September 9, 2010 at 5:27 pm

    I am designing a website for a newspaper. I used this tutorial to get the article permalinks to be http:…/article/[issue-date]/[section]/[article-headline]. It worked for a while but broke a few days later when I was working on something unrelated. I changed my code back but it still doesn’t work. It changes the permalinks correctly and the links lead to the correct place but I get a 404 page. Any ideas what could be wrong?

    Reply
    • Zak says

      September 9, 2010 at 5:49 pm

      Sorry for posting again but I forgot to add an observation I had made. I found it pretty odd that it could somehow get the correct article information but not find the article. I mean it needed the article in the first place to get the proper taxonomies, right?

      Reply
    • ShibaShake says

      September 10, 2010 at 12:56 pm

      My guess is that there is a conflict with some other permalink structure that you are using. If there is a conflict (i.e. two permalink rules that match the same address string), then only the first rule that matches will fire.

      It could also be that the permalink rules weren’t properly flushed before. Every time you change any permalink structure you want to flush your permalink rules so that you are sure that old permalink structures are fully cleared.

      Reply
      • Zak says

        September 10, 2010 at 6:56 pm

        I flush the permalinks about every 30 sec (sometimes twice after I make changes just to make sure) and I don’t know what other permalink structure could be conflicting. I even restarted my computer multiple times since it happened and manually cleared out whatever caches I could find. It is not just a browser specific problem though.

        I honestly don’t remember anymore what changes I made when I first encountered this problem but the first thing I did when it happened was to revert the changes. Upon researching I saw a lot of people mention the .htaccess file, could there maybe be conflicting rewrite rules there because I can’t think of anywhere else where I have played with rewrite rules.

        I don’t think it is a conflicting name problem as the whole reason I created this long permalink structure was to avoid conflicts and also it happens with all articles…

      • ShibaShake says

        September 10, 2010 at 7:41 pm

        Try linking into the ‘request’ filter and print out the query arguments when you access the 404 page.

        For example –

        add_filter('request', 'my_blog_request');  // parse_request function
        
        function my_blog_request($q) {
        	if (is_admin()) return;
                echo "";
                return $q;
        }
        

        This will help you to identify which rewrite rule got fired and why the page did not get retrieved.

      • Zak says

        September 11, 2010 at 12:57 pm

        Thanks for the suggestion, I had been looking for some way to debug the request. I did it though and only got this output:
        (condensed to one line for space) Not sure where do go from there. Does this mean that it is directly calling a 404 error or that the problem is happening before the call. The site is locally hosted so unfortunately I can’t provide an address to show you but if there is any code or settings that might help I would be happy to provide them. Thanks for the attempt though.

        Oh and would it make any difference what my normal post rewrite rules are set to? I have /%postname%/%post_id% now, which works for normal posts and printed out the right info from the code above in a comment.

      • Zak says

        September 12, 2010 at 4:03 am

        Sorry for the number of comments but I just noticed that in the above comment the output was cut off. Basically I got an array with “[error] => 404” in it.

      • ShibaShake says

        September 14, 2010 at 8:03 am

        Hmmm, that seems to indicate that none of the rewrite rules fired. Is article-headline a custom post type? It could be an issue with the rewrite tag or an issue with the add_permastruct call.

        At this point I would just try the taxonomy tags in your regular posts just to make sure that they work. Then I would test out your custom post type permalinks with the regular WP structure. Then test it out with your own structure but with no taxonomy tags. Once that is all working, slowly add in 1 taxonomy tag at a time.

      • Zak says

        September 14, 2010 at 11:52 am

        Well Article is the custom post type, article headline was what I was calling the title of the article. The odd thing is that it worked for a while so I know that it is possible to do. I will try adding the taxonomies back into regular posts and then seeing if it works with them.

        I feel like although it seems to not be firing the rewrite rules, it also seems like it has to be doing it. It changes the strings everywhere. When I go to edit an article the permalink displayed at the top will have the changes. All the links have the changes.

        I’ll keep looking through and try out your suggestions and post back whenever I have anything. Thanks.

      • Zak says

        September 15, 2010 at 3:38 am

        I just realized that I forgot to include an important (I think at least) detail. I mentioned that I am dealing with the article post type but the rewrite slug of article is set to “article%issue%%section%” with issue and section being replaced. I did it that way so that if for some reason an article does not have an issue or section it replaces it with “” and if it does it replaces it with “/{whatever}.” This worked for a while so I know the method isn’t what is messing up.

  8. Edward B says

    August 13, 2010 at 7:58 am

    You saved me a lot of time! thanks a lot for this !

    Reply
  9. Josh Byers says

    July 26, 2010 at 3:13 pm

    The taxonomy retrieval function is what I don’t understand.

    Does it work the same as when you are retrieving taxonomy values on a single post page?

    e.g.

    $terms = get_the_terms($post->ID, 'speaker-name');
    
    Reply
    • ShibaShake says

      July 26, 2010 at 3:56 pm

      Yeah you can do that. Now you just need to create a string out of the terms so that you may replace it into your permalink string at the %speaker-name% tag location. For example something like this –

      if (is_array($terms) && isset($terms[0]) && is_object($terms[0]))
      	return $terms[0]->slug;
      else return 'none';
      
      Reply
      • Josh Byers says

        July 26, 2010 at 4:13 pm

        Sorry I didn’t reply on the previous comment – feel free to move it if you want to keep the conversation context.

        So this is what I have:

        add_filter('post_type_link', 'podcast_permalink', 10, 3);
         
        function podcast_permalink($permalink, $post_id, $leavename) {
        	if (strpos($permalink, '%speaker-name%') === FALSE) return $permalink;
         
        	// Must operate on current post id
        	$post = get_post($post_id);
                // Enter your own rating function here
        	$terms = get_the_terms($post->ID, 'speaker-name');
        		if (is_array($terms) && isset($terms[0]) && is_object($terms[0]))
        			return $terms[0]->slug;
        		else return 'none';
         
        	if (!$terms) return str_replace('%speaker-name%', 'no-speaker', $permalink);
         
        	$podcast_obj = get_term($terms, 'rating');
        	if ($podcast_obj && !is_wp_error($rating_obj)) 
        		$permalink = str_replace('%speaker-name%', $podcast_obj->slug, $permalink);
        	else 	
        		$permalink = str_replace('%speaker-name%', 'no-speaker', $permalink);
        	return $permalink;
        }
        

        Do I need to specify any parameters in my custom post type as it relates to the rewrite value? With the above code I tried this with the rewrite value:

        'rewrite' => array( 'slug' => '%speaker-name%', 'with_front' => false ),
        

        But the permalink comes back as: wp-admin/none
        When I don’t add any rewrite parameter nothing changes in the permalink.

        Any ideas?

        Thanks for all the help

      • ShibaShake says

        July 26, 2010 at 4:37 pm

        add_filter('post_type_link', 'podcast_permalink', 10, 3);
        
        function podcast_permalink($permalink, $post_id, $leavename) {
        if (strpos($permalink, '%speaker-name%') === FALSE) return $permalink;
        
        // Must operate on current post id
        $post = get_post($post_id);
        // From here onward you just want to get your taxonomy value, convert it into a string, and replace it into your speaker name tag
        
        $terms = get_the_terms($post->ID, 'speaker-name');
        if (is_array($terms) && isset($terms[0]) && is_object($terms[0]))
        $speaker_name = $terms[0]->slug;
        else $speaker_name =  'no-speaker';
        
        $permalink = str_replace('%speaker-name%', $speaker_name, $permalink);
        return $permalink;
        }
        

        Also your podcast rewrite permalink should be something like

        /%speaker-name%/%podcast%
        
      • Josh Byers says

        July 26, 2010 at 10:30 pm

        Wonderful! Works great with a couple exceptions.

        First – when you hover over the view link when looking a list of posts in the admin it doesn’t fill in the taxonomy it defaults to the ‘else’ value.

        Second – the same thing happens when you query the posts for display on the front end and declare that the ‘post_type’ => ‘podcast’. If you don’t specify the post_type in your query the permalink comes up fine.

        I’m assume the admin is also querying the posts and specifying that the type is podcast, so the two issues are most likely related.

        That’s not a big deal for me at this point but its definitely not ideal.

        Anyway, thanks for the help. I really appreciate it.

      • ShibaShake says

        July 26, 2010 at 10:48 pm

        That sounds strange. So in both cases it is showing up as /no-speakers/test-1?

        Two things that come to mind –
        1. Make sure to flush your rewrite rules.
        2. Do some echos in your function and see what terms are being retrieved by wp_get_object_terms.

      • Josh Byers says

        July 27, 2010 at 2:41 pm

        Yep. Whatever value is assigned to ‘else’ shows up in the permalink in those two instances.

        I have flushed my rewrite rules by both visiting the permalinks page and by changing the default permalinks but neither helped.

        When I echoed out the terms it retrieved the correct object and displayed it fine.

        I then did some additional investigating and found another post on the subject: http://xplus3.net/2010/05/20/wp3-custom-post-type-permalinks/

        Comparing your code and his it looks like you have to declare the post_type so when you query it brings back the correct object.

        Doing that solved both issues!

        Thanks for the help and teaching me something new.

  10. Josh Byers says

    July 26, 2010 at 2:42 pm

    Thanks for all the different articles on changing up the permalinks.

    I’m a little fuzzy however trying to figure out how to enter my own function to retrieve a specific taxonomy value.

    I have a custom taxonomy called ‘speaker-name’ with the values of different speakers.

    I have a custom post type called ‘podcast’. I want the permalink to include the name of the speaker which is checked in the ‘speaker-name’ taxonomy.

    Thanks!

    Reply
    • ShibaShake says

      July 26, 2010 at 2:59 pm

      You want to hook into the post_type_link filter then.

      // Goes in the init function
      add_filter('post_type_link', 'podcast_permalink'), 10, 3);
      

      Then just pattern your podcast_permalink function similar to the rating_permalink example I showed above. In line 10 is where you want to put in your own taxonomy retrieval function. Then make sure to replace the %rating% tag with %speaker-name%.

      Reply
1 2 3 … 6 Next »

Recent Posts

  • Screenshot of an example article in code view of a modified Gutenberg editor.How to Harness the Power of WordPress Gutenberg Blocks and Combine It with Legacy Free-Form Text
  • Screenshot of the Success, WordPress has been installed page.Migrating Your WordPress Website to Amazon EC2 (AWS)
  • Screenshot of WinSCP for creating a SFTP configuration.How to Set-Up SFTP on Amazon EC2 (AWS)
  • WordPress Gutenberg code view screenshot of this article.How to Prevent Gutenberg Autop from Messing Up Your Code, Shortcodes, and Scripts
  • Screenshot of the Success, WordPress has been installed page.How to Create a WordPress Website on Amazon EC2 (AWS)

Recent Comments

  • Screenshot of the Success, WordPress has been installed page.How to Create a WordPress Website on Amazon EC2 (AWS) (1)
    • Erik
      - Great article. All worked great except for this step:apt install php-mysqlChanging to this fixed it:apt install ...
  • Add Custom Taxonomy Tags to Your WordPress Permalinks (125)
    • Anthony
      - Where does this code go? Like, what exact .php file please?
  • Screenshot of an example article in code view of a modified Gutenberg editor.How to Harness the Power of WordPress Gutenberg Blocks and Combine It with Legacy Free-Form Text (1)
    • tom
      - hi,my experience was like the same, but for me as theme developer the "lazy blocks"(https://wordpress.org/plugins/lazy-blocks/) ...
  • WordPress Custom Taxonomy Input Panels (106)
    • Phil T
      - This is unnecessarily confusing. Why declare a variable with the same name as your taxonomy? Why did you choose a taxonomy ...
  • Create Pop-up Windows in Your WordPress Blog with Thickbox (57)
    • Jim Camomile
      - I have used this tutorial several times and it is one of the few simple and effective ways to add popups with dynamic content, ...

Copyright © 2024 · Genesis Skins by ShibaShake · Terms of Service · Privacy Policy ·