Permalink post_type structure with taxonomy slug in it

Let’s look at the simple example of a eshop on WordPress. The shop has custom post type product and category for products product_cat. By default product links looks like /product/product-name/. How to change it to /{product category name}/{product name}/? For example we want to change /product/burton-cartel/ to /snowboard-bindings/burton-cartel/. The following code will let you do […]

#permalinks  /  April 12  /   6

Let’s look at the simple example of a eshop on WordPress.

The shop has custom post type product and category for products product_cat. By default product links looks like /product/product-name/.

How to change it to /{product category name}/{product name}/?

For example we want to change /product/burton-cartel/ to /snowboard-bindings/burton-cartel/.

The following code will let you do that. The code is for your current theme functions.php file and works great with the following permalink settings:

Recomended permalink settings for the code.

Rewrite Post type links and Change default request

add_filter('post_link', 'rudr_post_type_permalink', 20, 3);
add_filter('post_type_link', 'rudr_post_type_permalink', 20, 3);
 
function rudr_post_type_permalink($permalink, $post_id, $leavename) {
 
	$post_type_name = 'product'; // post type name, you can find it in admin area or in register_post_type() function
	$post_type_slug = 'product'; // the part of your product URLs, not always matches with the post type name
	$tax_name = 'product_cat'; // the product categories taxonomy name
 
	$post = get_post( $post_id );
 
	if ( strpos( $permalink, $post_type_slug ) === FALSE || $post->post_type != $post_type_name ) // do not make changes if the post has different type or its URL doesn't contain the given post type slug
		return $permalink;
 
        $terms = wp_get_object_terms( $post->ID, $tax_name ); // get all terms (product categories) of this post (product)
 
 
        if ( !is_wp_error( $terms ) && !empty( $terms ) && is_object( $terms[0] ) ) // rewrite only if this product has categories
        	$permalink = str_replace( $post_type_slug, $terms[0]->slug, $permalink );
 
	return $permalink;
}
 
 
add_filter('request', 'rudr_post_type_request', 1, 1 );
 
function rudr_post_type_request( $query ){
	global $wpdb;
 
	$post_type_name = 'product'; // specify your own here
	$tax_name = 'product_cat'; // and here
 
	$slug = $query['attachment']; // when we change the post type link, WordPress thinks that these are attachment pages
 
	// get the post with the given type and slug from the database
	$post_id = $wpdb->get_var(
		"
		SELECT ID
		FROM $wpdb->posts
		WHERE post_name = '$slug'
		AND post_type = '$post_type_name'
		"
	);
 
	$terms = wp_get_object_terms( $post_id, $tax_name ); // our post should have the terms
 
 
	if( isset( $slug ) && $post_id && !is_wp_error( $terms ) && !empty( $terms ) ) : // change the query
 
		unset( $query['attachment'] );
		$query[$post_type_name] = $slug;
		$query['post_type'] = $post_type_name;
		$query['name'] = $slug;
 
	endif;
 
	return $query;
}

How to perform 301 redirect from the old post URLs

add_action('template_redirect', 'rudr_post_type_redirect');
 
function rudr_post_type_redirect() {
 
	$post_type_name = 'product'; // specify your own here
	$post_type_slug = 'product'; // here
	$tax_name = 'platform'; // and here
 
	if( strpos( $_SERVER['REQUEST_URI'], $post_type_slug ) === FALSE) // do not redirect if the URL doesn't contain the given post type slug
		return;
 
	if( is_singular( $post_type_name ) ) : // if post type page
		global $post, $wp_rewrite;
 
		$terms = wp_get_object_terms( $post->ID, $tax_name ); // get terms attached
 
		if ( !is_wp_error( $terms ) && !empty( $terms ) && is_object( $terms[0] ) ) :
 
			wp_redirect( site_url() . '/' . $wp_rewrite->front . '/' . $terms[0]->slug . '/' . $post->post_name, 301 );
			// wp_redirect( get_permalink( $post->ID ), 301 ); // depends on the previous code from this post
 
			exit();
        	endif;
	endif;
 
}

Only the best of WordPress

Subscribe to this weekly newsletter to receive the latest blog posts by email.I respect your privacy. Your email is safe with me.

Comments 6

  • The code works,
    but it turns out this error:
    Notice: Undefined index: attachment in /home2/qgpalazz/public_html/sviluppo_fincos/wp-content/plugins/cpt-immobili/cpt-immobili.php on line 148

    In the line 148:
    $slug = $query[‘attachment’]; // when we change the post type link, WordPress thinks that these are attachment pages

    How we can resolve the error?
    Thanks,
    Riccardo

    • other request:
      If I call the page with the same name as the URL changes,
      It can ensure that the url remains the same because there is already the beginning of taxonomy url that holds different url?

      Thanks,
      Riccardo

      • Hi Riccardo,

        to prevent “Notice: Undefined index” you may turn off WP_DEBUG in wp-config.php, or in my code add the condition: if( isset( $query['attachment'] ) ).

        I don’t recommend to name the page the same name as the URL slugs.

  • There is a problem when you have 2 post types… For one i need to add category and for another one i need to just remove the base slug.

    • MishaAuthor December 9, 2016 at 08:46

      The task becomes more difficult when you work with 2 and more post types/taxonomies. Actually you can just copy the code for another post type.

      Hmm.. I think I will publish a simple plugin for that later.

  • Hehe. Thank you!

Leave your question or feedback

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