Search code examples
apache.htaccessmod-rewrite

Remove .php extension in .htaccess with already working friendly-url RewriteRule


I tried hundreds of answers from this site (questions from other users) but these answers did not worked in my case.

My website is using slugs to display seo-friendly urls and that part is working fine. But I would also like to have some NON dynamic links /static links like this:

example.com/contact.php to be displayed/linked without the .php extension, for example example.com/contact

But nothings seems to work, and after 12 hours this .htaccess is driving me crazy.

Here is what I have done until now

RewriteEngine On

#this is the part for see-friendly urls, this part is working
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([-/.a-zA-Z0-9]+)$ en.php?slug=$1 [QSA,L] 

#this is the part to remove php extension, this part is NOT working
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php [L]

Any idea?

EDIT I am linking the users like this example.com/contact but I get error 404


Solution

  • The important thing to remember is that a rewrite rule doesn't "display a pretty URL", it reads the URL sent by the browser, and decides what to do with it. Thinking about "removing the .php from the URL" will put you in the wrong frame of mind.

    What you need to be asking is, if the browser sends a URL of "/contact", how should the server decide what page to show - is it "/en.php?slug=contact", or is it "/contact.php"?

    The other thing to remember is that order of rules in the file matters - if the URL coming in matches the first rule in the file, the server doesn't keep looking down the file for a "better" match. (This is particularly true in this example, since your first rule has the flag "L" for "last"; if that wasn't there, it would be possible for a rule to match the new URL, but it still wouldn't be instead of the original rule.)

    So the solution in this case is simply to change the order of rules in the file: first put the section to check if there's a PHP file called "contact.php", and then only if that rule didn't match the server will reach the section that says to use "contact" as a slug.