Migrating to Ghost from Miniblog

It's that time of year again. I'm migrating my blog. Last year I moved from Wordpress to Miniblog. Now I'm moving from Miniblog to Ghost.

I usually start by giving the reasons for the move. This time is no different.

  • I want to write in Markdown.
  • I wanted more theming options.
  • I wanted to get away from Windows Live Writer.

Don't get me wrong, Miniblog is a great blogging platform and I will be keeping my fork on Github in case I decide to go back to it.

One of the main reasons for moving to Miniblog, was so that I could use Windows Live Writer to write/post/manage my articles. On the whole it worked well, however, I found that my stylesheet in Miniblog didn't really work very well with Live Writer and the writing experience was a little quirky. But the main negative for me (and why I wanted to move away from Live Writer) was that I wanted to write in Markdown. The HTML being produced by Live Writer was clean, but I just don't trust it in the same way that I trust Markdown.

Ghost Installation

One of the most important things about moving your blog is the installation. I decided to fork the AzureWebApps\Ghost-Azure and then use the amazing Deploy To Azure button. If you haven't seen this yet, go and take a look - it's great.

I initially tried deploying directly from the main repo, rather than forking, but soon realised that I wanted to make some customisations so would be easier to have my own repo.

The Deploy To Azure button makes deployment so simple. The Azure WebApp is automatically connected to the GitHub repository and monitoring it for changes. When I push a commit to it, a new deployment automatically appears in seconds.

Azure Deployments

If you haven't seen Azure Deployments, I would encourage you to take a look.

Data Transfer

This wasn't easy. A cursory Google will show you that there are plenty of blog migration tools, but I was unable to find a Miniblog to Ghost migrator. In the end I wrote one myself using the Ghost documentation.

You can find the migrator here. It is not a one-size-fits-all program. If you wish to use it, you will need to make changes to it. It is extremely rough and ready and was written in a very short time in order to import my data.

Handling Images

In my Miniblog installation, the images were uploaded alongside the post. It appears that at the time of writing, the Ghost import routine does not allow importing of images alongside the posts.

Instead, I signed up for the free version of Cloudinary in order to host my images. They have a free tier, which will last a very long time based on my current usage.

The migrator I wrote automatically looks for images within the posts, uploads the image to Cloudinary and then rewrites the URL with the new one from Cloudinary. All in all, it was a very simple process.

Missing Features

There were a number of missing features from the AzureWebApps\Ghost-Azure repository which I needed to fill in.

Slug Mapping

One of the biggest missing features I noticed was URL/Slug mapping. This is usually an issue when migrating blogs where you don't want to lose all your search engine indexes by changing the URL. In this case, the issue is that Miniblog uses the URL format posts/slug-name whereas Ghost omits posts. I assumed that this would be a simple feauture of Ghost, but seemingly I was wrong. Miniblog also uses a date format for it's urls. The format used is:

YYYY/MM/Slug

In the end, I had to amend the web.config and add another rewrite rule.

<rule name="SlugMap" stopProcessing="true">  
    <match url="^(post|\d{4}/\d{2})/(.*)" />
    <action type="Redirect" url="{R:2}" redirectType="Permanent"/>
</rule>  

This rule just simply removes the post and any year/month directory from the url.

Disqus

One of the customisations I made to Miniblog was adding Disqus for comments. I needed to do the same here for Ghost. There are plenty of examples of how to do this online, but I will briefly show what I did here.

I needed to amend several files from within the theme. The first was default.hbs and this was to get the comment counts against each post. I added the following before the tag.

<script type="text/javascript">  
    /* * * CONFIGURATION VARIABLES * * */
    var disqus_shortname = 'gregpakesblog';

    /* * * DON'T EDIT BELOW THIS LINE * * */
    (function () {
        var s = document.createElement('script'); s.async = true;
        s.type = 'text/javascript';
        s.src = '//' + disqus_shortname + '.disqus.com/count.js';
        (document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
    }());
</script>  

Next is putting the actual disqus feed on the bottom of each post. I edited post.hbs and placed the following before the tag.

<div id="disqus_thread"></div>  
<script type="text/javascript">  
    /* * * CONFIGURATION VARIABLES * * */
    var disqus_shortname = 'gregpakesblog';

    /* * * DON'T EDIT BELOW THIS LINE * * */
    (function() {
        var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
        dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();
</script>  
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>  

There are full instructions for this available on the Disqus site.

Syntax Highlighting

This was much simpler. I followed this very helpful blog and pasted the following into the Code Insertion section of the settings.

<!-- http://highlightjs.readthedocs.org/en/latest/css-classes-reference.html -->  
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.5/styles/github.min.css">  
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.5/highlight.min.js"></script>  
<script>hljs.initHighlightingOnLoad();</script>  
<style>  
  pre {
    word-wrap: normal;
    -moz-hyphens: none;
    -ms-hyphens: none;
    -webkit-hyphens: none;
    hyphens: none;
    font-size: 0.7em;
    line-height: 1.3em;
  }
    pre code, pre tt {
    white-space: pre;
  }
</style>  
Google Analytics

The last piece was to put Google Analytics back on the page. I did this by using the inbuilt code insertion section within Settings.

Conclusion

Ghost seems like a solid blogging platform. So far, I am happy with it. Support seems to be a little thin on the ground. Whilst I was researching the URL Rewriting, there were lots of people with the same questions on the ghost forums, but seemingly no answers.

If I decide to change platform again, I'll be sure to post about it.