Akismet Anti-Spam - Version 4.1

Version Description

Release Date - 12 November 2018

  • Added a WP-CLI method for retrieving stats.
  • Hooked into the new "Personal Data Eraser" functionality from WordPress 4.9.6.
  • Added functionality to clear outdated alerts from Akismet.com.
Download this release

Release Info

Developer cfinke
Plugin Icon 128x128 Akismet Anti-Spam
Version 4.1
Comparing to
See all releases

Code changes from version 4.0.8 to 4.1

akismet.php CHANGED
@@ -6,7 +6,7 @@
6
  Plugin Name: Akismet Anti-Spam
7
  Plugin URI: https://akismet.com/
8
  Description: Used by millions, Akismet is quite possibly the best way in the world to <strong>protect your blog from spam</strong>. It keeps your site protected even while you sleep. To get started: activate the Akismet plugin and then go to your Akismet Settings page to set up your API key.
9
- Version: 4.0.8
10
  Author: Automattic
11
  Author URI: https://automattic.com/wordpress-plugins/
12
  License: GPLv2 or later
@@ -37,7 +37,7 @@ if ( !function_exists( 'add_action' ) ) {
37
  exit;
38
  }
39
 
40
- define( 'AKISMET_VERSION', '4.0.8' );
41
  define( 'AKISMET__MINIMUM_WP_VERSION', '4.0' );
42
  define( 'AKISMET__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
43
  define( 'AKISMET_DELETE_LIMIT', 100000 );
6
  Plugin Name: Akismet Anti-Spam
7
  Plugin URI: https://akismet.com/
8
  Description: Used by millions, Akismet is quite possibly the best way in the world to <strong>protect your blog from spam</strong>. It keeps your site protected even while you sleep. To get started: activate the Akismet plugin and then go to your Akismet Settings page to set up your API key.
9
+ Version: 4.1
10
  Author: Automattic
11
  Author URI: https://automattic.com/wordpress-plugins/
12
  License: GPLv2 or later
37
  exit;
38
  }
39
 
40
+ define( 'AKISMET_VERSION', '4.1' );
41
  define( 'AKISMET__MINIMUM_WP_VERSION', '4.0' );
42
  define( 'AKISMET__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
43
  define( 'AKISMET_DELETE_LIMIT', 100000 );
class.akismet-admin.php CHANGED
@@ -74,6 +74,9 @@ class Akismet_Admin {
74
  add_filter( 'akismet_comment_form_privacy_notice_url_display', array( 'Akismet_Admin', 'jetpack_comment_form_privacy_notice_url' ) );
75
  add_filter( 'akismet_comment_form_privacy_notice_url_hide', array( 'Akismet_Admin', 'jetpack_comment_form_privacy_notice_url' ) );
76
  }
 
 
 
77
  }
78
 
