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


Generated: Mon Dec 9 01:00:03 2019 Cross-referenced by PHPXref 0.7.1