how do I use rewriteRule in htaccess - regex

I'm trying to redirect some urls to pretty urls and the thing is that I'm new to this so I can't seem to figure out what part I did wrong
this is the htaccess right now but the rewrite rule is not working.
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ -
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([.]+)/([.]+)$ index.php?search_categories%5B%5D=$1&search_location=$2 [QSA,L]
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

Try this rule:
RewriteRule ^(.+[^/])/(.+)$ index.php?search_categories=$1&search_location=$2 [QSA,L]
In your rule you have: search_categories%5B%5D, may be a mistake while copy/paste I removed the %5B%5D even this is not the problem
^(.+[^/])/(.+)$ match category/location the rule [^/] is to not match the slash /
EDIT:
It can also simplified with just: ^([^/]*)/(.*)$
In your code [.]+ the dot match Any single character but brackets is used for range like [abc] will match a, b or c, so it will not work with just [.]+, also like I wrote before you have to not match the slash with [^/] this last one must be inside brackets, more here and Cheat Sheet
Test here

Related

Query string not redirected on deeper level directories

I want to redirect each link with a query string to a specific address by appending the string. I have the following in my WordPress .htaccess:
RewriteEngine On
RewriteCond %{QUERY_STRING} catid=([0-9]+) [NC]
RewriteRule (.*) catid%1? [R=301,L]
When a user hits example.com/?catid=10, they are successfully redirected to example.com/catid10, which is what I want.
However, when they go a directory deeper (example.com/category/?catid=10), they are not redirected to example.com/category/catid10.
I have been reading manuals but can't find the answer.
Edit
If this is helpful, this is what WordPress has defined in my htaccess:
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
Providing RewriteBase / is already defined (which it normally is with WordPress and must be if your existing redirect is working) then you can do it like the following with a single rule:
RewriteCond %{QUERY_STRING} (?:^|&)catid=(\d+) [NC]
RewriteRule (.*?)/?$ $1/catid%1 [QSD,R=301,L]
The capturing group (.*?) is non-greedy so does not consume the optional trailing slash that follows.
Requests for the document root do not require RewriteBase, but all "deeper" URLs do, since the resulting substitution string will otherwise be a relative URL.
The non-capturing (?:^|&) prefix on the CondPattern ensures that it only matches the URL parameter name catid and not foocatid etc.
You just need to add the captured group from (.*) to your redirect target using $1. I'd break it up into a few rules so that you don't get duplicated slashes. Rather then ending your rewrite targets with a question mark, I would add the QSD (query string discard) flag to the rule. I would also add starts with (^) and ends with ($) to rewrite rule so you always match the whole thing. I also like to start my rules with an optional slash (/?) so that the rules can be used in both .htaccess and apache conf.
RewriteEngine On
# Home URL with catid query string
RewriteCond %{QUERY_STRING} catid=([0-9]+) [NC]
RewriteRule ^/?$ /catid%1 [R=301,L,QSD]
# Deep URL ending in slash with a catid query string
RewriteCond %{QUERY_STRING} catid=([0-9]+) [NC]
RewriteRule ^/?(.*)/$ /$1/catid%1 [R=301,L,QSD]
# Deep URL not ending in slash with a cadid query string
RewriteCond %{QUERY_STRING} catid=([0-9]+) [NC]
RewriteRule ^/?(.*)$ /$1/catid%1 [R=301,L,QSD]

String repeats 20 times in RewriteRule if i try to use it with $1, $2 etc. back-references. Weird. Why?

