PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.10
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.10
1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 0.8.7 All 34 releases
desktop-mode / apps / comments / parts / spam-score.php

spam-score.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 1.1.10, at apps/comments/parts/spam-score.php

144 lines 4.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Comments app — spam confidence scoring.
4 *
5 * Returns a 0–100 integer for every comment row exposing how likely
6 * the framework thinks the comment is spam. The default heuristics
7 * are intentionally cheap (no external API calls):
8 *
9 * - +35 Akismet flagged this comment as spam.
10 * - +25 Comment is in the 'spam' status.
11 * - +30 Author's prior spam rate ≥ 50%, or +20 when ≥ 20%
12 * (requires 3+ prior comments).
13 * - +15 Comment contains 4+ links, or +5 for 2–3 links.
14 * - +10 Comment matches the disallowed-keys list.
15 * - +10 Comment is from an unauthenticated author with no
16 * previously-approved comment.
17 *
18 * The score caps at 100 and floors at 0. Sites can shape this score
19 * via the `openstation_comments_window_spam_score` filter — that is
20 * the seam an external moderation plugin folds its own verdict into.
21 *
22 * @package OpenStation
23 */
24
25 defined( 'ABSPATH' ) || exit;
26
27 /**
28 * Compute a 0–100 spam confidence score for a comment.
29 *
30 * @param int|WP_Comment $comment Comment id or object.
31 * @return int 0–100. Higher = more spam-like.
32 */
33 function openstation_comments_window_spam_score( $comment ) {
34 $comment = get_comment( $comment );
35 if ( ! $comment instanceof WP_Comment ) {
36 return 0;
37 }
38
39 $score = 0;
40
41 // Akismet — if installed, its verdict is the strongest signal we have.
42 $akismet_result = (string) get_comment_meta( $comment->comment_ID, 'akismet_result', true );
43 if ( 'true' === $akismet_result ) {
44 $score += 35;
45 }
46
47 // In-spam status — already-decided spam ranks highest.
48 if ( 'spam' === wp_get_comment_status( $comment ) ) {
49 $score += 25;
50 }
51
52 // Author's prior spam rate (only when the author has 3+ comments to base it on).
53 $author_email = (string) $comment->comment_author_email;
54 if ( '' !== $author_email ) {
55 $prior_spam = (int) get_comments(
56 array(
57 'author_email' => $author_email,
58 'status' => 'spam',
59 'count' => true,
60 )
61 );
62 $prior_total = (int) get_comments(
63 array(
64 'author_email' => $author_email,
65 'status' => 'all',
66 'count' => true,
67 )
68 );
69 if ( $prior_total >= 3 ) {
70 $rate = $prior_spam / $prior_total;
71 if ( $rate >= 0.5 ) {
72 $score += 30;
73 } elseif ( $rate >= 0.2 ) {
74 $score += 20;
75 }
76 }
77 }
78
79 // Link count — 4+ links is the classic SEO spam signature.
80 $link_count = preg_match_all( '#https?://#i', (string) $comment->comment_content );
81 if ( $link_count >= 4 ) {
82 $score += 15;
83 } elseif ( $link_count >= 2 ) {
84 $score += 5;
85 }
86
87 // Disallowed keys (option 'disallowed_keys', the modern name for
88 // what used to be the comment blacklist).
89 $disallowed = (string) get_option( 'disallowed_keys', '' );
90 if ( '' !== trim( $disallowed ) ) {
91 $keys = array_filter( array_map( 'trim', explode( "\n", $disallowed ) ) );
92 foreach ( $keys as $key ) {
93 if ( '' === $key ) {
94 continue;
95 }
96 if ( false !== stripos( $comment->comment_content, $key )
97 || false !== stripos( $comment->comment_author, $key )
98 || false !== stripos( $comment->comment_author_email, $key )
99 || false !== stripos( $comment->comment_author_url, $key )
100 ) {
101 $score += 10;
102 break;
103 }
104 }
105 }
106
107 // Unauthenticated + no prior approved comment.
108 if ( 0 === (int) $comment->user_id ) {
109 $prior_approved = (int) get_comments(
110 array(
111 'author_email' => $author_email,
112 'status' => 'approve',
113 'count' => true,
114 )
115 );
116 if ( 0 === $prior_approved ) {
117 $score += 10;
118 }
119 }
120
121 // Clamp into the documented range BEFORE the filter so a runaway
122 // custom hook can't push it past 100. The filter is allowed to
123 // further clamp DOWN (e.g. force 0 for an allowlisted author).
124 $score = max( 0, min( 100, $score ) );
125
126 /**
127 * Filter the computed spam confidence score for a comment.
128 *
129 * Hook here to plug in an AI fallback when Akismet isn't installed
130 * but an AI provider is. The callback should return an integer
131 * clamped to 0–100 — values outside that range are clamped back.
132 *
133 * @param int $score Default heuristic score (0–100).
134 * @param WP_Comment $comment Comment object.
135 */
136 $score = (int) apply_filters(
137 'openstation_comments_window_spam_score',
138 $score,
139 $comment
140 );
141
142 return max( 0, min( 100, $score ) );
143 }
144