Rewrite Rules for Multiple (more than 2) Taxonomies

I am using woocommerce and have some 'product attributes' which are just a taxonomies.

I have the following taxonomies:

  • pa_color
  • pa_material
  • pa_style

the pa_ stands for product attribute and it is built-in to WooCommerce handles these taxonomies, so I can't change that.

WooCommerce also comes with product categories (product_cat) and product tags (product_tag) taxonomies.

the following query gets me all the Red, Vinyl products in the Fabrics product category

?product_cat=fabricspa_material=vinylpa_color=red

I'd like to turn this into a pretty permalink, something like:

product-category/fabrics/material/vinyl/color/red

This answer gets me pretty close to what I am trying to achieve:

URL rewrite rules for multiple taxonomies query

in that I can get my URL to handle 2 taxonomies (product_cat + 1 attribute taxonomy), but I am stuck on how to get 3 (or more) parameters.

So I can get:

/products-category/fabrics/color/red

or

/product-category/fabrics/material/vinyl

but not all 3 together

/product-category/fabrics/material/vinyl/color/red

edit / though i think it'd be ideal to have the URL be

/fabrics/vinyl/red

i'm not sure that is possible?

end edit/

WooCommerce also has some settings for modifying the permalinks (like prepending the URL with 'shop' or changing the product-category slug) so i'll need to account for that eventually, but right now I need to get this first step down.

for simplicity's sake, this is a stripped down version of my code. I'm actually getting the taxonomies from built-in woocommerce functions, but the question isn't limited to woocommerce... as it pertains to any site w/ a lot of taxonomies.

add_action( 'init', 'wpa_init' );
function wpa_init() {

  $taxonomies = array(
    'pa_color' = 'Color',
    'pa_material' = 'Material',
    'pa_style' = 'Style',
  );
  $base = 'product-category';

  foreach ( $taxonomies as $taxonomy = $mask ):
    $attribute = strtolower( sanitize_title( $mask ) );
    add_rewrite_rule(
      $base.'/(.+?)/' . $attribute . '/([^/]+)(/page/(\d+))?/?$',
      'index.php?product_cat=$matches[1]' . $taxonomy . '=$matches[2]paged=$matches[4]',
      'top'
    );
  endforeach;
}

this was the best resource i've found on taxonomy query permalinks: http://thereforei.am/2011/10/28/advanced-taxonomy-queries-with-pretty-urls/

but it, too, seems stuck at 2 taxonomies.

Topic rewrite-tag rewrite-rules url-rewriting Wordpress

Category Web


For future reference (like next year when I google and find my own question again) this can be converted into add_rewrite_rule() syntax by converting the keys in the $new_rules array into the $regex parameter of add_rewrite_rule() with the value as the $rewrite and 'top' as the $position.

add_rewrite_rule($regex,$rewrite, $position);

Or as an example of one of my requests from above:

function custom_rewrite() {

   add_rewrite_rule(
    'product-category/(.+?)/material/(.+?)/?$',
    'index.php?product_cat=matches[1]&pa_material=$matches[2]',
    'top'
    );

}
// refresh/flush permalinks in the dashboard if this is changed in any way
add_action( 'init', 'custom_rewrite' );

For some reason I was unsuccessful using regenerate_rewrite_rules as a hook/filter so switched to init.


You could try something like this:

function custom_rewrite( $wp_rewrite ) {

    $feed_rules = array(
        'product-category/(.+)/material/(.+)/color/(.+)'    =>  'index.php?product_cat='. $wp_rewrite->preg_index(1).'&pa_material='. $wp_rewrite->preg_index(2).'&pa_color='. $wp_rewrite->preg_index(3)
        'product-category/(.+)/color/(.+)'    =>  'index.php?product_cat='. $wp_rewrite->preg_index(1).'&pa_color='. $wp_rewrite->preg_index(2)
        'product-category/(.+)/material/(.+)'    =>  'index.php?product_cat='. $wp_rewrite->preg_index(1).'&pa_material='. $wp_rewrite->preg_index(2)
    );

    $wp_rewrite->rules = $feed_rules + $wp_rewrite->rules;
}
// refresh/flush permalinks in the dashboard if this is changed in any way
add_filter( 'generate_rewrite_rules', 'custom_rewrite' );

It may not work exactly as advertised, and you might need to do some regex modifications, but that's the general gist of what needs to be done (90% of the work).

You will need to flush the permalinks if you add/edit/remove this code, put it in functions.php or a custom plugin. You can flush permalinks by simply going into the admin area and re-saving the permalinks

As a sidenote, you may run into clashing issues if you start using heirarchies,

e.g. if you have a tshirts/small and a dresses/small category, and you use a URL such as /products-category/small/color/red you might not get the results you expected, e.g. small tshirts? or did you mean small dresses?

So beware of ambiguity

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.