[ Index ]

WordPress 5.4.1

[ Index ]     [ Classes ]     [ Functions ]     [ Variables ]     [ Constants ]     [ Statistics ]    

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


Generated: Tue May 19 15:51:04 2020 Cross-referenced by PHPXref 0.7.1