@benguild: The official homepage of Ben Guild.

Tumblr "redirect theme" that doesn't really work without modifying each post, but here's a Python script to do just that...

11 Sep 2013  |  Tags: , , , ,

So, you're moving your blog away from Tumblr? Migrating that traffic can be tricky.

What am I talking about exactly? Well, think about it. If your blog is hosted at some random subdomain of “http://tumblr.com”, and everyone including Google links to that, switching over to some other blogging provider is no simple task.

I moved my blog from Tumblr to a self-maintained Jekyll site recently and found that Tumblr makes it really difficult to do redirects from your old “Tumblog” to anything else. Luckily, Jekyll's “import” tool creates a folder called “post” with a subfolder for each of your old Tumblr's post IDs that functions as a redirect.

What I wanted to do was create a script to do a directory listing inside this folder, and setup a redirect on my old Tumblr blog for each old post that was imported. Why? Because, I wanted the traffic going to my new blog (from those older pages), and I wanted anyone looking through their past “likes” or “reblogs” on Tumblr to be able to find where the content is at now and where any new content will be, too.

Part of a Python script to replace Tumblr posts with links to their new location

Afterward, I coded a custom Tumblr theme to modify these edited “link-only” posts to redirect properly to their target destinations (for browser users and search-engine crawlers), while providing a hyperlink to not only Tumblr App users but Tumblr's website users as well.

On your new blog, as a minimum you'll need to handle Tumblr links for:

  • Posts with/without a “slug” text (both “/post/12345/” and “/post/12345/title-of-post/” work)
  • Tags (within the /tagged/ directory)
  • Archive (located at /archive/)
  • RSS feed (located at /rss/)

Overall, this works best if you were using a custom domain name with your Tumblr before, as then you will only need to really worry about the Tumblr's App and website users that stumble upon your leftover blog from now on. However, the “redirect theme” below takes care of any web visitors or search-engine crawlers as well, so you might as well set everything up.

The Python Script

Disclaimer: I have never written a line of Python code until tonight when I stumbled upon this script by “codingjester” that lets you make OAuth calls to Tumblr's API. I was able to modify it to do what I wanted... and, here it is!

Beforehand, you'll need to:

  1. Setup a dummy API application on Tumblr's website: http://www.tumblr.com/oauth/apps (eg. Just put some random title, and use your new blog URL as the “callback” URL)
  2. Have redirects in place on your new site for Tumblr links. (ie. /post/12345/)
  3. Have a folder full of Tumblr post IDs as subfolders where the script is located. — If you don't have this, you can try to modify the script to either pull from Tumblr a list of IDs (this requires multiple requests if you have over 50 posts) or edit your posts manually instead as I describe in the next section.

Upon engaging the script and by following the URL it gives you to visit, you will receive a prompt like this:

Myself authorizing a dummy application on Tumblr to redirect posts using this script

After you “allow” the application access to your Tumblr account, you must then copy the “oauth_verifier” value from inside the URL shown in your browser window back into the Python script. (it prompts you for it)

This script is designed to be run in the same folder that bears subfolders for each of your Tumblr post redirects. This is typical of a Jekyll setup for example, after importing a blog from Tumblr. In other words, doing an “ls” in that folder will give you a list of Tumblr post IDs. If you don't have this, this script won't work unless you modify it to work the way you want it to.

Dependencies: There are two dependencies, ‘httplib2’ and ‘python-oauth2’. Grab a “ZIP” of both, and simply drag the folders within each (the ones with the same exact names as quoted) to be in the same folder as the Python script itself.

WARNING: This will overwrite all of your posts' content on Tumblr permanently with a link to them on your new blog, instead. If you have not imported all of your posts to your new blogging platform, you must do this first! This data will be irrecoverable both on and from Tumblr afterward. Use this script at your own risk, as it will make permanent changes to your Tumblr blog if configured properly.

If you've never used Python, you can run the script like this after configuring the variables below and meeting the requirements listed above:

