I’ve been considering a change in the permalink structure for my posts for some time now. The /yyyy/mm/dd/post-name/ structure I started with is certainly nicer than what WordPress defaults to, but a problem with those dated URLs has emerged over the past few years: link ageism.

Link ageism is what I’ve begun calling the tendency most of us have to avoid URLs that indicate links to older content. With the year of publication front and center, my old URL structure was particularly susceptible to link ageism. When I began hearing from new readers who almost skipped over my still-relevant content just because the URL looked old, the dated URLs had to go.

Along with the obvious problem of redirecting old URLs to new, I ran into another issue that I hadn’t given much consideration before the change. The new URL scheme caused the counters on my Twitter and Delicious sharing widgets to reset to zero on all my existing posts.

Luckily, I was able to find a solution to the sharing counter problem, and I thought that workaround might be useful to others. What I’ll describe is specific to WordPress and the particular URL change that I made, but the same approach could be applied to save social sharing counters when changing URLs on most any publishing platform.


Preventing link rot

Changing URL structures isn’t all that difficult in most CMS software, but it’s important to be sure that you don’t break your existing URLs in the process. Requests to old URLs should result in a 301 “Moved permanently” response that points browsers and search engines to the content’s new canonical location.

Since my URL update was a simple, reductive change, instating 301 redirects from all my old URLs to their new locations only required this single line in my .htaccess:

RedirectMatch 301 /\d{4}/\d{2}/\d{2}/(.*) http://encosia.com/$1

That directive uses a regular expression to match URLs beginning with the pattern /nnnn/nn/nn/, where n is any numeric digit. If a requested URL matches that pattern, the request will be 301 redirected to the same URL with the /nnnn/nn/nn/ prefix removed.

Using a 301 redirect instead transparent URL rewriting has the important advantage of notifying search engines about your new URL scheme when they visit a post’s old URL. There are alternative methods for this, like rel=canonical, but 301 redirects are tried and true.

Avoiding social disproof

Whether it’s wise or not, most of us automatically assign higher value to things we believe are popular. This phenomenon is called social proof, and it’s just as useful to cultivate online as anywhere. To neutral readers, cues such as Twitter share counts can play a significant role in signaling the worth of content from sources that they aren’t familiar with.

There’s definitely such a thing as too much emphasis on social proof and self-promotion (please RT!!!), but I believe sharing counters fall short of social media douchebag territory. If you’ve got something worthwhile to share, there’s nothing wrong with lending that content authority that it has legitimately earned.

With that in mind, I wanted to do what I could to preserve what social proof the old URLs had accumulated over the past few years.

Known aliases: /yyyy/mm/dd/

As it turns out, preserving those counters isn’t difficult. The key is that both the Twitter and Delicious widgets I use here optionally allow you to specify what URL they should save/share, and that option also controls which URL their counters reflect.

Using old-style URLs for sharing isn’t ideal. It seems self-defeating to make a URL change and then put extra effort into undoing the change in some situations. However, URLs shared on Twitter are usually obfuscated by services like Bit.ly, and saves on Delicious typically happen beyond the threshold of link ageism.

That doesn’t mean I have to resign myself to sharing all content via old-style URLs though. Instead, I decided to only make that compromise on posts published before the URL switch, and standardizing on using the new URLs everywhere going forward.

A tale of two URLs

The first step toward that is to determine which URL scheme the post was originally published under. I’ll need to know that in order to know which type of URL should be sent to the social sharing widget. WordPress’ get_the_date() function returns the date a post was published, and PHP’s strtotime() makes comparing the post’s publish date with the URL change date simple enough:

// I changed my URLs on 5/28/2011.
$url_change_date = strtotime("5/28/2011");
$post_date = strtotime(get_the_date());
 
if ($post_date < $url_change_date) {
  // This post was originally published under the old URL scheme.
}

Now it’s just a case of devising a way to build either type of URL for a given post.

Note: It would have been slightly simpler to use a post ID in the comparison instead of using the cutover date. At this point though, the overwhelming majority of requests will be for posts that were published under the old URL structure, so I’ll usually need the post’s date for building the old URL anyway. Until that changes, it makes sense to go ahead and use the date for the comparison.

