最後更新:2026/10/15
二十年前的網站首頁都有一個「您是第 003847 位訪客」的計數器。現在的網站不需要那個,但有兩個類似的需求一直都在:文章想顯示「看過幾次」,讓新讀者知道這篇有人看;下載按鈕旁邊想顯示「已下載幾次」,讓講義、型錄、菜單的下載數看得到。Google Analytics 當然都有這些數字,但它只能自己在後台看,不能顯示在網站上給客人看。
自己做一個計數器有兩個常見的坑。一是快取:網站開了頁面快取之後,PHP 不會每次都跑,在 PHP 裡加一就算不到。二是灌水:同一個人重新整理十次算十次,自己編輯文章時也算。這篇的做法避開這兩個坑:由瀏覽器在頁面打開後悄悄送一個小請求回報,所以有快取也算得到;同一個人十分鐘內只算一次;登入的員工不算。
不想自己改?把這篇交給 AI
把這篇的網址(或全文)連同下面這段話貼給 AI:
我的網站是 WordPress。我想照下面這篇文章,在文章顯示瀏覽次數、在下載連結旁顯示下載次數,不裝外掛。
請先問我:我要算文章瀏覽還是連結點擊、要顯示在哪裡、網站有沒有快取外掛。
問清楚之後,再一步一步告訴我:要用哪一段程式碼、貼在哪裡、短代碼怎麼放、怎麼確認數字有在增加。
如果文章的做法不適合我的網站,請直接告訴我原因和替代做法。
文章:(貼上這篇的網址,或整篇內容)
改之前先備份,密碼不要貼給 AI。
完整程式碼
// 第 87 篇:網站計數器、下載次數自己做(不裝外掛、有快取也能算)
// 1. 接收計數的網址:/wp-json/mimi/v1/hit
add_action('rest_api_init', function () {
register_rest_route('mimi/v1', '/hit', [
'methods' => 'POST',
'permission_callback' => '__return_true',
'args' => ['post' => ['type' => 'integer'], 'key' => ['type' => 'string']],
'callback' => function ($req) {
if (current_user_can('edit_posts')) {
return ['skipped' => 'staff']; // 自己人不算
}
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$what = $req['key'] ? 'k:' . sanitize_key($req['key']) : 'p:' . (int) $req['post'];
$lock = 'mimi_hit_' . md5($ip . $what);
if (get_transient($lock)) {
return ['skipped' => 'repeat']; // 同一個人 10 分鐘內只算一次
}
set_transient($lock, 1, 10 * MINUTE_IN_SECONDS);
if ($req['key']) {
$clicks = get_option('mimi_clicks', []);
$clicks[sanitize_key($req['key'])] = ($clicks[sanitize_key($req['key'])] ?? 0) + 1;
update_option('mimi_clicks', $clicks, false);
return ['count' => $clicks[sanitize_key($req['key'])]];
}
$n = (int) get_post_meta((int) $req['post'], '_mimi_views', true) + 1;
update_post_meta((int) $req['post'], '_mimi_views', $n);
return ['count' => $n];
},
]);
});
// 2. 前台的小程式:打開文章時記一次;按了有 data-count 的連結也記一次
add_action('wp_footer', function () {
$post_id = is_singular() ? get_queried_object_id() : 0;
?>
<script>
(function () {
var url = <?php echo wp_json_encode(rest_url('mimi/v1/hit')); ?>;
function hit(data) {
var body = new Blob([JSON.stringify(data)], {type: 'application/json'});
if (!navigator.sendBeacon || !navigator.sendBeacon(url, body)) {
fetch(url, {method: 'POST', body: body, keepalive: true});
}
}
<?php if ($post_id) : ?>hit({post: <?php echo (int) $post_id; ?>});<?php endif; ?>
document.addEventListener('click', function (e) {
var a = e.target.closest('[data-count]');
if (a) { hit({key: a.dataset.count}); }
});
})();
</script>
<?php
});
// 3. 顯示:[mimi_views] 這篇看過幾次;[mimi_clicks key="menu-pdf"] 某個連結點過幾次
add_shortcode('mimi_views', function () {
return number_format_i18n((int) get_post_meta(get_the_ID(), '_mimi_views', true));
});
add_shortcode('mimi_clicks', function ($atts) {
$a = shortcode_atts(['key' => ''], $atts);
return number_format_i18n((int) (get_option('mimi_clicks', [])[sanitize_key($a['key'])] ?? 0));
});
// 4. 後台文章列表多一欄「瀏覽」
add_filter('manage_posts_columns', function ($cols) {
$cols['mimi_views'] = '瀏覽';
return $cols;
});
add_action('manage_posts_custom_column', function ($col, $id) {
if ($col === 'mimi_views') {
echo (int) get_post_meta($id, '_mimi_views', true);
}
}, 10, 2);
程式碼放在 Code Snippets 這類外掛或子主題,放法和備份方式見〈WooCommerce 結帳頁改成台灣習慣〉。
四段各做了什麼
第 1 段開一個接收計數的網址 /wp-json/mimi/v1/hit,瀏覽器用 POST 送「文章編號」或「連結代號」過來,它就加一。三個規則寫在裡面:登入而且能編輯文章的人(管理員、編輯、作者)不算;同一個 IP 對同一篇文章或同一個連結,十分鐘內只算一次(用 WordPress 的暫存資料記住);文章的次數存在文章的附加資料 _mimi_views,連結的次數存在一個選項裡,用代號分開。
第 2 段是前台的小程式,放在每一頁的最下面。打開單篇文章或頁面時,它用瀏覽器的 sendBeacon 送一次「這篇被看了」,這個方法不會拖慢頁面,就算客人馬上關掉分頁也送得出去;舊瀏覽器沒有這個方法就改用一般的請求。另外它監聽整個頁面的點擊,任何加了 data-count="代號" 屬性的連結或按鈕被按下,就送一次那個代號。所以下載連結只要寫成 <a href="menu.pdf" data-count="menu-pdf">下載菜單</a>,點一次就算一次。
因為計數是瀏覽器送的,頁面快取不影響它:快取的頁面照樣含這段小程式,客人的瀏覽器照樣會送。顯示出來的數字則會跟著快取停一陣子,和快取時間一樣長,這在計數器上無所謂。
第 3 段是顯示用的短代碼:[mimi_views] 放在文章裡顯示這篇的次數,[mimi_clicks key="menu-pdf"] 顯示某個代號的點擊數,數字會加千分位。短代碼的寫法在〈WordPress 自己寫短代碼〉。
第 4 段在後台「文章」列表多一欄「瀏覽」,哪篇最多人看,一排就看完。
測試結果
我們在本機測試站建一篇文章,內文放「看過 [mimi_views] 次」和一個 data-count="menu-pdf" 的下載連結:
- 訪客打開兩次:瀏覽數是 1,第二次在十分鐘內,沒有重複算。
- 訪客按一下下載連結:點擊數變成 1,頁面顯示「看過 1 次。下載菜單 下載 1 次」。
- 管理員打開同一篇:數字不變。
- 後台文章列表多了「瀏覽」欄,那篇顯示 1。
這個數字和 GA 的差別
Google Analytics 算的是「工作階段」和「事件」,會過濾機器人、分裝置、分來源,數字給你自己分析用;這篇的計數器只是一個簡單的加法,給網站上的訪客看。兩個數字不會一樣,也不需要一樣。要追蹤按鈕、電話、表單這些事件給自己分析,看〈GA4 追蹤電話和按鈕點擊〉;要讓客人看到「這篇很多人看」「這份講義很多人下載」,用這篇。
數字很小的時候要不要顯示,自己決定。新網站的文章顯示「看過 3 次」沒有說服力,可以先只在後台看,累積到幾百再放到前台;或者只顯示下載數不顯示瀏覽數。
數字會說話,但要說對的話
「已下載 1,200 次」放在講義旁邊,是一種見證:很多人拿過,你也可以拿。這和客人評價、案例數量一樣,都是讓新客人安心的訊號,怎麼用可以看〈網站有人看卻沒人聯絡?〉。重點是數字要真的,自己做的計數器你知道它怎麼算,也就能放心用。
如果你的網站想把下載、見證、案例這些信任訊號一起規劃,可以先看〈IG 帳號不是你的資產〉想想網站要做到什麼。MIMI 專做客製化網頁設計,客製功能網站可以依你的需求做這類小功能。MIMI 提供新北網頁設計服務,新北的創作者可以用電話、Email 直接和設計師討論;費用可以先看首頁的製作費用參考,歡迎聯絡 MIMI。
