临近放假事情不算多,利用空余时间陆陆续续对博客做了一些调整。

评论回复邮件通知延迟发送

无意发现了ze3kr 的评论回复邮件通知代码含有执行计划任务的代码,抄过来加到在用的评论回复邮件通知插件上,这个网站的评论回复邮件通知依赖 Comment Email Reply 插件,不知从 WordPress 的哪个版本开始这个插件便不再正常工作了,插件作者迟迟没有更新,一并做了修改,下面是修改后的完整代码:

<?php
/**
* Plugin Name: Comment Email Reply
* Plugin URI:  http://kilozwo.de/wordpress-comment-email-reply-plugin
* Description: Simply notifies comment-author via email if someone replies to his comment. Zero Configuration. Available in English and German. More languages welcome.
* Version:     1.0.5(dev)
* Author:      Jan Eichhorn
* Author URI:  http://kilozwo.de
* License:     GPLv2
*/

add_filter('wp_mail_content_type', function($contentType) { return 'text/html'; });
function cer_comment_notification($comment_id) {
    $comment_object = get_comment($comment_id);
    if ($comment_object->comment_approved == 1 && $comment_object->comment_parent > 0) {
        $comment_parent = get_comment($comment_object->comment_parent);

        $mailcontent =
            '<html>
            <head>
            <style>
                #mgy{margin:0;padding:0;font-size:16px;font-size:1rem;line-height:1.8;color:#444}
                #mgy .a{width:100%}
                #mgy .b{width:520px;margin:0 auto;padding:20px}
                #mgy .c{clear:both}
                #mgy .d,#mgy .n{margin:0 0 24px}
                #mgy .e{border-top:1px solid #DDD}
                #mgy .f{margin-bottom:10px}
                #mgy .g{margin:0 5px 0 0}
                #mgy .h{width:100px;height:32px;line-height:32px;padding:2px;border-radius:30px;color:#FFF;background:#52C69C;box-shadow:1px 1px 0 #DDD}
                #mgy .h:hover{background:#57AD68}
                #mgy .j{margin:0 6px;border-bottom:1px dotted;text-decoration:none}
                #mgy .k{text-align:center;text-decoration:none}
                #mgy .l{display:block}
                #mgy .m{color:#57AD68}
                #mgy .o{margin:5px 0}
                #mgy .p{color:#5A5A5A}
                #mgy .q{background:#F0F0F0;border-radius:4px;padding:8px;line-height:1.5rem;line-height:24px}
                #mgy .s{color:#2458A1}
                @media screen and (max-width:720px) {
                    #mgy{font-size:18px;font-size:1.125rem;line-height:2}
                    #mgy .b{width:100%;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
                }
            </style>
            </head>
            <body>
            <div id="mgy">
            <div class="a"><div class="b"><div class="o"><span class="g">'
            .$comment_parent->comment_author.
            ':</span>你好</div>'.
            '<div class="f"><span class="g s">'.$comment_object->comment_author.'</span>在'.
            '<a class="j" href="'.get_permalink($comment_parent->comment_post_ID).'">'.get_the_title($comment_parent->comment_post_ID).'</a>中 <span class="f">对你发表的评论:</span></div>'.
            '<div class="f q">'. esc_html($comment_parent->comment_content) .'</div>'.
            '<div class="f">作了如下回复:</div><div class="d s q">'
            . esc_html($comment_object->comment_content) .
            '</div>'.
            '<a class="d h k l" href="'.get_comment_link( $comment_parent->comment_ID ).'">继续回复</a>'.
            '<div class="f">感谢对<a class="j m" href="//maliyana.com">木瓜园</a>的支持,谢谢!</div>'.'<div class="e"><span class="p">MALI<span class="m">YA</span>NA</span></div></div></div></div>
            </body></html>';
        $email = $comment_parent->comment_author_email;
        $title ='来自 ['.get_option('blogname') . '] 的评论回复';
        wp_mail($email, $title, $mailcontent);
    }
}
add_action('comment_mail_notify','cer_comment_notification');

function comment_mail_notify_schedule($comment_id) {
    wp_schedule_single_event( time()+300, 'comment_mail_notify', array($comment_id));
}
add_action('wp_insert_comment','comment_mail_notify_schedule',99,2);

function cer_comment_status_changed($comment_id, $comment_status) {
    $comment_object = get_comment($comment_id);
    if ($comment_status == 'approve') {
        cer_comment_notification($comment_object->comment_ID, $comment_object);
    }
}
# Fire Email when comments gets approved later.
add_action('wp_set_comment_status','cer_comment_status_changed',99,2);
?>

更改防垃圾评论机制

卸载了 Akismet 插件,给评论功能加了两个小机关,配合起来效果不错,只是对人工垃圾评论无能为力。

