Shortlink support in WordPress 3

A plugin I made a long time ago for WordPress 2.x created short URLs for posts and stored them as a custom field for later use. This meant posts would get an automatic tinyurl (or similar address) for visitors to use. It always annoyed me however that this wasn’t built into the WordPress core. Not the generation of short URLs themselves, but that there was no standardised way to retrieve them from themes meaning each one had to be customised. Well I was pleasantly surprised to find that as of WordPress 3 there is now a set of functions for handling short URLs and they are even displayed within the admin area!

[UPDATE: Fixed a bug caused by WordPress not passing the correct Post ID under certain conditions]

The glue that holds all of this together is the_shortlink. This is a basic function that by default returns the non-pretty-permalink version of a posts URL, for example hybridlogic.co.uk/?p=1234. This means new themes can utilise this function to display shorturls as and when they’re needed. By default WordPress also injects a shortlink meta tag via wp_head into your theme as a bonus. Below is an example of how you can add shortlink support to your current theme now if it doesn’t already have it. As usual, only use this function within The Loop.

[php]
if( function_exists(‘the_shortlink’) ):
the_shortlink(‘This is a shortlink for this post.’);
endif;
[/php]

The fun begins when you hook into the filters for the the_shortlink to customise what it displays. There are two main filters, both defined in wp-includes/link-template.php, pre_get_shortlink and get_shortlink. The former runs before WordPress attempts to generate the short URL while the latter is run on the final output (of WordPress only, not custom generated short URLs). In this instance we’ll focus on pre_get_shortlink as it will allow us to generate our own short URLs.

I’m going to assume that you already have experience writing a plugin for WordPress and are familiar with the general concept of actions and filters, but if not feel free to read up and come back. In the following example we will register a new filter for pre_get_shortlink that will return a link that has been stored as a custom field for this post.

[php]
add_filter(‘pre_get_shortlink’, ‘my_custom_shortlink’, 10, 4);

function my_custom_shortlink($false, $post_id, $context, $allow_slugs) {
$short_link = get_post_meta($post_id, ‘shortlink’, true);
if(” == $short_link) return false;
return $short_link;
}
[/php]

This code first registers a new filter which will call the my_custom_shortlink function (please remember to prefix your plugins!) when a shortlink is requested. The function goes away and gets the ‘shortlink’ custom field for this particular post. If one hasn’t been set, it returns false and WordPress generates a shortlink as it normally would (/?p=1234). Otherwise it returns the custom field value as our new shortlink.

By itself, this plugin is now technically usable. You can go away and use it as is, copy and pasting the short URLs you want into a custom field box for each post. But let’s take it one step further and have it automatically generate short URLs for us. The following is a very basic complete example of how to integrate Bit.ly into this system and is provided more for demonstrative purposes than any production ready code. Feel free to use it as the basic to hook into non-standard systems though.

[php]
<?php
/*
Plugin Name: My Bit.ly Shortlink
Plugin URI: http://hybridlogic.co.uk/2010/08/shortlink-support-in-wordpress-3/
Description: This is an example plugin to demonstrate how to hook into the WordPress shortlink system. It uses Bit.ly for the URL shortening service.
Author: Luke Lanchester
Author URI: http://lukelanchester.com
Version: 1.0.0
*/

add_filter(‘pre_get_shortlink’, ‘my_custom_shortlink’, 10, 4);

function my_custom_shortlink($false, $post_id, $context, $allow_slugs) {

if($post_id==0) {
global $wp_query;
if ( ‘query’ == $context && is_single() ) {
$post_id = $wp_query->get_queried_object_id();
} elseif ( ‘post’ == $context ) {
$post = get_post($id);
$post_id = $post->ID;
}
}

if($post_id==0) return false;

$short_link = get_post_meta($post_id, ‘shortlink’, true);
if(” == $short_link) {
$short_link = my_bitly_shortlink_generator(home_url(‘?p=’.$post_id));
if(” == $short_link) return false;
update_post_meta($post_id, ‘shortlink’, $short_link);
}
return $short_link;
}

function my_bitly_shortlink_generator($long_url) {

$bitly_login = ‘example’; // replace @ http://bit.ly/a/your_api_key
$bitly_apikey = ‘abcdefg123456’; // replace @ http://bit.ly/a/your_api_key

$long_url = esc_url($long_url);
$url = ‘http://api.bit.ly/v3/shorten?login=’.urlencode($bitly_login).’&apiKey=’.urlencode($bitly_apikey).’&format=json&longUrl=’.urlencode($long_url);

$response = wp_remote_get($url); // Use the WordPress HTTP API
if(!$response or !is_array($response) or $response[‘response’][‘code’]!=200 or $response[‘body’]==”) return false;
$json = json_decode($response[‘body’]);
if(!$json or $json->status_code!=200) return false;

$short_url = $json->data->url;
if($short_url!=”) return $short_url;
return false;
}
[/php]

And that ends this weeks lesson on making WordPress Work For You™. Feel free to leave suggestions for next weeks instalment :)