python tumblr_migrate_overwrite.py

To configure: Replace the 4 variables at the top of this script based on your configuration, and then save the script (and its dependencies) in the folder containing your Tumblr post redirects. Note that it will only read the local folder's subfolder list, and will not write any changes to your local disk.

… Any finally, without further adieu, here is that Python script:

consumer_key = '???' # = the "OAuth Consumer Key" that the Tumblr "dummy" application you created provided
consumer_secret = '???' # = the "Secret key" the "dummy" application provided
old_blog_domain = 'yourname.tumblr.com' # = your old (but still currently working) tumblr blog address
new_blog_domain = 'yourname.com' # = your new tumblr blog address ... can be a custom domain

#########################################################
#########################################################
#########################################################

import urlparse
import oauth2 as oauth

request_token_url = 'http://www.tumblr.com/oauth/request_token'
access_token_url = 'http://www.tumblr.com/oauth/access_token'
authorize_url = 'http://www.tumblr.com/oauth/authorize'

consumer = oauth.Consumer(consumer_key, consumer_secret)
client = oauth.Client(consumer)

resp, content = client.request(request_token_url, "POST")
if resp['status'] != '200':
        raise Exception("Invalid response %s." % resp['status'])

request_token = dict(urlparse.parse_qsl(content))

print "Request Token:"
print "    - oauth_token        = %s" % request_token['oauth_token']
print "    - oauth_token_secret = %s" % request_token['oauth_token_secret']
print 

print "Go to the following link in your browser:"
print "%s?oauth_token=%s" % (authorize_url, request_token['oauth_token'])
print 

accepted = 'n'
while accepted.lower() == 'n':
        accepted = raw_input('Have you authorized me? (y/n) ')
        oauth_verifier = raw_input('What is the OAuth Verifier? ')

token = oauth.Token(request_token['oauth_token'],
    request_token['oauth_token_secret'])
token.set_verifier(oauth_verifier)
client = oauth.Client(consumer, token)

resp, content = client.request(access_token_url, "POST")
access_token = dict(urlparse.parse_qsl(content))

#########################################################
#########################################################
#########################################################

token = oauth.Token(access_token['oauth_token'], access_token['oauth_token_secret'])
client = oauth.Client(consumer, token)


print "Logged into Tumblr! Beginning to overwrite post bodies with links to new blog..."

import os
import urllib
import urllib2
import json

for dirname in os.walk('.').next()[1]:
	try:
		u = urllib2.urlopen("https://api.tumblr.com/v2/blog/" + old_blog_domain + "/posts?api_key=" + consumer_key + "&id=" + dirname)
		post_json=json.load(u)
		u.close()
		
		print post_json['response']['posts'][0]['post_url']
		
		oldhref=post_json['response']['posts'][0]['post_url'];
		newhref=oldhref.replace('http://'+old_blog_domain+'/','http://'+new_blog_domain+'/')
		
		html='<a href="'
		html+=newhref
		html+='">'
		html+=newhref
		html+='</a>'
		
		query_args = urllib.urlencode({'id': dirname, 'body': html, 'format': 'html'})
		
		client.request("https://api.tumblr.com/v2/blog/" + old_blog_domain + "/post/edit", method="POST", body=query_args)
		continue
		
	except:
		print "ERROR POST #"+dirname
		continue
		
	continue

Once the script finishes running, you can verify with Tumblr's “Mega Editor” that all of your posts there have all been replaced with links to them on your new blog. If any posts haven't been changed, or were changed incorrectly, they're probably not of the “text” post type. I'm not sure how to redirect Tumblr multimedia posts, as I've never had any of these.... You could perhaps just delete those posts or edit them manually to link and redirect via Tumblr's post editor using the HTML code in the next section.

If everything looks OK, you can delete the Python script and its dependencies from your “post” folder locally, and continue to the next section.

The final touch: The “redirect” theme!

