Redirecting specific parameters to subfolders - regex

I've been searching around a bit, but unfortunately I'm still at a loss when it comes to this problem, and being far from a veteran with .htaccess, I've been unable to work out a solution to my problem.
The platform is Wordpress, but since I'm convinced that this issue can be resolved with .htaccess I don't think that that should make much of a difference.
I need to rewrite searches when they are made to a more friendly URL structure, unfortunately, just changing ?s=Test to /search/Test isn't going to cut it. I need to pull 3 of the parameters out of the search and use them as subfolders, and then append the remaining parameters to the end of the search. Here's an example:
Old url:
http://www.XXXXX.com/?s=Ford&z=59105&ci=Billings&st=MT&r=450&m=15000&pmin=1000&pmax=30000&status=Used&submit=Refine
New url:
http://www.XXXXX.com/search/Used/MT/Billings/?s=Ford&z=59105&r=450&m=15000&pmin=1000&pmax=30000&submit=Refine
As you can see, the parameters "status", "st" and "ci" respectively have been inserted into the url with all of the remaining parameters following behind.
So essentially, I need to redirect the old url to the new url, but have the new url display the page that corresponds to the old url.
I've got the following written so far: (EDIT: *Changed {QUERY_STRING} to [L,QSA] as suggested by Explosion Pills*)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?search/([^/]+)/([^/]+)/([^/]+)/?s=([^/]+)?$ /index.php?s=$4&ci=$3&st=$2&status=$1 [L,QSA]
And it kind of works; you can type in the new url and it will display the page, though it seems that the "Used" directory isn't posting data correctly. It's also only half of the puzzle, as it doesn't redirect the old URL to the new one. It simple allows the new URL to exist.
Thank you very much for your help! This one has had me stumped for several days. now.

You may try this in one .htaccess file at root directory:
Options +FollowSymlinks -MultiViews
RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} s=([^&]+)&z=([^&]+)&r=([^&]+)&m=([^&]+)&pmin=([^&]+)&pmax=([^&]+)&submit=([^&]+) [NC]
RewriteCond %{REQUEST_URI} !index\.php [NC]
RewriteRule ^search/([^/]+)/([^/]+)/([^/]+) /index.php?s=%1&z=%2&ci=$3&st=$2&r=%3&m=%4&pmin=%5&pmax=%6&status=$1&submit=%7 [L,NC]
Maps silently:
http://www.XXXXX.com/search/Used/MT/Billings/?s=Ford&z=59105&r=450&m=15000&pmin=1000&pmax=30000&submit=Refine
to
http://www.XXXXX.com/index.php?s=Ford&z=59105&ci=Billings&st=MT&r=450&m=15000&pmin=1000&pmax=30000&status=Used&submit=Refine
For permanent redirection, replace [L,NC] with [R=301,L,NC]

Related

Regex: "Mod Rewrite" everything from a "wildcard" to an address, without changing the address?

I really didn't know how to write the title. I changed it several times before I posted. But feel free to change it to the most appropriate question.
I also can't believe I couldn't find an answer already to this pretty basic thing I wanna to. I searched both here and on Google but couldn't find anything that answered this.
So I have this default WordPress .htaccess code:
# 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
But what I would like to add, is the possibility of having all paths beginning with /cv/ to show the page for /cv/. So like a wildcard after, like /cv/*.
I tried with several versions of this:
RewriteRule /cv/.+ /cv/ - [L]
But none worked. Most things I tried redirected me to the "Couldn't find the page" page. But some just redirected back to /cv/. But I want the whatevers'-after-/cv/ should stay there. So if the address is for example /cv/hello, it should still be /cv/hello in the address but the page showing should be /cv/.
Don't think it should be so difficult. What have I missed?
ok, I set up a test now and got the following commands to work for domain.com/cv/hello
to redirect to domain.com/cv but keep the URL
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_URI} \/cv\/(.+)$ [NC]
# make sure to exit here, if there already was a redirect (to prevent endless redirecting)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^.*$ /cv/%1 [NC,P,R=301,L]
The "magic" is to FollowSymlinks, to use P that tells apache to proxy-pass the redirect, so that the URL remains the same, and to check if there already has been a redirect to the current URL in order to avoid endless redirecting
I solved it temporary (not a nice solution but..) by adding a rewrite rule in my functions file. So that everything from cv/* points to a specific page. In this case page with ID 8472.
/**
* Add Rewrite Rule
*/
function custom_rewrite_basic()
{
add_rewrite_rule('^cv/(.+)/?', 'index.php?page_id=8472', 'top');
remove_action('generate_after_header', 'generate_featured_page_header');
}
add_action('init', 'custom_rewrite_basic');
So, this is just the solution for WordPress. But I don't know. Maybe the other answers on this page would have worked if it wasn't WordPress.

