Ad

How Do I Simply Add A Forward Slash "/" To A Redirect Rule And Keep The UTM/Google Tracking Parameters

We have been having issues where the Google Tracking codes get dropped because the SEO/SEM group are not using the proper URL and WordPress is adding a forward slash "/" and by doing this redirect it drops the codes.

Is there a way to add a rewrite rule that adds the forward slash AND keeps the existing UTM codes?

The problem I have been having is two-fold:

  1. We have several different pages that this occurs on, so the slug is different.
  2. I do not know the exact pattern of the UTM order because I am not in control of the advertising side. But they keep blaming my site.

example.com/page1?utm_source=... needs to redirect to example.com/page1/?utm_source...

# Use UTF-8 encoding for anything served text/plain or text/html
AddDefaultCharset UTF-8
# Force UTF-8 for a number of file formats
<IfModule mod_mime.c>
AddCharset UTF-8 .atom .css .js .json .rss .vtt .xml
</IfModule>
# FileETag None is not enough for every server.
<IfModule mod_headers.c>
Header unset ETag
</IfModule>
# Since we’re sending far-future expires, we don’t need ETags for static content.
# developer.yahoo.com/performance/rules.html#etags
FileETag None
# Send CORS headers if browsers request them; enabled by default for images.
<IfModule mod_setenvif.c>
<IfModule mod_headers.c>
# mod_headers, y u no match by Content-Type?!
<FilesMatch "\.(cur|gif|png|jpe?g|svgz?|ico|webp)$">
SetEnvIf Origin ":" IS_CORS
Header set Access-Control-Allow-Origin "*" env=IS_CORS
</FilesMatch>
</IfModule>
</IfModule>
# Allow access to web fonts from all domains.
<FilesMatch "\.(eot|otf|tt[cf]|woff2?)$">
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
</FilesMatch>
<IfModule mod_alias.c>
<FilesMatch "\.(html|htm|rtf|rtx|txt|xsd|xsl|xml)$">
<IfModule mod_headers.c>
Header set X-Powered-By "WP Rocket/3.4.3"
Header unset Pragma
Header append Cache-Control "public"
Header unset Last-Modified
</IfModule>
</FilesMatch>
<FilesMatch "\.(css|htc|js|asf|asx|wax|wmv|wmx|avi|bmp|class|divx|doc|docx|eot|exe|gif|gz|gzip|ico|jpg|jpeg|jpe|json|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mpe|mpp|otf|odb|odc|odf|odg|odp|ods|odt|ogg|pdf|png|pot|pps|ppt|pptx|ra|ram|svg|svgz|swf|tar|tif|tiff|ttf|ttc|wav|wma|wri|xla|xls|xlsx|xlt|xlw|zip)$">
<IfModule mod_headers.c>
Header unset Pragma
Header append Cache-Control "public"
</IfModule>
</FilesMatch>
</IfModule>
# Expires headers (for better cache control)
<IfModule mod_expires.c>
    ExpiresActive on
    # Perhaps better to whitelist expires rules? Perhaps.
    ExpiresDefault                              "access plus 1 month"
    # cache.appcache needs re-requests in FF 3.6 (thanks Remy ~Introducing HTML5)
    ExpiresByType text/cache-manifest           "access plus 0 seconds"
    # Your document html
    ExpiresByType text/html                     "access plus 0 seconds"
    # Data
    ExpiresByType text/xml                      "access plus 0 seconds"
    ExpiresByType application/xml               "access plus 0 seconds"
    ExpiresByType application/json              "access plus 0 seconds"
    # Feed
    ExpiresByType application/rss+xml           "access plus 1 hour"
    ExpiresByType application/atom+xml          "access plus 1 hour"
    # Favicon (cannot be renamed)
    ExpiresByType image/x-icon                  "access plus 1 week"
    # Media: images, video, audio
    ExpiresByType image/gif                     "access plus 4 months"
    ExpiresByType image/png                     "access plus 4 months"
    ExpiresByType image/jpeg                    "access plus 4 months"
    ExpiresByType image/webp                    "access plus 4 months"
    ExpiresByType video/ogg                     "access plus 1 month"
    ExpiresByType audio/ogg                     "access plus 1 month"
    ExpiresByType video/mp4                     "access plus 1 month"
    ExpiresByType video/webm                    "access plus 1 month"
    # HTC files  (css3pie)
    ExpiresByType text/x-component              "access plus 1 month"
    # Webfonts
    ExpiresByType font/ttf                      "access plus 4 months"
    ExpiresByType font/otf                      "access plus 4 months"
    ExpiresByType font/woff                     "access plus 4 months"
    ExpiresByType font/woff2                    "access plus 4 months"
    ExpiresByType image/svg+xml                 "access plus 1 month"
    ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
    # CSS and JavaScript
    ExpiresByType text/css                      "access plus 1 year"
    ExpiresByType application/javascript        "access plus 1 year"
