0

I've been trying to wrap my head around .htaccess for most of the weekend, but I keep stumbling; I can get the server to work with one set of rules, but no more than one at a time.

My application is made up of several pages:

  • The Homepage pulls in content from the Detail page, (as well as content that the Detail page doesn't include), with an optional query string argument; e.g. ?s=item-name
  • The Detail page pulls in content with an optional query string argument (the same argument as the homepage; e.g. ?s=item-name - this would refer to exactly the same content)
  • A Collection page
  • A Related page

Each of these pages is a php file in the document root (index.php, detail.php, collection.php, related php).

What I would like to achieve:

  • The user should be able to go to mydomain.com/detail/ or mydomain.com/detail (so allow trailing slashes) instead of mydomain.com/details.php
  • If present, the query string argument (?s=item-name) should be entered after the page's trailing slash (so mydomain.com/item-name instead of mydomain.com/?s=item-name; mydomain.com/detail/item-name instead of mydomain.com/detail.php?s=item-name. This would be the case for all pages, so setting the rule on one page at a time seems rather cumbersome...

This is what my .htaccess file looks like at present, after much fiddling:

<IfModule mod_rewrite.c>  
    RewriteEngine on
    RewriteBase /
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php?s=$1 [L]
</IfModule>

This allows the homepage to pull in the correct content, and I'm sure it's not too far off allowing any page to do the same, but I can't quite fathom it.

Can anyone help?

MassivePenguin
  • 3,701
  • 4
  • 24
  • 46

1 Answers1

1
RewriteEngine On
RewriteBase /

# Specifics
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} ^/([^/]+)/(.+)/?$
RewriteCond %{DOCUMENT_ROOT}/%1.php -f
RewriteRule ^ %1.php?s=%2 [L]

# EDIT 1: This will also check for root pages. See notes below
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ([^/]+)/ $1 [R=301,L]
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule (.+) $1.php [L,QSA]

# Everything else
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?s=$1 [L]

Explanation:

  1. First, we check that the full REQUEST_FILENAME does not exist.
  2. Then, we check to see that the format is as follows: /<something-without-slash>/<everything else> (with an optional trailing slash).
  3. We then check to see if our first condition-capture exists as a PHP file in the document root. For example, if we request foo/bar, it would check to see if /foo.php exists.
  4. Then we simply route the request to the correct file, with the correct query string.

So, in your case, when you request detail/item-name, the server would actually be looking at detail.php?s=item-name to provide you with a response.

Note: If it does not exist, the request will simply send the request to index.php.

Edit: Have added detection for root pages. Note, however, that I cannot get it to leave a slash for this kind of detection as it automatically amends .php to the empty s query paramater. Not sure why... This is why when it reaches this stage, it will remove any trailing slashes. This is also good for SEO ratings/rankings as it is seen as one page, and not two duplicates.

Mike Rockétt
  • 8,947
  • 4
  • 45
  • 81