在把博客迁出 WordPress 的时候难免要一块儿把评论迁出来。怪了,全网常用的评论系统,Valine,Twikoo,怎么就没有 WordPress 导入呢?另一个评论系统,Artalk,倒是有个 Artransfer 工具,通过 WordPress 全部的导出文件解析评论,导出 Artrans 格式。但 sadly, it simply didn’t work. 它也并不能很好地处理重定向。
那总不能把评论一个一个输到 Twikoo 里面吧,那未免太不优雅了。何况即使五分钟手工能干成的事情,也要花两个小时去自动化完成(狗头)。
导出方法
WordPress 备份文件的组织形式我觉得挺麻的,幸好还有另一种获取评论的方式,即 REST API。该接口虽然是公开的,但是在进行认证之后,可以读取到评论的全部信息,包括发送者邮箱、IP 和 user-agent 等。而在以前使用的全部资料导出方式中,根本没办法导出 UA。
读出来某条评论大概是这个样子:
{
"id": 123, // 评论 ID
"post": 2345, // 文章 ID,即代表 /archives/2345 的那篇文章
"parent": 0, // 父评论 ID,0 代表没有父评论
"author": 0, // 作者 ID,0 代表未登录用户
"author_name": "AuthorName", // 作者名
"author_email": "author@example.com", // 作者邮箱
"author_url": "https:\/\/example.com", // 作者网站
"author_ip": "1.1.1.1", // 发送 IP
"author_user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0", // 发送者浏览器 UA
"date": "2000-00-00T00:00:00", // 本地和 GMT 发送时间
"date_gmt": "2000-00-00T00:00:00",
"content": {
"rendered": "content", // HTML 评论内容
"raw": "" // 纯文字评论内容
},
"link": "", // 评论链接,指向对应文章的对应评论
"status": "approved", // 是否过审
"type": "comment", // 好像只有 comment
"author_avatar_urls": { // 三种尺寸的头像链接。很难想象 WordPress 会直接预存三种链接,虽然都是 Gravatar 的
"24": "",
"48": "",
"96": ""
},
"meta": [], // 用于存放一些额外的 metadata
"_links": { // 相关 API endpoint
"self": [
{
"href": "https:\/\/example.com\/wp-json\/wp\/v2\/comments\/123"
}
],
"collection": [
{
"href": "https:\/\/example.com\/wp-json\/wp\/v2\/comments"
}
],
"children": [
{
"embeddable": true,
"href": "https:\/\/example.com\/wp-json\/wp\/v2\/comments?parent=123"
}
]
}
},
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
|
{
"id": 123, // 评论 ID
"post": 2345, // 文章 ID,即代表 /archives/2345 的那篇文章
"parent": 0, // 父评论 ID,0 代表没有父评论
"author": 0, // 作者 ID,0 代表未登录用户
"author_name": "AuthorName", // 作者名
"author_email": "author@example.com", // 作者邮箱
"author_url": "https:\/\/example.com", // 作者网站
"author_ip": "1.1.1.1", // 发送 IP
"author_user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0", // 发送者浏览器 UA
"date": "2000-00-00T00:00:00", // 本地和 GMT 发送时间
"date_gmt": "2000-00-00T00:00:00",
"content": {
"rendered": "content", // HTML 评论内容
"raw": "" // 纯文字评论内容
},
"link": "", // 评论链接,指向对应文章的对应评论
"status": "approved", // 是否过审
"type": "comment", // 好像只有 comment
"author_avatar_urls": { // 三种尺寸的头像链接。很难想象 WordPress 会直接预存三种链接,虽然都是 Gravatar 的
"24": "",
"48": "",
"96": ""
},
"meta": [], // 用于存放一些额外的 metadata
"_links": { // 相关 API endpoint
"self": [
{
"href": "https:\/\/example.com\/wp-json\/wp\/v2\/comments\/123"
}
],
"collection": [
{
"href": "https:\/\/example.com\/wp-json\/wp\/v2\/comments"
}
],
"children": [
{
"embeddable": true,
"href": "https:\/\/example.com\/wp-json\/wp\/v2\/comments?parent=123"
}
]
}
},
|
详细解析见 WordPress REST API Handbook。
要获取完整内容,需要在 WordPress 后台-用户-个人资料中生成一个“应用程序密码”(或使用 其他认证方式),然后在请求中加入对应的认证信息,并将 context
设为 edit
。比如使用 cURL:
curl --user "username:password" -X GET https://example.com/wp-json/wp/v2/comments?context=edit
1
|
curl --user "username:password" -X GET https://example.com/wp-json/wp/v2/comments?context=edit
|
输出格式
作为一个 Twikoo 用户,为什么不输出为 Twikoo JSON 呢,是因为不想用吗?
想啊,很想啊,但只有 Artalk 的 Artran 有现成的格式定义,而且数据定义也相对简单,起码比逆向 Twikoo JSON 简单得多。
{
"id": "123",
"rid": "233",
"content": "Hello Artalk",
"ua": "Artalk/6.6",
"ip": "233.233.233.233",
"created_at": "2021-10-28 20:50:15 +0800 +0800",
"updated_at": "2021-10-28 20:50:15 +0800 +0800",
"is_collapsed": "false",
"is_pending": "false",
"vote_up": "666",
"vote_down": "0",
"nick": "qwqcode",
"email": "qwqcode@github.com",
"link": "https://qwqaq.com",
"password": "",
"badge_name": "管理员",
"badge_color": "#FF716D",
"page_key": "https://artalk.js.org/guide/transfer.html",
"page_title": "数据迁移",
"page_admin_only": "false",
"site_name": "Artalk",
"site_urls": "http://localhost:3000/demo/,https://artalk.js.org"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
{
"id": "123",
"rid": "233",
"content": "Hello Artalk",
"ua": "Artalk/6.6",
"ip": "233.233.233.233",
"created_at": "2021-10-28 20:50:15 +0800 +0800",
"updated_at": "2021-10-28 20:50:15 +0800 +0800",
"is_collapsed": "false",
"is_pending": "false",
"vote_up": "666",
"vote_down": "0",
"nick": "qwqcode",
"email": "qwqcode@github.com",
"link": "https://qwqaq.com",
"password": "",
"badge_name": "管理员",
"badge_color": "#FF716D",
"page_key": "https://artalk.js.org/guide/transfer.html",
"page_title": "数据迁移",
"page_admin_only": "false",
"site_name": "Artalk",
"site_urls": "http://localhost:3000/demo/,https://artalk.js.org"
}
|
文档示例,简单易懂,对吧?唯一需要解释的就是 rid
,即父评论 ID。在不存在父评论的时候,可以直接设为 0。
实际上只含有下面的这些字段的话,也能用:id
、rid
、content
、ua
、ip
、is_collapsed
、created_at
、updated_at
、nick
、email
、link
、page_key
。在不太复杂的情况下,page_key
可以仅写作 /guide/transfer.html
。
链接重定向
如果迁移前后的评论系统附属网站 permalink 的格式不一样,那么评论的 page_key
也要做相应的修改。个人迁移前后的博客站点暂时是同时开放的,而迁移后 Hugo 也可以方便地设立重定向页面。
举个例子吧,假设原页面为 old.example.com/archives/2345,对应新页面为 new.example.com/post/new-post,则 Hugo 设立 alias 之后会在 new.example.com/archives/2345 生成一个重定向页面,内容为:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<title>https://new.example.com/post/new-post/</title>
<link rel="canonical" href="https://new.example.com/post/new-post/">
<meta name="robots" content="noindex">
<meta charset="utf-8">
<meta http-equiv="refresh" content="0; url=https://new.example.com/post/new-post/">
</head>
</html>
1
2
3
4
5
6
7
8
9
10
|
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<title>https://new.example.com/post/new-post/</title>
<link rel="canonical" href="https://new.example.com/post/new-post/">
<meta name="robots" content="noindex">
<meta charset="utf-8">
<meta http-equiv="refresh" content="0; url=https://new.example.com/post/new-post/">
</head>
</html>
|
假设我们在之前的 WordPress REST API 中已经获取到旧 WordPress 网站中某条评论的 post
字段值为 2345,那么只需要访问 new.example.com/archives/2345 ,运用正则表达式提取 refresh URL 即可提取到新的 page_key
,即 /post/new-post
。
代码实现
见 GitHub repo。
后记
写完程序之后,我变成了一个 Artalk 用户。