.htaccess URL redirect old link format to new

Recently I've changed the link format to articles on my self-hosted wordpress blog and I want old bookmarks to be able to redirect to the new links seamlessly, so that readers don't get page not found.
The old format was:https://domain.tld/index.php/yyyy/mm/dd/title-of-post
The new format is: https://domain.tld/title-of-post/
I made this change of course because it's a lot nicer and time isn't really a factor for my blog. I'm using Apache's RewriteRule directive in the .htaccess file but I'm having trouble getting the pattern to match. This is the current state of the .htaccess file:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php/[0-9]+/[0-9]+/[0-9]/.*?$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
But previously I've tried such patterns as:
^index\.php/?([-a-zA-Z0-9_+]+)/?([-a-zA-Z0-9_+]+)/?([-a-zA-Z0-9_+]+)/.*?$
and
^index\.php/2018/03/30/.*?$
and even
(index)(\\.)(php)(\\/)(\\d)(\\d)(\\d)(\\d)(\\/)(\\d)(\\d)(\\/)(\\d)(\\d)(\\/)((?:[a-z][a-z]+))
Of which the last I tried to use txt2re
None of this gave me any luck in matching the URL I'm giving it. I want old links to redirect to the new corresponding link.
Instead of modifying your .htaccess its a better idea to use Redirection plugin such as the following,
https://wordpress.org/plugins/redirection/
it will take care of all the redirection for you
This worked for me and many others. Please let me know if this works for you.
Edit:
For your specific case, following rule will work
RedirectMatch 301 ^/index\.php/([0-9]+)/([0-9]+)/([0-9]+)/(.*)$ http://yourdomain.com/$4
You can read more on this rule here,
https://perishablepress.com/redirect-wordpress-date-archives-htaccess/

Htaccess redirect old links to new only if query parameter is present

The old directory structure is being replaced with a new one and the /oldLms directory needs to go. However, for backward compatibility we'd like to still keep those old links active, but redirect them to the new area using htaccess. I have the possibility the place a .htaccess at the root of the site.
Here's a sample "old" link:
http://url.com/oldLms/index.php?auth_regen=1&modname=login&op=confirm&login_user=Hanna&time=1406883178&token=3dd7d9b37b5cc962aa16e9df4acc470a
and a new one:
http://url.com/lms/index.php?r=site/sso&auth_regen=1&modname=login&op=confirm&login_user=Hanna&time=1406883178&token=3dd7d9b37b5cc962aa16e9df4acc470a
Basically the difference is that old ones are handled by
/oldLms/index.php
whereas the new ones are handled by
/lms/index.php?r=site/sso
All other query parameters need to be preserved during the redirect.
However, there is a catch! We only need to redirect links that have the auth_regen=1 parameter. Others should not redirect.
You need following rule as your first rule in root .htaccess:
RewriteEngine On
RewriteCond %{QUERY_STRING} (^|&)auth_regen=1(&|$) [NC]
RewriteRule ^oldLms/(index\.php)$ /lms/$1?r=site/sso [L,NC,QSA,R=302]
You can add rewrite conditions:
RewriteCond %{REQUEST_URI} ^/oldLms$
RewriteCond %{REQUEST_URI} auth_regen=1 # only if this occurs in the URI
RewriteRule /oldLms/.* /lms/$1

Removing a string of characters in a URL through htaccess

I'm struggling to come up with the correct code to do what I need. I've searched through SO and other sites and found answers close to what I want, but I just can't quite piece it all together right, and .htaccess is a huge weakness of mine.
I'm trying to make it so an entire folder level gets removed from all URLs on a site, otherwise preserving the structure. After that, I need to add ".html" to the end. The addition isn't anything hard, but I'm missing what I need to strip out the folder.
Starting URL: www.domain.com/ANYFOLDER/any-page-name
(Bonus: www.domain.com/ANYFOLDER/ANYDEPTH/any-page-name)
Ending URL: www.domain.com/any-page-name.html
We have a client who is moving from a static site to CMS-driven, has some great ranks/traffic for his URLs, and is petrified he will lose this (we will not take Permanent Redirects as a solution).
You can use this rule for this redirect:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(?:[^/]*/)*((?!.+?\.html$)[^/]*)$ /$1.html [L,R=302,NC]

