[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-content/plugins/akismet/ -> class.akismet-admin.php (source)

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


Generated : Mon Aug 3 08:20:02 2020 Cross-referenced by PHPXref