WordPress 统计文章阅读次数

原始方案是页面每次请求,阅读次数在后台就+1了,这样出现一个问题:如果是爬虫抓取,或者简单的命令行加载某个 html 页面,阅读数也会增加;
这种情况下,肯定不能让阅读次数增加,抓取页面的时候,虽然是返回了 HTML,但是爬虫并不会将页面内容展示出来,只是将返回页面当做字符串处理,截取需要的内容,这时候页面 JavaScript 是不会执行的;

利用爬虫抓取页面 JS 不执行的特点,修改为页面加载完成后,发出 ajax 请求增加阅读次数,这样就过滤掉了爬虫,于是就有了下面的最新方案(2019-01-29 更新):

0、公共方法

公共方法是 WordPress 新增功能几篇文章中代码的基础,在这儿添加一下,其他文章中不再重复;

// 获取 int 类型的 meta 标签
function get_int_meta($key)
{
    global $post;
    $post_ID = $post->ID;
    $count = (int)get_post_meta($post_ID, $key, true);
    return $count;
}

/// 判断当前用户是否为管理员
function user_is_admin()
{
    // wp_get_current_user函数仅限在主题的functions.php中使用
    $currentUser = wp_get_current_user();
    return !empty($currentUser->roles) && in_array('administrator', $currentUser->roles);
}

// ajax 失败公共函数
function ajax_error($msg = '操作失败,请稍后再试')
{
    header('Content-Type: application/json,charset=utf-8');
    echo json_encode(array(code => 0, msg => $msg));
    wp_die();
}

// ajax 返回公共调试信息
function ajax_debug()
{
    $method = $_SERVER['REQUEST_METHOD'];
    $info = array(
        method => $method,
        debug => ($host != 'ashita.top' && $host != 'www.ashita.top')
    );
    return $info;
}

// ajax 成功公共回调
function ajax_success($res, $msg = '操作成功')
{
    header('Content-Type: application/json,charset=utf-8');
    $resp = array(code => 1, msg => $msg, data => $res);
    $debug = ajax_debug();
    $debug['debug'] && ($resp['debug'] = $debug);

    echo json_encode($resp);
    wp_die();
}

1、记录访问次数

主题根目录下的 functions.php 中,在最后添加如下代码:

define('my_views', 'my_views');

/// 记录文章的阅读次数
function record_visitors()
{
    //delete_post_meta_by_key('views');
    $method = $_SERVER['REQUEST_METHOD']; // 获取请求 method
    $post_id = $_POST['id'];   // 获取文章id
    $ua = get_user_agent();    // 获取ua

    // 只有method为post、文章id有值、ua有值、非管理员、数据库中能查到该记录
    if ($method !== 'POST' || !$post_id || !$ua || user_is_admin() || !get_post($post_id))
        return ajax_error();

    $post_views = (int)get_post_meta($post_id, my_views, true);
    if (!update_post_meta($post_id, my_views, ($post_views + 1))) 
        add_post_meta($post_id, my_views, 1, true);

    $res = array(count => $post_views + 1, id => $post_id);
    ajax_success($res);
}

function get_meta_views()
{
    return get_int_meta(my_views);
}

add_action('wp_ajax_visitor', 'record_visitors');
add_action('wp_ajax_nopriv_visitor', 'record_visitors');
// add_action('wp_head', 'record_visitors');

2、添加前端 ajax 请求

主题根目录下的 single.php 中,页面底部 “<?phpget_footer(); ” 之前,新增下面的代码:

<script>
    (function () {
        var $ = jQuery;
        // ajax 请求地址和文章id
        var url = "<?php echo admin_url('admin-ajax.php')?>";
        var id = '<?php the_ID(); ?>';

        $(function () {
            highCode();
            vote();
            freshVisitor();
        });
        // 代码高亮
        function highCode() {}
        // 投票
        function vote() {}

        // 更新阅读次数
        function freshVisitor() {
            $.ajax({
                url: url,
                type: 'post',
                data: {
                    action: 'visitor',
                    id: id, // post_id
                },
                success: function (resp) {
                    //console.log(resp);
                    if (resp.code !== 1) return console.log('操作失败,请稍后再试');
                    var count = resp.data.count;
                    var $span = $('.entry-meta').find('.fa.fa-eye');
                    $span.text($span.text().replace(/^\d+/, count));
                },
                error: function () {
                    //console.log('操作失败,请稍后再试');
                },
                complete: function () {
                }
            });
        }
    })();