Building the appropriate URL

Even if the post is one from the old URL scheme, the new URL will be the foundation for building its corresponding old URL. Of course, if the post was published after the URL change date, then the new URL is all that will be needed.

So either way, I’ll need to begin with the post’s current URL under the new scheme. WordPress makes that available via the get_permalink() function:

// Need to start with this regardless.
$sharing_url = get_permalink();

With the permalink handy, all that’s left is to prefix it with /yyyy/mm/dd if this post was originally published under the old URL scheme. I’ll do that when the date comparison returns true:

if ($post_date < $url_change_date) {
  // Build the /yyyy/mm/dd prefix to insert.
  $url_date_prefix = "/" . date("Y", $post_date) .
                     "/" . date("m", $post_date) .
                     "/" . date("d", $post_date);
 
  // Update $sharing_url by replacing the beginning of the URL with
  //  the beginning prefixed by the date prefix string I just built.
  $sharing_url = str_replace("://encosia.com",
                             "://encosia.com" . $url_date_prefix,
                             $sharing_url);
}

At this point, $sharing_url will contain exactly what should be presented to the social sharing widgets: a new URL for posts that were published after the switch (like this one), or an old URL for posts before that change.

Putting it all together

The end result is this block of PHP sitting in my template’s single.php, just before the markup for my Twitter and Delicious:

<?php
  // Changed URL structure from /yyyy/mm/dd/slug to /slug on 
  //  5/28/2011. This ensures older posts still present the old URLs 
  //  to sharing services so that share counts are maintained.
  $url_change_date = strtotime("5/28/2011");
  $post_date = strtotime(get_the_date());
 
  $sharing_url = get_permalink();
 
  if ($post_date < $url_change_date) {
    $url_date_prefix = "/" . date("Y", $post_date) .
                       "/" . date("m", $post_date) .
                       "/" . date("d", $post_date);
 
    $sharing_url = str_replace("://encosia.com",
                               "://encosia.com" . $url_date_prefix,
                               $sharing_url);
  }
 
  // At this point, $sharing_url is the correct URL to present
  //  to the social sharing APIs in order to maintain counters.
?>

Once all that has executed, $sharing_url will hold the correct URL to pass off to the Twitter and Delicious APIs, regardless of which URL scheme the post was originally published under.

A couple examples of implementation

How to use $sharing_url depends on the particular social sharing service. I’ll describe using it with Twitter and Delicious since those are the ones that I use here, but I’ll add example code for others if anyone has specific requests.

Twitter

For Twitter, I’m using the official Tweet Button. It’s a big improvement over the obtrusive Twitter buttons I’ve used in the past, which relied on document.write() and blocked page rendering.

Among the options that you can set on the placeholder markup is the data-url attribute, which allows you to specify which URL should be shared when the button is clicked. That defaults to the current page’s URL if you don’t specify one, but you can manually override it:

<a href="http://twitter.com/share"
   data-url="<?php echo $sharing_url; ?>">Tweet</a>

Now the Tweet Button will display a counter for $sharing_url instead of using the current page’s URL.

Delicious

To facilitate saving on Delicious, I’ve been using Mike More‘s unobtrusive Quite Delicious Button plugin to jQuery, which works great. Just like the Twitter sharing button, it provides an option for controlling the URL to be shared:

<a class="delicious-button" href="http://delicious.com/save">
   <!-- {
   url:"<?php echo $sharing_url; ?>",
   title:"<?php the_title(); ?>"
   } -->
   Save on Delicious
</a>

By using $sharing_url as the URL to query Delicious’ API for a count on, older posts continue displaying the correct number of times that they’ve been saved.

That’s it

This post has been pretty far off the beaten path of topics that I usually cover here, but hopefully some of you will find the information useful now or in the future. If not, don’t worry; I don’t plan on making posts about WordPress and/or PHP a habit.

If you need help making this work with a specific type of widget that I haven’t covered here (e.g. Facebook, StumbleUpon, etc), let me know in a comment. If it’s possible to use this approach with other widgets, I’ll update the post with those requested.