79
  public static function admin_init() {
@@ -1049,7 +1052,7 @@ class Akismet_Admin {
1049
  $message .= ' ';
1050
 
1051
  if ( $spam_count === 0 ) {
1052
- $message .= __( 'No comments were caught as spam.' );
1053
  }
1054
  else {
1055
  $message .= sprintf( _n( '%s comment was caught as spam.', '%s comments were caught as spam.', $spam_count, 'akismet' ), number_format( $spam_count ) );
@@ -1180,4 +1183,62 @@ class Akismet_Admin {
1180
  public static function jetpack_comment_form_privacy_notice_url( $url ) {
1181
  return str_replace( 'options-general.php', 'admin.php', $url );
1182
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1183
  }
74
  add_filter( 'akismet_comment_form_privacy_notice_url_display', array( 'Akismet_Admin', 'jetpack_comment_form_privacy_notice_url' ) );
75
  add_filter( 'akismet_comment_form_privacy_notice_url_hide', array( 'Akismet_Admin', 'jetpack_comment_form_privacy_notice_url' ) );
76
  }
77
+
78
+ // priority=1 because we need ours to run before core's comment anonymizer runs, and that's registered at priority=10
79
+ add_filter( 'wp_privacy_personal_data_erasers', array( 'Akismet_Admin', 'register_personal_data_eraser' ), 1 );
80
  }
81
 
82
  public static function admin_init() {
1052
  $message .= ' ';
1053
 
1054
  if ( $spam_count === 0 ) {
1055
+ $message .= __( 'No comments were caught as spam.', 'akismet' );
1056
  }
1057
  else {
1058
  $message .= sprintf( _n( '%s comment was caught as spam.', '%s comments were caught as spam.', $spam_count, 'akismet' ), number_format( $spam_count ) );
1183
  public static function jetpack_comment_form_privacy_notice_url( $url ) {
1184
  return str_replace( 'options-general.php', 'admin.php', $url );
1185
  }
1186
+
1187
+ public static function register_personal_data_eraser( $erasers ) {
1188
+ $erasers['akismet'] = array(
1189
+ 'eraser_friendly_name' => __( 'Akismet', 'akismet' ),
1190
+ 'callback' => array( 'Akismet_Admin', 'erase_personal_data' ),
1191
+ );
1192
+
1193
+ return $erasers;
1194
+ }
1195
+
1196
+ /**
1197
+ * When a user requests that their personal data be removed, Akismet has a duty to discard
1198
+ * any personal data we store outside of the comment itself. Right now, that is limited
1199
+ * to the copy of the comment we store in the akismet_as_submitted commentmeta.
1200
+ *
1201
+ * FWIW, this information would be automatically deleted after 15 days.
1202
+ *
1203
+ * @param $email_address string The email address of the user who has requested erasure.
1204
+ * @param $page int This function can (and will) be called multiple times to prevent timeouts,
1205
+ * so this argument is used for pagination.
1206
+ * @return array
1207
+ * @see https://developer.wordpress.org/plugins/privacy/adding-the-personal-data-eraser-to-your-plugin/
1208
+ */
1209
+ public static function erase_personal_data( $email_address, $page = 1 ) {
1210
+ $items_removed = false;
1211
+
1212
+ $number = 50;
1213
+ $page = (int) $page;
1214
+
1215
+ $comments = get_comments(
1216
+ array(
1217
+ 'author_email' => $email_address,
1218
+ 'number' => $number,
1219
+ 'paged' => $page,
1220
+ 'order_by' => 'comment_ID',
1221
+ 'order' => 'ASC',
1222
+ )
1223
+ );
1224
+
1225
+ foreach ( (array) $comments as $comment ) {
1226
+ $comment_as_submitted = get_comment_meta( $comment->comment_ID, 'akismet_as_submitted', true );
1227
+
1228
+ if ( $comment_as_submitted ) {
1229
+ delete_comment_meta( $comment->comment_ID, 'akismet_as_submitted' );
1230
+ $items_removed = true;
1231
+ }
1232
+ }
1233
+
1234
+ // Tell core if we have more comments to work on still
1235
+ $done = count( $comments ) < $number;
1236
+
1237
+ return array(
1238
+ 'items_removed' => $items_removed,
1239
+ 'items_retained' => false, // always false in this example
1240
+ 'messages' => array(), // no messages in this example
1241
+ 'done' => $done,
1242
+ );
1243
+ }
1244
  }
class.akismet-cli.php CHANGED
@@ -88,4 +88,98 @@ class Akismet_CLI extends WP_CLI_Command {
88
  WP_CLI::line( sprintf( _n( "%d comment could not be checked.", "%d comments could not be checked.", $total_counts['error'], 'akismet' ), number_format( $total_counts['error'] ) ) );
89
  }
90
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  }
88
  WP_CLI::line( sprintf( _n( "%d comment could not be checked.", "%d comments could not be checked.", $total_counts['error'], 'akismet' ), number_format( $total_counts['error'] ) ) );
89
  }
90
  }
