I have a single index.php
file in a /slug
subdirectory and would like to load dynamic content based on the file path. Regardless of what the url is, the content should reference that index.php
.
In my code below, the slash is not being added at the end of the url. For example, example.com/slug/33
should be displayed in the address bar as example.com/slug/33/
.
I have the following .htaccess in /slug
:
Options -Indexes
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /
# Dynamic url
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /slug/index.php/?path=$1 [NC,L,QSA]
I tried adding a /
between index.php
and ?path=$
but I'm not getting the desired result. Is this even possible?
CodePudding user response:
RewriteRule ^(.*)$ /slug/index.php/?path=$1 [NC,L,QSA]
Changing the substitution string here changes the target of your internal rewrite - it does nothing to change the visible URL. By adding a slash after index.php
you are (unnecessarily) adding additional pathname information (path-info) to the resulting URL that your application receives.
To change the visible URL (to append the slash) you need to implement an external redirect. However, to confirm... you must already be linking to the correct canonical URL (ie. with a slash) in your internal links. Appending the slash to the URL in .htaccess
is only if you have changed the URL and search engines or 3rd parties are still using the old non-canonical URL (without a trailing slash).
Since the .htaccess
file is in the /slug
subdirectory and you are rewriting to index.php
in that subdirectory then you don't need to prefix the rewritten URL with /slug/
. By default, a relative URL-path is relative to the directory that contains the .htaccess
file. However, you must also remove the RewriteBase
directive (or set this "correctly" to RewriteBase /slug
).
To redirect to append a trailing slash you can add the following before the current rewrite:
# Append trailing slash if omitted
RewriteRule ^(.*(?:^|/)[^/.] )$ /slug/$1/ [R=301,L]
This requires the /slug/
prefix on the substitution string (unless RewriteBase /slug
is set), otherwise the external redirect will attempt to redirect to a file-path, which will "break".
The RewriteRule
pattern ^(.*(?:^|/)[^/.] )$
captures URL-paths that do not already end in a slash and do not contain a dot in the last path segment. This is to avoid matching URLs that already contain (what looks-like) a file extension, ie. your static resources (images, CSS, JS, etc.). This should avoid the need for a filesystem check (which are relatively expensive) - to check that the request does not already map to a file. Although, if you are not referencing any static resources with the /slug/
prefix in the URL then this can be simplified.
NB: You should first test with a 302 (temporary) redirect to avoid potential caching issues.
In context (with the use of RewriteBase
):
Options -Indexes
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /slug
# Append trailing slash if omitted
RewriteRule ^(.*(?:^|/)[^/.] )$ $1/ [R=301,L]
# Dynamic url
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (. ) index.php?path=$1 [QSA,L]
The use of RewriteBase
avoids you having to specify /slug/
in the other directives.
In the regex ^(.*)$
, the start-of-string (^
) and end-of-string ($
) anchors are superfluous. And you might as well change this to use the
quantifier, since you don't want to match the base directory anyway (saves two additional filesystem checks). The NC
flag was also superfluous here.