If you read this post, you should know something about WP_Rewrite class. It allows you to change WordPress permalinks rewrite reules, change the structure of them.

In this post I won’t use WP_Rewrite, I just want to show you another way of changing permalinks of a certain object on your blog (any post type or any taxonomy). It is the manual way and consists of 3 simple steps: redirect, change query request, link rewrite.

Step 1. Redirect using «template_redirect»

If you want your pages to be accessible by the old URLs, set redirect 301 from all old URLs to the new ones (it can be implemented via .htaccess as well).

Note: In all examples below I use category as default categories prefix and tag as default post tags prefix.

Insert the following code to your current theme functions.php

function rudr_url_redirects() {
	/* in this array: old URLs=>new URLs  */
	$redirect_rules = array(
		array('old'=>'/category/uncategorized/','new'=>'/category/Uncategorized/'), // category
		array('old'=>'/contacts/','new'=>'/Contacts/'), // page
		array('old'=>'/hello-world/','new'=>'/hello-planet/'), // post
		array('old'=>'/tag/wordpress/','new'=>'/tag/WordPress/') // post tag
	);
	foreach( $redirect_rules as $rule ) :
		// if URL of request matches with the one from the array, then redirect
		if( urldecode($_SERVER['REQUEST_URI']) == $rule['old'] ) :
			wp_redirect( site_url( $rule['new'] ), 301 );
			exit();
		endif;
	endforeach;
}

add_action('template_redirect', 'rudr_url_redirects');

You may notice that I use this code mostly to capitalize URLs.

Step 2. Change request using hook «request»

Great, the redirects are ready. Now we need to make WordPress understand if the URL was rewritten.

function rudr_rewrite_request($query){

	$request_uri = urldecode($_SERVER['REQUEST_URI']);

	/* for categories */
	if( $request_uri == '/category/Uncategorized/' )
		$query['category_name'] = 'uncategorized';
		
	/* for pages */
	if( $request_uri == '/Contacts/' ){
		$query['pagename'] = urlencode('contacts');
		unset($query['name']);
	}
	
	/* for posts */
	if( $request_uri == '/hello-planet/' )
		$query['name'] = 'hello-world';
		
	/* for tags */
	if( $request_uri == '/tag/WordPress/' )
		$query['tag'] = 'wordpress';
		
	return $query;
}

add_filter( 'request', 'rudr_rewrite_request', 9999, 1 );

Step 3. Rewrite the links

If you do not want your browser to show old URL when you hover on a link, use the code below.

For posts and pages

function rudr_post_permalink( $url, $post ){
	if( !is_object( $post ) )
		$post = get_post( $post_id );
		
	$replace = $post->post_name;
		
	/* We should use a post ID to make a replacement. It is required if you use urf-8 characters in your URLs */
		
	if( $post->ID == 1 ) 
		$replace = 'hello-planet';
	if( $post->ID == 12 ) 
		$replace = 'Contacts';
		
	$url = str_replace($post->post_name, $replace, $url );
	return $url;
}

add_filter( 'post_link', 'rudr_post_permalink', 'edit_files', 2 );
add_filter( 'page_link', 'rudr_post_permalink', 'edit_files', 2 );
add_filter( 'post_type_link', 'rudr_post_permalink', 'edit_files', 2 );

If you do not know where to get a post ID, or a term ID, leave your comment and I will describe it for you.

For categories and tags

function rudr_term_permalink( $url, $term, $taxonomy ){
	$replace = $term->slug;
		
	/* by ID as well */
	if( $term->term_id == 5 ) 
		$replace = 'Uncategorized';
	if( $term->term_id == 55 ) 
		$replace = 'WordPress';

	$url = str_replace($term->slug, $replace, $url );
	
	return $url;
}

add_filter( 'term_link', 'rudr_term_permalink', 10, 3 );

Custom Permalinks plugin as an alternative

If you do not want to work with the code in your functions.php, I recommend you Custom Permalinks plugin then.

Example for categories: