Search code examples
phpapache.htaccessurl-rewritingseo

htaccess to rewrite url in order to remove php extension only at the root directory and not in subdirectories


I have a website composed as follows:

index.php
page1.php
page2.php
page3.php
 - images
   image1.jpg
   image2.jpg
 - style
   style.css

I want to write an htaccess file which can give me SEO friendly URL. In example:

  • https://example.com/page2.php should be https://example.com/page2

and also:

  • https://example.com/page2.php#mytab should be https://example.com/page2#mytab

But I would like to apply those rules only on the first directory, so "images" and "style" dirs can continue to be reached using the extensions.

Can somebody help? Thanks


Solution

    1. You should already be linking to the files without the .php extension on your internal URLs (ie. href="/page1", not href="/page1.php"). I'm also assuming that your URLs don't otherwise contain dots (which normally delimits the file extension).

    2. Implement a rewrite to append the .php extension if required. This needs to go near the top of the root .htaccess file:

      RewriteEngine On
      
      # Internally rewrite extenionless URLs to append ".php" if required
      # Tests only requests (that do not contain a dot) in the root directory
      RewriteCond %{DOCUMENT_ROOT}/$1.php -f
      RewriteRule ^([^./]+)$ $1.php [L]
      

      Alternative for the RewriteCond (filesystem check):

      RewriteCond %{REQUEST_FILENAME}.php -f
      :
      

      Alternatively, you could remove the RewriteCond directive altogether to unconditionally rewrite all requests in the root (without a file extension) to append the .php extension.

    3. (OPTIONAL) If you are changing a URL structure and removing .php from your URLs and the old URLs have been indexed by search engines and/or linked to by third parties then you need to also implement a redirect to remove the .php extension for SEO.

      Add the following immediately after the RewriteEngine directive above (before the internal rewrite):

      # Redirect to remove the `.php` extension inbound requests
      # Only affects the root directory
      RewriteCond %{ENV:REDIRECT_STATUS} ^$
      RewriteRule ^([^./]+)\.php$ /$1 [R=301,L]
      

      The condition that tests against the REDIRECT_STATUS environment variable ensures we don't redirect already rewritten requests by the later rewrite and this avoiding a redirect loop.

      NB: Test first with a 302 (temporary) redirect to avoid potential caching issues.

    4. Alternatively (instead of #3), to prevent direct access to the .php file and serve a 404 Not Found instead then add the following immediately after the RewriteEngine directive above (before the internal rewrite):

      # Prevent direct access to ".php" file and serve a 404 instead
      # Only affects the root directory
      RewriteCond %{ENV:REDIRECT_STATUS} ^$
      RewriteRule ^([^./]+)\.php$ - [R=404]
      

    what is the best way to show the content of my custom 404 page every time a 404 error occurs? (I would not like to use redirect)

    Use the following at the top of the .htaccess file, passing the full URL-path to the ErrorDocument directive.

    ErrorDocument 404 /error-docs/e404.php
    

    The stated error document is called using an internal subrequest (there is no external redirect).

    Note that this should include the .php file extension here - this is entirely invisible to the user.