91
+
92
+ /**
93
+ * Fetches stats from the Akismet API.
94
+ *
95
+ * ## OPTIONS
96
+ *
97
+ * [<interval>]
98
+ * : The time period for which to retrieve stats.
99
+ * ---
100
+ * default: all
101
+ * options:
102
+ * - days
103
+ * - months
104
+ * - all
105
+ * ---
106
+ *
107
+ * [--format=<format>]
108
+ * : Allows overriding the output of the command when listing connections.
109
+ * ---
110
+ * default: table
111
+ * options:
112
+ * - table
113
+ * - json
114
+ * - csv
115
+ * - yaml
116
+ * - count
117
+ * ---
118
+ *
119
+ * [--summary]
120
+ * : When set, will display a summary of the stats.
121
+ *
122
+ * ## EXAMPLES
123
+ *
124
+ * wp akismet stats
125
+ * wp akismet stats all
126
+ * wp akismet stats days
127
+ * wp akismet stats months
128
+ * wp akismet stats all --summary
129
+ */
130
+ public function stats( $args, $assoc_args ) {
131
+ $api_key = Akismet::get_api_key();
132
+
133
+ if ( empty( $api_key ) ) {
134
+ WP_CLI::error( __( 'API key must be set to fetch stats.', 'akismet' ) );
135
+ }
136
+
137
+ switch ( $args[0] ) {
138
+ case 'days':
139
+ $interval = '60-days';
140
+ break;
141
+ case 'months':
142
+ $interval = '6-months';
143
+ break;
144
+ default:
145
+ $interval = 'all';
146
+ break;
147
+ }
148
+
149
+ $response = Akismet::http_post(
150
+ Akismet::build_query( array(
151
+ 'blog' => get_option( 'home' ),
152
+ 'key' => $api_key,
153
+ 'from' => $interval,
154
+ ) ),
155
+ 'get-stats'
156
+ );
157
+
158
+ if ( empty( $response[1] ) ) {
159
+ WP_CLI::error( __( 'Currently unable to fetch stats. Please try again.', 'akismet' ) );
160
+ }
161
+
162
+ $response_body = json_decode( $response[1], true );
163
+
164
+ if ( is_null( $response_body ) ) {
165
+ WP_CLI::error( __( 'Stats response could not be decoded.', 'akismet' ) );
166
+ }
167
+
168
+ if ( isset( $assoc_args['summary'] ) ) {
169
+ $keys = array(
170
+ 'spam',
171
+ 'ham',
172
+ 'missed_spam',
173
+ 'false_positives',
174
+ 'accuracy',
175
+ 'time_saved',
176
+ );
177
+
178
+ WP_CLI\Utils\format_items( $assoc_args['format'], array( $response_body ), $keys );
179
+ }
180
+ else {
181
+ $stats = $response_body['breakdown'];
182
+ WP_CLI\Utils\format_items( $assoc_args['format'], $stats, array_keys( end( $stats ) ) );
183
+ }
184
+ }
185
  }
class.akismet-rest-api.php CHANGED
@@ -87,6 +87,48 @@ class Akismet_REST_API {
87
  'callback' => array( 'Akismet_REST_API', 'get_stats' ),
88
  )
89
  ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  }
91
 
