2

In May of 2016, I implemented several redirects on a client site using .htaccess. The client verified that all of the .htaccess redirects were working to their satisfaction before we closed out the project.

This week, I was notified by the client that these redirects no longer work. They don't know when this began to fail and, after a few hours of research, I can't find any reason why they wouldn't continue to work.

The client does not want to use a plugin for this.

I'm including the .htaccess file for review and suggestions.

# Disable XMLRPC
<Files "xmlrpc.php">
Order Deny,Allow
Deny from all
</Files>
# End Disable XMLRPC

# Force HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Redirects
# Change "www" to "www" when moved to live
RedirectMatch 301 ^/watermeloncakes/ //www.clienturl.com/watermelon-cakes-1/
RedirectMatch 301 ^/watermelon-cakes/ //www.clienturl.com/watermelon-cakes-1/
RedirectMatch 301 ^/edible-arrangements-coupons/ //www.clienturl.com/fruit-arrangements-coupons/
RedirectMatch 301 ^/edible-arrangements/ //www.clienturl.com/fruit-arrangements/
RedirectMatch 301 ^/edible-arrangements-5-reasons/ //www.clienturl.com/fruit-arrangements-5-reasons/
RedirectMatch 301 ^/candy/ //www.clienturl.com/blog/christmas-candy-platters
RedirectMatch 301 ^/candy //www.clienturl.com/blog/christmas-candy-platters
RedirectMatch 301 ^/pumpkin-carving-instruction-ray-villafane/ //www.clienturl.com/blog/shop/ray-villafanes-3d-pumpkin-carving/
RedirectMatch 301 ^/4thofjulyideas/ //www.clienturl.com/4th-of-july-ideas/
RedirectMatch 301 ^/pumpkin-carving-tattoos/ //www.clienturl.com/blog/shop/pumpkin-carving-patterns-tattoos/
RedirectMatch 302 ^/transfer-pattern-paper-carving-pumpkins-watermelons/ //www.clienturl.com/blog/product-category/patterns-and-transfer-papers/
RedirectMatch 302 ^/u-and-v-fruit-carving-tools/ //www.clienturl.com/blog/shop/u-v-fruit-carving-tools/
RedirectMatch 302 ^/fruit-carving-knife-set/ //www.clienturl.com/blog/shop/kom-kom-fruit-carving-knife-set/
RedirectMatch 302 ^/thai-pro-fruit-carving-knife/ //www.clienturl.com/blog/shop/thai-pro-carving-knife/
RedirectMatch 302 ^/13-pc-fruit-carving-tools/ //www.clienturl.com/blog/shop/pro-fruit-carving-tools-13-piece/
RedirectMatch 302 ^/corrugated-u-cutters-and-melon-baller/ //www.clienturl.com/blog/shop/corrugated-u-cutters/
RedirectMatch 301 ^/shop/ //www.clienturl.com/blog/shop/
RedirectMatch 301 ^/pp-resources/ //www.clienturl.com/blog/pumpkin-portraits-resources-members/
RedirectMatch 301 ^/dvd-lessons-and-tool-sets/ //www.clienturl.com/blog/shop/
RedirectMatch 301 ^/message-sent-success/ //www.clienturl.com/blog/your-message-successfully-sent/
RedirectMatch 301 ^/which-lessons-tools-for-you/ //www.clienturl.com/blog/best-lessons-for-you/
RedirectMatch 301 ^/fabric //www.clienturl.com/blog/shop/pattern-transfer-fabric/
RedirectMatch 301 ^/101 //www.clienturl.com/vegetable-and-fruit-carving-course-101
RedirectMatch 301 ^/weave //www.clienturl.com/blog/shop/melon-basket-weave/
RedirectMatch 301 ^/twirl //www.clienturl.com/blog/shop/twisty-twirl-tool/
RedirectMatch 301 ^/vegcurl //www.clienturl.com/blog/shop/vegetable-curler/
RedirectMatch 301 ^/wavy //www.clienturl.com/blog/shop/wavy-peeler/

#IndexIgnore .htaccess */.??* *~ *# */HEADER* */README* */_vti*