</script>

投票和代码高亮的功能请到“运维管理”分类下查找

*3、调用访问次数

这个调用只是为了页面初始化加载进来的时候,默认显示最新的阅读次数(不包括当前访问次数),不加也可以,因为 ajax 请求成功后更新了这个值;

在 inc/template-tags.php 中,直接 get_meta_views() 就能获取访问次数了,每个主题下该文件内容不一样,看情况加入下面的代码:

echo '<span class="fa-eye fa">' . get_meta_views() . '次浏览</span>';

上面的代码表示输出一个 span 标签,其中,fa fa-eye 这两个 class 也是根据主题来的,我用的 blog kit 主题有自己的字体图标,直接用就行了;

此处直接用 get_int_meta(my_views) 替换 get_meta_views() 也是可以的,但考虑到变量分散到多个地方,不好管理,所以将变量的声明、使用都统一放到了 functions.php 中;




下面是最初的原始方案,只是记录一下,没什么用了;

1、记录访问次数

打开主题根目录下的 functions.php 文件,在最后添加下面的代码:

define('my_views', 'my_views'); 

/// 记录文章的阅读次数
function record_visitors()
{
    // 非管理员且是单页面,添加/更新 my_views 字段
    if (!user_is_admin() && is_singular()) {
        global $post;
        $post_ID = $post->ID;

        delete_post_meta_by_key('views');
        if ($post_ID) {
            $post_views = (int)get_post_meta($post_ID, my_views, true);
            if (!update_post_meta($post_ID, my_views, ($post_views + 1))) {
                add_post_meta($post_ID, my_views, 1, true);
            }
        }
    }
}

add_action('wp_head', 'record_visitors');

// 获取文章的访问次数
function get_meta_views()
{
    return get_int_meta(my_views);
}

// 获取 int 类型的 meta 标签值
function get_int_meta($key)
{
    global $post;
    $post_ID = $post->ID;
    $count = (int)get_post_meta($post_ID, $key, true);
    return $count;
}

// 判断当前用户是否为管理员
function user_is_admin()
{
    // wp_get_current_user函数仅限在主题的functions.php中使用
    $currentUser = wp_get_current_user();
    return !empty($currentUser->roles) && in_array('administrator', $currentUser->roles);
}
  • record_visitors 中,有 post_meta 相关的操作,用我自己的话说,post_meta 表示页面的一个附属标签库;WrodPress 中 post 基本就表示页面,meta 表示标签,官方定义及术语可参考 这里
  • 标签库可以往里边随便加标签,标签包含 key 和 value,key 不能重复;数据库对应 xx_postmeta,里边有四列,meta_id、post_id、meta_key、meta_value;
  • record_visitors 方法是从 这里 找到的,拿来就能直接用;
  • user_is_admin 方法的内容是从 这里 找到的;
  • 统计访问次数,需要把管理员登录后的访问过滤掉,这样数据才准确;
  • get_meta_views 和 get_int_meta 两个方法分开,是因为下一篇文章也需要用到 get_int_meta 方法;
  • 因为 PHP 没有枚举类型,所以将 my_views 定义为一个常量,其他用到的地方都直接引用这个常量;

2、调用访问次数

在 inc/template-tags.php 中,直接 get_meta_views() 就能获取访问次数了,每个主题下该文件内容不一样,看情况加入下面的代码:

echo '<span class="fa-eye fa">' . get_meta_views() . '次浏览</span>';

上面的代码表示输出一个 span 标签,其中,fa fa-eye 这两个 class 也是根据主题来的,我当前用的 blog kit 主题有自己的字体图标,直接用就行了;

此处直接用 get_int_meta(my_views) 替换 get_meta_views() 也是可以的,但考虑到变量分散到多个地方,不好管理,所以将变量的声明、使用都统一放到了 functions.php 中;

如果这篇文章对你有用,可以点击下面的按钮告诉我

0

发表回复