从Wordpress迁移到Jekyll

http://pinkyjie.com/2013/10/24/migrate-from-wordpress-to-jekyll/

上周末闲着没事干突然想把博客从Wordpress迁移到Github pages上,于是周日花了一天时间做迁移,期间各种折腾,终于变成了现在这样还算满意的情况。虽然我已经好久不写博客了,但俗话说“书非借不能读也”,博客这一迁移也激起了我重新写博客的欲望。再说,这个博客还身兼重任,那就是——养媳妇!哈哈~还是说说迁移中遇到的乱七八糟的问题吧~

搭建本地环境

首先,自然是在自己的github上面new一个repository了,名字必须是yourname.github.com,虽然现在github pages的地址已经改为yourname.github.io了,但我还没有尝试过repository用io结尾行不。
完成以后,就是各种本地的设置了,搭建git环境,搭建ruby环境啊一类的,这里就不详细说了,ruby环境的搭建推荐使用RVM,很方便的说,当然,貌似不支持windows。。。如果在widnows下我推荐使用云IDE,就好像浏览器里的虚拟机,editor+terminal,我常用Nitrous.IO,给个我的推荐链接,有兴趣的可以试试。

然后就要在本地安装Jekyll了,一句话gem install jekyll搞定。Jekyll是一个ruby编写的静态站点生成器,在github上搭博客就靠它。但直接用jekyll貌似外观太朴素了,推荐直接使用jekyll-bootstrap,从名字就可以看出,这玩意把来自twitter的优秀CSS框架bootstrap结合进来,很多漂亮的主题可以选择,而且内置了很多常用的功能。直接从jekyll-bootstrap起步吧,先clone下来,然后把remote的地址改成自己的~

1
2
3
git clone https://github.com/plusjade/jekyll-bootstrap.git yourname.github.com
cd yourname.github.com
git remote set-url origin git@github.com:yourname/yourname.github.com.git

然后jekyll serve就可以在本地localhost:4000看到博客的样子,当然,现在空空如也~

先换主题

在导入文章进行各种设置之前,推荐先选一个自己喜欢的主题换上,因为后面很多定制涉及到修改主题文件,为了避免2次修改,先换一个主题比较方便。jekyll-bootstrap提供了一个主题预览网站,上面就有很多不错的主题。点击页面下面的主题名字进行预览,选择喜欢的以后,点击蓝色的Install Theme按钮,复制里面的代码执行,比如我选择的hooligan,代码如下:

1
2
rake theme:install git="https://github.com/dhulihan/hooligan.git"
rake theme:switch name="hooligan"

其中第一行将主题下载到_theme_packages里面,第二行切换到新主题。现在本地预览就可以看到新主题了。主题有两个相应的文件夹,一个是_includes/themes/xxx,这里放的是网页模板,另一个是 assets/themes/xxx,这里放的主题用到的css/js文件。我们要定制页面显示的内容通常修改第一个文件夹的东西,定制样式修改第二个,后面遇到了详细说。

Wordpress的文章迁移

现在可以导入原来的文章了,这个就比较闹心了,我的折腾时间有很大一部分花在这上面。官方文档专门讲解了各个常用的博客系统怎么迁移过来,wordpress的步骤也不复杂,从管理后台导出xml,然后执行一条命令即可将所有文章转换成.markdown,将其拷入_post文件夹即可。这个时候你本地预览就可以看到文章,标签以及分类信息了。闹心的事情来了,为什么我预览报一堆错误?为什么我的显示跟预期的不一样?唉,一个一个说吧~

乱七八糟的Could not find ref_id

这个问题浪费了我不少时间,最后发现原来是字符转义的问题!markdown语法里中括号[]是特殊字符,如果你的文章里出现则需要转义,加\号即可。Too Simple!

公式的显示

