0%

正威網路行銷工作室,專注於基隆、台北與全台客製化網頁設計,提供專業 RWD 響應式、SEO 搜尋引擎優化、品牌形象設計與網站維護託管服務。

搜尋文章
聯絡資訊
地址基隆市仁二路 220 號 5 樓
追蹤我們

網站目前在線人數怎麼顯示(不用外掛)

網站目前在線人數怎麼顯示(不用外掛) 封面

有些網站會在角落顯示「目前線上 12 人」,讓訪客感覺網站很熱鬧。網路上的舊教學多半是這樣做:每次有人打開網頁,PHP 就記下他的 IP,再數最近幾分鐘有幾個不同的 IP。

這個做法現在有兩個問題:

  • 網站開了快取就不準。快取外掛會把網頁存成固定的檔案,訪客拿到的是存好的頁面,PHP 根本沒有執行,人數就停在快取那一刻。
  • 記錄 IP 是個人資料,存了就要寫進隱私權政策,最好能不存就不存。

這篇換一種做法:網頁載入後,由訪客的瀏覽器每分鐘回報一次「我還在」,主機只記一組隨機產生的代號和時間,算出最近 5 分鐘有幾個人。

程式碼

放在子佈景主題的 functions.php,或用 Code Snippets 這類外掛新增:

PHP
// 1. 接收訪客瀏覽器每分鐘送來的「我還在」,回傳最近 5 分鐘內的人數
add_action( 'rest_api_init', function () {
	register_rest_route( 'zw/v1', '/online', array(
		'methods'             => 'POST',
		'permission_callback' => '__return_true',
		'callback'            => function ( WP_REST_Request $request ) {
			$id       = preg_replace( '/[^a-f0-9]/', '', strtolower( (string) $request->get_param( 'id' ) ) );
			$visitors = get_transient( 'zw_online' );
			$visitors = is_array( $visitors ) ? $visitors : array();
			$now      = time();
			foreach ( $visitors as $key => $time ) {
				if ( $now - $time > 5 * MINUTE_IN_SECONDS ) {
					unset( $visitors[ $key ] ); // 超過 5 分鐘沒消息,當作離開了
				}
			}
			if ( 16 === strlen( $id ) ) {
				$visitors[ $id ] = $now;
			}
			$visitors = array_slice( $visitors, -5000, null, true ); // 最多記 5000 人,避免被亂送資料塞爆
			set_transient( 'zw_online', $visitors, 10 * MINUTE_IN_SECONDS );
			return array( 'online' => count( $visitors ) );
		},
	) );
} );

// 2. 短代碼 [zw_online]:先放一個隱藏的位置,由瀏覽器取得人數後再顯示
add_shortcode( 'zw_online', function () {
	wp_register_script( 'zw-online', false, array(), null, true );
	wp_enqueue_script( 'zw-online' );
	wp_add_inline_script( 'zw-online', 'window.zwOnlineApi = ' . wp_json_encode( rest_url( 'zw/v1/online' ) ) . ';' . <<<'JS'
(() => {
  const el = document.querySelector('.zw-online');
  if (!el) return;
  let id = '';
  try { id = localStorage.getItem('zwOnlineId') || ''; } catch (e) {}
  if (!/^[a-f0-9]{16}$/.test(id)) {
    id = Array.from(crypto.getRandomValues(new Uint8Array(8)), (n) => n.toString(16).padStart(2, '0')).join('');
    try { localStorage.setItem('zwOnlineId', id); } catch (e) {}
  }
  const ping = () => fetch(window.zwOnlineApi, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ id }),
  })
    .then((res) => res.json())
    .then((data) => { el.querySelector('b').textContent = data.online; el.hidden = false; })
    .catch(() => {});
  ping();
  setInterval(() => { if (!document.hidden) ping(); }, 60000);
})();
JS
	);
	return '<span class="zw-online" hidden>目前線上:<b></b> 人</span>';
} );

在想顯示的地方放一個「短代碼」區塊,填 [zw_online]。頁尾、側欄的小工具也可以放。

程式在做什麼

主機這一端(第一段)

  • 註冊一個 REST API 網址 /wp-json/zw/v1/online,只接受 POST。
  • 收到代號後,先把超過 5 分鐘沒消息的人刪掉,再記下這個人現在的時間,回傳人數。
  • 代號只接受 16 個英文數字(0~9、a~f),其他格式的資料直接忽略;最多只記 5000 人,避免有人一直送假資料把它塞爆。
  • 資料存在 WordPress 的暫存資料(transient)裡,10 分鐘沒人回報就自動消失。

瀏覽器這一端(第二段的 JavaScript)

  • 第一次來的訪客,隨機產生一組代號存在瀏覽器裡(localStorage),之後同一個瀏覽器都用同一組。所以同一個人開好幾個分頁,只算一個人。
  • 網頁打開時回報一次,之後每分鐘回報一次。分頁切到背景、沒在看的時候不回報。
  • 拿到人數才把文字顯示出來。瀏覽器關掉 JavaScript、或連線失敗時,這段文字一直是隱藏的,不會出現「目前線上: 人」這種空白。

因為人數是瀏覽器另外去問的,網頁本身被快取也沒關係。

實際測試的結果

  1. 用 3 個不同的瀏覽器依序打開頁面:分別顯示 1 人、2 人、3 人。
  2. 第 1 個人在同一個瀏覽器再開一個分頁:還是 3 人,沒有重複計算。
  3. 直接送 4 筆格式不對的代號給 API:人數維持 3 人。
  4. 用 GET 方式打開 API 網址:WordPress 回應找不到(只接受 POST)。
  5. 模擬其他人都 6 分鐘沒有回報,第 3 個人重新整理頁面:變成 1 人。
  6. 關掉 JavaScript 打開頁面:線上人數的文字保持隱藏。

這是「大約」的人數

  • 同一個人用手機和電腦各開一次,會算成兩個人。
  • 兩個人在同一瞬間回報時,其中一筆可能被另一筆蓋掉,少算一個;下一分鐘回報就會補回來。
  • 「5 分鐘內」是自己定的,改程式裡的 5 * MINUTE_IN_SECONDS 就能調整。

拿來營造氣氛可以,不要拿它當正式的流量數據。

什麼情況不建議用

  • 流量很大的網站:每位訪客每分鐘都會打一次主機,線上 300 人就是每分鐘 300 次請求,而且這些請求都要執行 PHP,主機負擔不小。
  • 流量很小的網站:大部分時間都顯示「目前線上:1 人」(就是正在看的那個人),反而顯得冷清。
  • 想知道準確的流量:用 Google Analytics 的「即時」報表,能看到現在有多少人、在看哪一頁、從哪裡來,比自己數準確很多,也不會增加網站負擔。

舊教學裡常一起出現的「您是第幾位訪客」累計計數器,也不建議再做:被機器人、重新整理灌高的數字沒有意義,訪客也不太在意。

延伸閱讀

網站熱不熱鬧,最後還是要看有沒有帶來客人。正威網路行銷是 25 年經驗的基隆網頁設計工作室,網站管家年費包含每半年一次網站健檢報告,看流量和 Google 搜尋表現,台北與全台客戶也歡迎來聊聊。

分享這篇文章

返回文章列表更多「Wordpress代碼教學」文章

發表留言

還沒有人留言,歡迎第一個分享你的想法或問題。留言經審核後才會顯示,Email 不會公開。

讓我們一起打造
您的專屬網站!