ベン・ギルド (Ben Guild)


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

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

If your blog is hosted on some random subdomain of the “https://tumblr.com” website, and everyone (including Google) links to that, switching over to some other blogging provider and domain-name 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 generates a folder called “post” with a subfolder for each of your old Tumblr's post IDs to serve as a redirect to the posts' updated permalinks, so if you were hosting your blog on a custom domain-name before, most of the work is already done for you by completing that process. 👍🏻

What I needed to do from here was to create a script to do a directory listing inside this of “posts” folder, and setup a redirect on my old Tumblr blog for each old post that was imported. — Why? Because, I wanted the traffic from those older pages to point to my blog's new pages outside of Tumblr, and I wanted anyone looking through their past “likes” or “reblogs” on Tumblr to be able to see where the content is now at. (… And, where any new content will be, too!) 😅

Part of a Python script to replace Tumblr posts with links to their new location.
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 mobile-app users but also Tumblr's website users as well.

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

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

As mentioned, 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 had 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 needed… so, here it is!

Beforehand, you'll need to:

  1. Setup a dummy API application temporarily on Tumblr's website. (Just put some random title, and then use your new blog URL as the “callback” URL.)
  2. Have redirects in place on your new site for the Tumblr links. (i.e. /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… which may requires multiple requests if you have too many posts, or by editing 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:

Me, authorizing a dummy application on Tumblr to redirect posts using this script.
Me, authorizing a dummy application on Tumblr to redirect posts using this script.

After you “allow” the dummy 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 contains 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, executing `ls` in that folder in the terminal of your machine should give you a list of Tumblr post IDs. If you don't have this, then this script won't work unless you modify it to work the way you want it to.

The script has two dependencies, so grab a ZIP file of each, and drag their extracted folders (the ones with the same exact names as shown below) to be in the same folder as the Python script:

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 become irrecoverable from Tumblr afterward. Use this script at your own risk, as it will make permanent changes to your Tumblr blog when configured properly.

… If you've never used Python, you can run the script from the terminal on your machine 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 has run successfully, 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 myself. You could perhaps just delete them, or edit them manually to link and redirect using HTML code. (See “A fallback route” section, below.)

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

A fallback route

So, if you've gotten this far, all of your prior Tumblr posts should now 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 proceeding any further, you must go through and manually replace each of your posts' bodies with just a simple link to the 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>

The final touch: Adding the “redirect” theme to Tumblr!

OK, so all of your posts on Tumblr should just have this by now: a link only. — This may seem dumb… but this way, the Tumblr mobile-app and website (which may not correctly support the “redirect theme” below) will display this link to readers instead.

For web-based users (or search-engine crawlers) who may visit your site's old address directly, this custom HTML theme that I've coded (below) should redirect them automatically to the post's new location without having to actually click the link. — 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 to your computer as a backup! Then, replace the prior theme's code on Tumblr in its entirety with this simple, specially coded one for “link only” posts.

You'll need to replace each instance of “{URL}” in this template with your blog's new homepage link (including the “http://” or “https://” prefix) and quotation marks around it:

<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>

Once these changes take effect, visiting any page on your old Tumblr blog should provide a link and/or redirect the browser to the corresponding page at your blog's new location, automatically.

The Python script portion is definitely not for the faint of heart, but if you have redirects setup on your new host to match the old URLs, even just manually changing each Tumblr post to be a link is still better than nothing… even without implementing this theme! 👍🏻

Final thoughts

Because Tumblr unfortunately does not provide a “domainless” URL variable/constant in its HTML theming system, this theme and process is the best way to do this migration at this time of writing, as far as I know. — It seems impossible to retarget the domain-name portion of any bundled links/URLs in the post without relying solely on JavaScript. 😕

JavaScript isn't great nor terrible for SEO, but the embedded link for each post is most likely a must since Tumblr's own website and mobile-apps (iPhone, Android, etc.) won't handle that code nor the embedded HTML “meta refresh” either.

On the upside, your content will no longer be floating around on Tumblr's system because it's been replaced with a link only. — Each post's title and tag fields will remain for reference and some lingering discoverability on the platform, but everything else lives on your new blog from now on… where it belongs, and where you'll have full control to avoid constraints like this in the future.

Good luck! 😃