缘由

之前有过一篇记一次小站评论功能的修改,目的是为了防止xss攻击,当时我使用的评论 Markdown 解析器是 WP-Editor.md 插件,最近更新WP发现插件有冲突,遂禁用了它,换用代码实现,如果你和我一样使用的是同一款主题的话,commit 已提交,快去更新吧~

引入Markdown解析器

原理很简单,与 WP-Editor.md 类似,在评论提交时,首先检查评论的合法性,再将评论转换为 HTML 并写入数据库,同时,原 Markdown 评论也储存进数据库,为了这样,我在 wp_comments 里增加了一个字段 comment_markdown,在读取评论打印的时候,直接显示转换好的html,这样做有个好处就是不用每次都转换评论,节省了不少资源,同时,原格式的评论有一个存档,虽然增加了数据库的一点点体积,但我认为不错。
用到了下面这个程序

这里下载源码,我们所需要的是压缩包里面的 Parsedown.php ,将它放入主题目录的任一位置
functions.php 里面引入它:

...
include path/to/Parsedown.php
...

之后,就可以在想要使用的地方像下面这样来使用啦~

$Parsedown = new Parsedown();

echo $Parsedown->text('Hello _Parsedown_!'); # prints: <p>Hello <em>Parsedown</em>!</p>

转换评论

使用WP的 preprocess_comment 在评论写入数据库之前拦截它

function markdown_parser($incoming_comment) {
    global $comment_markdown_content;
    $comment_markdown_content = $incoming_comment['comment_content'];
    include 'path/to/Parsedown.php';
    $Parsedown = new Parsedown();
    $incoming_comment['comment_content'] = $Parsedown->text($incoming_comment['comment_content']);
    return $incoming_comment;
}
add_filter('preprocess_comment' , 'markdown_parser');

储存原评论

原评论也很重要,因为kses的关系,部分评论可能会被转义,这时候就需要原评论啦~

新建字段

global $wpdb;
$myCustomer = $wpdb->get_row("SELECT * FROM wp_comments");
if (!isset($myCustomer->comment_markdown)) {
    $wpdb->query("ALTER TABLE wp_comments ADD comment_markdown text");
}

存入数据

在之前我定义了一个全局变量 $comment_markdown_content,现在就要用到它啦,do_action("comment_post") ,写入数据库立即触发

//保存Markdown评论
function save_markdown_comment($comment_ID, $comment_approved) {
    global $wpdb,$comment_markdown_content;
    $comment = get_comment($comment_ID);
    $comment_content = $comment_markdown_content;
    $wpdb->query("UPDATE wp_comments SET comment_markdown='".$comment_content."' WHERE comment_ID='".$comment_ID."';");
}
add_action('comment_post', 'save_markdown_comment', 10, 2);

打开评论HTML标签限制

为了安全,除管理员外wp的评论都会经过kese,甚至有时候管理员的评论也会过滤,这就需要我们来打开这个限制

function allow_more_tag_in_comment() {
    global $allowedtags;
    $allowedtags['pre'] = array('class'=>array());
    $allowedtags['code'] = array('class'=>array());
    $allowedtags['h1'] = array('class'=>array());
    $allowedtags['h2'] = array('class'=>array());
    $allowedtags['h3'] = array('class'=>array());
    $allowedtags['h4'] = array('class'=>array());
    $allowedtags['h5'] = array('class'=>array());
    $allowedtags['ul'] = array('class'=>array());
    $allowedtags['ol'] = array('class'=>array());
    $allowedtags['li'] = array('class'=>array());
    $allowedtags['td'] = array('class'=>array());
    $allowedtags['th'] = array('class'=>array());
    $allowedtags['tr'] = array('class'=>array());
    $allowedtags['table'] = array('class'=>array());
    $allowedtags['thead'] = array('class'=>array());
    $allowedtags['tbody'] = array('class'=>array());
    $allowedtags['span'] = array('class'=>array());
}
add_action('pre_comment_on_post', 'allow_more_tag_in_comment');

为了更加安全,可以更进一步

...
$allowedtags['pre'] = array(
    'class' => true,
    'id' => true,
);
$allowedtags['code'] = array(
    'class' => true,
);
...

或者采用我的方法,直接禁止HTML代码

后记

大功告成啦,这次修改又学到了好多东西,后续我可能会把前端的评论给改了,加个编辑器