以前研究学术的时候写过好几篇满是公式的博文,原先wordpress里貌似用的是一种插件,到这里显然行不通了。一番搜索后发现一个叫MathJax的牛逼东西,用js来渲染公式。在_includes/themes/hooligan/default.html里加入

1
2
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

即可,这样就可以用$$作为开始结束符来输入公式了。注意这里的hooligan是你的主题名称,你的主题如果是别的就改成相应别的。这样的公式是独占一行的,如果要输入inline的公式,则还需要添加

1
2
3
4
5
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: { inlineMath: [['$','$'], ['\\(','\\)']] }
});
</script>

这样,使用$作开始结束符就可以输入行内的公式了。这里有个坑,有可能会遇到类似Liquid Exception: Variable xxx was not properly terminated with regexp xxx,这个我搜了半天,最后发现是公式内需要显示大括号时,原来会输入\{\},但jekyll中\也需要转义,改成\\{\\}即可。同样的问题还有公式换行的时候,原先的\\改成\\\\才行。有时[]也需要转义。转义——多么痛的领悟。

代码高亮

把博客整到github上的应该多半都是程序员吧,博客自然少不了一堆公式。在github上直接用类似

1
2
3
``` python
code
```

即可,但不知道为什么我的高亮一直没发生效,后来还是乖乖的用

1
2
3
{% highlight python %}
code
{% endhighlight %}

虽然写起来稍显复杂,但高亮效果不错,配合我的主题非常好看。另外,在写这篇文章的时候我又遇到一个问题,如何显示标签,比如像上面的代码里带有标签该如何转义书写呢,这个问题我也折腾了好久,很多人说用"进行嵌套,能解决问题,但是有点搞不清楚为啥这么写,后来发现,原来官方早就给答案了,把内容放到{% raw %}{% endraw %}里面就不会进行tag解析了。

图片迁移

博客搬过来了,图片不多的话自然也搬过来吧~在assets文件夹下新建文件夹imagesfiles,一个用来放图片,一个用来放文件附件。然后为了方便引用这两个路径,可以在_config.yml里定义变量:

1
2
img_url: /assets/images
file_url: /assets/files

