PluginProbe ʕ •ᴥ•ʔ
Akismet Anti-spam: Spam Protection / 4.0.7
Akismet Anti-spam: Spam Protection v4.0.7
5.7 3.0.4 3.0.5 3.1 3.1.1 3.1.10 3.1.11 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2 3.3 3.3.1 3.3.2 3.3.3 3.3.4 4.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.1 4.1.1 4.1.10 4.1.11 4.1.12 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 5.0 5.0.1 5.0.2 5.1 5.2 5.3 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4 5.5 5.6 trunk 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 2.3.0 2.4.0 2.4.1 2.5.0 2.5.1 2.5.10 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 3.0.0 3.0.0-RC1 3.0.1 3.0.2 3.0.3
akismet / class.akismet-admin.php
akismet Last commit date
_inc 8 years ago views 8 years ago .htaccess 10 years ago LICENSE.txt 10 years ago akismet.php 8 years ago class.akismet-admin.php 8 years ago class.akismet-cli.php 9 years ago class.akismet-rest-api.php 8 years ago class.akismet-widget.php 8 years ago class.akismet.php 8 years ago index.php 12 years ago readme.txt 8 years ago wrapper.php 9 years ago
class.akismet-admin.php
1184 lines
1 <?php
2
3 class Akismet_Admin {
4 const NONCE = 'akismet-update-key';
5
6 private static $initiated = false;
7 private static $notices = array();
8 private static $allowed = array(
9 'a' => array(
10 'href' => true,
11 'title' => true,
12 ),
13 'b' => array(),
14 'code' => array(),
15 'del' => array(
16 'datetime' => true,
17 ),
18 'em' => array(),
19 'i' => array(),
20 'q' => array(
21 'cite' => true,
22 ),
23 'strike' => array(),
24 'strong' => array(),
25 );
26
27 public static function init() {
28 if ( ! self::$initiated ) {
29 self::init_hooks();
30 }
31
32 if ( isset( $_POST['action'] ) && $_POST['action'] == 'enter-key' ) {
33 self::enter_api_key();
34 }
35
36 if ( ! empty( $_GET['akismet_comment_form_privacy_notice'] ) && empty( $_GET['settings-updated']) ) {
37 self::set_form_privacy_notice_option( $_GET['akismet_comment_form_privacy_notice'] );
38 }
39 }
40
41 public static function init_hooks() {
42 // The standalone stats page was removed in 3.0 for an all-in-one config and stats page.
43 // Redirect any links that might have been bookmarked or in browser history.
44 if ( isset( $_GET['page'] ) && 'akismet-stats-display' == $_GET['page'] ) {
45 wp_safe_redirect( esc_url_raw( self::get_page_url( 'stats' ) ), 301 );
46 die;
47 }
48
49 self::$initiated = true;
50
51 add_action( 'admin_init', array( 'Akismet_Admin', 'admin_init' ) );
52 add_action( 'admin_menu', array( 'Akismet_Admin', 'admin_menu' ), 5 ); # Priority 5, so it's called before Jetpack's admin_menu.
53 add_action( 'admin_notices', array( 'Akismet_Admin', 'display_notice' ) );
54 add_action( 'admin_enqueue_scripts', array( 'Akismet_Admin', 'load_resources' ) );
55 add_action( 'activity_box_end', array( 'Akismet_Admin', 'dashboard_stats' ) );
56 add_action( 'rightnow_end', array( 'Akismet_Admin', 'rightnow_stats' ) );
57 add_action( 'manage_comments_nav', array( 'Akismet_Admin', 'check_for_spam_button' ) );
58 add_action( 'admin_action_akismet_recheck_queue', array( 'Akismet_Admin', 'recheck_queue' ) );
59 add_action( 'wp_ajax_akismet_recheck_queue', array( 'Akismet_Admin', 'recheck_queue' ) );
60 add_action( 'wp_ajax_comment_author_deurl', array( 'Akismet_Admin', 'remove_comment_author_url' ) );
61 add_action( 'wp_ajax_comment_author_reurl', array( 'Akismet_Admin', 'add_comment_author_url' ) );
62 add_action( 'jetpack_auto_activate_akismet', array( 'Akismet_Admin', 'connect_jetpack_user' ) );
63
64 add_filter( 'plugin_action_links', array( 'Akismet_Admin', 'plugin_action_links' ), 10, 2 );
65 add_filter( 'comment_row_actions', array( 'Akismet_Admin', 'comment_row_action' ), 10, 2 );
66
67 add_filter( 'plugin_action_links_'.plugin_basename( plugin_dir_path( __FILE__ ) . 'akismet.php'), array( 'Akismet_Admin', 'admin_plugin_settings_link' ) );
68
69 add_filter( 'wxr_export_skip_commentmeta', array( 'Akismet_Admin', 'exclude_commentmeta_from_export' ), 10, 3 );
70
71 add_filter( 'all_plugins', array( 'Akismet_Admin', 'modify_plugin_description' ) );
72
73 if ( class_exists( 'Jetpack' ) ) {
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() {
80 load_plugin_textdomain( 'akismet' );
81 add_meta_box( 'akismet-status', __('Comment History', 'akismet'), array( 'Akismet_Admin', 'comment_status_meta_box' ), 'comment', 'normal' );
82
83 if ( function_exists( 'wp_add_privacy_policy_content' ) ) {
84 wp_add_privacy_policy_content(
85 __( 'Akismet', 'akismet' ),
86 __( 'We collect information about visitors who comment on Sites that use our Akismet anti-spam service. The information we collect depends on how the User sets up Akismet for the Site, but typically includes the commenter\'s IP address, user agent, referrer, and Site URL (along with other information directly provided by the commenter such as their name, username, email address, and the comment itself).', 'akismet' )
87 );
88 }
89 }
90
91 public static function admin_menu() {
92 if ( class_exists( 'Jetpack' ) )
93 add_action( 'jetpack_admin_menu', array( 'Akismet_Admin', 'load_menu' ) );
94 else
95 self::load_menu();
96 }
97
98 public static function admin_head() {
99 if ( !current_user_can( 'manage_options' ) )
100 return;
101 }
102
103 public static function admin_plugin_settings_link( $links ) {
104 $settings_link = '<a href="'.esc_url( self::get_page_url() ).'">'.__('Settings', 'akismet').'</a>';
105 array_unshift( $links, $settings_link );
106 return $links;
107 }
108
109 public static function load_menu() {
110 if ( class_exists( 'Jetpack' ) ) {
111 $hook = add_submenu_page( 'jetpack', __( 'Akismet Anti-Spam' , 'akismet'), __( 'Akismet Anti-Spam' , 'akismet'), 'manage_options', 'akismet-key-config', array( 'Akismet_Admin', 'display_page' ) );
112 }
113 else {
114 $hook = add_options_page( __('Akismet Anti-Spam', 'akismet'), __('Akismet Anti-Spam', 'akismet'), 'manage_options', 'akismet-key-config', array( 'Akismet_Admin', 'display_page' ) );
115 }
116
117 if ( $hook ) {
118 add_action( "load-$hook", array( 'Akismet_Admin', 'admin_help' ) );
119 }
120 }
121
122 public static function load_resources() {
123 global $hook_suffix;
124
125 if ( in_array( $hook_suffix, apply_filters( 'akismet_admin_page_hook_suffixes', array(
126 'index.php', # dashboard
127 'edit-comments.php',
128 'comment.php',
129 'post.php',
130 'settings_page_akismet-key-config',
131 'jetpack_page_akismet-key-config',
132 'plugins.php',
133 ) ) ) ) {
134 wp_register_style( 'akismet.css', plugin_dir_url( __FILE__ ) . '_inc/akismet.css', array(), AKISMET_VERSION );
135 wp_enqueue_style( 'akismet.css');
136
137 wp_register_script( 'akismet.js', plugin_dir_url( __FILE__ ) . '_inc/akismet.js', array('jquery'), AKISMET_VERSION );
138 wp_enqueue_script( 'akismet.js' );
139
140 $inline_js = array(
141 'comment_author_url_nonce' => wp_create_nonce( 'comment_author_url_nonce' ),
142 'strings' => array(
143 'Remove this URL' => __( 'Remove this URL' , 'akismet'),
144 'Removing...' => __( 'Removing...' , 'akismet'),
145 'URL removed' => __( 'URL removed' , 'akismet'),
146 '(undo)' => __( '(undo)' , 'akismet'),
147 'Re-adding...' => __( 'Re-adding...' , 'akismet'),
148 )
149 );
150
151 if ( isset( $_GET['akismet_recheck'] ) && wp_verify_nonce( $_GET['akismet_recheck'], 'akismet_recheck' ) ) {
152 $inline_js['start_recheck'] = true;
153 }
154
155 wp_localize_script( 'akismet.js', 'WPAkismet', $inline_js );
156 }
157 }
158
159 /**
160 * Add help to the Akismet page
161 *
162 * @return false if not the Akismet page
163 */
164 public static function admin_help() {
165 $current_screen = get_current_screen();
166
167 // Screen Content
168 if ( current_user_can( 'manage_options' ) ) {
169 if ( !Akismet::get_api_key() || ( isset( $_GET['view'] ) && $_GET['view'] == 'start' ) ) {
170 //setup page
171 $current_screen->add_help_tab(
172 array(
173 'id' => 'overview',
174 'title' => __( 'Overview' , 'akismet'),
175 'content' =>
176 '<p><strong>' . esc_html__( 'Akismet Setup' , 'akismet') . '</strong></p>' .
177 '<p>' . esc_html__( 'Akismet filters out spam, so you can focus on more important things.' , 'akismet') . '</p>' .
178 '<p>' . esc_html__( 'On this page, you are able to set up the Akismet plugin.' , 'akismet') . '</p>',
179 )
180 );
181
182 $current_screen->add_help_tab(
183 array(
184 'id' => 'setup-signup',
185 'title' => __( 'New to Akismet' , 'akismet'),
186 'content' =>
187 '<p><strong>' . esc_html__( 'Akismet Setup' , 'akismet') . '</strong></p>' .
188 '<p>' . esc_html__( 'You need to enter an API key to activate the Akismet service on your site.' , 'akismet') . '</p>' .
189 '<p>' . sprintf( __( 'Sign up for an account on %s to get an API Key.' , 'akismet'), '<a href="https://akismet.com/plugin-signup/" target="_blank">Akismet.com</a>' ) . '</p>',
190 )
191 );
192
193 $current_screen->add_help_tab(
194 array(
195 'id' => 'setup-manual',
196 'title' => __( 'Enter an API Key' , 'akismet'),
197 'content' =>
198 '<p><strong>' . esc_html__( 'Akismet Setup' , 'akismet') . '</strong></p>' .
199 '<p>' . esc_html__( 'If you already have an API key' , 'akismet') . '</p>' .
200 '<ol>' .
201 '<li>' . esc_html__( 'Copy and paste the API key into the text field.' , 'akismet') . '</li>' .
202 '<li>' . esc_html__( 'Click the Use this Key button.' , 'akismet') . '</li>' .
203 '</ol>',
204 )
205 );
206 }
207 elseif ( isset( $_GET['view'] ) && $_GET['view'] == 'stats' ) {
208 //stats page
209 $current_screen->add_help_tab(
210 array(
211 'id' => 'overview',
212 'title' => __( 'Overview' , 'akismet'),
213 'content' =>
214 '<p><strong>' . esc_html__( 'Akismet Stats' , 'akismet') . '</strong></p>' .
215 '<p>' . esc_html__( 'Akismet filters out spam, so you can focus on more important things.' , 'akismet') . '</p>' .
216 '<p>' . esc_html__( 'On this page, you are able to view stats on spam filtered on your site.' , 'akismet') . '</p>',
217 )
218 );
219 }
220 else {
221 //configuration page
222 $current_screen->add_help_tab(
223 array(
224 'id' => 'overview',
225 'title' => __( 'Overview' , 'akismet'),
226 'content' =>
227 '<p><strong>' . esc_html__( 'Akismet Configuration' , 'akismet') . '</strong></p>' .
228 '<p>' . esc_html__( 'Akismet filters out spam, so you can focus on more important things.' , 'akismet') . '</p>' .
229 '<p>' . esc_html__( 'On this page, you are able to update your Akismet settings and view spam stats.' , 'akismet') . '</p>',
230 )
231 );
232
233 $current_screen->add_help_tab(
234 array(
235 'id' => 'settings',
236 'title' => __( 'Settings' , 'akismet'),
237 'content' =>
238 '<p><strong>' . esc_html__( 'Akismet Configuration' , 'akismet') . '</strong></p>' .
239 ( Akismet::predefined_api_key() ? '' : '<p><strong>' . esc_html__( 'API Key' , 'akismet') . '</strong> - ' . esc_html__( 'Enter/remove an API key.' , 'akismet') . '</p>' ) .
240 '<p><strong>' . esc_html__( 'Comments' , 'akismet') . '</strong> - ' . esc_html__( 'Show the number of approved comments beside each comment author in the comments list page.' , 'akismet') . '</p>' .
241 '<p><strong>' . esc_html__( 'Strictness' , 'akismet') . '</strong> - ' . esc_html__( 'Choose to either discard the worst spam automatically or to always put all spam in spam folder.' , 'akismet') . '</p>',
242 )
243 );
244
245 if ( ! Akismet::predefined_api_key() ) {
246 $current_screen->add_help_tab(
247 array(
248 'id' => 'account',
249 'title' => __( 'Account' , 'akismet'),
250 'content' =>
251 '<p><strong>' . esc_html__( 'Akismet Configuration' , 'akismet') . '</strong></p>' .
252 '<p><strong>' . esc_html__( 'Subscription Type' , 'akismet') . '</strong> - ' . esc_html__( 'The Akismet subscription plan' , 'akismet') . '</p>' .
253 '<p><strong>' . esc_html__( 'Status' , 'akismet') . '</strong> - ' . esc_html__( 'The subscription status - active, cancelled or suspended' , 'akismet') . '</p>',
254 )
255 );
256 }
257 }
258 }
259
260 // Help Sidebar
261 $current_screen->set_help_sidebar(
262 '<p><strong>' . esc_html__( 'For more information:' , 'akismet') . '</strong></p>' .
263 '<p><a href="https://akismet.com/faq/" target="_blank">' . esc_html__( 'Akismet FAQ' , 'akismet') . '</a></p>' .
264 '<p><a href="https://akismet.com/support/" target="_blank">' . esc_html__( 'Akismet Support' , 'akismet') . '</a></p>'
265 );
266 }
267
268 public static function enter_api_key() {
269 if ( ! current_user_can( 'manage_options' ) ) {
270 die( __( 'Cheatin&#8217; uh?', 'akismet' ) );
271 }
272
273 if ( !wp_verify_nonce( $_POST['_wpnonce'], self::NONCE ) )
274 return false;
275
276 foreach( array( 'akismet_strictness', 'akismet_show_user_comments_approved' ) as $option ) {
277 update_option( $option, isset( $_POST[$option] ) && (int) $_POST[$option] == 1 ? '1' : '0' );
278 }
279
280 if ( ! empty( $_POST['akismet_comment_form_privacy_notice'] ) ) {
281 self::set_form_privacy_notice_option( $_POST['akismet_comment_form_privacy_notice'] );
282 } else {
283 self::set_form_privacy_notice_option( 'hide' );
284 }
285
286 if ( Akismet::predefined_api_key() ) {
287 return false; //shouldn't have option to save key if already defined
288 }
289
290 $new_key = preg_replace( '/[^a-f0-9]/i', '', $_POST['key'] );
291 $old_key = Akismet::get_api_key();
292
293 if ( empty( $new_key ) ) {
294 if ( !empty( $old_key ) ) {
295 delete_option( 'wordpress_api_key' );
296 self::$notices[] = 'new-key-empty';
297 }
298 }
299 elseif ( $new_key != $old_key ) {
300 self::save_key( $new_key );
301 }
302
303 return true;
304 }
305
306 public static function save_key( $api_key ) {
307 $key_status = Akismet::verify_key( $api_key );
308
309 if ( $key_status == 'valid' ) {
310 $akismet_user = self::get_akismet_user( $api_key );
311
312 if ( $akismet_user ) {
313 if ( in_array( $akismet_user->status, array( 'active', 'active-dunning', 'no-sub' ) ) )
314 update_option( 'wordpress_api_key', $api_key );
315
316 if ( $akismet_user->status == 'active' )
317 self::$notices['status'] = 'new-key-valid';
318 elseif ( $akismet_user->status == 'notice' )
319 self::$notices['status'] = $akismet_user;
320 else
321 self::$notices['status'] = $akismet_user->status;
322 }
323 else
324 self::$notices['status'] = 'new-key-invalid';
325 }
326 elseif ( in_array( $key_status, array( 'invalid', 'failed' ) ) )
327 self::$notices['status'] = 'new-key-'.$key_status;
328 }
329
330 public static function dashboard_stats() {
331 if ( did_action( 'rightnow_end' ) ) {
332 return; // We already displayed this info in the "Right Now" section
333 }
334
335 if ( !$count = get_option('akismet_spam_count') )
336 return;
337
338 global $submenu;
339
340 echo '<h3>' . esc_html( _x( 'Spam', 'comments' , 'akismet') ) . '</h3>';
341
342 echo '<p>'.sprintf( _n(
343 '<a href="%1$s">Akismet</a> has protected your site from <a href="%2$s">%3$s spam comment</a>.',
344 '<a href="%1$s">Akismet</a> has protected your site from <a href="%2$s">%3$s spam comments</a>.',
345 $count
346 , 'akismet'), 'https://akismet.com/wordpress/', esc_url( add_query_arg( array( 'page' => 'akismet-admin' ), admin_url( isset( $submenu['edit-comments.php'] ) ? 'edit-comments.php' : 'edit.php' ) ) ), number_format_i18n($count) ).'</p>';
347 }
348
349 // WP 2.5+
350 public static function rightnow_stats() {
351 if ( $count = get_option('akismet_spam_count') ) {
352 $intro = sprintf( _n(
353 '<a href="%1$s">Akismet</a> has protected your site from %2$s spam comment already. ',
354 '<a href="%1$s">Akismet</a> has protected your site from %2$s spam comments already. ',
355 $count
356 , 'akismet'), 'https://akismet.com/wordpress/', number_format_i18n( $count ) );
357 } else {
358 $intro = sprintf( __('<a href="%s">Akismet</a> blocks spam from getting to your blog. ', 'akismet'), 'https://akismet.com/wordpress/' );
359 }
360
361 $link = add_query_arg( array( 'comment_status' => 'spam' ), admin_url( 'edit-comments.php' ) );
362
363 if ( $queue_count = self::get_spam_count() ) {
364 $queue_text = sprintf( _n(
365 'There&#8217;s <a href="%2$s">%1$s comment</a> in your spam queue right now.',
366 'There are <a href="%2$s">%1$s comments</a> in your spam queue right now.',
367 $queue_count
368 , 'akismet'), number_format_i18n( $queue_count ), esc_url( $link ) );
369 } else {
370 $queue_text = sprintf( __( "There&#8217;s nothing in your <a href='%s'>spam queue</a> at the moment." , 'akismet'), esc_url( $link ) );
371 }
372
373 $text = $intro . '<br />' . $queue_text;
374 echo "<p class='akismet-right-now'>$text</p>\n";
375 }
376
377 public static function check_for_spam_button( $comment_status ) {
378 // The "Check for Spam" button should only appear when the page might be showing
379 // a comment with comment_approved=0, which means an un-trashed, un-spammed,
380 // not-yet-moderated comment.
381 if ( 'all' != $comment_status && 'moderated' != $comment_status ) {
382 return;
383 }
384
385 $link = add_query_arg( array( 'action' => 'akismet_recheck_queue' ), admin_url( 'admin.php' ) );
386
387 $comments_count = wp_count_comments();
388
389 echo '</div>';
390 echo '<div class="alignleft">';
391 echo '<a
392 class="button-secondary checkforspam"
393 href="' . esc_url( $link ) . '"
394 data-active-label="' . esc_attr( __( 'Checking for Spam', 'akismet' ) ) . '"
395 data-progress-label-format="' . esc_attr( __( '(%1$s%)', 'akismet' ) ) . '"
396 data-success-url="' . esc_attr( remove_query_arg( 'akismet_recheck', add_query_arg( array( 'akismet_recheck_complete' => 1, 'recheck_count' => urlencode( '__recheck_count__' ), 'spam_count' => urlencode( '__spam_count__' ) ) ) ) ) . '"
397 data-pending-comment-count="' . esc_attr( $comments_count->moderated ) . '"
398 >';
399 echo '<span class="akismet-label">' . esc_html__('Check for Spam', 'akismet') . '</span>';
400 echo '<span class="checkforspam-progress"></span>';
401 echo '</a>';
402 echo '<span class="checkforspam-spinner"></span>';
403
404 }
405
406 public static function recheck_queue() {
407 global $wpdb;
408
409 Akismet::fix_scheduled_recheck();
410
411 if ( ! ( isset( $_GET['recheckqueue'] ) || ( isset( $_REQUEST['action'] ) && 'akismet_recheck_queue' == $_REQUEST['action'] ) ) ) {
412 return;
413 }
414
415 $result_counts = self::recheck_queue_portion( empty( $_POST['offset'] ) ? 0 : $_POST['offset'], empty( $_POST['limit'] ) ? 100 : $_POST['limit'] );
416
417 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
418 wp_send_json( array(
419 'counts' => $result_counts,
420 ));
421 }
422 else {
423 $redirect_to = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : admin_url( 'edit-comments.php' );
424 wp_safe_redirect( $redirect_to );
425 exit;
426 }
427 }
428
429 public static function recheck_queue_portion( $start = 0, $limit = 100 ) {
430 global $wpdb;
431
432 $paginate = '';
433
434 if ( $limit <= 0 ) {
435 $limit = 100;
436 }
437
438 if ( $start < 0 ) {
439 $start = 0;
440 }
441
442 $moderation = $wpdb->get_col( $wpdb->prepare( "SELECT * FROM {$wpdb->comments} WHERE comment_approved = '0' LIMIT %d OFFSET %d", $limit, $start ) );
443
444 $result_counts = array(
445 'processed' => count( $moderation ),
446 'spam' => 0,
447 'ham' => 0,
448 'error' => 0,
449 );
450
451 foreach ( $moderation as $comment_id ) {
452 $api_response = Akismet::recheck_comment( $comment_id, 'recheck_queue' );
453
454 if ( 'true' === $api_response ) {
455 ++$result_counts['spam'];
456 }
457 elseif ( 'false' === $api_response ) {
458 ++$result_counts['ham'];
459 }
460 else {
461 ++$result_counts['error'];
462 }
463 }
464
465 return $result_counts;
466 }
467
468 // Adds an 'x' link next to author URLs, clicking will remove the author URL and show an undo link
469 public static function remove_comment_author_url() {
470 if ( !empty( $_POST['id'] ) && check_admin_referer( 'comment_author_url_nonce' ) ) {
471 $comment_id = intval( $_POST['id'] );
472 $comment = get_comment( $comment_id, ARRAY_A );
473 if ( $comment && current_user_can( 'edit_comment', $comment['comment_ID'] ) ) {
474 $comment['comment_author_url'] = '';
475 do_action( 'comment_remove_author_url' );
476 print( wp_update_comment( $comment ) );
477 die();
478 }
479 }
480 }
481
482 public static function add_comment_author_url() {
483 if ( !empty( $_POST['id'] ) && !empty( $_POST['url'] ) && check_admin_referer( 'comment_author_url_nonce' ) ) {
484 $comment_id = intval( $_POST['id'] );
485 $comment = get_comment( $comment_id, ARRAY_A );
486 if ( $comment && current_user_can( 'edit_comment', $comment['comment_ID'] ) ) {
487 $comment['comment_author_url'] = esc_url( $_POST['url'] );
488 do_action( 'comment_add_author_url' );
489 print( wp_update_comment( $comment ) );
490 die();
491 }
492 }
493 }
494
495 public static function comment_row_action( $a, $comment ) {
496 $akismet_result = get_comment_meta( $comment->comment_ID, 'akismet_result', true );
497 $akismet_error = get_comment_meta( $comment->comment_ID, 'akismet_error', true );
498 $user_result = get_comment_meta( $comment->comment_ID, 'akismet_user_result', true);
499 $comment_status = wp_get_comment_status( $comment->comment_ID );
500 $desc = null;
501 if ( $akismet_error ) {
502 $desc = __( 'Awaiting spam check' , 'akismet');
503 } elseif ( !$user_result || $user_result == $akismet_result ) {
504 // Show the original Akismet result if the user hasn't overridden it, or if their decision was the same
505 if ( $akismet_result == 'true' && $comment_status != 'spam' && $comment_status != 'trash' )
506 $desc = __( 'Flagged as spam by Akismet' , 'akismet');
507 elseif ( $akismet_result == 'false' && $comment_status == 'spam' )
508 $desc = __( 'Cleared by Akismet' , 'akismet');
509 } else {
510 $who = get_comment_meta( $comment->comment_ID, 'akismet_user', true );
511 if ( $user_result == 'true' )
512 $desc = sprintf( __('Flagged as spam by %s', 'akismet'), $who );
513 else
514 $desc = sprintf( __('Un-spammed by %s', 'akismet'), $who );
515 }
516
517 // add a History item to the hover links, just after Edit
518 if ( $akismet_result ) {
519 $b = array();
520 foreach ( $a as $k => $item ) {
521 $b[ $k ] = $item;
522 if (
523 $k == 'edit'
524 || $k == 'unspam'
525 ) {
526 $b['history'] = '<a href="comment.php?action=editcomment&amp;c='.$comment->comment_ID.'#akismet-status" title="'. esc_attr__( 'View comment history' , 'akismet') . '"> '. esc_html__('History', 'akismet') . '</a>';
527 }
528 }
529
530 $a = $b;
531 }
532
533 if ( $desc )
534 echo '<span class="akismet-status" commentid="'.$comment->comment_ID.'"><a href="comment.php?action=editcomment&amp;c='.$comment->comment_ID.'#akismet-status" title="' . esc_attr__( 'View comment history' , 'akismet') . '">'.esc_html( $desc ).'</a></span>';
535
536 $show_user_comments_option = get_option( 'akismet_show_user_comments_approved' );
537
538 if ( $show_user_comments_option === false ) {
539 // Default to active if the user hasn't made a decision.
540 $show_user_comments_option = '1';
541 }
542
543 $show_user_comments = apply_filters( 'akismet_show_user_comments_approved', $show_user_comments_option );
544 $show_user_comments = $show_user_comments === 'false' ? false : $show_user_comments; //option used to be saved as 'false' / 'true'
545
546 if ( $show_user_comments ) {
547 $comment_count = Akismet::get_user_comments_approved( $comment->user_id, $comment->comment_author_email, $comment->comment_author, $comment->comment_author_url );
548 $comment_count = intval( $comment_count );
549 echo '<span class="akismet-user-comment-count" commentid="'.$comment->comment_ID.'" style="display:none;"><br><span class="akismet-user-comment-counts">'. sprintf( esc_html( _n( '%s approved', '%s approved', $comment_count , 'akismet') ), number_format_i18n( $comment_count ) ) . '</span></span>';
550 }
551
552 return $a;
553 }
554
555 public static function comment_status_meta_box( $comment ) {
556 $history = Akismet::get_comment_history( $comment->comment_ID );
557
558 if ( $history ) {
559 echo '<div class="akismet-history" style="margin: 13px;">';
560
561 foreach ( $history as $row ) {
562 $time = date( 'D d M Y @ h:i:m a', $row['time'] ) . ' GMT';
563
564 $message = '';
565
566 if ( ! empty( $row['message'] ) ) {
567 // Old versions of Akismet stored the message as a literal string in the commentmeta.
568 // New versions don't do that for two reasons:
569 // 1) Save space.
570 // 2) The message can be translated into the current language of the blog, not stuck
571 // in the language of the blog when the comment was made.
572 $message = $row['message'];
573 }
574
575 // If possible, use a current translation.
576 switch ( $row['event'] ) {
577 case 'recheck-spam';
578 $message = __( 'Akismet re-checked and caught this comment as spam.', 'akismet' );
579 break;
580 case 'check-spam':
581 $message = __( 'Akismet caught this comment as spam.', 'akismet' );
582 break;
583 case 'recheck-ham':
584 $message = __( 'Akismet re-checked and cleared this comment.', 'akismet' );
585 break;
586 case 'check-ham':
587 $message = __( 'Akismet cleared this comment.', 'akismet' );
588 break;
589 case 'wp-blacklisted':
590 $message = __( 'Comment was caught by wp_blacklist_check.', 'akismet' );
591 break;
592 case 'report-spam':
593 if ( isset( $row['user'] ) ) {
594 $message = sprintf( __( '%s reported this comment as spam.', 'akismet' ), $row['user'] );
595 }
596 else if ( ! $message ) {
597 $message = __( 'This comment was reported as spam.', 'akismet' );
598 }
599 break;
600 case 'report-ham':
601 if ( isset( $row['user'] ) ) {
602 $message = sprintf( __( '%s reported this comment as not spam.', 'akismet' ), $row['user'] );
603 }
604 else if ( ! $message ) {
605 $message = __( 'This comment was reported as not spam.', 'akismet' );
606 }
607 break;
608 case 'cron-retry-spam':
609 $message = __( 'Akismet caught this comment as spam during an automatic retry.' , 'akismet');
610 break;
611 case 'cron-retry-ham':
612 $message = __( 'Akismet cleared this comment during an automatic retry.', 'akismet');
613 break;
614 case 'check-error':
615 if ( isset( $row['meta'], $row['meta']['response'] ) ) {
616 $message = sprintf( __( 'Akismet was unable to check this comment (response: %s) but will automatically retry later.', 'akismet'), $row['meta']['response'] );
617 }
618 break;
619 case 'recheck-error':
620 if ( isset( $row['meta'], $row['meta']['response'] ) ) {
621 $message = sprintf( __( 'Akismet was unable to recheck this comment (response: %s).', 'akismet'), $row['meta']['response'] );
622 }
623 break;
624 default:
625 if ( preg_match( '/^status-changed/', $row['event'] ) ) {
626 // Half of these used to be saved without the dash after 'status-changed'.
627 // See https://plugins.trac.wordpress.org/changeset/1150658/akismet/trunk
628 $new_status = preg_replace( '/^status-changed-?/', '', $row['event'] );
629 $message = sprintf( __( 'Comment status was changed to %s', 'akismet' ), $new_status );
630 }
631 else if ( preg_match( '/^status-/', $row['event'] ) ) {
632 $new_status = preg_replace( '/^status-/', '', $row['event'] );
633
634 if ( isset( $row['user'] ) ) {
635 $message = sprintf( __( '%1$s changed the comment status to %2$s.', 'akismet' ), $row['user'], $new_status );
636 }
637 }
638 break;
639
640 }
641
642 echo '<div style="margin-bottom: 13px;">';
643 echo '<span style="color: #999;" alt="' . $time . '" title="' . $time . '">' . sprintf( esc_html__('%s ago', 'akismet'), human_time_diff( $row['time'] ) ) . '</span>';
644 echo ' - ';
645 echo esc_html( $message );
646 echo '</div>';
647 }
648
649 echo '</div>';
650 }
651 }
652
653 public static function plugin_action_links( $links, $file ) {
654 if ( $file == plugin_basename( plugin_dir_url( __FILE__ ) . '/akismet.php' ) ) {
655 $links[] = '<a href="' . esc_url( self::get_page_url() ) . '">'.esc_html__( 'Settings' , 'akismet').'</a>';
656 }
657
658 return $links;
659 }
660
661 // Total spam in queue
662 // get_option( 'akismet_spam_count' ) is the total caught ever
663 public static function get_spam_count( $type = false ) {
664 global $wpdb;
665
666 if ( !$type ) { // total
667 $count = wp_cache_get( 'akismet_spam_count', 'widget' );
668 if ( false === $count ) {
669 $count = wp_count_comments();
670 $count = $count->spam;
671 wp_cache_set( 'akismet_spam_count', $count, 'widget', 3600 );
672 }
673 return $count;
674 } elseif ( 'comments' == $type || 'comment' == $type ) { // comments
675 $type = '';
676 }
677
678 return (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(comment_ID) FROM {$wpdb->comments} WHERE comment_approved = 'spam' AND comment_type = %s", $type ) );
679 }
680
681 // Check connectivity between the WordPress blog and Akismet's servers.
682 // Returns an associative array of server IP addresses, where the key is the IP address, and value is true (available) or false (unable to connect).
683 public static function check_server_ip_connectivity() {
684
685 $servers = $ips = array();
686
687 // Some web hosts may disable this function
688 if ( function_exists('gethostbynamel') ) {
689
690 $ips = gethostbynamel( 'rest.akismet.com' );
691 if ( $ips && is_array($ips) && count($ips) ) {
692 $api_key = Akismet::get_api_key();
693
694 foreach ( $ips as $ip ) {
695 $response = Akismet::verify_key( $api_key, $ip );
696 // even if the key is invalid, at least we know we have connectivity
697 if ( $response == 'valid' || $response == 'invalid' )
698 $servers[$ip] = 'connected';
699 else
700 $servers[$ip] = $response ? $response : 'unable to connect';
701 }
702 }
703 }
704
705 return $servers;
706 }
707
708 // Simpler connectivity check
709 public static function check_server_connectivity($cache_timeout = 86400) {
710
711 $debug = array();
712 $debug[ 'PHP_VERSION' ] = PHP_VERSION;
713 $debug[ 'WORDPRESS_VERSION' ] = $GLOBALS['wp_version'];
714 $debug[ 'AKISMET_VERSION' ] = AKISMET_VERSION;
715 $debug[ 'AKISMET__PLUGIN_DIR' ] = AKISMET__PLUGIN_DIR;
716 $debug[ 'SITE_URL' ] = site_url();
717 $debug[ 'HOME_URL' ] = home_url();
718
719 $servers = get_option('akismet_available_servers');
720 if ( (time() - get_option('akismet_connectivity_time') < $cache_timeout) && $servers !== false ) {
721 $servers = self::check_server_ip_connectivity();
722 update_option('akismet_available_servers', $servers);
723 update_option('akismet_connectivity_time', time());
724 }
725
726 if ( wp_http_supports( array( 'ssl' ) ) ) {
727 $response = wp_remote_get( 'https://rest.akismet.com/1.1/test' );
728 }
729 else {
730 $response = wp_remote_get( 'http://rest.akismet.com/1.1/test' );
731 }
732
733 $debug[ 'gethostbynamel' ] = function_exists('gethostbynamel') ? 'exists' : 'not here';
734 $debug[ 'Servers' ] = $servers;
735 $debug[ 'Test Connection' ] = $response;
736
737 Akismet::log( $debug );
738
739 if ( $response && 'connected' == wp_remote_retrieve_body( $response ) )
740 return true;
741
742 return false;
743 }
744
745 // Check the server connectivity and store the available servers in an option.
746 public static function get_server_connectivity($cache_timeout = 86400) {
747 return self::check_server_connectivity( $cache_timeout );
748 }
749
750 /**
751 * Find out whether any comments in the Pending queue have not yet been checked by Akismet.
752 *
753 * @return bool
754 */
755 public static function are_any_comments_waiting_to_be_checked() {
756 return !! get_comments( array(
757 // Exclude comments that are not pending. This would happen if someone manually approved or spammed a comment
758 // that was waiting to be checked. The akismet_error meta entry will eventually be removed by the cron recheck job.
759 'status' => 'hold',
760
761 // This is the commentmeta that is saved when a comment couldn't be checked.
762 'meta_key' => 'akismet_error',
763
764 // We only need to know whether at least one comment is waiting for a check.
765 'number' => 1,
766 ) );
767 }
768
769 public static function get_page_url( $page = 'config' ) {
770
771 $args = array( 'page' => 'akismet-key-config' );
772
773 if ( $page == 'stats' )
774 $args = array( 'page' => 'akismet-key-config', 'view' => 'stats' );
775 elseif ( $page == 'delete_key' )
776 $args = array( 'page' => 'akismet-key-config', 'view' => 'start', 'action' => 'delete-key', '_wpnonce' => wp_create_nonce( self::NONCE ) );
777
778 $url = add_query_arg( $args, class_exists( 'Jetpack' ) ? admin_url( 'admin.php' ) : admin_url( 'options-general.php' ) );
779
780 return $url;
781 }
782
783 public static function get_akismet_user( $api_key ) {
784 $akismet_user = false;
785
786 $subscription_verification = Akismet::http_post( Akismet::build_query( array( 'key' => $api_key, 'blog' => get_option( 'home' ) ) ), 'get-subscription' );
787
788 if ( ! empty( $subscription_verification[1] ) ) {
789 if ( 'invalid' !== $subscription_verification[1] ) {
790 $akismet_user = json_decode( $subscription_verification[1] );
791 }
792 }
793
794 return $akismet_user;
795 }
796
797 public static function get_stats( $api_key ) {
798 $stat_totals = array();
799
800 foreach( array( '6-months', 'all' ) as $interval ) {
801 $response = Akismet::http_post( Akismet::build_query( array( 'blog' => get_option( 'home' ), 'key' => $api_key, 'from' => $interval ) ), 'get-stats' );
802
803 if ( ! empty( $response[1] ) ) {
804 $stat_totals[$interval] = json_decode( $response[1] );
805 }
806 }
807
808 return $stat_totals;
809 }
810
811 public static function verify_wpcom_key( $api_key, $user_id, $extra = array() ) {
812 $akismet_account = Akismet::http_post( Akismet::build_query( array_merge( array(
813 'user_id' => $user_id,
814 'api_key' => $api_key,
815 'get_account_type' => 'true'
816 ), $extra ) ), 'verify-wpcom-key' );
817
818 if ( ! empty( $akismet_account[1] ) )
819 $akismet_account = json_decode( $akismet_account[1] );
820
821 Akismet::log( compact( 'akismet_account' ) );
822
823 return $akismet_account;
824 }
825
826 public static function connect_jetpack_user() {
827
828 if ( $jetpack_user = self::get_jetpack_user() ) {
829 if ( isset( $jetpack_user['user_id'] ) && isset( $jetpack_user['api_key'] ) ) {
830 $akismet_user = self::verify_wpcom_key( $jetpack_user['api_key'], $jetpack_user['user_id'], array( 'action' => 'connect_jetpack_user' ) );
831
832 if ( is_object( $akismet_user ) ) {
833 self::save_key( $akismet_user->api_key );
834 return in_array( $akismet_user->status, array( 'active', 'active-dunning', 'no-sub' ) );
835 }
836 }
837 }
838
839 return false;
840 }
841
842 public static function display_alert() {
843 Akismet::view( 'notice', array(
844 'type' => 'alert',
845 'code' => (int) get_option( 'akismet_alert_code' ),
846 'msg' => get_option( 'akismet_alert_msg' )
847 ) );
848 }
849
850 public static function display_privacy_notice_control_warning() {
851 if ( !current_user_can( 'manage_options' ) )
852 return;
853 Akismet::view( 'notice', array(
854 'type' => 'privacy',
855 ) );
856 }
857
858 public static function display_spam_check_warning() {
859 Akismet::fix_scheduled_recheck();
860
861 if ( wp_next_scheduled('akismet_schedule_cron_recheck') > time() && self::are_any_comments_waiting_to_be_checked() ) {
862 $link_text = apply_filters( 'akismet_spam_check_warning_link_text', sprintf( __( 'Please check your <a href="%s">Akismet configuration</a> and contact your web host if problems persist.', 'akismet'), esc_url( self::get_page_url() ) ) );
863 Akismet::view( 'notice', array( 'type' => 'spam-check', 'link_text' => $link_text ) );
864 }
865 }
866
867 public static function display_api_key_warning() {
868 Akismet::view( 'notice', array( 'type' => 'plugin' ) );
869 }
870
871 public static function display_page() {
872 if ( !Akismet::get_api_key() || ( isset( $_GET['view'] ) && $_GET['view'] == 'start' ) )
873 self::display_start_page();
874 elseif ( isset( $_GET['view'] ) && $_GET['view'] == 'stats' )
875 self::display_stats_page();
876 else
877 self::display_configuration_page();
878 }
879
880 public static function display_start_page() {
881 if ( isset( $_GET['action'] ) ) {
882 if ( $_GET['action'] == 'delete-key' ) {
883 if ( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], self::NONCE ) )
884 delete_option( 'wordpress_api_key' );
885 }
886 }
887
888 if ( $api_key = Akismet::get_api_key() && ( empty( self::$notices['status'] ) || 'existing-key-invalid' != self::$notices['status'] ) ) {
889 self::display_configuration_page();
890 return;
891 }
892
893 //the user can choose to auto connect their API key by clicking a button on the akismet done page
894 //if jetpack, get verified api key by using connected wpcom user id
895 //if no jetpack, get verified api key by using an akismet token
896
897 $akismet_user = false;
898
899 if ( isset( $_GET['token'] ) && preg_match('/^(\d+)-[0-9a-f]{20}$/', $_GET['token'] ) )
900 $akismet_user = self::verify_wpcom_key( '', '', array( 'token' => $_GET['token'] ) );
901 elseif ( $jetpack_user = self::get_jetpack_user() )
902 $akismet_user = self::verify_wpcom_key( $jetpack_user['api_key'], $jetpack_user['user_id'] );
903
904 if ( isset( $_GET['action'] ) ) {
905 if ( $_GET['action'] == 'save-key' ) {
906 if ( is_object( $akismet_user ) ) {
907 self::save_key( $akismet_user->api_key );
908 self::display_configuration_page();
909 return;
910 }
911 }
912 }
913
914 Akismet::view( 'start', compact( 'akismet_user' ) );
915
916 /*
917 // To see all variants when testing.
918 $akismet_user->status = 'no-sub';
919 Akismet::view( 'start', compact( 'akismet_user' ) );
920 $akismet_user->status = 'cancelled';
921 Akismet::view( 'start', compact( 'akismet_user' ) );
922 $akismet_user->status = 'suspended';
923 Akismet::view( 'start', compact( 'akismet_user' ) );
924 $akismet_user->status = 'other';
925 Akismet::view( 'start', compact( 'akismet_user' ) );
926 $akismet_user = false;
927 */
928 }
929
930 public static function display_stats_page() {
931 Akismet::view( 'stats' );
932 }
933
934 public static function display_configuration_page() {
935 $api_key = Akismet::get_api_key();
936 $akismet_user = self::get_akismet_user( $api_key );
937
938 if ( ! $akismet_user ) {
939 // This could happen if the user's key became invalid after it was previously valid and successfully set up.
940 self::$notices['status'] = 'existing-key-invalid';
941 self::display_start_page();
942 return;
943 }
944
945 $stat_totals = self::get_stats( $api_key );
946
947 // If unset, create the new strictness option using the old discard option to determine its default.
948 // If the old option wasn't set, default to discarding the blatant spam.
949 if ( get_option( 'akismet_strictness' ) === false ) {
950 add_option( 'akismet_strictness', ( get_option( 'akismet_discard_month' ) === 'false' ? '0' : '1' ) );
951 }
952
953 // Sync the local "Total spam blocked" count with the authoritative count from the server.
954 if ( isset( $stat_totals['all'], $stat_totals['all']->spam ) ) {
955 update_option( 'akismet_spam_count', $stat_totals['all']->spam );
956 }
957
958 $notices = array();
959
960 if ( empty( self::$notices ) ) {
961 if ( ! empty( $stat_totals['all'] ) && isset( $stat_totals['all']->time_saved ) && $akismet_user->status == 'active' && $akismet_user->account_type == 'free-api-key' ) {
962
963 $time_saved = false;
964
965 if ( $stat_totals['all']->time_saved > 1800 ) {
966 $total_in_minutes = round( $stat_totals['all']->time_saved / 60 );
967 $total_in_hours = round( $total_in_minutes / 60 );
968 $total_in_days = round( $total_in_hours / 8 );
969 $cleaning_up = __( 'Cleaning up spam takes time.' , 'akismet');
970
971 if ( $total_in_days > 1 )
972 $time_saved = $cleaning_up . ' ' . sprintf( _n( 'Akismet has saved you %s day!', 'Akismet has saved you %s days!', $total_in_days, 'akismet' ), number_format_i18n( $total_in_days ) );
973 elseif ( $total_in_hours > 1 )
974 $time_saved = $cleaning_up . ' ' . sprintf( _n( 'Akismet has saved you %d hour!', 'Akismet has saved you %d hours!', $total_in_hours, 'akismet' ), $total_in_hours );
975 elseif ( $total_in_minutes >= 30 )
976 $time_saved = $cleaning_up . ' ' . sprintf( _n( 'Akismet has saved you %d minute!', 'Akismet has saved you %d minutes!', $total_in_minutes, 'akismet' ), $total_in_minutes );
977 }
978
979 $notices[] = array( 'type' => 'active-notice', 'time_saved' => $time_saved );
980 }
981
982 if ( !empty( $akismet_user->limit_reached ) && in_array( $akismet_user->limit_reached, array( 'yellow', 'red' ) ) ) {
983 $notices[] = array( 'type' => 'limit-reached', 'level' => $akismet_user->limit_reached );
984 }
985 }
986
987 if ( !isset( self::$notices['status'] ) && in_array( $akismet_user->status, array( 'cancelled', 'suspended', 'missing', 'no-sub' ) ) ) {
988 $notices[] = array( 'type' => $akismet_user->status );
989 }
990
991 if ( false === get_option( 'akismet_comment_form_privacy_notice' ) ) {
992 $notices[] = array( 'type' => 'privacy' );
993 }
994
995 /*
996 // To see all variants when testing.
997 $notices[] = array( 'type' => 'active-notice', 'time_saved' => 'Cleaning up spam takes time. Akismet has saved you 1 minute!' );
998 $notices[] = array( 'type' => 'plugin' );
999 $notices[] = array( 'type' => 'spam-check', 'link_text' => 'Link text.' );
1000 $notices[] = array( 'type' => 'notice', 'notice_header' => 'This is the notice header.', 'notice_text' => 'This is the notice text.' );
1001 $notices[] = array( 'type' => 'missing-functions' );
1002 $notices[] = array( 'type' => 'servers-be-down' );
1003 $notices[] = array( 'type' => 'active-dunning' );
1004 $notices[] = array( 'type' => 'cancelled' );
1005 $notices[] = array( 'type' => 'suspended' );
1006 $notices[] = array( 'type' => 'missing' );
1007 $notices[] = array( 'type' => 'no-sub' );
1008 $notices[] = array( 'type' => 'new-key-valid' );
1009 $notices[] = array( 'type' => 'new-key-invalid' );
1010 $notices[] = array( 'type' => 'existing-key-invalid' );
1011 $notices[] = array( 'type' => 'new-key-failed' );
1012 $notices[] = array( 'type' => 'limit-reached', 'level' => 'yellow' );
1013 $notices[] = array( 'type' => 'limit-reached', 'level' => 'red' );
1014 */
1015
1016 Akismet::log( compact( 'stat_totals', 'akismet_user' ) );
1017 Akismet::view( 'config', compact( 'api_key', 'akismet_user', 'stat_totals', 'notices' ) );
1018 }
1019
1020 public static function display_notice() {
1021 global $hook_suffix;
1022
1023 if ( in_array( $hook_suffix, array( 'jetpack_page_akismet-key-config', 'settings_page_akismet-key-config' ) ) ) {
1024 // This page manages the notices and puts them inline where they make sense.
1025 return;
1026 }
1027
1028 if ( in_array( $hook_suffix, array( 'edit-comments.php' ) ) && (int) get_option( 'akismet_alert_code' ) > 0 ) {
1029 Akismet::verify_key( Akismet::get_api_key() ); //verify that the key is still in alert state
1030
1031 if ( get_option( 'akismet_alert_code' ) > 0 )
1032 self::display_alert();
1033 }
1034 elseif ( $hook_suffix == 'plugins.php' && !Akismet::get_api_key() ) {
1035 self::display_api_key_warning();
1036 }
1037 elseif ( $hook_suffix == 'edit-comments.php' && wp_next_scheduled( 'akismet_schedule_cron_recheck' ) ) {
1038 self::display_spam_check_warning();
1039 }
1040 else if ( isset( $_GET['akismet_recheck_complete'] ) ) {
1041 $recheck_count = (int) $_GET['recheck_count'];
1042 $spam_count = (int) $_GET['spam_count'];
1043
1044 if ( $recheck_count === 0 ) {
1045 $message = __( 'There were no comments to check. Akismet will only check comments in the Pending queue.', 'akismet' );
1046 }
1047 else {
1048 $message = sprintf( _n( 'Akismet checked %s comment.', 'Akismet checked %s comments.', $recheck_count, 'akismet' ), number_format( $recheck_count ) );
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 ) );
1056 }
1057 }
1058
1059 echo '<div class="notice notice-success"><p>' . esc_html( $message ) . '</p></div>';
1060 }
1061
1062 $akismet_comment_form_privacy_notice_option = get_option( 'akismet_comment_form_privacy_notice' );
1063 if ( ! in_array( $akismet_comment_form_privacy_notice_option, array( 'hide', 'display' ) ) ) {
1064 $api_key = Akismet::get_api_key();
1065 if ( ! empty( $api_key ) ) {
1066 self::display_privacy_notice_control_warning();
1067 }
1068 }
1069 }
1070
1071 public static function display_status() {
1072 if ( ! self::get_server_connectivity() ) {
1073 Akismet::view( 'notice', array( 'type' => 'servers-be-down' ) );
1074 }
1075 else if ( ! empty( self::$notices ) ) {
1076 foreach ( self::$notices as $index => $type ) {
1077 if ( is_object( $type ) ) {
1078 $notice_header = $notice_text = '';
1079
1080 if ( property_exists( $type, 'notice_header' ) ) {
1081 $notice_header = wp_kses( $type->notice_header, self::$allowed );
1082 }
1083
1084 if ( property_exists( $type, 'notice_text' ) ) {
1085 $notice_text = wp_kses( $type->notice_text, self::$allowed );
1086 }
1087
1088 if ( property_exists( $type, 'status' ) ) {
1089 $type = wp_kses( $type->status, self::$allowed );
1090 Akismet::view( 'notice', compact( 'type', 'notice_header', 'notice_text' ) );
1091
1092 unset( self::$notices[ $index ] );
1093 }
1094 }
1095 else {
1096 Akismet::view( 'notice', compact( 'type' ) );
1097
1098 unset( self::$notices[ $index ] );
1099 }
1100 }
1101 }
1102 }
1103
1104 private static function get_jetpack_user() {
1105 if ( !class_exists('Jetpack') )
1106 return false;
1107
1108 Jetpack::load_xml_rpc_client();
1109 $xml = new Jetpack_IXR_ClientMulticall( array( 'user_id' => get_current_user_id() ) );
1110
1111 $xml->addCall( 'wpcom.getUserID' );
1112 $xml->addCall( 'akismet.getAPIKey' );
1113 $xml->query();
1114
1115 Akismet::log( compact( 'xml' ) );
1116
1117 if ( !$xml->isError() ) {
1118 $responses = $xml->getResponse();
1119 if ( count( $responses ) > 1 ) {
1120 // Due to a quirk in how Jetpack does multi-calls, the response order
1121 // can't be trusted to match the call order. It's a good thing our
1122 // return values can be mostly differentiated from each other.
1123 $first_response_value = array_shift( $responses[0] );
1124 $second_response_value = array_shift( $responses[1] );
1125
1126 // If WPCOM ever reaches 100 billion users, this will fail. :-)
1127 if ( preg_match( '/^[a-f0-9]{12}$/i', $first_response_value ) ) {
1128 $api_key = $first_response_value;
1129 $user_id = (int) $second_response_value;
1130 }
1131 else {
1132 $api_key = $second_response_value;
1133 $user_id = (int) $first_response_value;
1134 }
1135
1136 return compact( 'api_key', 'user_id' );
1137 }
1138 }
1139 return false;
1140 }
1141
1142 /**
1143 * Some commentmeta isn't useful in an export file. Suppress it (when supported).
1144 *
1145 * @param bool $exclude
1146 * @param string $key The meta key
1147 * @param object $meta The meta object
1148 * @return bool Whether to exclude this meta entry from the export.
1149 */
1150 public static function exclude_commentmeta_from_export( $exclude, $key, $meta ) {
1151 if ( in_array( $key, array( 'akismet_as_submitted', 'akismet_rechecking', 'akismet_delayed_moderation_email' ) ) ) {
1152 return true;
1153 }
1154
1155 return $exclude;
1156 }
1157
1158 /**
1159 * When Akismet is active, remove the "Activate Akismet" step from the plugin description.
1160 */
1161 public static function modify_plugin_description( $all_plugins ) {
1162 if ( isset( $all_plugins['akismet/akismet.php'] ) ) {
1163 if ( Akismet::get_api_key() ) {
1164 $all_plugins['akismet/akismet.php']['Description'] = __( 'Used by millions, Akismet is quite possibly the best way in the world to <strong>protect your blog from spam</strong>. Your site is fully configured and being protected, even while you sleep.', 'akismet' );
1165 }
1166 else {
1167 $all_plugins['akismet/akismet.php']['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, just go to <a href="admin.php?page=akismet-key-config">your Akismet Settings page</a> to set up your API key.', 'akismet' );
1168 }
1169 }
1170
1171 return $all_plugins;
1172 }
1173
1174 private static function set_form_privacy_notice_option( $state ) {
1175 if ( in_array( $state, array( 'display', 'hide' ) ) ) {
1176 update_option( 'akismet_comment_form_privacy_notice', $state );
1177 }
1178 }
1179
1180 public static function jetpack_comment_form_privacy_notice_url( $url ) {
1181 return str_replace( 'options-general.php', 'admin.php', $url );
1182 }
1183 }
1184