RewriteCond in .htaccess with negated regex condition doesn't work?

I'm trying to prevent, in this case WordPress, from rewriting certain URLs. In this case I'm trying to prevent it from ever handling a request in the uploads directory, and instead leave those to the server's 404 page. So I'm assuming it's as simple as adding the rule:
RewriteCond %{REQUEST_URI} !^/wp-content/uploads/
This rule should evaluate to false and make the chain of rules fail for those requests, thus stopping the rewrite. But no... Perhaps I need to match the cover the full string in my expression?
RewriteCond %{REQUEST_URI} !^/wp-content/uploads/.*$
Nope, that's not it either. So after scratching my head I do a check of sanity. Perhaps something is wrong with the actual pattern. So I make a simple test case.
RewriteCond %{REQUEST_URI} ^/xyz/$
In this case, the rewrite happens if and only if the requested URL is /xyz/ and shows the server's 404 page for any other page. This is exactly what I expected. So I'll just stick in a ! to negate that pattern.
RewriteCond %{REQUEST_URI} !^/xyz/$
Now I'm expecting to see the exact opposite of the above condition. The rewrite should not happen for /xyz/ but for every other possible URL. Instead, the rewrite happens for every URL, both /xyz/ and others.
So, either the use of negated regexes in RewriteConds is broken in Apache, or there's something fundamental I don't understand about it. Which one is it?
The server is Apache2.
The file in its entirety:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/wp-content/uploads/
RewriteRule . /index.php [L]
</IfModule>
WordPress's default file plus my rule.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_URI} !^/wp-content/uploads/ [OR]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
So, after a lot of irritation, I figured out the problem, sort of. As it turned out, the rule in my original question actually did exactly what it was supposed to. So did a number of other ways of doing the same thing, such as
RewriteRule ^wp-content/uploads/.*$ - [L]
(Mark rule as last if pattern matches) or
RewriteRule ^wp-content/uploads/.*$ - [S=1]
(Skip the next rule if pattern matches) as well as the negated rule in the question, as mentioned. All of those rules worked just fine, and returned control to Apache without rewriting.
The problem happened after those rules were processed. Instead, the problem was that I deleted a the default 404.shtml, 403.shtml etc templates that my host provided. If you don't have any .htaccess rewrites, that works just fine; the server will dish up its own default 404 page and everything works. (At least that's what I thought, but in actual fact it was the double error "Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.")
When you do have a .htaccess, on the other hand, it is executed a second time for the 404 page. If the page is there, it will be used, but now, instead the request for 404.shtml was caught by the catch-all rule and rewritten to index.php. For this reason, all other suggestions I've gotten here, or elsewhere, have all failed because in the end the 404 page has been rewritten to index.php.
So, the solution was simply to restore the error templates. In retrospect it was pretty stupid to delete them, but I have this "start from scratch" mentality. Don't want anything seemingly unnecessary lying around. At least now I understand what was going on, which is what I wanted.
Finally a comment to Cecil: I never wanted to forbid access to anything, just stop the rewrite from taking place. Not that it matters much now, but I just wanted to clarify this.
If /wp-content/uploads/ is really the prefix of the requested URI path, your rule was supposed to work as expected.
But as it obviously doesn’t work, try not to match the path prefix of the full URI path but only the remaining path without the contextual per-directory path prefix, in case of the .htaccess file in the document root directory the URI path without the leading /:
RewriteCond $0 !^wp-content/uploads/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .+ /index.php [L]
If that doesn’t work neither, it would certainly help to get some insight into mod_rewrite’s rewriting process by using its logging feature. So set RewriteLogLevel to a level of at least 4, make your request and take a look at the entries in the log file specified with RewriteLog. There you can see how mod_rewrite handles your request and with RewriteLogLevel greater or equal to 4 you will also see the values of variables like %{REQUEST_URI}.
I have found many examples like this when taking a "WordPress First" approach. For example, adding:
ErrorDocument 404 /error-docs/404.html
to the .htaccess file takes care of the message ("Additionally, a 404 Not Found error...").
Came across this trying to do the same thing in a Drupal site, but might be the same for WP since it all goes through index.php. Negating index.php was the key. This sends everything to the new domain except old-domain.org/my_path_to_ignore:
RewriteCond %{REQUEST_URI} !^/my_path_to_ignore$
RewriteCond %{REQUEST_URI} !index.php
RewriteCond %{HTTP_HOST} ^old-domain\.org$ [NC]
RewriteRule ^(.*)$ http%{ENV:protossl}://new-domain.org/$1 [L,R=301]