</IfModule>
# Gzip compression
<IfModule mod_deflate.c>
# Active compression
SetOutputFilter DEFLATE
# Force deflate for mangled headers
<IfModule mod_setenvif.c>
<IfModule mod_headers.c>
SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
# Don’t compress images and other uncompressible content
SetEnvIfNoCase Request_URI \
\.(?:gif|jpe?g|png|rar|zip|exe|flv|mov|wma|mp3|avi|swf|mp?g|mp4|webm|webp|pdf)$ no-gzip dont-vary
</IfModule>
</IfModule>
# Compress all output labeled with one of the following MIME-types
<IfModule mod_filter.c>
AddOutputFilterByType DEFLATE application/atom+xml \
                                  application/javascript \
                                  application/json \
                                  application/rss+xml \
                                  application/vnd.ms-fontobject \
                                  application/x-font-ttf \
                                  application/xhtml+xml \
                                  application/xml \
                                  font/opentype \
                                  image/svg+xml \
                                  image/x-icon \
                                  text/css \
                                  text/html \
                                  text/plain \
                                  text/x-component \
                                  text/xml
</IfModule>
<IfModule mod_headers.c>
Header append Vary: Accept-Encoding
</IfModule>
</IfModule>
# END WP Rocket
# BEGIN GD-SSL
<IfModule mod_rewrite.c>
Options +FollowSymLinks
RewriteEngine ON
RewriteCond %{HTTPS} On
RewriteCond %{HTTP_USER_AGENT} ^(.+)$
RewriteCond %{SERVER_NAME} ^handylockselfstorage\.com$
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,QSA]
Header add Strict-Transport-Security "max-age=300"
</IfModule>
# END GD-SSL

# BEGIN Imagify: webp file type
<IfModule mod_mime.c>
    AddType image/webp .webp
</IfModule>
# END Imagify: webp file type
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L,NE]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L,NE]
</IfModule>
# END WordPress
# BEGIN GA
RewriteEngine On
RewriteRule ^([\w-]+)$ /$1/ [R=302,L]
# END GA```
Ad

Answer

Assuming you have a single path segment that can consist of the characters a-z, A-Z, 0-9, _ (underscore) and - (hyphen).

Try something like the following near the top of your .htaccess file, before the existing WordPress front-controller:

RewriteRule ^([\w-]+)$ /$1/ [R=302,L]

This directive matches against the URL-path only, not the query string. Whatever query string (eg. utm_source=...) is present on the request (if any) is passed through to the target URL by default - there is nothing extra you need to do to enable this.

Only change the 302 (temporary) redirect to 301 (permanent) - if that is the intention - once you have confirmed that it works Ok.

UPDATE: Having looked at your updated .htaccess file it seems you've put the directives in the wrong place. As mentioned above, this needs to go "near the top of your .htaccess file, before the existing WordPress front-controller". However, you have put it at the very end, after the WP front-controller. (The WP front-controller is the code block between the # BEGIN WordPress .. # END WordPress comment markers).

(In fact, I'm surprised the directive would have done anything by placing it at the very end of the file?!)

Putting this directive immediately before the # BEGIN WordPress line should be sufficient.


Aside:

RewriteCond %{HTTPS} On
RewriteCond %{HTTP_USER_AGENT} ^(.+)$
RewriteCond %{SERVER_NAME} ^handylockselfstorage\.com$
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,QSA]

What is this supposed to be doing? It looks like it should perhaps be an HTTP to HTTPS redirect, however, it's not doing anything by the looks. In fact, it is very close to triggering a redirect loop, had you used on, instead of On in the first condition. I would expect the first condition to always fail since HTTPS is either on or off, not On (case-sensitive comparison).

Ad
source: stackoverflow.com
Ad