WordPress评论ajax动态加载,解决静态缓存下评论不更新问题

这是一个历史遗留问题,自从博客部署了 PHP 纯静态缓存之后,所有页面都是 html 静态内容了,而且在七牛 CDN 静态分离之后,速度更是达到极致!

不过也带来不少疑难问题,在之前写的《启用 WP Super Cache 纯代码版本之后的一些优化措施》一文中已经总结一些解决办法。其中为了解决用户无法看到最新回复的问题,我也想了多个办法,比如成功提交评论就会删除该页缓存、右下角集成清理缓存按钮等。在我多次改进之后,已经趋向于完美,而且这个 php 缓存优化也是张戈博客有偿服务最受欢迎的项目之一。

前不久,有朋友拿我的网站练手,用大量代理 IP 对我的博客进行 DDos 攻击,无奈之下博客临时转入到百度云加速。转入之后,如果把云加速的页面缓存也打开,那么就有了 2 层缓存:【CDN 节点的 html 缓存】和【服务器的 html 缓存】。那么我之前写的ajax 清理缓存以及评论删除缓存失去了效果,因为只能删除本地的 html 缓存,而 CDN 节点的缓存百度并未提供 API 控制接口,所以用户看到的还是缓存内容!

当然,不是强迫症的话,直接关闭百度的页面缓存就可以了!但这只是逃避问题,而没有解决问题!所以,本文就分享一下,强迫症是如何解决这个非必须问题的。

一、自动动态加载评论

这是我最初想到的、而且是老早就想实现一种方案:当静态的 html 页面加载时,评论部分实时从数据库动态拉取数据,由于是纯静态下的 html 页面,所以这个功能需要 JS+Ajax 来实现。

①、php 评论动态拉取接口代码

<?php
if ('comment_list.php' == basename($_SERVER['SCRIPT_FILENAME']) && !isset($_POST['post_id'])) {
    header("content-type:text/html; charset=utf-8");
    echo '您好!请不要直接访问这个页面!';
    exit();
}
require('../wp-blog-header.php');
header("Content-type: text/html;charset=UTF-8");
header('HTTP/1.1 200 OK');
$comments = get_comments(array(
	'post_id' => $_POST['post_id'],
	'status' => 'approve'
));
echo '<ol class="commentlist">';
wp_list_comments('type=comment&reverse_top_level=true&page=0&callback=mytheme_comment&end-callback=mytheme_end_comment',$comments);
echo '</ol>';
?>

Ps:代码的原理就不赘述了,主要用到 wp_list_comments 内置函数,感兴趣的可以自行了解下。

以上代码保存为 php 文件,比如 ajax-comments.php,保存到网站根目录,备用。

②、Ajax 评论请求代码

<script type="text/javascript">
/* 将函数放置到ready里面,页面加载后自动执行 */
jQuery(document).ready(function($){
     Ajax_Comments();   
});
/* Ajax请求,分开写方便调用 */
function Ajax_Comments(){
$.ajax({
    type: "POST",
    url: location.origin+"/ajax-comments.php",
    data:{"post_id":<?php echo $post->ID;?>},
    dataType: "html",
    success: function(out){
        /* 用实时拉取的内容替换原来的内容 */
        $('.commentlist').html($(out).fadeIn(500));
    }
});
}
</script>

以上代码可以直接贴到网站的 footer.php 当中。如果你要添加到 js 文件中,请除去首尾的 script 标签,而且 post_id 值需要在外部通过 php 动态定义(搞不清的还是直接贴 footer 吧)!

特别说明下,2 段代码中的【.commentlist】是指评论列表的 class,比如知更鸟主题的评论列表的是<ol class="commentlist">评论列表</ol>,实际上请根据主题的评论列表 class 或 ID 来自行修改!

部署无误之后,每次页面加载都会动态去拉取一次最新的评论,并呈现给用户。

优点:每次打开页面用户都能看到最新评论; 缺点:每次打开页面都会动态拉取评论,降低了纯静态效果,拉取的评论分页有点误差(影响不大)。

二、手动动态刷新评论

这个方法灵感源自网络上流行的评论分页 Ajax 加载:点击评论的下一页,不会刷新整个页面,而是通过 ajax 拉取被点击那个分页的全部内容,然后找到评论部分并加载。

简单解释下原理:

比如,张戈博客的留言板,有 100 页评论,那么第 99 页的评论地址应该是:http://zhangge.net/liuyan/comment-page-99/,当点击【99】这个分页链接时,将触发 ajax 函数,先隐藏当前分页的所有评论,然后 ajax 拉取第 99 页的内容,然后将评论部分加载出来,实现不刷新页面来加载评论。

分析了这个过程,我们可以发现一个特征关键字,那就是分页地址后面的 comment-page-xx !这是个好东西,因为我可以在云加速和本地的缓存中排除这个关键词的缓存即可!也就说,浏览器直接访问带comment-page-xx这类关键词的地址,就略过缓存,加载动态内容!

因此,当我们部署了 ajax 评论分页,点击其他分页将会显示非缓存内容!但是这还不是我需要的,因为我想要当前页面也实现动态评论。也许聪明人会说,你点到其他评论分页,再点回来不就好了嘛?

确实,实现 ajax 评论分页后,我点到其他评论分页,然后再点回来,确实可以实现评论刷新,但是却用了 2 次点击!

好,下面我们换个角度,既然 comment-page-xx 是动态页面,那么 comment-page-1 肯定也是动态页面咯!

于是就有 2 种情况:第一种,文章评论数量还不够生成分页,那这时候只要拉取 comment-page-1 就可以了;第二种,评论已经存在分页,那么只要拉取这个 comment-page-【页码】即可,所以 ajax 拉取之前,我们只要通过 js 判断来决定要拉取的目标地址即可。

那么,js 如何判断评论是否有分页了呢?很简单,先分析下网页代码:

可以发现分页是有分页对应的 class 的,那么 js 只要判断这个 class 是否存在就好啦!而且我还可以发现当前的分页和其他分页的 class 还是不一样的:当前分页的 class 是【page-numbers current】,而 其他分页则是【page-numbers】,如以此来,我们还可以用 js 代码 $('.page-numbers.current').html() 获得当前分页的页码!!!

那问题就好解决了,我们只要先判断是否存在分页,然后根据不同情况抓取不同的目标地址即可!

下面开始分享代码:

/* 评论ajax获取函数 */
function Ajax_Comments(){
    $.ajax({
        type: "GET",
        url: ajax_url,
        beforeSend: function(){
            /* 触发后移除评论列表、评论分页及评论统计(不清楚的可参考张戈博客的评论ID元素) */
            $('.navigation_c').remove();
            $('.commentlist').remove();
	    $('#comments').remove();
            /* 显示正在加载中效果 */
            $('#loading-comments').slideDown();
            /* 这里判断评论开启并没有评论的情况,sofa是我定义的抢沙发DIV */
            if($('.sofa').html() == undefined && $('.nocomments').html() == undefined ){
                $body.animate({scrollTop: $('.refresh').offset().top - 65}, 800 );
            /*  这里判断评论已关闭,nocomments是提示本文评论已关闭的div */
            } else if ($('.nocomments').html() != undefined){
                alert('很抱歉!本文评论已关闭。您可以到留言板</a>畅所欲言。');
                return false;
            }
        },
        dataType: "html",
        success: function(out){
            /* 在ajax拉取内容中查找评论列表部分 */
	    commentlist = $(out).find('.commentlist');
            /* 如果没有评论,则提示抢沙发 */
            if(commentlist.length == 0) {
                $('#loading-comments').hide();
                alert('暂无评论,您可以抢沙发哟~!;');
                return false;
            /* 如果有评论,则移除抢沙发模块 */
            } else {
                $('#sofa').remove();
            }
            /* 获取评论统计DIV模块,有的主题可能没有 */
            comments = $(out).find('#comments'); 
            /* 获取评论分页DIV模块 */
            nextlink = $(out).find('.navigation_c');
            $('#loading-comments').slideUp('fast');
            /* 将评论统计输出到(加载中)模块的后面,并移除[加载中]模块 */
	    $('#loading-comments').after(comments.fadeIn(500));
            /* 将评论列表输出到评论统计模块的后面 */
	    $('#comments').after(commentlist.fadeIn(500));
            /* 将评论分页输出到评论列表的后面,完成本次加载 */
            $('.commentlist').after(nextlink);
        }
    });  
}
 
