原文出自绛木子博客:https://lixianhua.com/te_ajax_comment_without_pluign.html
为了不使用插件实现Ajax
评论功能需要实现:
1,监听评论表单,改用ajax
方式提交
2,创建新的评论表单提交地址(用Typecho
主题提供的系统方法themeInit
实现)
当访问文章加载主题时,themeInit
方法首先被加载,可在此方法中判断是否为添加评论的操作,即新的评论表单地址为文章的链接(permalink
).具体判断方法如下
// 主题初始化 function themeInit($archive){ // 判断是否是添加评论的操作 // 为文章或页面、post操作,且包含参数`themeAction=comment`(自定义) if($archive->is('single') && $archive->request->isPost() && $archive->request->is('themeAction=comment')){ // 为添加评论的操作时 ajaxComment($archive); } }
要实现ajax
评论,则无法使用系统默认的feedback
,这里我们将复制feedback
功能并改造为我们需要的方法
/** * ajaxComment * 实现Ajax评论的方法(实现feedback中的comment功能) * @param Widget_Archive $archive * @return void */ function ajaxComment($archive){ $options = Helper::options(); $user = Typecho_Widget::widget('Widget_User'); $db = Typecho_Db::get(); // Security 验证不通过时会直接跳转,所以需要自己进行判断 // 需要开启反垃圾保护,此时将不验证来源 if($archive->request->get('_') != Helper::security()->getToken($archive->request->getReferer())){ $archive->response->throwJson(array('status'=>0,'msg'=>_t('非法请求'))); } /** 评论关闭 */ if(!$archive->allow('comment')){ $archive->response->throwJson(array('status'=>0,'msg'=>_t('评论已关闭'))); } /** 检查ip评论间隔 */ if (!$user->pass('editor', true) && $archive->authorId != $user->uid && $options->commentsPostIntervalEnable){ $latestComment = $db->fetchRow($db->select('created')->from('table.comments') ->where('cid = ?', $archive->cid) ->where('ip = ?', $archive->request->getIp()) ->order('created', Typecho_Db::SORT_DESC) ->limit(1)); if ($latestComment && ($options->gmtTime - $latestComment['created'] > 0 && $options->gmtTime - $latestComment['created'] < $options->commentsPostInterval)) { $archive->response->throwJson(array('status'=>0,'msg'=>_t('对不起, 您的发言过于频繁, 请稍侯再次发布'))); } } $comment = array( 'cid' => $archive->cid, 'created' => $options->gmtTime, 'agent' => $archive->request->getAgent(), 'ip' => $archive->request->getIp(), 'ownerId' => $archive->author->uid, 'type' => 'comment', 'status' => !$archive->allow('edit') && $options->commentsRequireModeration ? 'waiting' : 'approved' ); /** 判断父节点 */ if ($parentId = $archive->request->filter('int')->get('parent')) { if ($options->commentsThreaded && ($parent = $db->fetchRow($db->select('coid', 'cid')->from('table.comments') ->where('coid = ?', $parentId))) && $archive->cid == $parent['cid']) { $comment['parent'] = $parentId; } else { $archive->response->throwJson(array('status'=>0,'msg'=>_t('父级评论不存在'))); } } $feedback = Typecho_Widget::widget('Widget_Feedback'); //检验格式 $validator = new Typecho_Validate(); $validator->addRule('author', 'required', _t('必须填写用户名')); $validator->addRule('author', 'xssCheck', _t('请不要在用户名中使用特殊字符')); $validator->addRule('author', array($feedback, 'requireUserLogin'), _t('您所使用的用户名已经被注册,请登录后再次提交')); $validator->addRule('author', 'maxLength', _t('用户名最多包含200个字符'), 200); if ($options->commentsRequireMail && !$user->hasLogin()) { $validator->addRule('mail', 'required', _t('必须填写电子邮箱地址')); } $validator->addRule('mail', 'email', _t('邮箱地址不合法')); $validator->addRule('mail', 'maxLength', _t('电子邮箱最多包含200个字符'), 200); if ($options->commentsRequireUrl && !$user->hasLogin()) { $validator->addRule('url', 'required', _t('必须填写个人主页')); } $validator->addRule('url', 'url', _t('个人主页地址格式错误')); $validator->addRule('url', 'maxLength', _t('个人主页地址最多包含200个字符'), 200); $validator->addRule('text', 'required', _t('必须填写评论内容')); $comment['text'] = $archive->request->text; /** 对一般匿名访问者,将用户数据保存一个月 */ if (!$user->hasLogin()) { /** Anti-XSS */ $comment['author'] = $archive->request->filter('trim')->author; $comment['mail'] = $archive->request->filter('trim')->mail; $comment['url'] = $archive->request->filter('trim')->url; /** 修正用户提交的url */ if (!empty($comment['url'])) { $urlParams = parse_url($comment['url']); if (!isset($urlParams['scheme'])) { $comment['url'] = 'http://' . $comment['url']; } } $expire = $options->gmtTime + $options->timezone + 30*24*3600; Typecho_Cookie::set('__typecho_remember_author', $comment['author'], $expire); Typecho_Cookie::set('__typecho_remember_mail', $comment['mail'], $expire); Typecho_Cookie::set('__typecho_remember_url', $comment['url'], $expire); } else { $comment['author'] = $user->screenName; $comment['mail'] = $user->mail; $comment['url'] = $user->url; /** 记录登录用户的id */ $comment['authorId'] = $user->uid; } /** 评论者之前须有评论通过了审核 */ if (!$options->commentsRequireModeration && $options->commentsWhitelist) { if ($feedback->size($feedback->select()->where('author = ? AND mail = ? AND status = ?', $comment['author'], $comment['mail'], 'approved'))) { $comment['status'] = 'approved'; } else { $comment['status'] = 'waiting'; } } if ($error = $validator->run($comment)) { $archive->response->throwJson(array('status'=>0,'msg'=> implode(';',$error))); } /** 添加评论 */ $commentId = $feedback->insert($comment); if(!$commentId){ $archive->response->throwJson(array('status'=>0,'msg'=>_t('评论失败'))); } Typecho_Cookie::delete('__typecho_remember_text'); $db->fetchRow($feedback->select()->where('coid = ?', $commentId) ->limit(1), array($feedback, 'push')); // 返回评论数据 $data = array( 'cid' => $feedback->cid, 'coid' => $feedback->coid, 'parent' => $feedback->parent, 'mail' => $feedback->mail, 'url' => $feedback->url, 'ip' => $feedback->ip, 'agent' => $feedback->agent, 'author' => $feedback->author, 'authorId' => $feedback->authorId, 'permalink' => $feedback->permalink, 'created' => $feedback->created, 'datetime' => $feedback->date->format('Y-m-d H:i:s'), 'status' => $feedback->status, ); // 评论内容 ob_start(); $feedback->content(); $data['content'] = ob_get_clean(); $data['avatar'] = Typecho_Common::gravatarUrl($data['mail'], 48, Helper::options()->commentsAvatarRating, NULL, $archive->request->isSecure()); $archive->response->throwJson(array('status'=>1,'comment'=>$data)); }
当已经在functions.php
文件中添加完上述方法时,就已经可以接收ajax
评论了。
此时我们需要修改评论表单添加的方式及提交的地址。
在footer.php
文件中添加方法
// 依赖jquery,请自行加载 $(function(){ // 监听评论表单提交 $('#comment-form').submit(function(){ var form = $(this), params = form.serialize(); // 添加functions.php中定义的判断参数 params += '&themeAction=comment'; // 解析新评论并附加到评论列表 var appendComment = function(comment){ // 评论列表 var el = $('#comments > .comment-list'); if(0 != comment.parent){ // 子评论则重新定位评论列表 var el = $('#comment-'+comment.parent); // 父评论不存在子评论时 if(el.find('.comment-children').length < 1){ $('<div class="comment-children"><ol class="comment-list"></ol></div>').appendTo(el); }else if(el.find('.comment-children > .comment-list').length <1){ $('<ol class="comment-list"></ol>').appendTo(el.find('.comment-children')); } el = $('#comment-'+comment.parent).find('.comment-children').find('.comment-list'); } if(0 == el.length){ $('<ol class="comment-list"></ol>').appendTo($('#comments')); el = $('#comments > .comment-list'); } // 评论html模板,根据具体主题定制 var html = '<li id="comment-{coid}" class="comment-body comment-ajax"><div class="comment-author"><span><img class="avatar" src="{avatar}" alt="{author}" width="32" height="32"></span><cite class="fn">{author}</cite></div><div class="comment-meta"><a href="{permalink}"><time>{datetime}</time></a></div><div class="comment-content">{content}</div></li>'; $.each(comment,function(k,v){ regExp = new RegExp('{'+k+'}', 'g'); html = html.replace(regExp, v); }); $(html).appendTo(el); } // ajax提交评论 $.ajax({ url: '<?php $this->permalink();?>', type: 'POST', data: params, dataType: 'json', beforeSend: function() { form.find('.submit').addClass('loading').html('<i class="icon icon-loading icon-pulse"></i> 提交中...').attr('disabled','disabled');}, complete: function() { form.find('.submit').removeClass('loading').html('提交评论').removeAttr('disabled');}, success: function(result){ if(1 == result.status){ // 新评论附加到评论列表 appendComment(result.comment); form.find('textarea').val(''); }else{ // 提醒错误消息 alert(undefined === result.msg ? '<?php _e('评论出错!');?>' : result.msg); } }, error:function(xhr, ajaxOptions, thrownError){ alert('评论失败,请重试'); } }); return false; }); });
ajax
评论需要自定义评论模板,获取使用其他方式拼接评论html
。
评论form
表单的提交按钮需要添加class="submit"
或修改代码为其他自定义的class
注:需开启评论的反垃圾保护
以上为转载内容,在实际投入使用时遇到了两点问题
一,通过ajax进行评论,邮件通知插件并不会发出通知!
原因是因为重写了评论的函数,而函数中没写评论完成后触发插件接口,所以邮件通知插件不会发邮件给作者。
解决方法也很简单在上述php代码$db->fetchRow($feedback->select()->where('coid = ?', $commentId)->limit(1), array($feedback, 'push'));
后面加入$feedback->pluginHandle()->finishComment($feedback);
即可。
二,评论过滤插件也会失效!
原因也是没有写入评论过滤的接口
这个接口我试着往里面写,没有成功,所以换了个方式来解决,直接在里面写过滤,而不是用插件过滤评论。
比如在$commentId = $feedback->insert($comment);
前面加入
if (preg_match("/[\x{4e00}-\x{9fa5}]/u", $comment['text']) == 0) { $archive->response->throwJson(array('status'=>0,'msg'=>_t('评论内容请不少于一个中文汉字'))); }
即可屏蔽非中文评论,建议同时使用评论过滤插件,因为有些垃圾评论是通过评论机器人完成的,并不会经过ajax评论,所以还需要继续使用评论过滤插件,亦或者在模板层面上用上评论过滤接口(我是这么做的,目前来看大概是有效果的)
觉得文章有用就打赏一下文章作者
微信扫一扫打赏