外观上的一些调整

  • 过年了,要有气氛,临时改了个有春节喜庆氛围的配色;
  • 无限滚动改了新的加载动画,这是个 css3 动画,主要目的是改善手机无图模式下的浏览体验,同时,对 css3的支持,就意味着逐步停止对 IE 老旧浏览器的支持了。

今天手机被孩子拿着开 Garageband 打鼓,对着屏幕敲敲打打,忽然怎么也敲不响了,孩子觉得奇怪问为什么敲不响了。检查手机屏幕完好无损,只是失灵了,表现为屏幕触摸失灵。

屏幕失灵具体表现

  1. 无论怎么按 Home 键始终无反应,来电屏幕会亮,铃声振动也正常,能够触摸屏幕接通电话,仅仅是能接电话,其它操作统统失灵;
  2. 电源键有效,可以通过按电源键正常点亮或熄灭屏幕,但触摸屏幕仍处于失灵状态;
  3. 电源键+Home 并不能重启手机;
  4. 登录 iCloud 可以定位到手机,同时也可通过查找我的 iPhone 功能让手机响铃和振动,屏幕弹出的对话框时,能且只能点掉“好”这个按钮。

搜索 iPhone 7 Plus 屏幕失灵 这组关键字,发现有人遇到同样的情况,看来应该不是个例。

如何解决

解决办法其实很简单,以往 iPhone 是通过同时按住电源键+Home键强行重启的,只不过到了 iPhone 7/iPhone 7 Plus 这一代做了调整,不再支持电源键+Home键强行重启了,而是更换为音量-+电源键了,所以解决办法很简单,只需要同时按住音量-+电源键便会自动重启,即下图中的调低音量睡眠/唤醒按钮,重启后问题解决。

同时按住音量-+电源键重启,好熟悉的组合呀,这不是 Android 机的惯例么,不禁要让人多想了,怎么回事?细细一想也不能怪库克:作为首要技术更新,iPhone 7 和 iPhone 7 Plus 这一代的 Home 键不是实体键,是()不下去的(Taptic Engine 成功欺骗了每个人),想到一个成语:殊途同归!

上次介绍的方法可以有效阻止通过 wp-comment-post.php 提交的常规垃圾评论,却防不了通过 trackback 发送的垃圾评论。

WordPress 的评论类型 comment_type 共有三种:

  1. 表示是通过 wp-comment-post.php 提交的常规评论;
  2. trackback 通过 wp-trackback.php 提交,wp-trackback.php 只被 trackback 服务调用,查看 nginx 日志会发现 trackback 来的垃圾评论是直接在目标页面地址后面加上 “/trackback” POST 过来的;
  3. pingback 通过 xmlrpc.php 提交,xmlrpc.php 除了被 pingback 调用之外,通过 WordPress APP 访问博客时也需要调用它。

普通方法

这样就好办了,暴力一点的做法可以通过 nginx 配置文件直接禁止对 wp-trackback.php 文件的访问,但 xmlrpc.php 不能随便禁止,因为有其它服务要用到它,下面有个更好的办法可以避免这个问题。

更好的办法

更好的做法是在评论被写入 comment 表前判断评论类型,放过常规评论(阻止常规垃圾评论请见本文开头处的链接,除非人工提交或专门针对规则开发针对性的程序,理论上不会有漏网之鱼),单独对 trackback 和 pingback 类型做处理,得到下面的代码,放入主题的 function.php 文件即可:


//block trackback spam comments
function trackback_check($commentdata) {
    extract($commentdata);
    $post_object = get_post($comment->comment_post_ID);
    if ($comment_type == 'trackback' /* if pingbacks || $comment_type == 'pingback' */) {
        wp_die('Trackbacks are currently disabled!');
    }
    return $commentdata;
}
add_filter('preprocess_comment', 'trackback_check', 1);

上面代码只阻止未登陆用户的 trackback,pingback 以及博客内部的 trackback 则可正常工作,如要同时阻止 pingback,只需把|| $comment_type == 'pingback'加到 $comment_type == 'trackback'后面,这样一来即不影响类似 WordPress APP 这种需要调用 xmlrpc.php 来正常工作的服务,又能屏蔽外部的 pingback 了。

改动一下上述代码可将 trackback 垃圾评论的详细内容推送到邮箱,基本上 trackback 来的全是垃圾评论,几乎不存在误杀。

trackback 垃圾评论详情

最近对博客评论功能做了一些调整,防垃圾评论便是其一。即便作为一个无名小站每天也会收到几条垃圾评论,这之前一直用 Akismet 插件来防垃圾评论,Akismet 阻止下来的垃圾评论仍需要手动清理,久而久之快要被动地锻炼成定期查看垃圾评论的强迫症了,便想着要换掉 Akismet。

搜集了一些关于 WordPress 垃圾邮件工作机制介绍的资料,一般情况下垃圾评论是通过机器发送了,机器会向id="comment"name="comment"的文本框填充垃圾评论内容,并直接提交给 wp-comments-post.php 文件生成评论。

