It used to be a really simple process; click a button on Disqus admin, log into blogger, and then comments are migrated. But Disqus was left with a broken import link when Google deprecated some of their APIs. Given that it's been broken for a while, I didn't see that being fixed anytime soon.
So, I finally got some time to roll my own fix based off a bit of code I previously wrote. Now that it's been tested for a few weeks, I've decided to make it public.
This is a multi-step process but doesn't take more than a few minutes each to set up.
Exporting your existing comments
- Go to your Blogger admin and then find the settings item on the left menu.
- Under that, look for "Other settings"
- Click "Export blog" at the top.
- Save the backup file somewhere.
I don't blame you for having trouble finding it. Below is a screenshot of where to click.
Converting your comments to WXR
What you have now are comments in some God-awful XML format which you'll need to convert to Wordpress WXR format, one that Disqus can import.
You can either use my online "Blogger to Disqus comment converter" tool which uses django-disqus, or (if you don't trust me) check out the source and run it yourself.
import arrow | |
from bs4 import BeautifulSoup | |
from disqus.wxr_feed import ContribCommentsWxrFeed | |
from HTMLParser import HTMLParser | |
from twigcorp.utils import Url | |
class BloggerCommentsWxrFeed(ContribCommentsWxrFeed): | |
""" | |
Blogger comments in WXR format for Disqus. | |
""" | |
def get_object(self, request, requested_file): | |
self.posts_by_url = {} | |
self.comment_ids = [] | |
self.soup = BeautifulSoup(requested_file, "html5lib", from_encoding="utf-8") | |
self.site_url = self.soup.find('link', rel='alternate').get('href') | |
""" | |
posts_by_url[url] = { id, title, pubdate, guid, comments } | |
comment = { id, user_id, username, user_email, user_url, ip, submit_date, comment, approved, parent_id } | |
""" | |
return self.posts_by_url | |
def items(self, posts_by_url_arg): | |
parser = HTMLParser() | |
for category in self.soup.find_all('category', term="http://schemas.google.com/blogger/2008/kind#post"): | |
post = None | |
for el in category.parents: | |
if el.name == 'entry': | |
post = el | |
break | |
if post is None: | |
print "Unable to find entry" | |
continue | |
link_element = post.find('link', rel="alternate") | |
if link_element is None: | |
continue | |
post_id = post.find('id').text | |
url = link_element.get('href') | |
self.posts_by_url[url] = { | |
'id': post_id.split('-')[-1], | |
'url': url, | |
'title': post.find('title').text, | |
'pubdate': post.find('published').text, | |
'guid': post_id, | |
'comments': [] | |
} | |
for category in self.soup.find_all('category', term="http://schemas.google.com/blogger/2008/kind#comment"): | |
comment = category.parent | |
comment_id = comment.find('id').text.split('-')[-1] | |
reply_to = comment.find('thr:in-reply-to') | |
url = reply_to.get('href') | |
author = comment.find('author') | |
author_uri_el = author.find('uri') | |
parent_comment = comment.find('link', rel='related', type="application/atom+xml") | |
comment_text = comment.find('content').text.strip() | |
comment_text = parser.unescape(comment_text) | |
for br in [ '<br />', '<BR />', '<br/>', '<BR/>' ]: | |
comment_text = comment_text.replace(br, '\n') | |
# { id, user_id, username, user_email, user_url, ip, submit_date, comment, approved, parent_id } | |
self.posts_by_url[url]['comments'].append({ | |
'id': comment_id, | |
'user_id': 0, | |
'user_name': author.find('name').text, | |
'user_email': author.find('email').text.lower(), | |
'user_url': author_uri_el.text if author_uri_el is not None else '', | |
'ip': '', | |
'submit_date': comment.find('published').text, | |
'comment': comment_text, | |
'approved': True, | |
'parent_id': parent_comment.get('href').split('/')[-1] if parent_comment is not None else '', | |
}) | |
self.comment_ids.append(comment_id) | |
return self.posts_by_url.values() | |
def item_title(self, item): | |
# print "*** title", item['title'] | |
return item['title'] | |
def item_description(self, item): | |
# return item['title'] | |
return u'' | |
def item_pubdate(self, item): | |
return arrow.get(item['pubdate']).datetime | |
def item_guid(self, item): | |
""" | |
The path to the comments thread. | |
""" | |
# The Disqus blogger plugin uses the Post ID as the Disqus identifier. | |
return item['id'] | |
def item_comment_status(self, item): | |
# Can people comment on this item? One of either 'open' or 'closed'. | |
return "open" | |
def item_link(self, item): | |
return item['url'] | |
def item_comment_status(self, item): | |
return "open" | |
def item_comments(self, item): | |
return item['comments'] | |
# Comment information | |
def comment_id(self, comment): | |
# print "comment", comment['id'] | |
return comment['id'] | |
def comment_user_id(self, comment): | |
return comment['user_id'] | |
def comment_user_name(self, comment): | |
return comment['user_name'] | |
def comment_user_email(self, comment): | |
return comment['user_email'] if comment['user_email'] != 'noreply@blogger.com' else '' | |
def comment_user_url(self, comment): | |
# Comment author's homepage URL - we use this as a honeypot | |
return comment['user_url'] | |
def comment_ip_address(self, comment): | |
return comment['ip'] | |
def comment_submit_date(self, comment): | |
return arrow.get(comment['submit_date']).datetime | |
def comment_comment(self, comment): | |
return comment['comment'] | |
def comment_is_approved(self, comment): | |
return '1' if comment['approved'] else '0' | |
def comment_parent(self, comment): | |
# Should match comment_id() | |
if comment['parent_id'] and comment['parent_id'] in self.comment_ids: | |
return comment['parent_id'] | |
return 0 |
Setting up Disqus
This part is fairly straight forward.
- Create a Disqus forum for your site.
- Go to the admin and then the Discussions tab
- Click Import
- Select the Generic tab
- Upload the converted WXR file
- While you wait, continue with the setup below.
Setting up Disqus on Blogger
Now that the import process has started, there's just one more thing left to do on your blog. While you wait for the import to complete, set up the Disqus plugin on your blogger so the old comments don't show anymore.
There is a page on Disqus that lets you quickly add the plugin to the site of your choice.
Click on this link and then:
- Click the "Add <disqus forum name> to my Blogger site" button (Step 1. You can ignore step 2 because we already did that)
- Select a blog you wish to use Disqus
- Click "Add widget"
Supporting Internet Explorer users
For those who wish to support Internet Explorer users, there is an extra step involved.
Check the source of your blog and search for "X-UA-Compatible" and check that it's using "EDGE". If it's not there or it's not showing "EDGE", Disqus has a decent tutorial written up here on how to add it into your Blogger template.
And that's the end of that! The Disqus widget on Blogger will handle the rest.
You're finally done!