WordPress ships with the ability to create shortlinks for you. Most of the time that means something like http://yoursite.com/?p=123
. Or, if you opted in, a wp.me
shortlink.
Those are solid options, but what if you want to use your own shortlink service? Or you want short links that are a little bit prettier? Fortunately nearly everything in WordPress has a hook attached to it, meaning it’s very easy to modify that built in shortlink functionality without changing the code.
Making Pretty Shortlinks
?p=123 at the end of a URL is not so pretty. The first half of this tutorial will be learning how you can create a better, cleaner shortlink. This involves using WordPress’s built in Rewrite API.
1. Setting Up a Rewrite
The first thing we’re going to do is add a rewrite rule. add_rewrite_rule
takes three arguments: the regular expression that WP will try to match a URL against, the rewrite destination, and the priority.
We’re hooking into init
here because need to be sure the entire WordPress environment (including our add_rewrite_rule
function) is loaded. The add_rewrite_rule
says, “whenever someone visits a URL that starts with s, followed by a slash and one or more digits, rewrite that URL to index.php?short=the_digits
.
Unfortunately WordPress will see that short
query argument on the URL and not recognize it. As such, it will get stripped out. So we need to tell WordPress that short
is a valid query argument by hooking into the query_vars
filter.
Aside: Rewriting vs. Redirecting
When a URL is redirected, it changes. When it’s rewritten, it’s done so transparently at the server level without the user knowing: the URL does not change. Rewrites are how the WordPress permalink system works. What we’re doing here is harnessing that system to roll our own rewrites.
2. Dealing With the Rewritten URL
Despite us telling WordPress that short
is a valid query argument, it still has no idea what to do. For that, we need to hook into template redirect, a hook that fires right before WordPress chooses which PHP file in your current theme to use.
First, we’ll check to see if short
argument is there with get_query_var
. If it isn’t, we’ll bail and let WordPress continue doing its thing.
Next we’ll try to turn our query argument into an absolute integer, and get a permalink out of it. If either of those fail, we’ll say that this is a 404, error page and return out of our function. The last step is calling wp_redirect
to send people on the canonical URL.
if( ! $id )
{
$wp_query->is_404 = true;
return;
}$link = get_permalink( $id );
if( ! $link )
{
$wp_query->is_404 = true;
return;
}wp_redirect( esc_url( $link ), 301 );
exit();
}
That’s it! you now have custom shortlinks, but we’re not done yet.
3. Modifying the Shortlink API
WordPress lets you click on that handy Get Shortlink button to grab your shortlink in the admin section. It also adds the shortlink into the <head>
section of your site. We need to modify that output to reflect our new, pretty shortlinks.
The filter in question here is get_shortlink
.
You can see this entire thing in action as a plugin.
Using An External Source for Shortlinks
If you’re using an external service, you don’t need to worry about steps one and two above. Instead, you’ll need something that interacts with a service’s API, grabs the shortlink and puts it int he correct places.
For this tutorial, we’ll be using dlvr.it as our external shortlink provider.
To start, we’ll keep a good portion of our get_shortlink
function above. This will be in a plugin, so we’ll also include PHP class that encapsulates the Dlvr.it API.
require_once( plugin_dir_path( __FILE__ ) . ‘api.php’ );add_filter( ‘get_shortlink’, ‘pmgtut2_get_shortlink’, 10, 3 );
function pmgtut2_get_shortlink( $link, $id, $context )
{
if( ‘query’ == $context && is_singular() )
{
$id = get_queried_object_id();
}
}
Now it gets a bit tricky. We don’t necessarily want to hit the API every single time we get the shortlink. Remember the mention above about how WordPress put the shortlink in the <head>
section? Hitting the API on the load of every single post page is probably not a good idea: extra HTTP requests, etc. Instead, we’ll store our shortlink as a value in the wp_postmeta
table. The first step is seeing if that value is there. If it is, we’ll return the short URL right away.
if( $dlvrit = get_post_meta( $id, ‘_pmg_dlvrit_url’, true ) )
{
return $dlvrit;
}
If we dont’ have a stored value, we’ll create a new wpDlvrit object, then get the posts permalink, and fetch the short url.
if( $dlvrit = get_post_meta( $id, ‘_pmg_dlvrit_url’, true ) )
{
return $dlvrit;
}
else
{
$dlvrit = new wpDlvrit( ‘your_api_key’ );
$long = esc_url( get_permalink( $id ) );
$short = $dlvrit->get_shortlink( $long );// If there’s a problem, return the original link
if( ! $short ) return $link;
Since the API class doesn’t handle json decoding or any of that jazz, we’ll have to take care of that ourselves here. Assuming everything goes according to plan, we’ll update the postmeta
table and return the shortlink.
if( $dlvrit = get_post_meta( $id, ‘_pmg_dlvrit_url’, true ) )
{
return $dlvrit;
}
else
{
$dlvrit = new wpDlvrit( ‘your_api_key’ );
$long = esc_url( get_permalink( $id ) );
$short = $dlvrit->get_shortlink( $long );// If there’s a problem, return the original link
if( ! $short ) return $link;$body = json_decode( $short[‘body’] );
if( ! isset( $body[0]->short ) ) return $link;
update_post_meta( $id, ‘_pmg_dlvrit_url’, esc_url( $body[0]->short ) );
return esc_url( $body[0]->short );
}
}
The entire example is available as a WordPress plugin.