[ Index ]

PHP Cross Reference of WordPress

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&#8217;t have permission to do that.', 'akismet' ),
 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                      case 'wp-disallowed':
 616                          $message = sprintf(
 617                              /* translators: The placeholder is a WordPress PHP function name. */
 618                              esc_html( __( 'Comment was caught by %s.', 'akismet' ) ),
 619                              function_exists( 'wp_check_comment_disallowed_list' ) ? '<code>wp_check_comment_disallowed_list</code>' : '<code>wp_blacklist_check</code>'
 620                          );
 621                      break;
 622                      case 'report-spam':
 623                          if ( isset( $row['user'] ) ) {
 624                              $message = esc_html( sprintf( __( '%s reported this comment as spam.', 'akismet' ), $row['user'] ) );
 625                          }
 626                          else if ( ! $message ) {
 627                              $message = esc_html( __( 'This comment was reported as spam.', 'akismet' ) );
 628                          }
 629                      break;
 630                      case 'report-ham':
 631                          if ( isset( $row['user'] ) ) {
 632                              $message = esc_html( sprintf( __( '%s reported this comment as not spam.', 'akismet' ), $row['user'] ) );
 633                          }
 634                          else if ( ! $message ) {
 635                              $message = esc_html( __( 'This comment was reported as not spam.', 'akismet' ) );
 636                          }
 637                      break;
 638                      case 'cron-retry-spam':
 639                          $message = esc_html( __( 'Akismet caught this comment as spam during an automatic retry.' , 'akismet') );
 640                      break;
 641                      case 'cron-retry-ham':
 642                          $message = esc_html( __( 'Akismet cleared this comment during an automatic retry.', 'akismet') );
 643                      break;
 644                      case 'check-error':
 645                          if ( isset( $row['meta'], $row['meta']['response'] ) ) {
 646                              $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>' );
 647                          }
 648                          else {
 649                              $message = esc_html( __( 'Akismet was unable to check this comment but will automatically retry later.', 'akismet' ) );
 650                          }
 651                      break;
 652                      case 'recheck-error':
 653                          if ( isset( $row['meta'], $row['meta']['response'] ) ) {
 654                              $message = sprintf( esc_html( __( 'Akismet was unable to recheck this comment (response: %s).', 'akismet') ), '<code>' . esc_html( $row['meta']['response'] ) . '</code>' );
 655                          }
 656                          else {
 657                              $message = esc_html( __( 'Akismet was unable to recheck this comment.', 'akismet' ) );
 658                          }
 659                      break;
 660                      default:
 661                          if ( preg_match( '/^status-changed/', $row['event'] ) ) {
 662                              // Half of these used to be saved without the dash after 'status-changed'.
 663                              // See https://plugins.trac.wordpress.org/changeset/1150658/akismet/trunk
 664                              $new_status = preg_replace( '/^status-changed-?/', '', $row['event'] );
 665                              $message = sprintf( esc_html( __( 'Comment status was changed to %s', 'akismet' ) ), '<code>' . esc_html( $new_status ) . '</code>' );
 666                          }
 667                          else if ( preg_match( '/^status-/', $row['event'] ) ) {
 668                              $new_status = preg_replace( '/^status-/', '', $row['event'] );
 669  
 670                              if ( isset( $row['user'] ) ) {
 671                                  $message = sprintf( esc_html( __( '%1$s changed the comment status to %2$s.', 'akismet' ) ), $row['user'], '<code>' . esc_html( $new_status ) . '</code>' );
 672                              }
 673                          }
 674                      break;
 675                      
 676                  }
 677  
 678                  if ( ! empty( $message ) ) {
 679                      echo '<p>';
 680                      echo '<span style="color: #999;" alt="' . $time . '" title="' . $time . '">' . sprintf( esc_html__('%s ago', 'akismet'), human_time_diff( $row['time'] ) ) . '</span>';
 681                      echo ' - ';
 682                      echo $message; // esc_html() is done above so that we can use HTML in some messages.
 683                      echo '</p>';
 684                  }
 685              }
 686          }
 687          else {
 688              echo '<p>';
 689              echo esc_html( __( 'No comment history.', 'akismet' ) );
 690              echo '</p>';
 691          }
 692      }
 693  
 694  	public static function plugin_action_links( $links, $file ) {
 695          if ( $file == plugin_basename( plugin_dir_url( __FILE__ ) . '/akismet.php' ) ) {
 696              $links[] = '<a href="' . esc_url( self::get_page_url() ) . '">'.esc_html__( 'Settings' , 'akismet').'</a>';
 697          }
 698  
 699          return $links;
 700      }
 701  
 702      // Total spam in queue
 703      // get_option( 'akismet_spam_count' ) is the total caught ever
 704  	public static function get_spam_count( $type = false ) {
 705          global $wpdb;
 706  
 707          if ( !$type ) { // total
 708              $count = wp_cache_get( 'akismet_spam_count', 'widget' );
 709              if ( false === $count ) {
 710                  $count = wp_count_comments();
 711                  $count = $count->spam;
 712                  wp_cache_set( 'akismet_spam_count', $count, 'widget', 3600 );
 713              }
 714              return $count;
 715          } elseif ( 'comments' == $type || 'comment' == $type ) { // comments
 716              $type = '';
 717          }
 718  
 719          return (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(comment_ID) FROM {$wpdb->comments} WHERE comment_approved = 'spam' AND comment_type = %s", $type ) );
 720      }
 721  
 722      // Check connectivity between the WordPress blog and Akismet's servers.
 723      // 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).
 724  	public static function check_server_ip_connectivity() {
 725          
 726          $servers = $ips = array();
 727  
 728          // Some web hosts may disable this function
 729          if ( function_exists('gethostbynamel') ) {    
 730              
 731              $ips = gethostbynamel( 'rest.akismet.com' );
 732              if ( $ips && is_array($ips) && count($ips) ) {
 733                  $api_key = Akismet::get_api_key();
 734                  
 735                  foreach ( $ips as $ip ) {
 736                      $response = Akismet::verify_key( $api_key, $ip );
 737                      // even if the key is invalid, at least we know we have connectivity
 738                      if ( $response == 'valid' || $response == 'invalid' )
 739                          $servers[$ip] = 'connected';
 740                      else
 741                          $servers[$ip] = $response ? $response : 'unable to connect';
 742                  }
 743              }
 744          }
 745          
 746          return $servers;
 747      }
 748      
 749      // Simpler connectivity check
 750  	public static function check_server_connectivity($cache_timeout = 86400) {
 751          
 752          $debug = array();
 753          $debug[ 'PHP_VERSION' ]         = PHP_VERSION;
 754          $debug[ 'WORDPRESS_VERSION' ]   = $GLOBALS['wp_version'];
 755          $debug[ 'AKISMET_VERSION' ]     = AKISMET_VERSION;
 756          $debug[ 'AKISMET__PLUGIN_DIR' ] = AKISMET__PLUGIN_DIR;
 757          $debug[ 'SITE_URL' ]            = site_url();
 758          $debug[ 'HOME_URL' ]            = home_url();
 759          
 760          $servers = get_option('akismet_available_servers');
 761          if ( (time() - get_option('akismet_connectivity_time') < $cache_timeout) && $servers !== false ) {
 762              $servers = self::check_server_ip_connectivity();
 763              update_option('akismet_available_servers', $servers);
 764              update_option('akismet_connectivity_time', time());
 765          }
 766  
 767          if ( wp_http_supports( array( 'ssl' ) ) ) {
 768              $response = wp_remote_get( 'https://rest.akismet.com/1.1/test' );
 769          }
 770          else {
 771              $response = wp_remote_get( 'http://rest.akismet.com/1.1/test' );
 772          }
 773  
 774          $debug[ 'gethostbynamel' ]  = function_exists('gethostbynamel') ? 'exists' : 'not here';
 775          $debug[ 'Servers' ]         = $servers;
 776          $debug[ 'Test Connection' ] = $response;
 777          
 778          Akismet::log( $debug );
 779          
 780          if ( $response && 'connected' == wp_remote_retrieve_body( $response ) )
 781              return true;
 782          
 783          return false;
 784      }
 785  
 786      // Check the server connectivity and store the available servers in an option. 
 787  	public static function get_server_connectivity($cache_timeout = 86400) {
 788          return self::check_server_connectivity( $cache_timeout );
 789      }
 790  
 791      /**
 792       * Find out whether any comments in the Pending queue have not yet been checked by Akismet.
 793       *
 794       * @return bool
 795       */
 796  	public static function are_any_comments_waiting_to_be_checked() {
 797          return !! get_comments( array(
 798              // Exclude comments that are not pending. This would happen if someone manually approved or spammed a comment
 799              // that was waiting to be checked. The akismet_error meta entry will eventually be removed by the cron recheck job.
 800              'status' => 'hold',
 801              
 802              // This is the commentmeta that is saved when a comment couldn't be checked.
 803              'meta_key' => 'akismet_error',
 804              
 805              // We only need to know whether at least one comment is waiting for a check.
 806              'number' => 1,
 807          ) );
 808      }
 809  
 810  	public static function get_page_url( $page = 'config' ) {
 811  
 812          $args = array( 'page' => 'akismet-key-config' );
 813  
 814          if ( $page == 'stats' )
 815              $args = array( 'page' => 'akismet-key-config', 'view' => 'stats' );
 816          elseif ( $page == 'delete_key' )
 817              $args = array( 'page' => 'akismet-key-config', 'view' => 'start', 'action' => 'delete-key', '_wpnonce' => wp_create_nonce( self::NONCE ) );
 818  
 819          $url = add_query_arg( $args, class_exists( 'Jetpack' ) ? admin_url( 'admin.php' ) : admin_url( 'options-general.php' ) );
 820  
 821          return $url;
 822      }
 823      
 824  	public static function get_akismet_user( $api_key ) {
 825          $akismet_user = false;
 826  
 827          $subscription_verification = Akismet::http_post( Akismet::build_query( array( 'key' => $api_key, 'blog' => get_option( 'home' ) ) ), 'get-subscription' );
 828  
 829          if ( ! empty( $subscription_verification[1] ) ) {
 830              if ( 'invalid' !== $subscription_verification[1] ) {
 831                  $akismet_user = json_decode( $subscription_verification[1] );
 832              }
 833          }
 834  
 835          return $akismet_user;
 836      }
 837      
 838  	public static function get_stats( $api_key ) {
 839          $stat_totals = array();
 840  
 841          foreach( array( '6-months', 'all' ) as $interval ) {
 842              $response = Akismet::http_post( Akismet::build_query( array( 'blog' => get_option( 'home' ), 'key' => $api_key, 'from' => $interval ) ), 'get-stats' );
 843  
 844              if ( ! empty( $response[1] ) ) {
 845                  $stat_totals[$interval] = json_decode( $response[1] );
 846              }
 847          }
 848  
 849          return $stat_totals;
 850      }
 851      
 852  	public static function verify_wpcom_key( $api_key, $user_id, $extra = array() ) {
 853          $akismet_account = Akismet::http_post( Akismet::build_query( array_merge( array(
 854              'user_id'          => $user_id,
 855              'api_key'          => $api_key,
 856              'get_account_type' => 'true'
 857          ), $extra ) ), 'verify-wpcom-key' );
 858  
 859          if ( ! empty( $akismet_account[1] ) )
 860              $akismet_account = json_decode( $akismet_account[1] );
 861  
 862          Akismet::log( compact( 'akismet_account' ) );
 863          
 864          return $akismet_account;
 865      }
 866      
 867  	public static function connect_jetpack_user() {
 868      
 869          if ( $jetpack_user = self::get_jetpack_user() ) {
 870              if ( isset( $jetpack_user['user_id'] ) && isset(  $jetpack_user['api_key'] ) ) {
 871                  $akismet_user = self::verify_wpcom_key( $jetpack_user['api_key'], $jetpack_user['user_id'], array( 'action' => 'connect_jetpack_user' ) );
 872                              
 873                  if ( is_object( $akismet_user ) ) {
 874                      self::save_key( $akismet_user->api_key );
 875                      return in_array( $akismet_user->status, array( 'active', 'active-dunning', 'no-sub' ) );
 876                  }
 877              }
 878          }
 879          
 880          return false;
 881      }
 882  
 883  	public static function display_alert() {
 884          Akismet::view( 'notice', array(
 885              'type' => 'alert',
 886              'code' => (int) get_option( 'akismet_alert_code' ),
 887              'msg'  => get_option( 'akismet_alert_msg' )
 888          ) );
 889      }
 890  
 891  	public static function get_usage_limit_alert_data() {
 892          return array(
 893              'type'         => 'usage-limit',
 894              'code'         => (int) get_option( 'akismet_alert_code' ),
 895              'msg'          => get_option( 'akismet_alert_msg' ),
 896              'api_calls'    => get_option( 'akismet_alert_api_calls' ),
 897              'usage_limit'  => get_option( 'akismet_alert_usage_limit' ),
 898              'upgrade_plan' => get_option( 'akismet_alert_upgrade_plan' ),
 899              'upgrade_url'  => get_option( 'akismet_alert_upgrade_url' ),
 900              'upgrade_type' => get_option( 'akismet_alert_upgrade_type' ),
 901          );
 902      }
 903  
 904  	public static function display_usage_limit_alert() {
 905          Akismet::view( 'notice', self::get_usage_limit_alert_data() );
 906      }
 907  
 908  	public static function display_spam_check_warning() {
 909          Akismet::fix_scheduled_recheck();
 910  
 911          if ( wp_next_scheduled('akismet_schedule_cron_recheck') > time() && self::are_any_comments_waiting_to_be_checked() ) {
 912              $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() ) ) );
 913              Akismet::view( 'notice', array( 'type' => 'spam-check', 'link_text' => $link_text ) );
 914          }
 915      }
 916  
 917  	public static function display_api_key_warning() {
 918          Akismet::view( 'notice', array( 'type' => 'plugin' ) );
 919      }
 920  
 921  	public static function display_page() {
 922          if ( !Akismet::get_api_key() || ( isset( $_GET['view'] ) && $_GET['view'] == 'start' ) )
 923              self::display_start_page();
 924          elseif ( isset( $_GET['view'] ) && $_GET['view'] == 'stats' )
 925              self::display_stats_page();
 926          else
 927              self::display_configuration_page();
 928      }
 929  
 930  	public static function display_start_page() {
 931          if ( isset( $_GET['action'] ) ) {
 932              if ( $_GET['action'] == 'delete-key' ) {
 933                  if ( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], self::NONCE ) )
 934                      delete_option( 'wordpress_api_key' );
 935              }
 936          }
 937  
 938          if ( $api_key = Akismet::get_api_key() && ( empty( self::$notices['status'] ) || 'existing-key-invalid' != self::$notices['status'] ) ) {
 939              self::display_configuration_page();
 940              return;
 941          }
 942          
 943          //the user can choose to auto connect their API key by clicking a button on the akismet done page
 944          //if jetpack, get verified api key by using connected wpcom user id
 945          //if no jetpack, get verified api key by using an akismet token    
 946          
 947          $akismet_user = false;
 948          
 949          if ( isset( $_GET['token'] ) && preg_match('/^(\d+)-[0-9a-f]{20}$/', $_GET['token'] ) )
 950              $akismet_user = self::verify_wpcom_key( '', '', array( 'token' => $_GET['token'] ) );
 951          elseif ( $jetpack_user = self::get_jetpack_user() )
 952              $akismet_user = self::verify_wpcom_key( $jetpack_user['api_key'], $jetpack_user['user_id'] );
 953              
 954          if ( isset( $_GET['action'] ) ) {
 955              if ( $_GET['action'] == 'save-key' ) {
 956                  if ( is_object( $akismet_user ) ) {
 957                      self::save_key( $akismet_user->api_key );
 958                      self::display_configuration_page();
 959                      return;
 960                  }
 961              }
 962          }
 963  
 964          Akismet::view( 'start', compact( 'akismet_user' ) );
 965  
 966          /*
 967          // To see all variants when testing.
 968          $akismet_user->status = 'no-sub';
 969          Akismet::view( 'start', compact( 'akismet_user' ) );
 970          $akismet_user->status = 'cancelled';
 971          Akismet::view( 'start', compact( 'akismet_user' ) );
 972          $akismet_user->status = 'suspended';
 973          Akismet::view( 'start', compact( 'akismet_user' ) );
 974          $akismet_user->status = 'other';
 975          Akismet::view( 'start', compact( 'akismet_user' ) );
 976          $akismet_user = false;
 977          */
 978      }
 979  
 980  	public static function display_stats_page() {
 981          Akismet::view( 'stats' );
 982      }
 983  
 984  	public static function display_configuration_page() {
 985          $api_key      = Akismet::get_api_key();
 986          $akismet_user = self::get_akismet_user( $api_key );
 987          
 988          if ( ! $akismet_user ) {
 989              // This could happen if the user's key became invalid after it was previously valid and successfully set up.
 990              self::$notices['status'] = 'existing-key-invalid';
 991              self::display_start_page();
 992              return;
 993          }
 994  
 995          $stat_totals  = self::get_stats( $api_key );
 996  
 997          // If unset, create the new strictness option using the old discard option to determine its default.
 998          // If the old option wasn't set, default to discarding the blatant spam.
 999          if ( get_option( 'akismet_strictness' ) === false ) {
1000              add_option( 'akismet_strictness', ( get_option( 'akismet_discard_month' ) === 'false' ? '0' : '1' ) );
1001          }
1002          
1003          // Sync the local "Total spam blocked" count with the authoritative count from the server.
1004          if ( isset( $stat_totals['all'], $stat_totals['all']->spam ) ) {
1005              update_option( 'akismet_spam_count', $stat_totals['all']->spam );
1006          }
1007  
1008          $notices = array();
1009  
1010          if ( empty( self::$notices ) ) {
1011              if ( ! empty( $stat_totals['all'] ) && isset( $stat_totals['all']->time_saved ) && $akismet_user->status == 'active' && $akismet_user->account_type == 'free-api-key' ) {
1012  
1013                  $time_saved = false;
1014  
1015                  if ( $stat_totals['all']->time_saved > 1800 ) {
1016                      $total_in_minutes = round( $stat_totals['all']->time_saved / 60 );
1017                      $total_in_hours   = round( $total_in_minutes / 60 );
1018                      $total_in_days    = round( $total_in_hours / 8 );
1019                      $cleaning_up      = __( 'Cleaning up spam takes time.' , 'akismet');
1020  
1021                      if ( $total_in_days > 1 )
1022                          $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 ) );
1023                      elseif ( $total_in_hours > 1 )
1024                          $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 );
1025                      elseif ( $total_in_minutes >= 30 )
1026                          $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 );
1027                  }
1028                  
1029                  $notices[] =  array( 'type' => 'active-notice', 'time_saved' => $time_saved );
1030              }
1031              
1032              if ( !empty( $akismet_user->limit_reached ) && in_array( $akismet_user->limit_reached, array( 'yellow', 'red' ) ) ) {
1033                  $notices[] = array( 'type' => 'limit-reached', 'level' => $akismet_user->limit_reached );
1034              }
1035          }
1036          
1037          if ( !isset( self::$notices['status'] ) && in_array( $akismet_user->status, array( 'cancelled', 'suspended', 'missing', 'no-sub' ) ) ) {
1038              $notices[] = array( 'type' => $akismet_user->status );
1039          }
1040  
1041          $alert_code = get_option( 'akismet_alert_code' );
1042          if ( isset( Akismet::$limit_notices[ $alert_code ] ) ) {
1043              $notices[] = self::get_usage_limit_alert_data();
1044          }
1045  
1046          /*
1047          // To see all variants when testing.
1048          $notices[] = array( 'type' => 'active-notice', 'time_saved' => 'Cleaning up spam takes time. Akismet has saved you 1 minute!' );
1049          $notices[] = array( 'type' => 'plugin' );
1050          $notices[] = array( 'type' => 'spam-check', 'link_text' => 'Link text.' );
1051          $notices[] = array( 'type' => 'notice', 'notice_header' => 'This is the notice header.', 'notice_text' => 'This is the notice text.' );
1052          $notices[] = array( 'type' => 'missing-functions' );
1053          $notices[] = array( 'type' => 'servers-be-down' );
1054          $notices[] = array( 'type' => 'active-dunning' );
1055          $notices[] = array( 'type' => 'cancelled' );
1056          $notices[] = array( 'type' => 'suspended' );
1057          $notices[] = array( 'type' => 'missing' );
1058          $notices[] = array( 'type' => 'no-sub' );
1059          $notices[] = array( 'type' => 'new-key-valid' );
1060          $notices[] = array( 'type' => 'new-key-invalid' );
1061          $notices[] = array( 'type' => 'existing-key-invalid' );
1062          $notices[] = array( 'type' => 'new-key-failed' );
1063          $notices[] = array( 'type' => 'limit-reached', 'level' => 'yellow' );
1064          $notices[] = array( 'type' => 'limit-reached', 'level' => 'red' );
1065          $notices[] = array( 'type' => 'usage-limit', 'api_calls' => '15000', 'usage_limit' => '10000', 'upgrade_plan' => 'Enterprise', 'upgrade_url' => 'https://akismet.com/account/' );
1066          */
1067          
1068          Akismet::log( compact( 'stat_totals', 'akismet_user' ) );
1069          Akismet::view( 'config', compact( 'api_key', 'akismet_user', 'stat_totals', 'notices' ) );
1070      }
1071  
1072  	public static function display_notice() {
1073          global $hook_suffix;
1074  
1075          if ( in_array( $hook_suffix, array( 'jetpack_page_akismet-key-config', 'settings_page_akismet-key-config' ) ) ) {
1076              // This page manages the notices and puts them inline where they make sense.
1077              return;
1078          }
1079  
1080          if ( in_array( $hook_suffix, array( 'edit-comments.php' ) ) && (int) get_option( 'akismet_alert_code' ) > 0 ) {
1081              Akismet::verify_key( Akismet::get_api_key() ); //verify that the key is still in alert state
1082  
1083              $alert_code = get_option( 'akismet_alert_code' );
1084              if ( isset( Akismet::$limit_notices[ $alert_code ] ) ) {
1085                  self::display_usage_limit_alert();
1086              } elseif ( $alert_code > 0 ) {
1087                  self::display_alert();
1088              }
1089          }
1090          elseif ( ( 'plugins.php' === $hook_suffix || 'edit-comments.php' === $hook_suffix ) && ! Akismet::get_api_key() ) {
1091              // Show the "Set Up Akismet" banner on the comments and plugin pages if no API key has been set.
1092              self::display_api_key_warning();
1093          }
1094          elseif ( $hook_suffix == 'edit-comments.php' && wp_next_scheduled( 'akismet_schedule_cron_recheck' ) ) {
1095              self::display_spam_check_warning();
1096          }
1097          
1098          if ( isset( $_GET['akismet_recheck_complete'] ) ) {
1099              $recheck_count = (int) $_GET['recheck_count'];
1100              $spam_count = (int) $_GET['spam_count'];
1101              
1102              if ( $recheck_count === 0 ) {
1103                  $message = __( 'There were no comments to check. Akismet will only check comments awaiting moderation.', 'akismet' );
1104              }
1105              else {
1106                  $message = sprintf( _n( 'Akismet checked %s comment.', 'Akismet checked %s comments.', $recheck_count, 'akismet' ), number_format( $recheck_count ) );
1107                  $message .= ' ';
1108              
1109                  if ( $spam_count === 0 ) {
1110                      $message .= __( 'No comments were caught as spam.', 'akismet' );
1111                  }
1112                  else {
1113                      $message .= sprintf( _n( '%s comment was caught as spam.', '%s comments were caught as spam.', $spam_count, 'akismet' ), number_format( $spam_count ) );
1114                  }
1115              }
1116              
1117              echo '<div class="notice notice-success"><p>' . esc_html( $message ) . '</p></div>';
1118          }
1119          else if ( isset( $_GET['akismet_recheck_error'] ) ) {
1120              echo '<div class="notice notice-error"><p>' . esc_html( __( 'Akismet could not recheck your comments for spam.', 'akismet' ) ) . '</p></div>';
1121          }
1122      }
1123  
1124  	public static function display_status() {
1125          if ( ! self::get_server_connectivity() ) {
1126              Akismet::view( 'notice', array( 'type' => 'servers-be-down' ) );
1127          }
1128          else if ( ! empty( self::$notices ) ) {
1129              foreach ( self::$notices as $index => $type ) {
1130                  if ( is_object( $type ) ) {
1131                      $notice_header = $notice_text = '';
1132                      
1133                      if ( property_exists( $type, 'notice_header' ) ) {
1134                          $notice_header = wp_kses( $type->notice_header, self::$allowed );
1135                      }
1136                  
1137                      if ( property_exists( $type, 'notice_text' ) ) {
1138                          $notice_text = wp_kses( $type->notice_text, self::$allowed );
1139                      }
1140                      
1141                      if ( property_exists( $type, 'status' ) ) {
1142                          $type = wp_kses( $type->status, self::$allowed );
1143                          Akismet::view( 'notice', compact( 'type', 'notice_header', 'notice_text' ) );
1144                          
1145                          unset( self::$notices[ $index ] );
1146                      }
1147                  }
1148                  else {
1149                      Akismet::view( 'notice', compact( 'type' ) );
1150                      
1151                      unset( self::$notices[ $index ] );
1152                  }
1153              }
1154          }
1155      }
1156  
1157  	private static function get_jetpack_user() {
1158          if ( !class_exists('Jetpack') )
1159              return false;
1160  
1161          if ( defined( 'JETPACK__VERSION' ) && version_compare( JETPACK__VERSION, '7.7', '<' ) ) {
1162              // For version of Jetpack prior to 7.7.
1163              Jetpack::load_xml_rpc_client();
1164          }
1165  
1166          $xml = new Jetpack_IXR_ClientMulticall( array( 'user_id' => get_current_user_id() ) );
1167  
1168          $xml->addCall( 'wpcom.getUserID' );
1169          $xml->addCall( 'akismet.getAPIKey' );
1170          $xml->query();
1171  
1172          Akismet::log( compact( 'xml' ) );
1173  
1174          if ( !$xml->isError() ) {
1175              $responses = $xml->getResponse();
1176              if ( count( $responses ) > 1 ) {
1177                  // Due to a quirk in how Jetpack does multi-calls, the response order
1178                  // can't be trusted to match the call order. It's a good thing our
1179                  // return values can be mostly differentiated from each other.
1180                  $first_response_value = array_shift( $responses[0] );
1181                  $second_response_value = array_shift( $responses[1] );
1182                  
1183                  // If WPCOM ever reaches 100 billion users, this will fail. :-)
1184                  if ( preg_match( '/^[a-f0-9]{12}$/i', $first_response_value ) ) {
1185                      $api_key = $first_response_value;
1186                      $user_id = (int) $second_response_value;
1187                  }
1188                  else {
1189                      $api_key = $second_response_value;
1190                      $user_id = (int) $first_response_value;
1191                  }
1192                  
1193                  return compact( 'api_key', 'user_id' );
1194              }
1195          }
1196          return false;
1197      }
1198      
1199      /**
1200       * Some commentmeta isn't useful in an export file. Suppress it (when supported).
1201       *
1202       * @param bool $exclude
1203       * @param string $key The meta key
1204       * @param object $meta The meta object
1205       * @return bool Whether to exclude this meta entry from the export.
1206       */
1207  	public static function exclude_commentmeta_from_export( $exclude, $key, $meta ) {
1208          if ( in_array( $key, array( 'akismet_as_submitted', 'akismet_rechecking', 'akismet_delayed_moderation_email' ) ) ) {
1209              return true;
1210          }
1211          
1212          return $exclude;
1213      }
1214      
1215      /**
1216       * When Akismet is active, remove the "Activate Akismet" step from the plugin description.
1217       */
1218  	public static function modify_plugin_description( $all_plugins ) {
1219          if ( isset( $all_plugins['akismet/akismet.php'] ) ) {
1220              if ( Akismet::get_api_key() ) {
1221                  $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' );
1222              }
1223              else {
1224                  $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' );
1225              }
1226          }
1227          
1228          return $all_plugins;
1229      }
1230  
1231  	private static function set_form_privacy_notice_option( $state ) {
1232          if ( in_array( $state, array( 'display', 'hide' ) ) ) {
1233              update_option( 'akismet_comment_form_privacy_notice', $state );
1234          }
1235      }
1236      
1237  	public static function register_personal_data_eraser( $erasers ) {
1238          $erasers['akismet'] = array(
1239              'eraser_friendly_name' => __( 'Akismet', 'akismet' ),
1240              'callback' => array( 'Akismet_Admin', 'erase_personal_data' ),
1241          );
1242  
1243          return $erasers;
1244      }
1245      
1246      /**
1247       * When a user requests that their personal data be removed, Akismet has a duty to discard
1248       * any personal data we store outside of the comment itself. Right now, that is limited
1249       * to the copy of the comment we store in the akismet_as_submitted commentmeta.
1250       *
1251       * FWIW, this information would be automatically deleted after 15 days.
1252       * 
1253       * @param $email_address string The email address of the user who has requested erasure.
1254       * @param $page int This function can (and will) be called multiple times to prevent timeouts,
1255       *                  so this argument is used for pagination.
1256       * @return array
1257       * @see https://developer.wordpress.org/plugins/privacy/adding-the-personal-data-eraser-to-your-plugin/
1258       */
1259  	public static function erase_personal_data( $email_address, $page = 1 ) {
1260          $items_removed = false;
1261          
1262          $number = 50;
1263          $page = (int) $page;
1264  
1265          $comments = get_comments(
1266              array(
1267                  'author_email' => $email_address,
1268                  'number'       => $number,
1269                  'paged'        => $page,
1270                  'order_by'     => 'comment_ID',
1271                  'order'        => 'ASC',
1272              )
1273          );
1274  
1275          foreach ( (array) $comments as $comment ) {
1276              $comment_as_submitted = get_comment_meta( $comment->comment_ID, 'akismet_as_submitted', true );
1277              
1278              if ( $comment_as_submitted ) {
1279                  delete_comment_meta( $comment->comment_ID, 'akismet_as_submitted' );
1280                  $items_removed = true;
1281              }
1282          }
1283  
1284          // Tell core if we have more comments to work on still
1285          $done = count( $comments ) < $number;
1286          
1287          return array(
1288              'items_removed' => $items_removed,
1289              'items_retained' => false, // always false in this example
1290              'messages' => array(), // no messages in this example
1291              'done' => $done,
1292          );
1293      }
1294  }


Generated: Fri Dec 6 01:00:02 2024 Cross-referenced by PHPXref 0.7.1