0

My attempt:

RewriteCond %{QUERY_STRING}     ^id=(.*)$    [NC]
RewriteRule ^/product$       /product/%1      [NC,L,R=301]

I want to apply this rule to /product/ and /supplier/ directories only. They are both first level sub directories.

Note: product/?id={xxx} is actually product/index.php?id={xxx}. Apache hides my extensions and indexes. Just want to point that out.

My product/index.php handles the parameter given and determines what page it should show:

index.php

if ( isset( $_GET['id'] ) && !empty( $_GET['id'] ) ) {
   //html for individual page e.g. /product/?id=foo
   //e.g. <h1><?= $_GET['id'] ?> Page</h1>
} else {
   //html for product list e.g. /product/ (no parameters)
}
meiryo
  • 11,157
  • 14
  • 47
  • 52

1 Answers1

1

Try this in one .htaccess file at root directory:

Options +FollowSymlinks -MultiViews
RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} id=(.+)          [NC]
RewriteRule ^(product|supplier)/?$   /$1/%1? [NC,L,R=301]

In .htaccess files the URI-path test it in the rule does not have a leading slash (^/product), therefore the regex cannot have it either. The trailng ? deletes the incoming query.

If the rule-set is to be placed at Apache main configuration files, the leading slash should be kept: ^/(product|supplier)/?$

UPDATE

To show the wanted URL but still get the data from the original URL.

Request: /product/?id=parameter

Options +FollowSymlinks -MultiViews
RewriteEngine On
RewriteBase /

RewriteCond %{THE_REQUEST} ^(GET|HEAD)\s/(product|supplier)/\?id=([^\s]+) [NC]
# Strip the query and redirect permanently
RewriteRule  ^(product|supplier)  /$1/%3?   [R=301,L,NC]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{QUERY_STRING} ^$
# Map internally to the original request
RewriteRule  ^(product|supplier)/([^/]+)/?  /$1/?id=$2  [L,NC]

Another option is to use directly the "pretty" URL in the request:

Request /product/parameter to /product/?id=parameter

Options +FollowSymlinks -MultiViews
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{QUERY_STRING} ^$
RewriteRule  ^(product|supplier)/([^/]+)/?  /$1/?id=$2  [L,NC]
Community
  • 1
  • 1
Felipe Alameda A
  • 11,791
  • 3
  • 29
  • 37
  • Why do we want to delete the incoming GET query? E.g. `product/?id=pickles` => `product/pickles will give me a 404 instead of showing a page for pickles. – meiryo Apr 19 '13 at 04:37
  • The script can't GET the parameter from the new URL you asked for, because it doesn't hold a query string. The only way to achieve what you need is to redirect to `/product/{xyz}`, just to show that URL in the browser's address bar, while silently map back to `product/?id=pickles` to allow the script to GET the query string. I guess that's what you really need. – Felipe Alameda A Apr 19 '13 at 06:27
  • Cool. Would silently mapping back cause the URL to change back to `/product/?id=pickles` again? If not how would I do this? – meiryo Apr 19 '13 at 06:32
  • Yes. But maybe it's possible to use the pretty URL instead of the one with the query. Could you please check this [answer](http://stackoverflow.com/questions/13832468/how-to-stop-htaccess-loop/13832827#13832827) where both options are described and let me know which one fits your requirements? – Felipe Alameda A Apr 19 '13 at 06:37
  • I think 2nd method is what I want. But my approach could be wrong and bad practice. Typically when you visit the product directory of a website and click on an item how would they send you to the page using an `id` parameter? Surely they wouldn't create a sub directory for each product page. Much like how a Wordpress blog would generate redirect it's pretty URLs from post id's. – meiryo Apr 19 '13 at 06:54
  • You are right. The second method should be used only when it is impossible to modify all existing links. But it's not the best one, though. The usual way to do it, is using the first option. In that case, the sub-directory or nothing in the URI-path of the request has to exist. That's one of the advantages of mod_rewrite. If the request is `/product/pickles`, for example, `pickles` does not have to exist, although is the parameter passed in the rewrite rule. i.e. `product/?id=pickles`. – Felipe Alameda A Apr 19 '13 at 07:06
  • Maybe that's the best option in your case as long as the existing links, if any, can be modified to point to the "pretty" URL without the query. – Felipe Alameda A Apr 19 '13 at 07:07
  • 1
    Updated my answer with both options. Hope one of them is what you need. – Felipe Alameda A Apr 19 '13 at 07:19
  • I modified slightly the 1st option because the `?` in THE_REQUEST variable was not escaped. – Felipe Alameda A Apr 19 '13 at 07:31