
WordPress 網站開放留言之後,很快就會收到一堆看不懂的英文、日文留言,內容多半是廣告連結。這些垃圾留言不只讓後台很難整理,萬一不小心被核准公開,訪客也會覺得這個網站沒人在管。
擋垃圾留言沒有一招就搞定的方法,比較好的做法是一層一層擋:先用 WordPress 內建的設定,再裝一個防垃圾留言外掛,用不到留言的地方直接關掉,最後才視需要加上程式碼。這篇就照這個順序整理。
(原本另外三篇〈用代碼實現 wordpress 評論留言數字驗證〉、〈wordpress 使用 .htaccess 有效的杜絕垃圾評論〉、〈用代碼設定 wordpress 留言評價的最大字數及最小字數〉的內容,已經整合到這裡。)
第一層:調整「設定 → 討論」
到後台「設定 → 討論」,下面這幾個選項不用裝任何東西,就能擋掉大部分的垃圾留言(選項文字依 WordPress 版本會有些不同):
- 留言者必須填寫姓名及電子郵件地址:建議勾選。
- 留言必須經過人工核准,或是留言者先前必須有一則已核准的留言:勾選後,新面孔的留言要你按「核准」才會公開,垃圾留言就算送進來,也不會出現在網站上。
- 自動關閉舊文章的留言:垃圾留言最常鎖定發佈很久的舊文章,設定發佈超過 30~90 天後自動關閉,對真正的讀者影響很小。
- 留言裡的連結數量:預設包含 2 個以上連結的留言會先進入審核,可以改成 1,只要有連結就先擋下來給你看。
- 留言審核關鍵字:留言的內容、名稱、網址、電子郵件或 IP 符合清單裡的字,就會先進入審核。
- 不允許使用的關鍵字(舊版叫「留言黑名單」):符合清單的留言會直接被移到垃圾桶。
兩個關鍵字清單都是一行填一個字或一個 IP。要注意它會比對「字的一部分」,例如填 press 也會擋到 WordPress,所以不要填太短、太常見的字。
第二層:安裝防垃圾留言外掛
設定只能擋掉比較明顯的垃圾留言,大量自動送出的廣告留言,交給外掛判斷比較省事。下面兩個擇一即可:
- Akismet:WordPress.com 的母公司 Automattic 推出,下載 WordPress 時就內附這個外掛,啟用後才會作用。留言送出時會交給 Akismet 的伺服器判斷,是垃圾留言就自動移到「垃圾留言」。要到官網申請金鑰,個人、非商業網站可以免費使用,公司或商業網站依官方規定要選付費方案。因為留言資料會送到國外的伺服器,記得在網站的隱私權政策裡說明。
- Antispam Bee:免費、不用申請帳號,主要在自己的主機上判斷,例如用蜜罐欄位、檢查留言是不是填得太快,比較沒有資料外送的顧慮。
誤判的時候,到「留言」頁面的「垃圾留言」分類裡找到那則留言,把它標記為不是垃圾留言,就能救回來。
如果垃圾留言真的多到擋不完,也可以加上 Cloudflare Turnstile 或 Google reCAPTCHA 這類人機驗證(外掛目錄搜尋就有相關外掛),代價是真正的讀者留言時會多一個步驟。
第三層:用不到留言的地方,直接關掉
公司形象網站的頁面、媒體附件頁,本來就不需要留言,開著只會招來垃圾留言。關閉的方法請看WordPress 關閉留言功能。
另外,Pingback、Trackback 這兩個舊功能,現在收到的幾乎都是垃圾通知,也建議一起關閉,做法請看WordPress 關閉 Pingback 與 Trackback。
第四層:用程式碼加強
下面的程式碼都是加到子主題的 functions.php,或用 Code Snippets 外掛新增,不要直接改主題本身的檔案(原因請看WordPress functions.php 實用程式碼整理)。每加一段,都用無痕視窗(沒有登入)實際留言一次,確認真人還能正常留言。
1. 蜜罐欄位:讓機器人自己露出馬腳
「蜜罐」(Honeypot)是在留言表單裡多放一個真人看不到的欄位。真人不會填它,但自動送留言的程式通常會把每個欄位都填滿,只要這個欄位有值,就知道是機器送的。
它也能順便擋掉「根本沒打開網頁、直接對 wp-comments-post.php 送資料」的程式,因為這種送法不會帶著這個欄位。
// 1) 在留言表單裡加一個真人看不到的欄位
add_action( 'comment_form', function () {
echo '<p class="ahwei-hp" aria-hidden="true" style="position:absolute;left:-9999px;">'
. '<label for="ahwei-hp">這個欄位請保持空白</label>'
. '<input type="text" id="ahwei-hp" name="ahwei_hp" value="" tabindex="-1" autocomplete="off">'
. '</p>';
} );
// 2) 送出留言時檢查:沒有這個欄位(沒經過表單)或欄位被填了,就是機器
add_action( 'pre_comment_on_post', function () {
if ( is_user_logged_in() ) {
return;
}
if ( ! isset( $_POST['ahwei_hp'] ) || '' !== $_POST['ahwei_hp'] ) {
wp_die(
'留言送出失敗,請回上一頁重新整理後再試一次。',
'留言送出失敗',
array( 'response' => 403, 'back_link' => true )
);
}
} );- 欄位用 CSS 移到畫面外;
tabindex="-1"和aria-hidden是讓用鍵盤操作、用螢幕報讀軟體的真人,也不會跑到這個欄位。 - 如果你的主題留言表單是自己寫的、沒有呼叫
comment_form這個 hook,欄位就不會出現,所有訪客的留言都會被擋。所以加好之後一定要實際測試。
2. 限制留言的最少、最多字數
太短的「Nice post!」、太長的一整篇廣告文,都是垃圾留言的特徵。
原本文章用 strlen() 計算長度,但它算的是「位元組」而不是字數。一個中文字在 UTF-8 裡佔 3 個位元組,設定「最少 60 個字元」其實 20 個中文字就達標,跟原本寫的「約 30 個中文字」對不起來。改用 mb_strlen() 算的才是真正的字數:
add_filter( 'preprocess_comment', function ( $commentdata ) {
// 只檢查一般留言;管理員、編輯在後台回覆不受限制
$type = isset( $commentdata['comment_type'] ) ? $commentdata['comment_type'] : '';
if ( ! in_array( $type, array( '', 'comment' ), true ) || current_user_can( 'moderate_comments' ) ) {
return $commentdata;
}
$min = 5; // 最少幾個字
$max = 1000; // 最多幾個字
$text = trim( wp_strip_all_tags( $commentdata['comment_content'] ) );
$length = mb_strlen( $text, 'UTF-8' );
if ( $length < $min ) {
wp_die(
sprintf( '留言太短了,最少要 %d 個字喔!', $min ),
'留言太短',
array( 'response' => 400, 'back_link' => true )
);
}
if ( $length > $max ) {
wp_die(
sprintf( '留言太長了,最多 %d 個字。', $max ),
'留言太長',
array( 'response' => 400, 'back_link' => true )
);
}
return $commentdata;
} );$min、$max改成你要的字數。最少字數不要設太高,「謝謝分享!」只有 5 個字,設成 30 字會把真心但簡短的留言也擋掉。- 有審核留言權限的管理員、編輯不受限制,在後台回覆留言不會被擋。
- 只檢查一般留言,不影響 Pingback、Trackback。
3. 只收中文留言(適合讀者都在台灣的網站)
原本文章的第二種方法,是把沒有任何中文字、或含有日文假名的留言視為垃圾留言。但原本的程式碼呼叫了一個不存在的 err() 函式,在新版 PHP 會直接出錯。下面是修正後的寫法,而且改成丟進「垃圾留言」而不是直接擋掉,萬一誤判還能救回來:
add_filter( 'pre_comment_approved', function ( $approved, $commentdata ) {
// 已經被判定為垃圾留言的,就不用再檢查
if ( is_wp_error( $approved ) || in_array( $approved, array( 'spam', 'trash' ), true ) ) {
return $approved;
}
// 管理員、編輯的留言不檢查
if ( current_user_can( 'moderate_comments' ) ) {
return $approved;
}
// 只檢查一般留言
$type = isset( $commentdata['comment_type'] ) ? $commentdata['comment_type'] : '';
if ( ! in_array( $type, array( '', 'comment' ), true ) ) {
return $approved;
}
$text = $commentdata['comment_content'];
$has_chinese = preg_match( '/\p{Han}/u', $text );
$has_kana = preg_match( '/[\x{3040}-\x{30FF}]/u', $text );
if ( ! $has_chinese || $has_kana ) {
return 'spam';
}
return $approved;
}, 10, 2 );\p{Han}代表中文字(漢字),\x{3040}-\x{30FF}是日文的平假名與片假名。日文留言裡也會有漢字,所以要另外檢查假名。- 網站有外國讀者、或常有人用英文留言的話,就不要用這段。
用 .htaccess 擋「直接送出」的留言:有用,但有風險
原本另一篇文章的做法,是在 .htaccess 裡檢查送往 wp-comments-post.php 的留言:如果不是從自己網站的網頁送出(看瀏覽器帶的 Referer),或是沒有瀏覽器資訊(User-Agent),就擋掉。舊寫法的網域比對太寬鬆,擋下來之後還會把對方轉到一個奇怪的網址。修正後的寫法如下,放在 # BEGIN WordPress 的上面,example\.com 換成自己的網域:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_METHOD} POST
RewriteCond %{REQUEST_URI} wp-comments-post\.php [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com/ [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^$
RewriteRule ^ - [F]
</IfModule>意思是:送出留言時,如果來源不是自己的網站,或沒有瀏覽器資訊,就回應 403 拒絕。
但這個方法有幾個限制與風險,使用前要想清楚:
- 擋不住聰明一點的程式:Referer 和 User-Agent 都是送出的一方自己填的,要偽造非常容易,擋得到的只有最簡陋的機器人。
- 可能誤擋真人:有些瀏覽器的隱私設定、擴充功能或公司防火牆會把 Referer 拿掉,這些訪客留言時會直接看到 403 錯誤,而你完全不會知道。
- 網址改了要記得改:網站換網域時忘了同步修改,所有人都會無法留言。
- 只適用 Apache、LiteSpeed 主機,Nginx 主機不讀
.htaccess。
上面的蜜罐欄位一樣能擋掉「沒經過表單」的留言,又不會誤擋把 Referer 拿掉的真人,建議優先用蜜罐。.htaccess 的其他常用設定,請看.htaccess 用法大全。
舊版文章裡不建議再用的做法
- 在
.htaccess一個一個封鎖 IP:舊寫法Order Allow,Deny、Deny from是舊版 Apache 的語法,建議改用Require。更大的問題是垃圾留言的 IP 幾乎每次都不一樣,一個一個封效果很有限。真的要封,把 IP 填進「討論」設定的關鍵字清單最簡單。 - 自己寫程式比對特定關鍵字:舊程式碼一樣用了不存在的
err(),還要把記錄寫進主機的系統資料夾,一般虛擬主機沒有這個權限。關鍵字過濾請直接用「討論」設定裡的清單。 - 自製數字驗證碼、加法驗證(原本〈數字驗證〉那篇):舊寫法把正確答案、或是要相加的兩個數字,放在表單的隱藏欄位裡一起送出,機器人只要讀取網頁就能拿到答案,等於沒擋。需要人機驗證的話,請改用前面提到的 Turnstile、reCAPTCHA 外掛。
延伸閱讀
- WordPress 關閉留言功能:全站關閉、只關頁面、舊文章自動關閉的做法
- WordPress 關閉 Pingback 與 Trackback:擋掉垃圾通知與自我 Ping
- .htaccess 用法大全:轉址、HTTPS、安全防護、壓縮與快取常用設定(WordPress 適用)
垃圾留言擋得好,後台才不會每天被廣告淹沒。正威網路行銷是 25 年經驗的基隆網頁設計工作室,也提供網站維護託管,網站的日常更新與安全設定不想自己顧的話,歡迎來聊聊。







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