Vanity URLs can be extremely useful, especially in offline marketing materials. I covered two techniques for creating vanity URLs in PHP in earlier posts: using a subfolder with a header redirect and using rewrite rules in Apache. After publishing those two posts, someone asked me how to keep a record of the number of times site visitors access each vanity URL. We’ll eventually want to store that data in a database, but we’ll first need to change the way the vanity URLs are redirected.
We’ll still want to define all the vanity URLs in Apache: creating subfolders for every single one would get too messy and redundant. But we can’t access a database directly from the htaccess file; we need to do that in PHP. In this post, I’ll walk you through how to change the vanity URL redirects to use a new technique: a query string parameter.
My htaccess file currently looks like this:
RewriteEngine On RewriteRule ^wcsf[/]*$ /wordpress/subordinate-post-types/ [R=301,L]
This rule matches any web address that has nothing in between the beginning and the end besides the characters w, c, s, and f (in that order), followed by an optional slash, and redirects it to the full web address with a 301 status code.
I now want to change it to this:
RewriteEngine On RewriteRule ^wcsf[/]*$ /vanity.php?vanity=wcsf&full=/wordpress/subordinate-post-types/ [L]
This new rule also has four separate pieces, all separated by spaces. The first two remained the same, but the last two have changed. Let me walk you through both of them:
When someone visits the
wcsf vanity URL, by default Apache will look for a subfolder called
wcsf to show either an index.php file in that subfolder or a directory listing. This rewrite rule changes how Apache handles it. Instead, Apache will now load a new
vanity.php (which I’ll need to create) with two variables added to the end: one for the short vanity version entered and one for the full version for the redirect.
This new rewrite rule only has one flag,
[L], which still indicates to Apache that this is the last rule it should apply and should not keep looking at the rewritten address to see if it should apply other rules. But what’s conspicuously absent here is the
[R=301] flag. We do not want this rule to redirect. We do not need to tell the visitor’s browser that we are going to a vanity.php file at all. They ask for
wcsf, and Apache will silently rewrite that rule to
vanity.php?… without sending that back to the browser.
I will now put that vanity.php I mentioned in the rewrite rule in the main folder of my website. (Depending on your server configuration, that folder might be called public_html, www, htdocs, or something similar: it will be the same folder with the htaccess file.) I’ll add this code to it for the moment:
<?php echo "Ha! This is really vanity.php!"; ?>
If I visit this page in the browser, you’ll see this message displayed. (Be sure to notice that the web address still shows the vanity URL: without the
[R] flag in the rewrite rule, Apache silently rewrites the web address. It does not redirect to the new page.)
After I remove that temporary message, I’ll next load the two variables from the query string into regular PHP variables like this:
Once I have these variables, I will want to complete two tasks with them:
- Create a record in a database for this visit
- Redirect to the full web address
For the second task, redirecting to the full web address, I’ll use the two header commands we looked at originally. (We’ll skip the first task involving a database for now; I’ll put a comment there as a placeholder.)
<?php $vanity = $_GET["vanity"]; $full = $_GET["full"]; // TODO: log visit in database header ("HTTP/1.1 301 Moved Permanently"); header("Location: " . $full); ?>
Notice that we’re now concatenating the value from the
$full variable as part of the header, instead of specifying a static web address like we were before. (We aren’t using the
$vanity variable yet; we’ll do that when we log this visit in the database.)
Let’s take one last look at the htaccess file. I don’t like that the vanity part of the web address appears in two places, in the pattern to match and in the new web address. We can clean this up by making two changes to the rewrite rule:
RewriteEngine On RewriteRule ^(wcsf)[/]*$ /vanity.php?vanity=$1&full=/wordpress/subordinate-post-types/ [L]
I placed the vanity part of the web address in parentheses. In a regular expression, this creates what’s known as a backreference. With rewrite rules, you can then reference part of the matched pattern in the new web address kind of like a variable.
Backreferences receive a number, starting with 1 and then increasing left to right. References to a backreferences start with a dollar sign followed by the corresponding number, so the
$1 in this rule tells Apache to take the first value in parentheses from the matched pattern and insert it here in the new web address.
To add a new vanity URL, I simply type a similar rewrite rule below this one. I’ll next add a rule for a talk I gave last fall at WordCamp Toronto. I specify a different name for the vanity in the pattern to match, and I specify a different destination in the new web address.
RewriteEngine On RewriteRule ^(wcsf)[/]*$ /vanity.php?vanity=$1&full=/wordpress/subordinate-post-types/ [L] RewriteRule ^(wcto)[/]*$ /vanity.php?vanity=$1&full=/wordpress/structured-data/ [L]
Our vanity URLs are now all specified in the htaccess file and then redirected by a single PHP file that receives a query string parameter. With the rewrite rules and the PHP file in place, we’re ready to tackle the database portion. Next time, we’ll look at the code we’ll need to add in this PHP file that will record visits to vanity URLs.