PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.9.3
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.9.3
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 / includes / comments-window / spam-score.php

spam-score.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 0.9.3, at includes/comments-window/spam-score.php

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