I am setting up a cache system for my blog (not a WordPress) and I want to store the cached files in a posts/
folder, so I don’t fill my root folder with post files.
I have a file called post.php
that creates these posts files if the slug corresponds to an actual post in a different website (I check this with WordPress REST API). So when I visit mywebsite.com/slug-to-post
and this URL doesn’t match any of my files on the root level, it fallbacks to post.php
using FallbackResource post.php
in .htaccess
, and post.php
uses this slug to create a cached version and stores it, but since there can be thousands of posts, I don’t want the files to be stored in the root level, but in posts/name-of-the-file
.
So that file would be accessed via mywebsite.com/posts/slug-to-post
but for SEO purposes I still want it to be mywebsite.com/slug-to-post
.
What should I write in my .htaccess to fallback any unknown file to the posts/
folder, and if the file doesn’t exists there, fallback again to post.php
, which is stored on root level?
Nothing I’ve tried has worked so far. To cache the files I’m using the code present here: https://phppot.com/php/php-cache-for-dynamic-web-pages/
UPDATE: This is my current .htaccess
file:
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME}.php -f RewriteRule ^(.*)$ $1.php [NC,L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{DOCUMENT_ROOT}/posts/$1 -f RewriteRule ^([^/]+.php)$ /posts/$1 [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^[^/]+.php$ post.php [L]
Advertisement
Answer
You are requesting a file of the form /<post-slug>
, which either:
Maps to a file of the form
/<post-slug>.php
in the document root.OR, maps to a cached version of this file of the form
/posts/<post-slug>.php
.Otherwise, the request should fallback to
/post.php
in the document root.
Try something like the following (using mod_rewrite) in addition to your FallbackResource
directive:
# Disable MultiViews Options -MultiViews RewriteEngine On # 1. Check for file in the document root RewriteCond %{DOCUMENT_ROOT}/$1.php -f RewriteRule ^([^/.]+)$ /$1.php [L] # 2. Check for cached version in the "/posts" subdirectory RewriteCond %{DOCUMENT_ROOT}/posts/$1.php -f RewriteRule ^([^/.]+)$ /posts/$1.php [L] # 3. Request does not map to a file, so fallback to "/post.php" FallbackResource /post.php
This does assume that your <post-slug>
does not contain dots (.
). This makes it easier to avoid conflicts with static resource or create an unnecessary filesystem check after rewriting the request to <post-slug>.php
. If the <post-slug>
can contain dots then we’ll need to alter the RewriteRule
pattern and add an additional condition.
NB: MultiViews needs to be disabled for this to work properly (it may already be disabled on your server).
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME}.php -f RewriteRule ^(.*)$ $1.php [NC,L]
Just a few notes on your original rule block.
If you make the
RewriteRule
pattern more restrictive, rather than matching anything (ie..*
) then you can probably avoid the condition that checks that the request does not map to a filesystem directory. (Is a request for a filesystem directory ever a valid request?)A literal dot in the
RewriteCond
TestString (1st argument) does not need to be backslash escaped. This is an “ordinary” string, not a regex.Note that
%{REQUEST_FILENAME}.php
is not necessarily the same as the (potentially) rewritten URL$1.php
– it will depend on the request and the filesystem (sinceREQUEST_FILENAME
is calculated after the request has been mapped to the filesystem), but since you are allowing anything (ie..*
) then there is potential for error here.The
NC
flag is superfluous, since theRewriteRule
pattern is not case-sensitive anyway.