Remove taxonomy slugs (categories, post tags and custom taxonomies) from URL

In this post I will show you how to remove «category» from WordPress categories URL, how to remove «tag» from post tags URLs, and how to remove custom taxonomy slugs («product_cat») from term URLs: Here is the main part of thе code, you can insert it into your current theme functions.php, just do not forget […]

January 4, 2016

In this post I will show you how to remove «category» from WordPress categories URL,

How to remove category slug from URLs

how to remove «tag» from post tags URLs,

How to remove tag from post_tags URLs.

and how to remove custom taxonomy slugs («product_cat») from term URLs:

Remove taxonomy slug from term URL.

Here is the main part of thе code, you can insert it into your current theme functions.php, just do not forget to change taxonomy names/slugs in each function to your own values.

add_filter('request', 'rudr_change_term_request', 1, 1 );
 
function rudr_change_term_request($query){
 
	$tax_name = 'product_cat'; // specify you taxonomy name here, it can be also 'category' or 'post_tag'
 
	// Request for child terms differs, we should make an additional check
	if( $query['attachment'] ) :
		$include_children = true;
		$name = $query['attachment'];
	else:
		$include_children = false;
		$name = $query['name'];
	endif;
 
 
	$term = get_term_by('slug', $name, $tax_name); // get the current term to make sure it exists
 
	if (isset($name) && $term && !is_wp_error($term)): // check it here
 
		if( $include_children ) {
			unset($query['attachment']);
			$parent = $term->parent;
			while( $parent ) {
				$parent_term = get_term( $parent, $tax_name);
				$name = $parent_term->slug . '/' . $name;
				$parent = $parent_term->parent;
			}
		} else {
			unset($query['name']);
		}
 
		switch( $tax_name ):
			case 'category':{
				$query['category_name'] = $name; // for categories
				break;
			}
			case 'post_tag':{
				$query['tag'] = $name; // for post tags
				break;
			}
			default:{
				$query[$tax_name] = $name; // for another taxonomies
				break;
			}
		endswitch;
 
	endif;
 
	return $query;
 
}
 
 
add_filter( 'term_link', 'rudr_term_permalink', 10, 3 );
 
function rudr_term_permalink( $url, $term, $taxonomy ){
 
	$taxonomy_name = 'product_cat'; // your taxonomy name here
	$taxonomy_slug = 'product_cat'; // the taxonomy slug can be different with the taxonomy name (like 'post_tag' and 'tag' )
 
	// exit the function if taxonomy slug is not in URL
	if ( strpos($url, $taxonomy_slug) === FALSE || $taxonomy != $taxonomy_name ) return $url;
 
	$url = str_replace('/' . $taxonomy_slug, '', $url);
 
	return $url;
}

And do not forget about 301 redirect from old URLs, it is required for your website SEO.

add_action('template_redirect', 'rudr_old_term_redirect');
 
function rudr_old_term_redirect() {
 
	$taxonomy_name = 'product_cat';
	$taxonomy_slug = 'product_cat';
 
	// exit the redirect function if taxonomy slug is not in URL
	if( strpos( $_SERVER['REQUEST_URI'], $taxonomy_slug ) === FALSE)
		return;
 
	if( ( is_category() && $taxonomy_name=='category' ) || ( is_tag() && $taxonomy_name=='post_tag' ) || is_tax( $taxonomy_name ) ) :
 
        	wp_redirect( site_url( str_replace($taxonomy_slug, '', $_SERVER['REQUEST_URI']) ), 301 );
		exit();
 
	endif;
 
}

The code was tested with different hierarchical and non-hierarchical taxonomies and works great with this permalink settings.

Recomended permalink settings for the code.

Only the best of WordPress

once a week, no spam