然后就可以在文章里像这样![](http://pinkyjie-blog.qiniudn.com/images/picture.jpg)插入图片了。其实这里可以发现,_config.yml里就是这样定义变量的,然后文章里就可用site.xxx来访问了,后面添加评论的时候还会用到。_config.yml里还有很多有用的配置,比如作者信息,博客的名字等等,不多说,自己研究吧。添加图片路径后,巨大的工作量来自——下载原博客里的图片,这里推荐一个chrome插件Fatkun图片批量下载,谁用谁知道。

评论系统

由于是静态网站,评论什么的就知道使用第三方的套件来实现了,jekyll-bootstrap里自带的是国外很有名的社交评论系统disqus,只要在_config.yml里配置自己的帐号即可。但入乡随俗嘛,我用disqus 国内 山寨为关键词Google了一把,立马发现了符合我朝国情的产品,类似友言多说等等,随便看了一下,最后决定多说吧。。。据说多说可以将原wordpress的评论导入,反正我是没成功。注册一个多说,填写相关的站点信息,就可以在工具=>获取代码=>通用代码里得到需要粘贴的代码,其中<div class="ds-thread"></div>是具体显示评论的代码,其他部分是js代码。仿照前面的,将js代码复制到_includes/themes/hooligan/default.html里。为了不写死代码,我们将short_name这一行修改为

1
2
3
var duoshuoQuery = {
short_name: "{{ site.JB.comments.duoshuo.short_name }}"
};

后面我们会在_config.yml里配置这个short_name。然后另外的代码放哪里呢?首先,将你的多说信息配置到_config.yml里面,找到_config.ymlcomments这一段,改成:

1
2
3
4
comments :
provider : duoshuo
duoshuo :
short_name : xxxx

其中的short_name就是多说的通用代码里的short_name值。然后根据jekll-bootstrap的结构,评论由_includes/JB/comments管理,打开发现里面是一个ruby的switch-case分支结构,在{% endcase %}之前加上多说的判断即可:

1
2
{% when "duoshuo" %}
{% include JB/comments-providers/duoshuo %}

可以看到,实际的评论代码是放在_includes/JB/comments-probiders目录下的,在该目录下新建一个文件duoshuo,然后将刚才通用代码里的<div class="ds-thread"></div>复制进去即可。因为这个_includes/JB/comments会被很多模板自动引用,所以评论已经被添加到需要的地方去了。另外,如果你想定制评论,比如每篇博客右侧显示最近的评论和最近的来访者,可以修改_includes/themes/hooligan/page.html,这个是页面的默认模板,加一个<div class="span4">,熟悉bootstrap的孩子一定不陌生,这里就是右侧边栏,在这个div的最后面加入:

1
2
3
4
5
6
7
8
<section>
<h3>Latest Comments</h3>
<ul class="ds-recent-comments" data-num-items="10" data-show-avatars="0" data-show-time="0" data-show-title="0" data-show-admin="0" data-excerpt-length="18"></ul>
</section>
<section>
<h3>Recently Visitors</h3>
<ul class="ds-recent-visitors" data-num-items="4" data-avatar-size="45" style="margin-top:10px;"></ul>
</section>

首页的定制:分页与摘要

到现在博客应该像模像样了吧,但唯一不爽的就是首页了,默认的首页index.md显示的是所有文章的存档,比较朴素,怎样改成像传统wordpress那样显示文章的摘要和合理分页呢?官方文档同样专门有一节讲分页。首先,在_config.yml里配置分页,即添加paginate: 5,其中的5为每页的文章数,自己把握。然后,删除index.md,新建index.html,这一步很重要,我原来设置分页一直不成功就卡在这里,官方文档里也有讲,分页只对html生效!文档中有中规中矩的写法,大家可以参考,这里放出我修改过的版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
---
layout: page
title: 进击的马斯特
tagline: Go Fighting! Master!
---
 
{% for post in paginator.posts %}
<div class="post-wrapper">
<h2 class="h2 entry-title">
<a href="{{ post.url }}">{{ post.title }}</a>
</h2>
<div class="entry-meta">
<i class="icon-user"></i> <span>{{ post.author }}</span>  
<i class="icon-calendar"></i> <span>{{ post.date | date:"%Y-%m-%d" }}</span>  
{% unless post.categories == empty %}
<i class="icon-bookmark"></i>
{% for category in post.categories %}
<a href="/categories.html#{{ category }}-ref" target="_blank">
<span class="label post-category">{{ category }}</span>
</a>
{% endfor %}
{% endunless %}
 
{% unless post.tags == empty %}
<i class="icon-tag"></i>
{% for tag in post.tags %}
<a href="/tags.html#{{ tag }}-ref" target="_blank">
<span class="label post-tag">{{ tag }}</span>
</a>
{% endfor %}
{% endunless %}
</div>
<br /><br />
<div class="entry">
{{ post.content | split: '<!--more-->' | first }}
<p>
<a href="{{ post.url }}/#more" class="more-link btn">
<span class="readmore">阅读全文 »</span>
</a>
</p>
</div>
</div>
<br />
{% endfor %}
 
<!-- Pagination links -->
<div class="pagination pagination-centered">
<hr />
<ul>
<li class="disabled"><a>{{ paginator.page }} / {{ paginator.total_pages }}</a></li>
<li><a href="/">«</a></li>
{% if paginator.previous_page %}
{% if paginator.previous_page == 1 %}
<li><a href="/" class="current"><</a></li>
{% else %}
<li><a href="/page{{paginator.previous_page}}/"><</a></li>
{% endif %}
{% else %}
<li class="disabled"><a><</a></li>
{% endif %}
{% for count in (2..paginator.total_pages) limit:6 %}
{% if count == paginator.page %}
<li class="active"><a>{{count}}</a></li>
{% else %}
<li><a href="/page{{count}}/">{{count}}</a></li>
{% endif %}
{% endfor %}
{% if paginator.next_page %}
<li><a href="/page{{paginator.next_page}}/">></a></li>
{% else %}
<li class="disabled"><a>></a></li>
{% endif %}
<li><a href="/page{{paginator.total_pages}}/">»</a></li>
</ul>
</div>
<br />
<br />

头部就是主标题副标题,这个没啥说的,下面开始,paginator.posts里保存的是该页的所有文章信息,每篇文章的结构大致是.post-wrapper > .entry-title > .entry-meta > .entrydiv嵌套,这些样式你可以在assets/themes/hooligan/css/style.css里自定义。其中可以看到entry-meta里会输出文章的分类信息和标签信息,.entry里输出摘要。摘要如何实现网上有千奇百怪的版本,我也试了很多,心力憔悴,最后发现居然一句话就能实现,网上还有很多为了这个自己写插件的。。。其实想想原理就不难,因为wordpress里使用<!--more-->来显示摘要,只要在post.content里查找<!--more-->的位置显示其前面的内容就是摘要啊!所以{{ post.content | split: '<!--more-->' | first }}用这种类似管道的filter方式,先以<!--more-->调用split分割,然后用first取前面即可。其实我不太明白为什么直接写{{ post.content.split('!--more-->').first }}为啥不行。。。有懂的可以告诉我~后面的部分就是分页的页码了,我这里为了风格统一,套用了bootstrap的分页样式,具体可以看bootstrap分页文档。这样“高大上”的首页就诞生了。

大段代码的显示

大段代码的显示推荐使用github的gist,否则转义累死人啊!上面的大段代码就是用的gist显示的,配合了自定义的gist样式。这里值得说一下,gist也是个坑!关于在jekyll嵌入gist,可以使用官方的方案,直接写<script src="https://gist.github.com/yourname/xxx.js"></script>,也可以用jekyll的gist标签:{% gist xxx %}。很不幸,这两种方案都有问题,本地预览时正常显示,但上传到github后发现,gist后面的内容被截断,匪夷所思。经过一番算搜索发现,又是jekyll的标签解析惹得货啊。详细可以看这两篇文章:Fixing your embedding gist snippets 和 Why don’t self-closing script tags work?。简单来说就是,这两种方式会生成<script src="https://gist.github.com/yourname/xxx.js" />这样的标签,而很多浏览器解析这样的“自关闭标签”有bug,很奇怪吧,非常简单的问题居然有bug!!那怎么破呢,非常简单,加个空格即可,如:<script src="https://gist.github.com/yourname/xxx.js"> </script>

push到github时没效果

一切就绪,push到github去吧,相信很多人遇到过这个问题:明明我本地预览正常,为啥push到github不生效呢?快去查查邮箱,有没有收到github给你发的page build failure邮件啊,我是收到过五六封。。。其实这是因为github为了安全考虑禁止使用第三方插件,所以首先删除你_plugins文件夹下除了debug.rb以外的其他文件,然后本地预览时使用jekyll serve --safe --watch命令,--safe确保满足github的安全要求,--watch可以不用重启jekyll使修改即时生效。

总结

好了,博客现在差不多了,但对美有要求的你应该不会停止。jekyll-bootstrap由于是以bootstrap为基础的,所以熟悉前端的孩子修改起来特别方便,比如首页加个侧边栏,各种样式修改,加入font-awesome图标等等,慢慢探索吧~用bootstrap的另外一大好处就是,这个框架本来就是响应式的,所以不用费心去像wordpress一样装个插件去优化手机版,各种尺寸的屏幕都能做到自适应,非常方便!快把你的博客也迁过来吧!

上一篇:Chapter 5 : Control Structures 2 : Repetition


下一篇:List排序Collections.sort 重写compare