Desired permalink structure (only these structures exist for products)

Product 1: /shop/category/subcategory/product1/
Product 2: /shop/category/product2/

Woocommerce Product View Settings

View for shopbase:     Show categories
View for categories:   Show products


Products are only checked for one category OR subcategory

Permalink Settings

Normal settings:       /%category%/%postname%/
Base for categories:   shop
For products:          /shop/%product_cat%/


Since there are over 100 subcategories, I want to use an archive to list all 
the products.

Attempts to solve

With the below attempts I've been able to produce a working Product-page but while doing so, also 404:ing the subcategory page. I can't recall which option produces what result.

  1. I have tried different permalink settings for the product categorybase, including %category%/%product_cat%, %category%/%product_cat%/%postname%, %product_cat%/%product_cat%, shop/%product_cat%, shop/%product_cat%/%postname%, and all those above combinations with an ending as /. as well
  2. I've tried swapping above with the base shop permalink setting.
  3. I've tried chaning Product View Settings to show subcategories instead of products.
  4. I've tried creating pages for the subcategories while having a working Product page, but the subcategory page still returns a 404.
  5. I've tried this SO attempt with no luck.

What am I doing wrong or what part can I rewire to make this work? So greatful for any hints or leads or answers. Thank you for reading this!


1 Answer 1


I was able to resolve this with the following code which generates rewrite_rules for each subcategory, which is preferred during matching since it's more specific:

function wpse_291143_generate_taxonomy_rewrite_rules( $wp_rewrite ) {

    global $wp_rewrite;
    $base = "shop";

    $rules = array();
    $terms = get_terms( array( 'taxonomy' => 'product_cat', 'hide_empty' => false ));

    foreach($terms as $term) {
        $term_children = get_terms( array(
            'taxonomy' => 'product_cat',
            'parent' => intval($term->term_id),
            'hide_empty' => false
        if($term_children) {
            foreach ( $term_children as $term_child ) {
                $rules[$base . '/' . $term->slug . '/' . $term_child->slug . '/?$'] = 'index.php?product_cat=' . $term_child->slug;

    $wp_rewrite->rules = $rules + $wp_rewrite->rules;
    return $wp_rewrite->rules;

add_action('generate_rewrite_rules', 'wpse_291143_generate_taxonomy_rewrite_rules');

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