Comments 22

  • I used quite some time to get this working on multiple custom taxonomies but here it is: (spot anything horrible in this?)

    function rudr_change_term_request($query_vars){
     
      $tax_names = array('aktiviteettityyppi','tapahtumatyyppi','kohdetyyppi','palvelutyyppi','palveluluokka'); // specify you taxonomy name here, it can be also 'category' or 'post_tag'
     
      if( isset($query_vars['attachment']) ? $query_vars['attachment'] : null) :
     
        $include_children = true;
        $name = $query_vars['attachment'];
     
      else:
     
        if( isset($query_vars['name']) ? $query_vars['name'] : null) {
          $include_children = false;
          $name = $query_vars['name'];
        }
     
      endif;
     
      if (isset($name)):
     
        foreach ($tax_names as $tax_name) {
     
          $term = get_term_by('slug', $name, $tax_name);
     
          if ($term && !is_wp_error($term)):
     
          if( $include_children ) {
     
            unset($query_vars['attachment']);
            $parent = $term->parent;
     
            while( $parent ) {
     
              $parent_term = get_term( $parent, $tax_name);
              $name = $parent_term->slug . '/' . $name;
              $parent = $parent_term->parent;
     
            }
     
          } else {
     
            unset($query_vars['name']);
     
          }
     
          $query_vars[$tax_name] = $name;
     
          endif;
     
        }
     
      endif;
     
      return $query_vars;
     
    }
     
    add_filter('request', __NAMESPACE__ . '\\rudr_change_term_request', 1, 1 );
     
    function rudr_term_permalink( $url, $term, $taxonomy ){
     
      $taxonomy_slugs = array('aktiviteettityyppi','tapahtumatyyppi','kohdetyyppi','palvelutyyppi','palveluluokka');
     
      foreach ($taxonomy_slugs as $taxonomy_slug) {
     
        if ( stripos($url, $taxonomy_slug) === TRUE || $taxonomy == $taxonomy_slug ) {
     
          $url = str_replace('/' . $taxonomy_slug, '', $url);
     
        }
      }
     
      return $url;
    }
     
    add_filter( 'term_link', __NAMESPACE__ . '\\rudr_term_permalink', 10, 3 );
  • I’m sorry I left some uneccesary code in there. I’d fix it if I could edit the comment. (namely, one can remove __NAMESPACE__ from filters and those taxnames are from a project I’m working on. Also, this code is based on the fact that the taxnames and slugs are the same and I removed some features that weren’t needed for my case. So basically my code isn’t a perfect here but it works…

  • Thanks for this – exactly what I was looking for.

  • Hi, very nice snippet, but there are few notice in wp_debug… http://prntscr.com/bvzumz

    Coud you fixed it? Thanks

  • My certain terms does not redirect and shows the attachement page.

  • Rudra what i found is the code does not handle the request to attachment page with the same url as that of any term.

  • Well it is set to /%postname%/

  • Hi! I found it doesn’t work when a taxonomy’s term slug contains within a slug of the taxonomy..

    • Hi, try to change str_replace() function everywhere to str_replace_first().

      And here it is:

      function str_replace_first( $replace_from, $replace_to, $where ) {
       
      	$replace_from = '/'.preg_quote($replace_from, '/').'/';
      	return preg_replace($replace_from, $replace_to, $where, 1);
       
      }

      Please, let me know if it works.

      • Thanks for your reply! URLs is ok now. But redirect cuts all the taxonomy slug name pieces from the URL until they’re all gone. As a result it’s Error 404.

        • Can you please describe me it more in details? On what pages this appears?

          • For example, I have a taxonomy with an argument ‘rewrite’

            'rewrite' => array( 'slug' => 'cars', 'hierarchical' => true )

            This taxonomy contains a term with slug = “volvo_cars”, and this taxonomy term have a child term with slug = “sedan_cars”.

            Without the last part of your code (redirect hook) it works perfectly, and when we wanna get to the “sedan_cars” page it looks like

            http://domain.name/volvo_cars/sedan_cars/

            instead of

            http://domain.name/cars/volvo_cars/sedan_cars/

            . Cool, it has no taxonomy “cars” slug and it contains “cars” in terms’ slugs and URLs .

            But if I turn the redirect hook on I get

            http://domain.name/volvo_/sedan_/

            . It has no “cars” at all, it’s 404 page. Although all links on the site contains correct URLs (withount taxonomy “cars” slug only).

          • Yes, your problem is clear for me now.

            Yes, unfortunately this is how it works, but I know how to help you. First of make unique slug for your taxonomy.

            'rewrite' => array( 'slug' => 'cars183', 'hierarchical' => true )

            Well, that’s all you need to do :) And change this slug everywhere in my code.

          • Nice decision :) I got it. Thanks a lot for your code and for your feedback!

          • You’re welcome! Subscribe to my blog :)

  • I have a Page not found. I removed category from url. It ok if category level 2, but not ok in level 3 …
    EX:
    http://woo.local/uncategorized => ok
    http://woo.local/uncategorized/test-sub-category/ => ok
    http://woo.local/uncategorized/test-sub-category/test-sub-2/ => Page not found.

    I also update permalink

Leave your question or feedback

phpjsHTMLCSSSQLCode
Please, enter a comment
Please, enter a name
Incorrect email