92
  /**
@@ -231,6 +273,50 @@ class Akismet_REST_API {
231
  return rest_ensure_response( $stat_totals );
232
  }
233
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  private static function key_is_valid( $key ) {
235
  $response = Akismet::http_post(
236
  Akismet::build_query(
@@ -253,6 +339,15 @@ class Akismet_REST_API {
253
  return current_user_can( 'manage_options' );
254
  }
255
 
 
 
 
 
 
 
 
 
 
256
  public static function sanitize_interval( $interval, $request, $param ) {
257
  $interval = trim( $interval );
258
 
87
  'callback' => array( 'Akismet_REST_API', 'get_stats' ),
88
  )
89
  ) );
90
+
91
+ register_rest_route( 'akismet/v1', '/alert', array(
92
+ array(
93
+ 'methods' => WP_REST_Server::READABLE,
94
+ 'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ),
95
+ 'callback' => array( 'Akismet_REST_API', 'get_alert' ),
96
+ 'args' => array(
97
+ 'key' => array(
98
+ 'required' => false,
99
+ 'type' => 'string',
100
+ 'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ),
101
+ 'description' => __( 'A 12-character Akismet API key. Available at akismet.com/get/', 'akismet' ),
102
+ ),
103
+ ),
104
+ ),
105
+ array(
106
+ 'methods' => WP_REST_Server::EDITABLE,
107
+ 'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ),
108
+ 'callback' => array( 'Akismet_REST_API', 'set_alert' ),
109
+ 'args' => array(
110
+ 'key' => array(
111
+ 'required' => false,
112
+ 'type' => 'string',
113
+ 'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ),
114
+ 'description' => __( 'A 12-character Akismet API key. Available at akismet.com/get/', 'akismet' ),
115
+ ),
116
+ ),
117
+ ),
118
+ array(
119
+ 'methods' => WP_REST_Server::DELETABLE,
120
+ 'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ),
121
+ 'callback' => array( 'Akismet_REST_API', 'delete_alert' ),
122
+ 'args' => array(
123
+ 'key' => array(
124
+ 'required' => false,
125
+ 'type' => 'string',
126
+ 'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ),
127
+ 'description' => __( 'A 12-character Akismet API key. Available at akismet.com/get/', 'akismet' ),
128
+ ),
129
+ ),
130
+ )
131
+ ) );
132
  }
133
 
134
  /**
273
  return rest_ensure_response( $stat_totals );
274
  }
275
 
276
+ /**
277
+ * Get the current alert code and message. Alert codes are used to notify the site owner
278
+ * if there's a problem, like a connection issue between their site and the Akismet API,
279
+ * invalid requests being sent, etc.
280
+ *
281
+ * @param WP_REST_Request $request
282
+ * @return WP_Error|WP_REST_Response
283
+ */
284
+ public static function get_alert( $request ) {
285
+ return rest_ensure_response( array(
286
+ 'code' => get_option( 'akismet_alert_code' ),
287
+ 'message' => get_option( 'akismet_alert_msg' ),
288
+ ) );
289
+ }
290
+
291
+ /**
292
+ * Update the current alert code and message by triggering a call to the Akismet server.
293
+ *
294
+ * @param WP_REST_Request $request
295
+ * @return WP_Error|WP_REST_Response
296
+ */
297
+ public static function set_alert( $request ) {
298
+ delete_option( 'akismet_alert_code' );
299
+ delete_option( 'akismet_alert_msg' );
300
+
301
+ // Make a request so the most recent alert code and message are retrieved.
302
+ Akismet::verify_key( Akismet::get_api_key() );
303
+
304
+ return self::get_alert( $request );
305
+ }
306
+
307
+ /**
308
+ * Clear the current alert code and message.
309
+ *
310
+ * @param WP_REST_Request $request
311
+ * @return WP_Error|WP_REST_Response
312
+ */
313
+ public static function delete_alert( $request ) {
314
+ delete_option( 'akismet_alert_code' );
315
+ delete_option( 'akismet_alert_msg' );
316
+
317
+ return self::get_alert( $request );
318
+ }
319
+
320
  private static function key_is_valid( $key ) {
321
  $response = Akismet::http_post(
322
  Akismet::build_query(
339
  return current_user_can( 'manage_options' );
340
  }
341
 
342
+ /**
343
+ * For calls that Akismet.com makes to the site to clear outdated alert codes, use the API key for authorization.
344
+ */
345
+ public static function remote_call_permission_callback( $request ) {
346
+ $local_key = Akismet::get_api_key();
347
+
348
+ return $local_key && ( strtolower( $request->get_param( 'key' ) ) === strtolower( $local_key ) );
349
+ }
350
+
351
  public static function sanitize_interval( $interval, $request, $param ) {
352
  $interval = trim( $interval );
353
 
class.akismet.php CHANGED
@@ -762,7 +762,6 @@ class Akismet {
762
  || strtotime( $comment->comment_date_gmt ) < strtotime( "-15 days" ) // Comment is too old.
763
  || $comment->comment_approved !== "0" // Comment is no longer in the Pending queue
764
  ) {
765
- echo "Deleting";
766
  delete_comment_meta( $comment_id, 'akismet_error' );
767
  delete_comment_meta( $comment_id, 'akismet_delayed_moderation_email' );
768
  continue;
762
  || strtotime( $comment->comment_date_gmt ) < strtotime( "-15 days" ) // Comment is too old.
763
  || $comment->comment_approved !== "0" // Comment is no longer in the Pending queue
764
  ) {
 
765
  delete_comment_meta( $comment_id, 'akismet_error' );
766
  delete_comment_meta( $comment_id, 'akismet_delayed_moderation_email' );
767
  continue;
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: matt, ryan, andy, mdawaffe, tellyworth, josephscott, lessbloat, eoigal, cfinke, automattic, jgs, procifer, stephdau
3
  Tags: akismet, comments, spam, antispam, anti-spam, anti spam, comment moderation, comment spam, contact form spam, spam comments
4
  Requires at least: 4.0
5
- Tested up to: 4.9.6
6
- Stable tag: 4.0.8
7
  License: GPLv2 or later
8
 
9
  Akismet checks your comments and contact form submissions against our global database of spam to protect you and your site from malicious content.
@@ -30,6 +30,13 @@ Upload the Akismet plugin to your blog, Activate it, then enter your [Akismet.co
30
 
31
  == Changelog ==
32
 
 
 
 
 
 
 
 
33
  = 4.0.8 =
34
  *Release Date - 19 June 2018*
35
 
2
  Contributors: matt, ryan, andy, mdawaffe, tellyworth, josephscott, lessbloat, eoigal, cfinke, automattic, jgs, procifer, stephdau
3
  Tags: akismet, comments, spam, antispam, anti-spam, anti spam, comment moderation, comment spam, contact form spam, spam comments
4
  Requires at least: 4.0
5
+ Tested up to: 5.0
6
+ Stable tag: 4.1
7
  License: GPLv2 or later
8
 
9
  Akismet checks your comments and contact form submissions against our global database of spam to protect you and your site from malicious content.
30
 
31
  == Changelog ==
32
 
33
+ = 4.1 =
34
+ *Release Date - 12 November 2018*
35
+
36
+ * Added a WP-CLI method for retrieving stats.
37
+ * Hooked into the new "Personal Data Eraser" functionality from WordPress 4.9.6.
38
+ * Added functionality to clear outdated alerts from Akismet.com.
39
+
40
  = 4.0.8 =
41
  *Release Date - 19 June 2018*
42