Devlog

URL structure of WordPress custom post types and taxonomies

Explanation about register_taxonomy and register_post_type and how this is reflected in the URL structure.

register_taxonomy(
  'my_newscat',
  ['post'],
  [
    'labels' => ['name' => 'News category'],
    'public' => true,
    'hierarchical' => true,
    'show_admin_column' => true,
    'rewrite' => [
      'slug' => 'newscategories'
    ],
    'query_var' => 'newscategories'
  ]
);

If we didn’t specify a rewrite slug, we had to use:

/my_newscat/[term]

After setting the rewrite slug to “newscategories”, we can do:

/newscategories/[term]

After setting the query_var to “newscategories” we can do:

?newscategories=[term]

or if we want to filter for multiple newscategories:

?newscategories[]=[term1]&newscategories[]=[term2]
register_post_type(
  'my_news',
  [
    'label' => 'News',
    'public' => true,
    'has_archive' => 'news-archive',
    'rewrite' => [
      'slug' => 'news'
    ],
    'taxonomies' => ['my_newscat'],
    'query_var' => 'news-query-var'
  ]
);

By setting the has_archive to ‘news-archive’, we have the archive at:

/news-archive

By setting the rewrite slug to ‘news’ we have a single item at:

/news/[item]

By setting the ‘query_var’ to ‘news-query-var’ we can get a single item at:

?news-query-var=[item]

Stop automatic redirect

WordPress does some magic behind the scenes if it finds an invalid URL. For example if we have a post at /2017/01/02/my-post we can get to this post also at /my-post or /sdf/sdf/sdf/sdf/sdf/my-post. If this is not what you want, you can alter the redirect_canonical filter:

function my_redirect_canonical($redirect_url, $requested_url) {
  if (is_404()) {
    return false;
  }
  return $redirect_url;
}
add_filter('redirect_canonical', 'my_redirect_canonical', 10, 2);

Filter custom post type with custom taxonomies

This only works if your custom taxonomy is unique for this custom post type. You register a custom post type with a specific archive slug and then you register a custom taxonomy with the slug of the post type as a prefix. For example if the slug of your custom post type archive is “/music”, you can specify “/music/styles” as the slug of the custom taxonomy. This way you can have the music items available at “/music/my-music-post-item” and all classical music items at “/music/styles/classical”:

register_post_type('my_music', [
  'public' => true,
  'has_archive' => 'music',
  'rewrite' => ['slug' => 'music']
]);

register_taxonomy('my_music_styles', ['my_music'], [
  'public' => true,
  'rewrite' => ['slug' => 'music/styles']
]);