Directory Auto-Includes
Posted by: jordan in best practices, tags: auto-includes, ssi, templatingToday is a good day–a good day for a little bit of Apache black magic, URL rewriting, and environment variables. Apache, in its creators’ great benevolence, allows us to set and use our own custom environment variables that are available from anywhere on your website through Server-Side Includes.
Traditionally, people use them to determine if someone is hotlinking images by setting an environment variable based on the referring page.
However, today is a new day. Today, we want to use URL rewriting and our secret powers to write out an environment variable based on what URL we’re browsing to on our site.
Why would we want to do that, you ask? Well, once we’ve figured out which section of a site we’re on, we can also conditionally include files using SSI. The most obvious benefit to this is to automatically include a header or footer for the current section of a site you’re on.
Of course, by now some of you are surely saying “oh gee, that would be so easy to do with PHP”. Well, this is pretty easy too, and it’s language independent so it appeals to a wider crowd.
The ground rules
I like to keep all my assets, including CSS, JavaScript, and includes in one folder: the all-powerful /_assets/ folder. Include files go in the /_assets/includes/ folder. Today, we’ll be working with /_assets/includes/header.shtml and /_assets/includes/footer.shtml. They have the .shtml extension so that they can do SSI work–more on that later.
Step 1: Set up URL rewriting rules
Rewrite rules take the following form:
RewriteRule PATTERN SUBSTITUTION [FLAGS]
In our case, we’re not going to be substituting any URLs, because we don’t actually want to redirect the URL, we only want to read it and set a variable from it. So, instead of a URL, we use a “-” (dash).
To actually set a variable, we’re going to need to set a flag in the form [E=VARIABLE_NAME:VALUE]. You’ve probably used [R=301] and [R=302] if you’ve done some URL rewriting in the past, so this might look familiar.
So, here are the RewriteRules we need to detect the current section.
RewriteRule ^((index|default)\.(.*)|)$ - [E=CURRENT_SECTION:index,NC,L]
RewriteRule ^(.+?)/(.*)$ - [E=CURRENT_SECTION:$1,L]
Pretty easy, right? Both rules set the CURRENT_SECTION variable; rule 1 sets it to “index” if you’re on an index page, rule 2 sets it to the name of the directory you’re in. Rule 2 only runs if rule 1 doesn’t catch the URL; i.e. you’re not on the front page.
If you’re on http://www.example.com/jordan/, “jordan” would be the value of CURRENT_SECTION.
All set? Let’s move on.
Parsing .shtml files for SSI
Before we leave our .htaccess file, we also need one more thing: the ability to parse .shtml files for SSI directives. Our /_assets/includes/header.shtml and /_assets/includes/footer.shtml files both will be using SSI, so we need to make sure that they’re parsed for it. Most hosts have this enabled, but let’s not assume anything, ok?
Simply add this line somewhere in your .htaccess file:
AddHandler server-parsed .shtml
Create section folders
We’re going to store all our files at /_assets/includes/sections/NAME_OF_SECTION/. For the sake of this example, we’re going to assume we’re at the URL http://www.example.com/jordan/, and that we want to include a header and footer file.
So, create the folder /_assets/includes/sections/jordan/, and create 2 new files: header.shtml and footer.shtml.
Set up variable checking
The last thing we need to do is create the checks in our /_assets/includes/header.shtml and /_assets/includes/footer.shtml files to read in CURRENT_SECTION and include the header and footer files, respectively.
The following code goes in your header.shtml file, wherever you want to actually include the sub-header.
<!--#include virtual="/_assets/includes/sections/${CURRENT_SECTION}/header.shtml"-->
In our example, this will point to /_assets/includes/sections/jordan/header.shtml.
Well, this works, except it tries to find this folder no matter what, even on the index page. What we need to do is exclusive lock out folders that we don’t want to have the section header. While we’re at it, let’s create a way to turn this off at the flick of a switch.
First of all, put this above the include directive:
<!--#set var="USE_SECTION_HEADER" value="true"-->
Now, let’s add in the checks to make sure we actually want to include for this folder:
<!--#set var="USE_SECTION_HEADER" value="true"-->
<!--#if expr="
$USE_SECTION_HEADER = true &&
$CURRENT_SECTION != 'index'
"-->
<!--#include virtual="/_assets/includes/sections/${CURRENT_SECTION}/header.shtml"-->
<!--#endif-->
You may also want to wrap the include directive with a div tag so that you can target it with your CSS. If there are other directories you don’t want to have a sub-header for, you can add them into the if block as well.
So, our final code to place in the the header looks like this:
<!--#set var="USE_SECTION_HEADER" value="true"-->
<!--#if expr="
$USE_SECTION_HEADER = true &&
$CURRENT_SECTION != 'index' &&
$CURRENT_SECTION != 'directory-with-no-section-header'
"-->
<!–#include virtual=”/_assets/includes/sections/${CURRENT_SECTION}/header.shtml”–>
<!–#endif–>
We can copy and paste this into /_assets/includes/footer.shtml, and then change a few things so that it looks like this:
<!--#set var="USE_SECTION_FOOTER" value="true"-->
<!--#if expr="
$USE_SECTION_FOOTER = true &&
$CURRENT_SECTION != 'index' &&
$CURRENT_SECTION != 'directory-with-no-section-footer'
"-->
<div id="section-footer">
<!--#include virtual="/_assets/includes/sections/${CURRENT_SECTION}/footer.shtml"-->
</div>
<!--#endif-->
Level Up
Maybe you can take these concepts and do something even cooler with them. It’s relatively easy to expand the URL rewriting to include sub-subsections, so maybe that’ll give you a start.