Search code examples
nginx

Issues with NGINX rewrite capturing last part of URL & matching first part


I have an NGINX rewrite/return block as follows:

if ($request_uri ~ /product-category/(.*)/$) {
   return 301 /shop/?categories[]=$1;
}

This correctly matches https://example.com/product-category/cat-1/ and redirects that to https://example.com/shop/?categories[]=cat-1.

But, I have a few URLS that have a variable number of directories between the product-category and final cat-1, i.e.

https://example.com/product-category/parent/cat-1/
https://example.com/product-category/gparent/parent/cat-1/
https://example.com/product-category/distant-relative/gparent/parent/cat-1/
...

I am looking for a rewrite or return rule that would match any URL that starts with product-category after the domain, extracts the very last directory name, and compiles my redirect like in the first example.

Said another way, I need some way for all of the URLs in my second example above to redirect to https://example.com/shop/?categories[]=cat-1 no matter how many ancestor directories may exist between the product-category and final directory.

Any advice would be super appreciated.


Solution

  • Try: ^/product-category/(?:.*/)?([^/]+)/$


    The $request_uri variable contains the path and query parts of the original URL.

    In your examples, it always begins with /product-category/ and ends with / and may contain any number of path segments in between.

    The solution breaks down as follows:

    1. ^/product-category/
    2. (?:.*/)?
    3. ([^/]+)
    4. /$

    Step (1) matches the path segment at the beginning (hence the start of string anchor ^).

    Step (2) is a non-capturing group that matches any text that ends with a /, including text containing multiple /s, and will therefore consume one or more path segments. We add a trailing ? to make it optional, so it also matches zero path segments.

    Step (3) captures $1, which is the text between two /s.

    Step (4) completes the expression with the final / and the end of string anchor.

    This solution assumes that there is no query string or separating ?.