/* 评论ajax分页 */
$('.page-numbers').live('click', function(e){
    e.preventDefault();
    if ($(this).attr('href') != undefined) {
        ajax_url = $(this).attr('href');
    } else {
        /* 点击当前分页页码也可以刷新评论 */
        ajax_url = page_url+"/comment-page-"+$('.page-numbers.current').html()+"/#comments";
    }
    Ajax_Comments()
});
 
/* 手动刷新评论 */
function refresh_Comments(){
    /* 根据文章是否存在分页,定义不同的抓取地址 */
    if ($('.page-numbers.current').html() != undefined) {
        /* 如果存在分页,则抓取当前分页地址 */
        ajax_url = page_url+"/comment-page-"+$('.page-numbers.current').html()+"/#comments";
    } else {
        /* 如果没有分页,则抓取comment-page-1 */
        ajax_url = page_url+"/comment-page-1/#comments";
    }
    Ajax_Comments();
}
 
/* 将评论刷新函数绑定到ID为refresh的点击事件上 */
$(function(){ 
    $("#refresh").click(function(){
        refresh_Comments();
    }); 
});

使用方法很简单,把这个代码添加到主题已有的 js 中,然后在任意位置新增一个 ID 为 refresh 的 html 元素即可,比如:

<div id="refresh">刷新评论</div>

Ps:这个代码参考修改自:《WordPress Ajax 评论分页 | Kayo's Melody》,因此如果没看懂 ajax 评论分页,本文分享的也会看得稀里糊涂的,尤其是代码中的 ID 元素,不同主题是不一样的。

本文分享的方法和思路,如果不是真正需要,我想会看得很痛苦,因为我写的也很痛苦!很多地方不好解释,因为你没有需求,就可能看不懂!!但是,只要是我用心折腾过的功能,我都想分享出来,网络这个林子那么大,不可能就没有同样需求的人吧?!有时候,【解决思路】真心比【实现代码】来的更加难得!

这种看似很复杂的文章,实际上,光看文章是很费解的,个人建议结合自己的需求,然后对比张戈博客的页面源代码去参考,会更容易理解一些。

好了,废话说了够多了,还是那句话,文章是分享给真正有需要的人,没有需求,又说不出个甲乙丙丁的人,建议不要在本文浪费口水,说三道四比较好!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Youngxj

在线听歌房源码 - MKOnlineMusicPlayer V2.21

2213
来自专栏何俊林

Android组件化项目详细实施方案

导读:组件化,插件化开发,将是未来Android中不可或缺的一环。今天来自张华洋的分享,张华洋的blog地址:http://blog.csdn.net/guiy...

1966
来自专栏不止是前端

Vue:在Vue中实现微信网页授权和分享

1.6K16
来自专栏企鹅号快讯

Webpack 持久化缓存实践

作者:happylindz https://github.com/happylindz/blog/issues/7 前言 最近在看 webpack 如何做持久化...

2425
来自专栏贾鹏辉的技术专栏@CrazyCodeBoy

React Native 每日一学(Learn a little every day)

本文出自《React Native学习笔记》系列文章。 每天一个知识点(技巧,经验,填坑日记等),每天学一点,离大神近一点。 汇聚知识,分享精华。 如果你是一...

3369
来自专栏BestSDK

开发微信小程序,必知的40个小技巧

微信小程序开发者和开发需求者必读的40条技巧分享: Q:为什么脚本内不能使用window等对象 A:页面的脚本逻辑是在JsCore中运行,JsCore是一个没有...

4373
来自专栏编程

Python爬虫之urllib库—进阶篇

urllib库除了一些基础的用法外,还有很多高级的功能,可以更加灵活的适用在爬虫应用中,比如,用HTTP的POST请求方法向服务器提交数据实现用户登录、当服务器...

1898
来自专栏我思故我在

ABP框架 - 启动配置

1545
来自专栏惶心 - 技术博客

Grouper.html: 分享群组的最佳方式

之前看到 狗子 的 https://getrbq.com ,是给 DIYgod 的群组做的一个加群页面,发现他是用 折影轻梦 的模板修改了一下做好的。虽然说这个...

1136
来自专栏我和PYTHON有个约会

Django来敲门~第一部分【6.1 视图函数】

在我们创建好的应用polls/中,可以定义视图函数,专门用于接收和响应URL请求操作的函数; 该函数默认第一个参数接收的就是一个请求对象HttpRequest...

511

扫码关注云+社区