You may recall my ancient post about customizing your custom post type permalinks. When I wrote that, I was still stumbling somewhat blindly through WordPress’s rewrite API. After hacking a little more with it, I think I finally understand what I’m doing enough to write a little more confidently.
Rewrite Tags
In my previous post, I had a slug like project/%issue_project%/issue
for my issue
post type. What exactly is that %issue_project%
in the middle of that?
That would be a rewrite tag. WordPress uses these as keys for regular expressions it will add to its rewrite rules. When you add a custom post type or a custom taxonomy, WordPress automatically creates appropriate rewrite tags for you. E.g., when you create an issue
post type, WordPress will automatically create a rewrite tag called %issue%
, with the pattern ([^/]+)
, or (.+?)
if it’s a hierarchical post type, and this regexp will be rewritten to post_type=issue&name=$matches[1]
.
In my previous post, %issue_project%
was the tag for the rewrite rule matching the issue_project
taxonomy I had created using register_taxonomy
.
Making Your Own Rewrite Tags
Knowing all this, you can create your own rewrite tags and use them in the slugs for your custom post types.
For my issue/bug tracking plugin, I decided that I should use another custom post type instead of taxonomy for projects. That means that WordPress won’t automatically create the %issue_project%
rewrite tag. I don’t want to use the %project%
rewrite tag that it creates for my project
post type, as that will add inappropriate (and conflicting) rules to my rewrite rules.
The solution is to create my own %issue_project%
rewrite tag.
global $wp_rewrite; $wp_rewrite->add_rewrite_tag('%issue_project%', '(.+?/)?', 'issue_project=');
This matches (.+?/)?
in a URL and puts the match into an ignored query var. Having created the rewrite tag, I can now use it in my post type’s slug.
register_post_type('issue', array( 'label'=>'Issues', 'hierarchical' => FALSE, 'rewrite' => array( 'slug' => '%issue_project%issue', 'with_front' => FALSE, ), ));
This creates rewrite rules like
[(.+?/)?issue/([^/]+)(/[0-9]+)?/?$] => index.php?issue_project=$matches[1]&issue=$matches[2]&page=$matches[3]
Creating Links
Whenever you create your own rewrite tags, or use them in non-standard ways in post type slugs, you have to handle the rewrite tag in a post_type_link
filter, replacing it with the appropriate string.
add_filter('post_type_link', 'my_post_type_link'), 1, 3); function my_post_type_link( $post_link, $post = 0, $leavename = FALSE ) { if ( strpos('%issue_project%', $post_link) === 'FALSE' ) { return $post_link; } if ( is_object($post) ) { $post_id = $post->ID; } else { $post_id = $post; $post = get_post($post_id); } if ( !is_object($post) || $post->post_type != 'issue' ) { return $post_link; } $project_slug = ''; $project_id = get_post_meta($post_id, '_issue_project', TRUE); if ( $project_id ) { $project_slug = get_page_uri($project_id); } if ( !$project_slug ) { // remove project prefix return str_replace('%issue_project%', '', $post_link); } // put project slug in place of %issue_project% return str_replace('%issue_project%', 'project/'.$project_slug.'/', $post_link); }
So what if you want your custom post type to not have a prefix slug? For example:
If you create a custom post type “people” and the permalinks naturally go to example.com/people/slug-of-people-post
But
you want them to be example.com/slug-of-people-post so that they are a first level slug in the url almost just appearing as if they are a page?
Hello,
Using your solution, is it possible to have a structure like this without getting 404 :
custom post type (= product1) is set to have a custom taxonomy (=subcat-customtax) which in turn is a child of the parent category (=customtax). Is it possible that the url
http://site.com/customtax/subcat-customtax/product1/ to return the above mentioned post correctly ??
I currently can see all the posts within subcat-customtax, the url being site.com/customtax/subcat-customtax/
All the products have just the assigned category, not the full structure (parent/child tax) and even so, upon accessing i get a 404.