So, if you've gotten this far, and all of your Tumblr posts have been replaced with links to that particular post on your new blog! However, if you weren't already able to do this using the Python script above, before using this template you must go through and replace each of your posts' bodies with just a simple link to each post's new location:

<p><a href="http://yournewblog.com/post/12345/that-random-post">http://yournewblog.com/post/12345/that-random-post</a></p>

All of your posts on Tumblr should have just this from now on: a link only.

This may seem dumb, but this way the Tumblr App and website will display this link. Using this custom HTML theme I've coded (below), any future visitors or search-engines will be redirected to the post's new location automatically. If you wish to replace your old Tumblr blog's theme with this, first copy its existing HTML code into a text document and save that somewhere on your computer as a backup. Then, replace your current Tumblr theme's code in its entirety with this simple, specially coded one for “link only” posts:

<html>
<head>
  {block:PermalinkPage}{block:Posts}
  <link rel="canonical" href="{PlaintextBody}" />
  <meta http-equiv="refresh" content="0; url={PlaintextBody}" />
  {/block:Posts}{/block:PermalinkPage}
  
  <title>{Title}{block:PostTitle} | {PostTitle}{/block:PostTitle}{block:TagPage}{Tag}{/block:TagPage}</title>
  <meta name="robots" content="noindex,follow" />
  
  <script>
  	window.location="{URL}"+window.location.pathname; /* Replace {URL} here, and in the body below, with your new blog's address. (ex. http://yournewblog.com ) .... It must have quotes around it. DO NOT include a "/" at the end of your blog's URL! */
  </script>
  
</head>

<body>
    <h1>{Title}{block:PostTitle} | {PostTitle}{/block:PostTitle}{block:TagPage}{Tag}{/block:TagPage}</h1>
    
    {block:PermalinkPage}{block:Posts}<p>This blog has moved! See this post at its new location: {Body}</p>{/block:Posts}{/block:PermalinkPage}
    {block:IndexPage}<p>This blog has moved! <a href="{URL}">See this page at its new location?</a></p>{/block:IndexPage}
    {block:TagPage} <p>This blog has moved! <a href="{URL}">See this page at its new location?</a></p>{/block:TagPage}
    
</body>

</html>

Note, that this will only work if your posts have already been replaced with a single link only (as directed above or as performed by the Python script included above). Also, you'll need to replace each instance of “{URL}” in this template only with your blog's new homepage link, including the “http://” and quotation marks around it as shown.

Once these changes take effect, visiting any page on your old Tumblr blog should provide a link and/or redirect to your new blog, automatically. The Python script is definitely not for the faint of heart, but if you have redirects setup on your new host, even just manually changing each Tumblr post to be a link will still work. It just takes more time.

This theme and process is the best current way to do this migration because Tumblr unfortunately does not provide a “domainless” URL variable/constant in its HTML theming system. Without this or some way to dynamically create it before the page is actually rendered, it's impossible to retarget the domain name portion of any bundled links/URLs in the page/post without relying solely on JavaScript. JavaScript isn't really any better for SEO or user-experience, so that's not a good solo solution, and Tumblr's own website and Apps (iPhone, Android, etc.) would still display the previously posted content ignoring any formatting or custom themes/templates anyway. Replacing the posts themselves with the links and using this theme to redirect web traffic seemed like the only way to capture all lingering traffic.

I think the largest benefit to doing it this way is that it's hardcoded and a somewhat automatic redirect to your new site for web users without relying solely on JavaScript. Additionally, your content is no longer floating around on Tumblr's system with people stumbling upon it unsure of where you're actually posting from now on. This will provide links on the old posts to their new location, without deleting the posts themselves (only their content) from Tumblr. It leaves each post's title and tag fields intact on Tumblr for searchability and for historical reasons. All the content that is removed, of course, lives on on your new blog… where it belongs.

Good luck!

Comments are in a testing stage. Enabled since 2013/09/09.