I try to do a RewriteRule redirect in .htaccess where the output URL has some additional text beside the captured text from the capture groups.
Original url: https://example.com/places/europe/hungary/budapest/
My regex pattern: ^places/([a-zA-Z-_]+/)?([a-zA-Z-_]+/)?([a-zA-Z-_]+/)?
i want to add a 'text-' string in the destination url around some $1, $2..
The full line in .htaccess: RewriteRule ^places/([a-zA-Z-_]+/)?([a-zA-Z-_]+/)?([a-zA-Z-_]+/)? https://example.com/places/$1text-$2$3 [R=301,L]
but it outputs exactly this:
https://example.com/places/europe/text-text-text-text-text-text-text-text-text-text-text-text-text-text-text-text-text-text-text-text-hungary/budapest/
Instead of this: https://example.com/places/europe/text-hungary/budapest/
Yep, the additional 'text-' is repeating 20x times instead of 1.
If I don't put the 'text-' in the substitution string, all works as expected i.e:
https://example.com/places/$1$2$3 [R=301,L]
gives
https://example.com/places/europe/hungary/budapest/
What may cause this strange (to me) anomaly?
Is this should work without glitches or what is the correct syntax for this case?
All the other code in the .htaccess file (positioned after this RewriteRule part in question):
# BEGIN rlrssslReallySimpleSSL rsssl_version[3.3.5]
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTPS} !=on [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
</IfModule>
# END rlrssslReallySimpleSSL
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Yes it's a wordpress install.
Thanks a lot for any help!
As suggested in comments by Amit that you're running into this issue because pattern [a-zA-Z_-]+/ matches original string hungary as well as the target string text-hungary, thus results in a redirect loop.
You may use this rule with a negative lookahead to prevent a redirect loop as you're experiencing in your current rule:
RewriteRule ^places/([a-zA-Z_-]+/)((?!text-)[a-zA-Z_-]+/)([a-zA-Z_-]+/?)$ /places/$1text-$2$3 [R=301,L]
(?!text-) is a negative lookahead condition that will fail the match when $2 starts with text-.
Also note that an unescaped - should be placed at the start or end of a character class [...].
Make sure to clear your browser cache before testing this change.

htaccess RewriteRule regex

I have hundreds of these old links I need to redirect.
Here is one example:
/index.php?option=com_content&view=article&id=433:seventh-character-code-categories-and-icd-10-cm&Itemid=101&showall=1
to
/seventh-character-code-categories-and-icd-10-cm
Essentially I need to remove the /index.php?option=com_content&view=article&id=433: part.
I tried this but I am getting confused with the [0-9] and : parts, so the following does not work:
RewriteRule ^/index.php?option=com_content&view=article&id=[0-9]:(.*)$ /$1 [L,R=301]
Say you want to capture from after : to right before & in the query string you mentioned, then try this expression:
^[^\:]*\:([^\&]*)\&.*$
As #starkeen mentioned in comments, you got to check against the query string. This can be done using RewriteCond %{QUERY_STRING}
So if index.php is in the root folder:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^\/index\.php$
RewriteCond %{QUERY_STRING} ^[^\:]*\:([^\&]*)\&.*$
RewriteRule ^(.*)$ http://example.com/%1 [R=301,L]
Here's another example. This one is for a sub folder:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^\/pages\/index\.php$
RewriteCond %{QUERY_STRING} ^[^\:]*\:([^\&]*)\&.*$
RewriteRule ^(.*)$ /pages/%1? [R=301,L]
Also, notice the ? at the end of the url /pages/%1?, this prevents from re-attaching the query string.
Another thing, captured groups will be set to variables %{number} since set in the RewriteCond.
BTW, depending on your server's configuration, you may need to add the NE flag, like [NE,L,R=301] Plus test whether it is necessary to double escape the literal characters.
what is about direct approach. Skip all till semicolon, mach string till & and replace all with first much
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{QUERY_STRING} [^:]+:([\w-]+[^&]).*
RewriteRule .*$ \/%1? [R=301,L]
</IfModule>

ExpressionEngine mod_rewrite Rule to Redirect URLs with Underscores to Dashes

I'm using ExpressionEngine as my CMS and would like to remove underscores from my site's URLs and replace them with dashes.
For example, I've got a URL that is formatted like this:
http://example.com/index.php/menu/friday-lunch
To remove index.php from the URL, I'm using the following mod_rewrite rule:
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
Which works, since I can just type in: http://example.com/menu/friday-lunch
On the old site I used underscores instead of hyphens for page URIs, so I wrote a mod_rewrite rule to to redirect URIs with underscores to use dashes.
So friday_lunch becomes friday-lunch using the following RewriteRule:
RewriteRule ^([^_]*)_([^_]*_.*) $1-$2 [N]
RewriteRule ^([^_]*)_([^_]*)$ /$1-$2 [L,R=301]
This rule works rather well, except that it 301 Redirects to example.com/index.php/menu/friday-lunch instead of example.com/menu/friday-lunch — notice the addition of index.php.
Here's the entire .htaccess I'm currently using:
<IfModule mod_rewrite.c>
RewriteEngine On
# Removes index.php
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
RewriteRule ^([^_]*)_([^_]*_.*) $1-$2 [N]
RewriteRule ^([^_]*)_([^_]*)$ /$1-$2 [L,R=301]
</IfModule>
How can I redirect all of my URLs with underscores to the equivalent with dashes?
Bonus: to make matters worse, URLs that lead to /system, must not be rewritten with a hyphen, e.g.: example.com/system/login_in/.
Here's a complete set of RewriteRules that should do what you need:
<IfModule mod_rewrite.c>
# Enable Apache's RewriteEngine
RewriteEngine On
# Ignore Matching Directories
RewriteRule ^(images|themes|system) - [L,NC]
# Replace Underscores with Dashes
RewriteRule ^([^_]*)_([^_]*)_(.*)$ /$1-$2-$3 [R=301,L]
RewriteRule ^([^_]*)_(.*)$ /$1-$2 [R=301,L]
# Remove index.php from ExpressionEngine URLs
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
</IfModule>
To have your mod_rewrite rules ignore the ExpressionEngine system folder and not replace underscores _ with dashes - use the following:
RewriteRule ^(images|themes|system) - [L,NC]
Dissecting the RewriteRule into plain English:
The - flag instructions Apache to do nothing, and to not rewrite the URI
The L flags means this should be last rule; ignore everything following
The NC flag means no-case (so "System" or "SYSTEM" is also matched)
This "ignore" rule is especially important and you may need to add additional directories to exclude depending on your directory structure.
Otherwise, you may end up with images and other files saved with underscores that get replaced with dashes.
Note: If your URLs contain more than three underscores, you'll need to add another RewriteRule above the existing ones for each Word Separator for URL Titles you want to replace:
RewriteRule ^([^_]*)_([^_]*)_(.*)_(.*)_(.*)$ /$1-$2-$3-$4-$5 [R=301,L]
RewriteRule ^([^_]*)_([^_]*)_(.*)_(.*)$ /$1-$2-$3-$4 [R=301,L]
You included 'index.php' in your replacement string.
RewriteRule ^(.*)$ index.php/$1 -> RewriteRule ^(.*)$ $1

Help with regular expression with mod_rewrite

I have links like these that I want to change:
mypage.com?page=missions&id=5
mypage.com?page=hello
I tried to change them into easier links with this:
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^([^/]*)/([^/]*)$ /index.php?page=$1&id=$2 [L]
It works but if I want to access pages like (mypage.com?page=hello) I have to write:
mypage.com/hello/
and if I write without the slash in the end like this
mypage.com/hello
it doesn't work.
How do I fix it? :)
This should work:
RewriteRule ^([^/]*)(/([^/]*))?$ /index.php?page=$1&id=$3 [L]
This will make the slash optional by including it in an optional group (denoted by (...)?), along with the optional second half of the query string. Since this introduces a new group between the first and second (left parenthesis determines the order), we have to change the second backreference from $2 to $3.
If the logic becomes much more complex than this, it may be easier to split up the rules.
You could add a second rule that omits the second parameter and optionally the slash:
RewriteRule ^([^/]+)/?$ /index.php?page=$1
RewriteRule ^([^/]+)/(\d+)/?$ /index.php?page=$1&id=$2
This might work too:
RewriteRule ^([^/]+)(?:/(\d+))?/?$ /index.php?page=$1&id=$2
For SEO, you'll probably want to redirect requests missing the slash to the same address with a slash. Use RedirectMatch for that.
I read about the trailing slash with SEO (didn't know about it, thank you mathew!) and the final result was this:
RewriteRule ^([a-zA-Z0-9_-]+)/$ /index.php?page=$1 [L]
RewriteRule ^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/$ /index.php?page=$1&id=$2 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$
RewriteRule (.*)$ http://www.mypage.com/$1/ [R=301,L]
So now I force it to have a trailing slash.