I have already rewritten my old “ugly” URL:
http://example.com/ppd-brands/generic/?gen_id=Mjky
to
http://example.com/ppd-brands/generic/gen_id/Mjky
using the code below
RewriteRule ^ppd-brands/generic/gen_id/([^/]*)$ /ppd-brands/generic/?gen_id=$1 [L]
and it’s working.
Now my problem is how can I redirect the old “ugly” URL to the new URL when the user visits the old “ugly” URL?
2
Answers
change old and new URL according to your need. Hope it helps you
Just a precursor… whilst your old “ugly” URL was of the form
/ppd-brands/generic/?gen_id=Mjky
, you should ideally be rewriting to the actual file that handles the request, eg.index.php
, instead of allowing mod_dir to issue an additional internal subrequest to the directory index – which is what I assume is happening here.For example:
Now, your main question… to externally redirect from the old “ugly” URL to the new URL. In this case, you need to be careful of a redirect loop, since if we simply redirect then the above rewrite will rewrite it back again in an endless loop. You can’t use a mod_alias
Redirect
(as the other answer suggests) for this reason. (And a mod_aliasRedirect
can’t match the query string either – another reason.)Aside: Since we changed the above rewrite to include
index.php
in the rewritten URL, which would appear to differ from the old “ugly” URL, we could perhaps get away with a simple redirect if you are on Apache 2.4 (but Apache 2.2 would result in a conflict because mod_dir would issue an internal subrequest forindex.php
before we can process the URL with mod_rewrite).We need to only redirect initial requests, not requests that we have already rewritten. We can do this by checking against the
REDIRECT_STATUS
environment variable, which is empty on the initial request and set to “200” (as in200 OK
HTTP status) after the first successful rewrite. (Another way is to check againstTHE_REQUEST
, instead of the dynamic/rewritable URL-path.)For example, try the following before your existing rewrite:
Note that in order to match the query string we need a condition (
RewriteCond
directive) that checks against theQUERY_STRING
server variable. The URL-path matched by theRewriteRule
pattern notably excludes the query string.The
index.php
in the request URL is optional, so it matches/ppd-brands/generic/?gen_id=Mjky
or/ppd-brands/generic/index.php?gen_id=Mjky
(if that is the actual URL).The
$1
backreference is simply to save typing/duplication. This will always containppd-brands/generic
when the directive matches. We could have done the same with “gen_id”, but that could make the susbstitution string look a bit too cryptic.The
%1
backreference (note the%
prefix) is a backreference to the captured group in the last matched CondPattern (as opposed to$1
which refers to theRewriteRule
pattern), ie. the value of thegen_id
URL parameter.The
QSD
flag (Apache 2.4+) strips the query string from the redirected URL. Otherwisegen_id=XYZ
would be passed through to the target URL. If you are still on Apache 2.2 then you would need to append a?
to the end of the substitution string instead (essentially an empty query string). eg./$1/gen_id/%1?
The “magic” is really the first condition that checks the
REDIRECT_STATUS
env var. As mentioned above, this ensures that we only process initial requests and not the rewritten request, thus avoiding redirect loop.Note that this is currently a 302 (temporary) redirect. Only change to a 301 (permanent) once you have tested this works OK. 301s are cached persistently by the browser so can make testing problematic.
And just to clarify… a redirect like this should only be implemented once you have already changed all the URLs in your application. This redirect is to simply redirect search engines, backlinks and anyone who should manually type the URL (unlikely).