Create a clean URL for your custom post type’s category archives

Categories: ,

WordPress gained great functionality by adding custom post types and one great feature of custom post types is that it can share the same categories as regular posts. However, while you can view an archive of posts by category you can’t do so with a custom post type without using an ugly URL.

Let’s say you have a custom post type, gallery and a category, portraits. To view an archive of galleries in the portrait category you could do it with two URLs.

/gallery/?category_name=portraits or /category/portraits/?post_type=gallery

While this works it’s not very pretty. So here’s how to rewrite that first URL to something cleaner.

/* Can be added to functions.php */
add_filter( 'rewrite_rules_array','my_insert_rewrite_rules' );
add_filter( 'query_vars','my_insert_query_vars' );
add_action( 'wp_loaded','my_flush_rules' );
// flush_rules() if our rules are not yet included
function my_flush_rules() {
$rules = get_option( 'rewrite_rules' );
if ( ! isset( $rules['gallery/category/(.*/?)$'] ) ) {
global $wp_rewrite;
// Adding a new rule
function my_insert_rewrite_rules( $rules ) {
$newrules = array();
$newrules['gallery/category/(.*/?)$'] = 'index.php?post_type=gallery&my_gallery_cat=$matches[1]';
return $newrules + $rules;
// Adding the my_gallery_cat var so that WP recognizes it
function my_insert_query_vars( $vars ) {
array_push($vars, 'my_gallery_cat');
return $vars;

If we just used the category_name variable then WordPress would try to override our custom URL, so instead, we’ll use a made-up variable my_gallery_cat. To use this variable create an archive template for your custom post type, in this case archive-gallery.php, and modify the query to accept changes to the category:

global $wp_query;
$args = array_merge( $wp_query->query, array(
'category_name' => $my_gallery_cat
query_posts( $args );

The final result is a nice URL for the category archive: /gallery/category/portraits/

You may have to flush your rewrite rules by going to Settings -> Permalinks, then just hit Save Changes.

Update 2012-01-06
Forgot to mention that you may need to flush your rewrite rules, thanks e01.

Update 2012-01-06
Added add_filter(‘query_vars’, ‘my_insert_query_var’);, thanks Arnaud

Contact Me

How can I help you?

© 2023 Seth Stevenson Marketing. All rights reserved.