Thanks so much for this in depth post. Really saved me on a bad permalink custom post type I had set up. I updated the permalink structure and they all broke. They are fixed now!
There was a question about showing cats and sub-cats in the url, like you can with regular wordpress categories. Of note here is when you register the taxonomy, there is a setting in the rewrite rules to do this.
Under rewrite, the argument pair ‘hierarchical’ => true, turns on allowing /topic/sub-topic/super-sub-topic/, based on your structure, in the example called topic.
Very basic error, not sure if I’m being silly. I’ve put the ‘// Add filter to plugin init function’ at the top of functions and then am using a custom post type called features, followed all your steps above.
Thanks for the info! It worked great to change the permalinks on my custom post type, but I am getting a 404 when I try to view the post? Is there something I’m missing? I’ve tried saving the Permalinks Settings Page, but that hasn’t done anything. Thanks in advance!
Hello there, thanks for your job, I have set a permalink structure for my custom type ‘spartiti’ in this way:
/%year%/%monthnum%/%day%/%postname%/
but I would like to have my archive for this custom post type in this way:
Works great, thanks a billion!!! I modified it slightly for a custom post that I wanted to display like /books/%post_id%/%postname% so I was able to remove much of the code, and it looks like this:
I am having problems with creating this for two CPT,
$wp_rewrite->add_permastruct(‘event’, $event_structure, false);
$wp_rewrite->add_permastruct(‘place’, $place_structure, false);
They seem to cancel each other out, if i comment one out the other will work but not both, do u have any advice?
Hey Shibashake, thanks for the awesome post on a topic I can’t find much info on anywhere else. If you’re still checking this post, could you help? I’m having trouble implementing this, as so:
add_action('init', 'videos_rewrite');
function videos_rewrite() {
global $wp_rewrite;
$wp_rewrite->add_permastruct('videos', '/videos/%year%/%monthnum%/%postname%', false);
}
Along with your post_type_link hook. The permalinks change correctly, but all head to 404 pages. Am I doing something wrong? I know the structure is to be slightly different from your own.
(note the p= rather than videos= as my non-fancy permalinks are http://domain.com/?post_type=videos&p=1234 rather than how you describe. This may be where I’m going wrong?)
Yes p= expects the post id whereas your %videos% rewrite tag is passing it the post name (e.g. video-title) instead. I would suggest using a regular query argument (e.g. videos) rather than ‘p’ since p is the wordpress standard for post id.
Thanks for this great example. However I do have a problem.
I have the custom post type “Game”. I use the code exactly as above but when this is activated my normal posts and pages won’t work anymore. It says “Page cannot be found”. Any ideas how this is possible?
I have resaved permalink structure.
The permalink for posts is /%year%/%postname%
%ean% is replaced by a custom taxonomy value. Which works fine.
In the gallery_permalink() function I added:
if ( strpos($permalink, '%ean%') !== false ) {
$terms = wp_get_post_terms( $post_id->ID, 'ean' );
$ean = ( !empty( $terms[0]->name ) && is_numeric( $terms[0]->name ) ) ? $terms[0]->name : '1';
}
Thanks for your great tutorials! Always super in-depth
I was able to follow your tutorial and get this working on a website I’m building. One question I do have though, is how can I make archives work for the cpt? i.e. I would like to display a list of all posts made in 2010 when visiting: http://shibashake.com/wordpress-theme/galleries/2010/
Hello James,
One way is to hook into the request filter and then manually insert in the custom post type into the query args. If the custom post type is not specified, then it defaults to ‘post’.
- any idea how to add a username in a link?
for exampe. site url: http://mysite.com/
now adding a username makes it http://mysite.com/username
note. ...
Thanks so much for this in depth post. Really saved me on a bad permalink custom post type I had set up. I updated the permalink structure and they all broke. They are fixed now!
There was a question about showing cats and sub-cats in the url, like you can with regular wordpress categories. Of note here is when you register the taxonomy, there is a setting in the rewrite rules to do this.
Under rewrite, the argument pair ‘hierarchical’ => true, turns on allowing /topic/sub-topic/super-sub-topic/, based on your structure, in the example called topic.
register_taxonomy('topic', 'gam_qa',
array(
'labels' => array(
'name' => _x( 'Topics', 'taxonomy general name' ),
'singular_name' => _x( 'Topic', 'taxonomy singular name' ),
'search_items' => __( 'Search Topics' ),
'all_items' => __( 'All Topics' ),
'parent_item' => __( 'Parent Topic' ),
'parent_item_colon' => __( 'Parent Topic:' ),
'edit_item' => __( 'Edit Topic' ),
'update_item' => __( 'Update Topic' ),
'add_new_item' => __( 'Add New Topic' ),
'new_item_name' => __( 'New Topic Name' ),
'menu_name' => __( 'Topics' ),
),
'public' => true,
'show_ui' => true,
'hierarchical' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'q-and-a/topic', 'with_front' => true, 'hierarchical' => true ),
'capabilities' => array(
'manage_terms' => 'manage_qa_terms',
'edit_terms' => 'edit_qa_terms',
'delete_terms' => 'delete_qa_terms',
'assign_terms' => 'assign_qa_terms'
)
)
);
Then the function you call from. This is a stripped down version, using only the %topic% tag, which will be the name of your custom taxonomy.
The code looks for a parent to the topic, and as long as it finds one, adds it to the url.
function gam_qa_permalinks($permalink, $post_id, $leavename) {
$post = get_post($post_id);
$rewrite_code = array(
'%topic%'
);
if ( '' != $permalink && !in_array($post->post_status, array('draft', 'pending', 'auto-draft')) ) {
if ( strpos($permalink, '%topic%') !== false ) {
$terms = wp_get_object_terms($post->ID, 'topic');
if (!is_wp_error($terms) && !empty($terms) && is_object($terms[0])) {
$topics[] = $terms[0]->slug;
$parent = $terms[0]->parent;
while($parent) {
$term = get_term($parent, 'topic');
$parent = $term->parent;
$topics[] = $term->slug;
}
$topics = array_reverse($topics);
$taxonomy_slug = join('/', $topics);
}else{
$taxonomy_slug = 'no-topic';
}
}else{
$taxonomy_slug = '';
}
$rewrite_replace =
array(
$taxonomy_slug
);
$permalink = str_replace($rewrite_code, $rewrite_replace, $permalink);
} else { // if they're not using the fancy permalink option
}
return $permalink;
}
You just saved my sanity. I’ve been fighting with these dang ole permalinks/pagination issues for the last week straight.
Great stuff, keep it up and thanks!
Very basic error, not sure if I’m being silly. I’ve put the ‘// Add filter to plugin init function’ at the top of functions and then am using a custom post type called features, followed all your steps above.
I want my structure to be
features/%year%/%month/%day%/%postname%
but I’m just getting a 404 error?
add_action('init', 'feature_register');function feature_register() {
$labels = array(
'name' => _x('Feature', 'post type general name'),
'singular_name' => _x('Feature', 'post type singular name'),
'add_new' => _x('Add New', 'Feature item'),
'add_new_item' => __('Add New Feature'),
'edit_item' => __('Edit Feature Item'),
'new_item' => __('New Feature Item'),
'view_item' => __('View Feature Item'),
'search_items' => __('Search Feature'),
'not_found' => __('Nothing found'),
'not_found_in_trash' => __('Nothing found in Trash'),
'parent_item_colon' => ''
);
$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'query_var' => true,
'rewrite' => false,
'capability_type' => 'post',
'hierarchical' => false,
'has_archive' => true,
'menu_position' => null,
'supports' => array('title','editor','thumbnail', 'comments','trackbacks', 'author'),
'taxonomies' => array('post_tag'),
);
register_post_type( 'feature' , $args );
}
// add to our plugin init function
global $wp_rewrite;
$feature_structure = '/features/%year%/%monthnum%/%day%/%postname%';
$wp_rewrite->add_rewrite_tag("%feature%", '([^/]+)', "feature=");
$wp_rewrite->add_permastruct('feature', $feature_structure, false);
Any help appreciated, thanks
Try
‘/features/%year%/%monthnum%/%day%/%feature%’
Hi, nice article, but is it possible to use a custom post meta in the permalink?
Already solved this and it is possible, however when visiting the url, it gives a 404.
I checked the comments, but could not find a good solution for this.
http://shibashake.com/wordpress-theme/add-custom-taxonomy-tags-to-your-wordpress-permalinks
Thanks for the info! It worked great to change the permalinks on my custom post type, but I am getting a 404 when I try to view the post? Is there something I’m missing? I’ve tried saving the Permalinks Settings Page, but that hasn’t done anything. Thanks in advance!
Sorry, I wrote too soon! I saw you already answered it in the previous comments and that worked for me too. Thanks again for the great info!
[...] http://shibashake.com/wordpress-theme/custom-post-type-permalinks-part-2 (Good introduction) [...]
Hi
great thanks for this tutorial. It works for me, but….
when I set rewrite as “%category%” im my post custom type there is conflict with pemalink for standard post.
How can I solve this?
Add in a unique slug.
http://shibashake.com/wordpress-theme/custom-post-type-permalinks-part-2#conflict
Hello there, thanks for your job, I have set a permalink structure for my custom type ‘spartiti’ in this way:
/%year%/%monthnum%/%day%/%postname%/
but I would like to have my archive for this custom post type in this way:
mywebsite/spartiti
Is this possible?
Thank you
Works great, thanks a billion!!! I modified it slightly for a custom post that I wanted to display like
/books/%post_id%/%postname%so I was able to remove much of the code, and it looks like this:function BookPermalink( $permalink, $post_id, $leavename )
{
$post = get_post( $post_id );
// Don't rewrite unless it's published
if ( '' != $permalink && !in_array( $post->post_status, array('draft', 'pending', 'auto-draft') ) )
{
// These are the things we'll look for
$rewrite_old = array(
'%post_id%',
$leavename? '' : '%pagename%',
$leavename? '' : '%postname%'
);
// And here we decide what to replace them with
$rewrite_new = array(
$post->ID,
$post->post_name,
$post->post_name
);
// Now do the replacing
$permalink = str_replace($rewrite_old, $rewrite_new, $permalink);
}
return $permalink;
}
Hi,
I am having problems with creating this for two CPT,
$wp_rewrite->add_permastruct(‘event’, $event_structure, false);
$wp_rewrite->add_permastruct(‘place’, $place_structure, false);
They seem to cancel each other out, if i comment one out the other will work but not both, do u have any advice?
Steven
What is $event_structure and $place_structure?
Hey Shibashake, thanks for the awesome post on a topic I can’t find much info on anywhere else. If you’re still checking this post, could you help? I’m having trouble implementing this, as so:
add_action('init', 'videos_rewrite');
function videos_rewrite() {
global $wp_rewrite;
$wp_rewrite->add_permastruct('videos', '/videos/%year%/%monthnum%/%postname%', false);
}
Along with your post_type_link hook. The permalinks change correctly, but all head to 404 pages. Am I doing something wrong? I know the structure is to be slightly different from your own.
Thanks in advance.
Try using %videos% (or whatever rewrite tag you are using for your custom post type) instead of %postname%.
Thanks for getting back to me. I’ve attempted:
function videos_rewrite() {global $wp_rewrite;
$wp_rewrite->add_rewrite_tag("%videos%", '([^/]+)', "p=");
$wp_rewrite->add_permastruct('videos', '/videos/%year%/%monthnum%/%videos%', false);
}
(note the p= rather than videos= as my non-fancy permalinks are http://domain.com/?post_type=videos&p=1234 rather than how you describe. This may be where I’m going wrong?)
Now that I’ve refreshed permalinks the page redirects to monthly archives, so http://domain.com/videos/2011/09/video-title is actually displaying what is located at http://domain.com/2011/09. Quite frustrating! Any thoughts on my problems, greatly appreciated!
Yes p= expects the post id whereas your %videos% rewrite tag is passing it the post name (e.g. video-title) instead. I would suggest using a regular query argument (e.g. videos) rather than ‘p’ since p is the wordpress standard for post id.
Hi,
Thanks for this great example. However I do have a problem.
I have the custom post type “Game”. I use the code exactly as above but when this is activated my normal posts and pages won’t work anymore. It says “Page cannot be found”. Any ideas how this is possible?
I have resaved permalink structure.
The permalink for posts is /%year%/%postname%
regards,
Léon
Hello Léon,
What is the permalink structure of your custom post type?
It sounds like a permalink conflict issue.
http://shibashake.com/wordpress-theme/custom-post-type-permalinks-part-2#conflict
Hi,
Sorry for late reply.
Structure is: /%ean%/%game%
$wp_rewrite->add_rewrite_tag("%game%", '([^/]+)', "game=");
$wp_rewrite->add_permastruct('game', '/%ean%/%game%', false);
add_filter('post_type_link', 'game_permalink', 10, 3);
%ean% is replaced by a custom taxonomy value. Which works fine.
In the gallery_permalink() function I added:
if ( strpos($permalink, '%ean%') !== false ) {
$terms = wp_get_post_terms( $post_id->ID, 'ean' );
$ean = ( !empty( $terms[0]->name ) && is_numeric( $terms[0]->name ) ) ? $terms[0]->name : '1';
}
Yes this is a premalink conflict issue. Try adding a unique keyword to your permalink structure, e.g.
/my-unique-keyword/%ean%/%game%
Hi Shibashake,
Thanks for your great tutorials! Always super in-depth
I was able to follow your tutorial and get this working on a website I’m building. One question I do have though, is how can I make archives work for the cpt? i.e. I would like to display a list of all posts made in 2010 when visiting:
http://shibashake.com/wordpress-theme/galleries/2010/
Likewise, http://shibashake.com/wordpress-theme/galleries/2010/06/ would display all posts from June of 2010.
Thanks!
Hello James,
One way is to hook into the request filter and then manually insert in the custom post type into the query args. If the custom post type is not specified, then it defaults to ‘post’.
This article has an example of hooking into the request filter -
http://shibashake.com/wordpress-theme/mastering-the-wordpress-loop
I do some of this on my blog-art site which shows archives, recent posts, etc all on my gallery custom post type.
Good article, but I keep wondering what’s the deal with all digital women on this site hmm?