Làm bộ đếm lượt xem không cần plugin

Mấy hôm nay mình có việc phải đụng tới bảng wp_options và giật mình khi bảng này có tới nửa triệu dòng. Hoá ra là dữ liệu rác của cái plugin đếm lượt xem.

Mình mới dùng cái plugin này khoảng 3 tháng, thấy nó chạy rất ngon lành. Nhưng lắm rác thế này thì không thể chấp nhận được.

Và thế là đi tìm cái plugin khác. Tìm nửa ngày thì chán và trong lúc định đành chấp nhận cái đang dùng thì thấy một cái tiêu đề rất lá cải “How to Display Popular Posts by Views in WordPress without a Plugin”.

Lạy bố, không viết nó thành plugin thì tống nó vào đâu đó trong theme chứ gì. Tiêu đề thì lá cải nhưng giải pháp trông cũng lành. Và việc của mình là bổ sung cho nó thêm tí hoa lá cành :p

<?php
// Original concerpt: http://wpbeg.in/Mo67Vt
 $week = date('YW',current_time('timestamp',7));
$month = date('Ym',current_time('timestamp',7));
$year = date('Y',current_time('timestamp',7));
 $view_keys = array (
'total' => '', // All time, easier to sum up
'week' => $week, // Current week, to be used somewhere
'month' => $month, // Current month, will be used one or two times
'year' => $year // Current year, never used :p
);
 function luom_set_post_views($postID) {
global $view_keys;
 if (is_user_logged_in()) {return;} // Don't count for logged in users
 foreach ( $view_keys as $k => $v ) { // week => 52
$metakey = 'luom_views_' . $k;
$old_value = get_post_meta($postID, $metakey, true);
 if($old_value==''){ // Never counted
$new_value = ($k != 'total') ? "$v:1" : "1";
delete_post_meta($postID, $metakey);
add_post_meta($postID, $metakey, $new_value);
} else { // Counted
if ($k != 'total') { // Views by Week/Month/Year
$count_array = explode(':', $old_value);
$count_key = $count_array[0];
$count_value = $count_array[1];
} else { // Total views
$count_key = '';
$count_value = $old_value;
}
// New count value
$count = ($v == $count_key) ? (int)$count_value : '0';
$count++;
$new_value = ($k != 'total') ? "$v:$count" : "$count";
update_post_meta($postID, $metakey, $new_value);
}
}
}
//To keep the count accurate, lets get rid of prefetching
remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0);
 function luom_track_post_views ($postID) {
if ( !is_single() ) return; // Track for single post only
if ( empty ( $postID) ) {
global $post;
$postID = $post->ID;
}
luom_set_post_views($postID);
}
add_action( 'wp_head', 'luom_track_post_views');
 function luom_get_post_views($postID, $type = 'total'){
$metakey = 'luom_views_' . $type;
$got_value = get_post_meta($postID, $metakey, true);
if($got_value==''){ // Never counted
return "0";
}
if ($type == 'total') { // Total views
$count = $got_value;
} else { // Views by Week/Month/Year
$array = explode(":", $got_value);
$count = $array[1];
}
return $count;
}
 function luom_get_most_views_list($type = 'total', $items = '5', $show_count = false) {
global $wpdb, $view_keys;
 $metakey = "luom_views_" . $type;
$time_prefix = $view_keys[$type];
 if ($type == 'total') { // Total views
$posts = $wpdb->get_results("
SELECT
$wpdb->posts.ID,
$wpdb->posts.post_author,
$wpdb->posts.post_date,
$wpdb->posts.post_name,
$wpdb->posts.post_parent,
$wpdb->posts.post_status,
$wpdb->posts.post_type,
CAST($wpdb->postmeta.meta_value AS SIGNED) AS views
FROM
$wpdb->posts, $wpdb->postmeta
WHERE
$wpdb->posts.ID = $wpdb->postmeta.post_id
AND $wpdb->postmeta.meta_key = '$metakey'
ORDER BY views DESC
LIMIT $items"
);
} else { // Views by Week/Month/Year
 $posts = $wpdb->get_results("
SELECT
$wpdb->posts.ID,
$wpdb->posts.post_author,
$wpdb->posts.post_date,
$wpdb->posts.post_name,
$wpdb->posts.post_parent,
$wpdb->posts.post_status,
$wpdb->posts.post_type,
CAST(SUBSTRING($wpdb->postmeta.meta_value,LOCATE(':',$wpdb->postmeta.meta_value)+1) AS SIGNED) AS views
FROM
$wpdb->posts, $wpdb->postmeta
WHERE
$wpdb->posts.ID = $wpdb->postmeta.post_id
AND $wpdb->postmeta.meta_key = '$metakey'
AND $wpdb->postmeta.meta_value LIKE '$time_prefix%'
ORDER BY views DESC
LIMIT $items"
);
}
 if ($posts) { // Has results
echo "<ul>";
foreach ( $posts as $p ) {
$p->post_status = 'publish';
$p->filter = 'sample';
$url = get_permalink($p);
$title = get_the_title($p);
$count = '';
if ($show_count)
$count = " ($p->views)";
echo "<li><a href='$url'>$title</a>$count</li>";
clean_object_term_cache( $p->ID, $p->post_type );
}
echo "</ul>";
}
}

Nhu cầu của mình đại loại là với một post thì cần đếm số lượt xem ở các mức sau:

  • Tổng số lượt xem
  • Lượt xem trong tuần hiện tại (xin nhấn mạnh là hiện tại)
  • Lượt xem trong tháng hiện tại (một lần nữa nhấn mạnh ở hiện tại)
  • Lượt xem trong năm hiện tại (chỉ năm hiện tại thôi, không lưu năm khác)

Dữ liệu thứ nhất thì đương nhiên là để hiện thị trong bài. Cái thứ 2 hoặc thứ 3 thì làm cái danh sách xem nhiều nhất ở sidebar. Còn dữ liệu thứ 4 (lượt xem trong năm) thì chắc chả bao giờ dùng đến, nhưng thôi, cứ để cho nó đủ.

Cơ bản là mình không có nhu cầu làm biểu đồ thống kê, mặc dù đôi khi cũng hữu ích.

Mình cũng đếm luôn cả bot cho số nó hoành. Nếu bị DDos (mà vẫn sống) thì triệu viu cũng thích 😆

Tất nhiên là mình biết cả cách chuyển đổi dữ liệu của cái plugin đang dùng sang giải pháp này. Và sau khi chuyển đổi, xoá dữ liệu rác thì dung lượng cơ sở dữ liệu của mình giảm đi hơn nửa. Thật là vãi nhái!