Input data:

  1. There is a Custom Post Type, with Companies posts that relates to Company category;
  2. There is a Custom Post Type, with Products posts that tied to Items -> Item-type category;
  3. There is a Custom Post Type, with Articles posts that tied to Articles category;

Summarizing, structure looks like this:

+ Companies (cat)
   |- Company-1 (post)
   `- Company-2
+ Items (cat)
   `- Item-type-1 (cat)
   |   |- Product-1-1 (post)
   |   `- Product-1-2
   `- Item-type-2 (cat)
       |- Product-2-1 (post)
       `- Product-2-2
+ Articles (cat)
   |- Article-1 (post)
   `- Article-2

The Problem:

I'll be appreciate for a way to implement the structure that can be accessed like this:

http://examplecom/company-2/items/item-type-1/product-1 //(note that both company 1 and 2 can produce a similar product)

Both Products and Articles posts have got a custom fields that stores post-IDs of companies they're tied to.


I was thinking about developing it with custom taxonomies:


Can you advice more suitable way?

1 Answer 1


In wordpress, the slug (post name) is unique per post type.

So, an url like /company-1/items/item-type-1/product-1 and one like /company-2/items/item-type-1/product-1 where product-1 is the post name, cannot address to 2 different products.

If you create 2 products with same title Wordpress on saving will set an unique slug.

Same thing is for articles.

For this reason in a url like:


can simply be rewritten in


and a url like:


can simply be rewritten in


So, as you can see, no matter for category.

You need only 2 rewrite rules:


function my_rewrite_rules() {
    add_rewrite_rule( '[^/]+/items/[^/]+/(.+)/?$' , 'index.php?post_type=products&name=$matches[1]' , 'top' );
    add_rewrite_rule( '[^/]+/articles/(.+)/?$' , 'index.php?post_type=articles&name=$matches[1]' , 'top' );

After that you have to flushing rewrite rules going Settings->Permalink section in your backend and saving changes.

Now the urls work as you expect, if you manually write them on browser, but the problem is generate the right url using the_permalink function. You have to use the 'post_link' filter and generate the right url:

add_filter('post_link', 'my_custom_permalink', 99, 3);

function my_custom_permalink($permalink, $post, $leavename) {
  if ( $post->post_type == 'products' )
     return products_permalink($permalink, $post, $leavename);
  if ( $post->post_type == 'articles' )
     return articles_permalink($permalink, $post, $leavename);
  return $permalink;

function products_permalink($permalink, $post, $leavename) {
  if ( $post->post_type != 'products' ) return $permalink;
  $cats = get_the_category( $post->ID );
  $companies = get_term_by('slug', 'companies', 'category');
  $items= get_term_by('slug', 'items', 'category');
  if ( empty($cats) || empty($companies) || empty($items) ) return $permalink;
  $item = '';
  $company = '';
  while ( ! empty($cats) ) {
    if ( $item && $company )
      return home_url() . '/' . $company . '/items/' . $item . '/' . $post->name;
    $cat = array_pop($cats);
    if ( $cat->parent == $companies->term_id ) $company = $cat->slug;
    if ( $cat->parent == $items->term_id ) $item = $cat->slug;
  return $permalink;

function articles_permalink($permalink, $post, $leavename) {
  if ( $post->post_type != 'articles' ) return $permalink;
  $cats = get_the_category( $post->ID );
  $companies = get_term_by('slug', 'companies', 'category');
  if ( empty($cats) || empty($companies) ) return $permalink;
  $company = '';
  while ( ! empty($cats) ) {
    if ( $company )
      return home_url() . '/' . $company . '/articles/' . $post->name;
    $cat = array_pop($cats);
    if ( $cat->parent == $companies->term_id ) $company = $cat->slug;
  return $permalink;

Here I assume you are using only standard categories, where the category 'Companies' is the parent category for companies and 'Items' is the parent category for items.

Also assumed cpt are named 'products' and 'articles' (note the plural).

Ajust the functions if something is different in your configuration.

  • Thank you for your great answer, but I have 2 points that still not clear: 1) When I'm talking about product-1 under /company-1/ and /company-2/ URLs I mean that a single(unique) Product can be found under both Companies, so company-1/../product-1 and company-2/../product-1 url technically should direct us to the same page, but.. 2) To avoid search-engine side inconveniences (2 links can't point at the same data), i need that /company-X/ part in url to build a custom layout for a page (example: including company name as header, etc.) Can you please advice me, how can i deal with it
    – Ignat B.
    Commented Sep 17, 2013 at 19:08
  • 1
    This is problematic. The url, if manually inserted, works for both companies. (for a non-limited number of companies). But the function that create the url, will always create one url. For this reason and to avoid SEO inconvenience if the product is unique, the url should be unique. However you you absolutely need have 2 url for same product, you can use $_SERVER['REQUEST_URI'] var to recognize the company-* part and manipulate the content according to it. But I can't find a way to create 2 different url when you call the_permalink @IgnatB.
    – gmazzap
    Commented Sep 17, 2013 at 22:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.