#<Limit GET POST>
#The next line modified by DenyIP
#order allow,deny
#The next line modified by DenyIP
#deny from all
#allow from all
#</Limit>
#<Limit PUT DELETE>
#order deny,allow
#deny from all
#</Limit>
#AuthName vegetablefruitcarving.com

# stop hotlinking and serve alternate content
# <IfModule mod_rewrite.c>
# RewriteEngine on
# RewriteCond %{HTTP_REFERER} !^$
# RewriteCond %{HTTP_REFERER} !^http://(www\.)?vegetablefruitcarving\.com/.*$ [NC]
# RewriteCond %{HTTP_REFERER} !^https://(www\.)?vegetablefruitcarving\.com/.*$ [NC]
# RewriteCond %{HTTP_REFERER} !^http://(www\.)?sbox\.vegetablefruitcarving\.com/.*$ [NC]
# RewriteCond %{HTTP_REFERER} !^http://(www\.)?twitter\.com/.*$ [NC]
# RewriteCond %{HTTP_REFERER} !^https://(www\.)?twitter\.com/.*$ [NC]
# RewriteCond %{HTTP_REFERER} !^http://(www\.)?facebook\.com/.*$ [NC]
# RewriteCond %{HTTP_REFERER} !^https://(www\.)?facebook\.com/.*$ [NC]
# RewriteCond %{HTTP_REFERER} !^http://(www\.)?pinterest\.com/.*$ [NC]
# RewriteCond %{HTTP_REFERER} !^https://(www\.)?pinterest\.com/.*$ [NC]
# RewriteCond %{HTTP_REFERER} !^http://(www\.)?youtube\.com/.*$ [NC]
# RewriteCond %{HTTP_REFERER} !^https://(www\.)?youtube\.com/.*$ [NC]
# RewriteCond %{HTTP_REFERER} !^http://(www\.)?flickr\.com/.*$ [NC]
# RewriteCond %{HTTP_REFERER} !^https://(www\.)?flickr\.com/.*$ [NC]
# RewriteCond %{HTTP_REFERER} !^http://(www\.)?plus.google\.com/.*$ [NC]
# RewriteCond %{HTTP_REFERER} !^https://(www\.)?plus.google\.com/.*$ [NC]
# RewriteRule .*\.(gif|jpg|png|pdf)$ //altlab.com/hotlinking.html [R,NC,L]
# </ifModule>

<Files 403.shtml>
order allow,deny
allow from all
</Files>

deny from 79.29.221.71

