Spam Guards
Spam guards run in their configured order and stop at the first match. Each guard implements Stillat\Meerkat\Contracts\SpamGuard and receives isSpam($entry, $comment).
#The default checks
1'spam' => [
2 'guards' => [
3 GtubeGuard::class,
4 IpFilterGuard::class,
5 WordListGuard::class,
6 DeceptiveMarkupGuard::class,
7 AkismetGuard::class,
8 ],
9],
| Guard | What it flags |
|---|---|
GtubeGuard |
Comments containing the GTUBE test string. |
IpFilterGuard |
Comments from blocked IP addresses. |
WordListGuard |
Comments containing a blocked word, phrase, or domain. See How the banned-word list is matched. |
DeceptiveMarkupGuard |
Markdown that renders to <a> tags with empty text content (a common spam pattern). |
AkismetGuard |
Sends the comment body, author, and captured user_ip/user_agent/referer to Akismet for scoring. |
#How the banned-word list is matched
Meerkat compares the blocked list against the comment, author name, author email, and stored comment fields. Matching is case-insensitive and normalizes accents, full-width and look-alike characters, invisible Unicode characters, and repeated whitespace.
Single words match on word boundaries. Phrases and domains match as substrings. Separators inside a word (s.p.a.m) and character substitutions (sp4m) require separate blocked-list entries.
#Writing a custom guard
A guard is a class implementing three methods:
1namespace App\Spam;
2
3use Statamic\Contracts\Entries\Entry;
4use Stillat\Meerkat\Contracts\SpamGuard;
5use Stillat\Meerkat\Database\Models\Comment;
6
7class LinkCountGuard implements SpamGuard
8{
9 public function isSpam(Entry $entry, Comment $comment): bool
10 {
11 preg_match_all('/https?:\/\//i', $comment->comment_text, $matches);
12 return count($matches[0]) > 3;
13 }
14
15 public function reportHam(Entry $entry, Comment $comment): void
16 {
17 }
18
19 public function reportSpam(Entry $entry, Comment $comment): void
20 {
21 }
22}
Then add it to the guards list in config/meerkat.php:
1'spam' => [
2 'guards' => [
3 GtubeGuard::class,
4 IpFilterGuard::class,
5 WordListGuard::class,
6 DeceptiveMarkupGuard::class,
7 \App\Spam\LinkCountGuard::class,
8 AkismetGuard::class,
9 ],
10],
Place local checks before services such as Akismet.
#Receiving moderator corrections
When a Control Panel user selects Mark as Spam or Mark as Ham, Meerkat can report the correction. Enable Submit Moderator Results to send reportSpam or reportHam to each guard. Most guards take no action. Services that learn from corrections, such as Akismet, use these calls.
The correction contains the original Comment model with its stored user_ip, user_agent, and referer. The external service receives connection data for the comment author, not the moderator.
#Disabling a built-in guard
Remove its class from meerkat.spam.guards.
#What happens when a guard errors
A failed guard is logged without marking the comment as spam. To hold the comment for review, set:
1'spam' => [
2 'guard_unpublish_on_guard_failure' => true,
3],
With this enabled, Meerkat leaves the comment unpublished and pending for another spam check. It does not mark the comment as spam.
#Holding spam for review
Use these settings to check new comments and hold matches as unpublished:
1'spam' => [
2 'auto_check_spam' => true,
3 'auto_delete_spam' => false,
4 'auto_unpublish_spam' => true,
5],