既如此,可不可以用一个取巧的办法:

  1. 将评论表单默认的comment文本框通过display:none隐藏掉(或者直接移除之);
  2. 单独增加一个对访客可见的替代文本框,取名为real_comment,用户在页面填写的评论内容实际是放在 real_comment 文本框的;
  3. 由于 WordPress 通过 comment 文本框取评论内容,所以,在评论提交给 wp-comments-post.php 前需要判断处理一下:comment 文本框不为空,说明是垃圾邮件,直接返回错误就行了;comment 文本框为空,说明是用户填写的,提交前需要进行一次置换,即把 comment_content 文本框的内容填充到 comment 文本框,完成置换后再进行提交。

改造评论表单

这个主题评论框用的是<?php comment_form(); ?>(一般是在主题文件夹的 comments.php 文件里),加额外字段需要对comment_form()做处理。

添加额外文本框

把要加的文本框

<textarea id="real_comment" name="real_comment" class="comment-textarea"></textarea>

加入文件 comments.php 之后得到如下代码:

<?php comment_form( array(
            'fields' => array(
                'author' => '<p class="commentform"><input type="text" name="author" id="author" class="ipt cmt-input" placeholder="昵称" aria-required="true" size="30" value="' . esc_attr( $commenter['comment_author'] ) . '"></p>',
                'email' => '<p class="commentform"><input type="text" name="email" id="email" class="ipt cmt-input" placeholder="邮箱[保密]" aria-required="true" size="30" value="' . esc_attr( $commenter['comment_author_email'] ) . '"></p>',
                'url' => '<p class="commentform"><input type="text" name="url" id="url" class="ipt cmt-input" placeholder="网址[可不填]" size="30" value="'.$comment_author_url.'"></p>'
                ),
            'comment_field' => '<p><textarea id="comment" name="comment"></textarea></p>
            <p><textarea id="real_comment" name="real_comment" class="ipt comment-textarea" placeholder="添加评论..." aria-required="true" cols="45" rows="8"></textarea></p>',
            'comment_notes_before' => '',
            'comment_notes_after' => '',
            'action' => '/stop-spam.php',
            'class_submit' => 'submit'
        ));
    ?>

替换表单 action

下一步需要对 wp-comments-post.php 做修改,考虑到 WordPress 版本更新覆盖旧文件问题,最好不要直接改动 wp-comments-post.php 文件,建议在博客根目录(wp-comments-post.php 所在的文件夹)新建一个单独的文件做跳板,如:wp-stop-spam.php,comment_form()默认的action是 wp-comments-post.php,现在要把action改为 wp-stop-spam.php,只需将'action' => '/wp-stop-spam.php',放到上面代码'class_submit' => 'submit'的前一行即可。

跳板文件

接下来打开 wp-stop-spam.php,把下面代码放入并保存:

<?php
nocache_headers();
$comment = trim($_POST['comment']);
// Proceed with regular comments.
if ( empty( $comment ) ) {
    $_POST['comment'] = trim($_POST['real_comment']);
    require( dirname(__FILE__) . '/wp-comments-post.php' );
}
if ( ! empty( $comment ) ) {
    require( dirname(__FILE__) . '/wp-load.php' );
    wp_die('You are not a human!');
}

大功告成,一旦 wp-stop-spam.php 收到提交上来的表单,首先检查comment文本框是否为空,不为空就是机器填写的(comment文本框做了隐藏后正常人是看不到的),直接组织评论生成并给出提示。

如果为空,则认为是正常访客提交的(正常访客只会在他们看到的real_comment文本框内填写评论内容,接着将real_comment文本框里的内容取作评论传给 wp-comments-post.php 生成评论。

禁止直接访问 wp-comments-post.php

如果还是不放心,那就直接禁止对 wp-comments-post.php 文件的直接访问,这个博客搭建在 nginx 上,把下面这段代码加入到 nginx 的主机配置文件重启 nginx 即可实现禁止直接访问 wp-comments-post.php 文件的目的(不影响 wp-stop-spam.php 文件 require 它)。

location = /wp-comments-post.php {
	return 404;
}

用了两周效果很不错,没有一条垃圾评论!

以上方法对使用机器通过 wp-comment-post.php 提交的垃圾评论有效(对人工提交的垃圾评论爱莫能助),往往还有一些垃圾评论是通过 trackback 发送的,如需屏蔽 trackback 请参照如何屏蔽 trackback/pingback 垃圾评论

上个月的这个时候在郑州经历的一场雪

雪下的很大,一大早街道上满是积雪

雪下了一整天:
冬季·河南·郑州·大雪

积雪的梧桐树:
大雪天的法国梧桐

公交车开的非常非常慢

下了雪,落了叶,这辆车真幸福:
积雪落叶

雪给人们带来了惊喜

积雪的法国梧桐