# BEGIN WPSuperCache
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
#If you serve pages from behind a proxy you may want to change 'RewriteCond %{HTTPS} on' to something more sensible
AddDefaultCharset UTF-8
RewriteCond %{REQUEST_URI} !^.*[^/]$
RewriteCond %{REQUEST_URI} !^.*//.*$
RewriteCond %{REQUEST_METHOD} !POST
RewriteCond %{QUERY_STRING} !.*=.*
RewriteCond %{HTTP:Cookie} !^.*(comment_author_|wordpress_logged_in|wp-postpass_).*$
RewriteCond %{HTTP:X-Wap-Profile} !^[a-z0-9\"]+ [NC]
RewriteCond %{HTTP:Profile} !^[a-z0-9\"]+ [NC]
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{HTTPS} on
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/supercache/%{SERVER_NAME}/$1/index-https.html.gz -f
RewriteRule ^(.*) "/wp-content/cache/supercache/%{SERVER_NAME}/$1/index-https.html.gz" [L]

RewriteCond %{REQUEST_URI} !^.*[^/]$
RewriteCond %{REQUEST_URI} !^.*//.*$
RewriteCond %{REQUEST_METHOD} !POST
RewriteCond %{QUERY_STRING} !.*=.*
RewriteCond %{HTTP:Cookie} !^.*(comment_author_|wordpress_logged_in|wp-postpass_).*$
RewriteCond %{HTTP:X-Wap-Profile} !^[a-z0-9\"]+ [NC]
RewriteCond %{HTTP:Profile} !^[a-z0-9\"]+ [NC]
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{HTTPS} !on
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/supercache/%{SERVER_NAME}/$1/index.html.gz -f
RewriteRule ^(.*) "/wp-content/cache/supercache/%{SERVER_NAME}/$1/index.html.gz" [L]

RewriteCond %{REQUEST_URI} !^.*[^/]$
RewriteCond %{REQUEST_URI} !^.*//.*$
RewriteCond %{REQUEST_METHOD} !POST
RewriteCond %{QUERY_STRING} !.*=.*
RewriteCond %{HTTP:Cookie} !^.*(comment_author_|wordpress_logged_in|wp-postpass_).*$
RewriteCond %{HTTP:X-Wap-Profile} !^[a-z0-9\"]+ [NC]
RewriteCond %{HTTP:Profile} !^[a-z0-9\"]+ [NC]
RewriteCond %{HTTPS} on
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/supercache/%{SERVER_NAME}/$1/index-https.html -f
RewriteRule ^(.*) "/wp-content/cache/supercache/%{SERVER_NAME}/$1/index-https.html" [L]

RewriteCond %{REQUEST_URI} !^.*[^/]$
RewriteCond %{REQUEST_URI} !^.*//.*$
RewriteCond %{REQUEST_METHOD} !POST
RewriteCond %{QUERY_STRING} !.*=.*
RewriteCond %{HTTP:Cookie} !^.*(comment_author_|wordpress_logged_in|wp-postpass_).*$
RewriteCond %{HTTP:X-Wap-Profile} !^[a-z0-9\"]+ [NC]
RewriteCond %{HTTP:Profile} !^[a-z0-9\"]+ [NC]
RewriteCond %{HTTPS} !on
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/supercache/%{SERVER_NAME}/$1/index.html -f
RewriteRule ^(.*) "/wp-content/cache/supercache/%{SERVER_NAME}/$1/index.html" [L]
</IfModule>

# END WPSuperCache

# 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
1
  • Can you confirm the URL you are requesting and the resulting "non-working" redirect you are seeing (if any).
    – MrWhite
    Commented Nov 10, 2018 at 1:52

2 Answers 2

1
RedirectMatch 301 ^/watermeloncakes/ //www.clienturl.com/watermelon-cakes-1/

(I assuming www.clienturl.com is the hostname for this site.)

Well, here's the thing... this would never have worked on any version of Apache!? Because protocol-relative URLs are not supported by mod_alias RedirectMatch (or Redirect) or mod_rewrite for that matter.

From the Apache docs:

The new URL may be either an absolute URL beginning with a scheme and hostname, or a URL-path beginning with a slash. In this latter case the scheme and hostname of the current server will be added.

A protocol-relative URL such as //www.clienturl.com/watermelon-cakes-1/ will simply be seen as root-relative ("a URL-path beginning with a slash"), so the above directive would result in a malformed redirect to:

https://www.clienturl.com//www.clienturl.com/watermelon-cakes-1/

It's possible that another redirect later corrected this (perhaps in WordPress itself)!? But there is no evidence of this in your .htaccess file.

It is Apache that constructs this absolute URL when it creates the Location header to send back to the client. It doesn't send back a protocol-relative URL and expect the client to resolve it (which you could do if you manually assigned a value to the Location header in your server-side script).

If these directives ever worked, then it looks like someone has either removed the protocol (https: or http:?) from the target URL, or added the hostname (//www.clienturl.com)? Is it possible that these were initially redirects to http: and someone thought they'd try to avoid the "double redirect" (since you are forcing HTTPS) by making them "protocol relative"?

The above directive would need to either use a full absolute URL:

RedirectMatch 301 ^/watermeloncakes/ https://www.clienturl.com/watermelon-cakes-1/

Or use a root-relative URL:

RedirectMatch 301 ^/watermeloncakes/ /watermelon-cakes-1/

Use mod_rewrite instead

However, you should really be using mod_rewrite RewriteRule for these redirects instead of a mod_alias RedirectMatch (or Redirect) directive. Simply because you should avoid mixing redirects/rewrites from both modules and you are already using mod_rewrite throughout your .htaccess file - WordPress itself uses mod_rewrite to implement its front-controller model.

For example:

RewriteRule ^watermeloncakes/ /watermelon-cakes-1/ [R=301,L]

(There is no need to repeat the RewriteEngine directive.)

Apache modules execute independently and at different times throughout the request. mod_rewrite executes before mod_alias, regardless of the apparent order of the directives in the .htaccess file. You could, for instance, place all the RedirectMatch directives at the end of the file and it would make no difference to the execution order.

So, by mixing redirects from both modules you can end up with unexpected conflicts, since mod_rewrite will always take priority, regardless of the order. But also, all the mod_rewrite directives are being processed first, before the mod_alias redirects - everything is being processed on every request (regardless of whether there is a redirect or not). If you use mod_rewrite then the redirect occurs immediately and the remaining directives are bypassed.

Use WordPress instead (preferable)

However, since all these redirects look as if they are probably just correcting URLs, URLs that would otherwise trigger 404s then it would be preferable to perform these redirects in your server-side code (ie. WordPress) instead. For example, once WordPress has determined the URL would result in a 404, then check your redirects. Doing it this way avoids any of the redirect code "slowing down" normal site usage.

4
  • This is a far better answer, even I have learned something from it! Thank you, I have upvoted yours. Commented Nov 10, 2018 at 6:15
  • Thank you for your thoughtful reply, @MrWhite. It is most likely that your instincts about this were right. "If these directives ever worked, then it looks like someone has either removed the protocol (https:) from the target URL, or added the hostname (//www.clienturl.com)? " The client added another layer of confusion with Cloud Flare subsequent to the .htaccess work. After tweaking some settings there, all is well with our redirect world.
    – Marj Wyatt
    Commented Nov 11, 2018 at 17:19
  • So, presumably, you added the https: prefix back to the target URLs (or removed the hostname) to get the redirects to work? Just a thought, is it possible that these were originally implemented as redirects to http:? And someone tried to edit the directives to avoid the double (or even triple) redirect (since you are forcing HTTPS)?
    – MrWhite
    Commented Nov 11, 2018 at 18:24
  • @MrWhite - My client independently implemented CloudFlare. Despite the fact that I have a login for that account, I leave it to her to communicate with CloudFlare and make changes recommended by them. In other words, I don't know exactly what was done to make the redirects work again nor what caused them to fail to begin with. Thanks again for your thoughtful response.
    – Marj Wyatt
    Commented Nov 12, 2018 at 17:45
0

Enable the Apache mod_rewrite module.
And enable the ReWriteEngine in the mod_rewrite module.

Below an example of how to use RewriteRule:

# Turning on the rewrite engine is necessary for the following rules and
# features. "+FollowSymLinks" must be enabled for this to work symbolically.

<IfModule mod_rewrite.c>
Options +FollowSymLinks
RewriteEngine on

RewriteRule ^panda$ /tiger [R=301,L]
RewriteRule ^house$ /car [R=301,L]
RewriteRule ^monkey$ /deer [R=301,L]
</IfModule>

Also some other advice, I see you're using WP Super Cache and I would like to recommend WP Fastest Cache this is one of the best free caching plugins out there. See: https://wordpress.org/plugins/wp-fastest-cache/

And if your theme supports this, you could use this in combination with Fast Velocity Minify see: https://wordpress.org/plugins/fast-velocity-minify/

With this combination, our company website tend to score almost a perfect 100 on gtmetrix.com, using WP Fastest Cache and Fast Velocity Minify

Also, keep things simple, there is also a plugin called Redirection who is doing the same thing you're trying to achieve. I highly recommend this plugin for any redirect: https://wordpress.org/plugins/redirection/

2
  • "...avoid using RedirectMatch, because it's too sophisticated" - It's the other way round: RewriteRule (mod_rewrite) is far more "sophisticated" than RedirectMatch (mod_alias). But that isn't why mod_rewrite should be used in this instance. It's simply that mod_rewrite is already being used here and it is advisable not to mix rewrites/redirects from both modules in the same context.
    – MrWhite
    Commented Nov 10, 2018 at 1:33
  • @MrWhite Okay I didn't know that. Commented Nov 10, 2018 at 6:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.