wp/wp-content/plugins/akismet/class.akismet-admin.php
changeset 7 cf61fcea0001
parent 5 5e2f62d02dcd
child 9 177826044cd9
equal deleted inserted replaced
6:490d5cc509ed 7:cf61fcea0001
     2 
     2 
     3 class Akismet_Admin {
     3 class Akismet_Admin {
     4 	const NONCE = 'akismet-update-key';
     4 	const NONCE = 'akismet-update-key';
     5 
     5 
     6 	private static $initiated = false;
     6 	private static $initiated = false;
     7 	private static $notices = array();
     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 	);
     8 
    26 
     9 	public static function init() {
    27 	public static function init() {
    10 		if ( ! self::$initiated ) {
    28 		if ( ! self::$initiated ) {
    11 			self::init_hooks();
    29 			self::init_hooks();
    12 		}
    30 		}
    13 
    31 
    14 		if ( isset( $_POST['action'] ) && $_POST['action'] == 'enter-key' ) {
    32 		if ( isset( $_POST['action'] ) && $_POST['action'] == 'enter-key' ) {
    15 			self::enter_api_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'] );
    16 		}
    38 		}
    17 	}
    39 	}
    18 
    40 
    19 	public static function init_hooks() {
    41 	public static function init_hooks() {
    20 		// The standalone stats page was removed in 3.0 for an all-in-one config and stats page.
    42 		// The standalone stats page was removed in 3.0 for an all-in-one config and stats page.
    39 		add_action( 'wp_ajax_comment_author_reurl', array( 'Akismet_Admin', 'add_comment_author_url' ) );
    61 		add_action( 'wp_ajax_comment_author_reurl', array( 'Akismet_Admin', 'add_comment_author_url' ) );
    40 		add_action( 'jetpack_auto_activate_akismet', array( 'Akismet_Admin', 'connect_jetpack_user' ) );
    62 		add_action( 'jetpack_auto_activate_akismet', array( 'Akismet_Admin', 'connect_jetpack_user' ) );
    41 
    63 
    42 		add_filter( 'plugin_action_links', array( 'Akismet_Admin', 'plugin_action_links' ), 10, 2 );
    64 		add_filter( 'plugin_action_links', array( 'Akismet_Admin', 'plugin_action_links' ), 10, 2 );
    43 		add_filter( 'comment_row_actions', array( 'Akismet_Admin', 'comment_row_action' ), 10, 2 );
    65 		add_filter( 'comment_row_actions', array( 'Akismet_Admin', 'comment_row_action' ), 10, 2 );
    44 		add_filter( 'comment_text', array( 'Akismet_Admin', 'text_add_link_class' ) );
       
    45 		
    66 		
    46 		add_filter( 'plugin_action_links_'.plugin_basename( plugin_dir_path( __FILE__ ) . 'akismet.php'), array( 'Akismet_Admin', 'admin_plugin_settings_link' ) );
    67 		add_filter( 'plugin_action_links_'.plugin_basename( plugin_dir_path( __FILE__ ) . 'akismet.php'), array( 'Akismet_Admin', 'admin_plugin_settings_link' ) );
    47 		
    68 		
    48 		add_filter( 'wxr_export_skip_commentmeta', array( 'Akismet_Admin', 'exclude_commentmeta_from_export' ), 10, 3 );
    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 		}
    49 	}
    77 	}
    50 
    78 
    51 	public static function admin_init() {
    79 	public static function admin_init() {
    52 		load_plugin_textdomain( 'akismet' );
    80 		load_plugin_textdomain( 'akismet' );
    53 		add_meta_box( 'akismet-status', __('Comment History', 'akismet'), array( 'Akismet_Admin', 'comment_status_meta_box' ), 'comment', 'normal' );
    81 		add_meta_box( 'akismet-status', __('Comment History', 'akismet'), array( 'Akismet_Admin', 'comment_status_meta_box' ), 'comment', 'normal' );
       
    82 
       
    83 		if ( function_exists( 'wp_add_privacy_policy_content' ) ) {
       
    84 			wp_add_privacy_policy_content(
       
    85 				__( 'Akismet', 'akismet' ),
       
    86 				__( 'We collect information about visitors who comment on Sites that use our Akismet anti-spam service. The information we collect depends on how the User sets up Akismet for the Site, but typically includes the commenter\'s IP address, user agent, referrer, and Site URL (along with other information directly provided by the commenter such as their name, username, email address, and the comment itself).', 'akismet' )
       
    87 			);
       
    88 		}
    54 	}
    89 	}
    55 
    90 
    56 	public static function admin_menu() {
    91 	public static function admin_menu() {
    57 		if ( class_exists( 'Jetpack' ) )
    92 		if ( class_exists( 'Jetpack' ) )
    58 			add_action( 'jetpack_admin_menu', array( 'Akismet_Admin', 'load_menu' ) );
    93 			add_action( 'jetpack_admin_menu', array( 'Akismet_Admin', 'load_menu' ) );
    70   		array_unshift( $links, $settings_link ); 
   105   		array_unshift( $links, $settings_link ); 
    71   		return $links; 
   106   		return $links; 
    72 	}
   107 	}
    73 
   108 
    74 	public static function load_menu() {
   109 	public static function load_menu() {
    75 		if ( class_exists( 'Jetpack' ) )
   110 		if ( class_exists( 'Jetpack' ) ) {
    76 			$hook = add_submenu_page( 'jetpack', __( 'Akismet' , 'akismet'), __( 'Akismet' , 'akismet'), 'manage_options', 'akismet-key-config', array( 'Akismet_Admin', 'display_page' ) );
   111 			$hook = add_submenu_page( 'jetpack', __( 'Akismet Anti-Spam' , 'akismet'), __( 'Akismet Anti-Spam' , 'akismet'), 'manage_options', 'akismet-key-config', array( 'Akismet_Admin', 'display_page' ) );
    77 		else
   112 		}
    78 			$hook = add_options_page( __('Akismet', 'akismet'), __('Akismet', 'akismet'), 'manage_options', 'akismet-key-config', array( 'Akismet_Admin', 'display_page' ) );
   113 		else {
    79 
   114 			$hook = add_options_page( __('Akismet Anti-Spam', 'akismet'), __('Akismet Anti-Spam', 'akismet'), 'manage_options', 'akismet-key-config', array( 'Akismet_Admin', 'display_page' ) );
    80 		if ( version_compare( $GLOBALS['wp_version'], '3.3', '>=' ) ) {
   115 		}
       
   116 		
       
   117 		if ( $hook ) {
    81 			add_action( "load-$hook", array( 'Akismet_Admin', 'admin_help' ) );
   118 			add_action( "load-$hook", array( 'Akismet_Admin', 'admin_help' ) );
    82 		}
   119 		}
    83 	}
   120 	}
    84 
   121 
    85 	public static function load_resources() {
   122 	public static function load_resources() {
    86 		global $hook_suffix;
   123 		global $hook_suffix;
    87 
   124 
    88 		if ( in_array( $hook_suffix, array(
   125 		if ( in_array( $hook_suffix, apply_filters( 'akismet_admin_page_hook_suffixes', array(
    89 			'index.php', # dashboard
   126 			'index.php', # dashboard
    90 			'edit-comments.php',
   127 			'edit-comments.php',
    91 			'comment.php',
   128 			'comment.php',
    92 			'post.php',
   129 			'post.php',
    93 			'settings_page_akismet-key-config',
   130 			'settings_page_akismet-key-config',
    94 			'jetpack_page_akismet-key-config',
   131 			'jetpack_page_akismet-key-config',
    95 		) ) ) {
   132 			'plugins.php',
    96 			wp_register_style( 'akismet.css', AKISMET__PLUGIN_URL . '_inc/akismet.css', array(), AKISMET_VERSION );
   133 		) ) ) ) {
       
   134 			wp_register_style( 'akismet.css', plugin_dir_url( __FILE__ ) . '_inc/akismet.css', array(), AKISMET_VERSION );
    97 			wp_enqueue_style( 'akismet.css');
   135 			wp_enqueue_style( 'akismet.css');
    98 
   136 
    99 			wp_register_script( 'akismet.js', AKISMET__PLUGIN_URL . '_inc/akismet.js', array('jquery','postbox'), AKISMET_VERSION );
   137 			wp_register_script( 'akismet.js', plugin_dir_url( __FILE__ ) . '_inc/akismet.js', array('jquery'), AKISMET_VERSION );
   100 			wp_enqueue_script( 'akismet.js' );
   138 			wp_enqueue_script( 'akismet.js' );
   101 			wp_localize_script( 'akismet.js', 'WPAkismet', array(
   139 			
       
   140 			$inline_js = array(
   102 				'comment_author_url_nonce' => wp_create_nonce( 'comment_author_url_nonce' ),
   141 				'comment_author_url_nonce' => wp_create_nonce( 'comment_author_url_nonce' ),
   103 				'strings' => array(
   142 				'strings' => array(
   104 					'Remove this URL' => __( 'Remove this URL' , 'akismet'),
   143 					'Remove this URL' => __( 'Remove this URL' , 'akismet'),
   105 					'Removing...'     => __( 'Removing...' , 'akismet'),
   144 					'Removing...'     => __( 'Removing...' , 'akismet'),
   106 					'URL removed'     => __( 'URL removed' , 'akismet'),
   145 					'URL removed'     => __( 'URL removed' , 'akismet'),
   107 					'(undo)'          => __( '(undo)' , 'akismet'),
   146 					'(undo)'          => __( '(undo)' , 'akismet'),
   108 					'Re-adding...'    => __( 'Re-adding...' , 'akismet'),
   147 					'Re-adding...'    => __( 'Re-adding...' , 'akismet'),
   109 				)
   148 				)
   110 			) );
   149 			);
       
   150 
       
   151 			if ( isset( $_GET['akismet_recheck'] ) && wp_verify_nonce( $_GET['akismet_recheck'], 'akismet_recheck' ) ) {
       
   152 				$inline_js['start_recheck'] = true;
       
   153 			}
       
   154 
       
   155 			wp_localize_script( 'akismet.js', 'WPAkismet', $inline_js );
   111 		}
   156 		}
   112 	}
   157 	}
   113 
   158 
   114 	/**
   159 	/**
   115 	 * Add help to the Akismet page
   160 	 * Add help to the Akismet page
   127 					array(
   172 					array(
   128 						'id'		=> 'overview',
   173 						'id'		=> 'overview',
   129 						'title'		=> __( 'Overview' , 'akismet'),
   174 						'title'		=> __( 'Overview' , 'akismet'),
   130 						'content'	=>
   175 						'content'	=>
   131 							'<p><strong>' . esc_html__( 'Akismet Setup' , 'akismet') . '</strong></p>' .
   176 							'<p><strong>' . esc_html__( 'Akismet Setup' , 'akismet') . '</strong></p>' .
   132 							'<p>' . esc_html__( 'Akismet filters out your comment and trackback spam for you, so you can focus on more important things.' , 'akismet') . '</p>' .
   177 							'<p>' . esc_html__( 'Akismet filters out spam, so you can focus on more important things.' , 'akismet') . '</p>' .
   133 							'<p>' . esc_html__( 'On this page, you are able to setup the Akismet plugin.' , 'akismet') . '</p>',
   178 							'<p>' . esc_html__( 'On this page, you are able to set up the Akismet plugin.' , 'akismet') . '</p>',
   134 					)
   179 					)
   135 				);
   180 				);
   136 
   181 
   137 				$current_screen->add_help_tab(
   182 				$current_screen->add_help_tab(
   138 					array(
   183 					array(
   139 						'id'		=> 'setup-signup',
   184 						'id'		=> 'setup-signup',
   140 						'title'		=> __( 'New to Akismet' , 'akismet'),
   185 						'title'		=> __( 'New to Akismet' , 'akismet'),
   141 						'content'	=>
   186 						'content'	=>
   142 							'<p><strong>' . esc_html__( 'Akismet Setup' , 'akismet') . '</strong></p>' .
   187 							'<p><strong>' . esc_html__( 'Akismet Setup' , 'akismet') . '</strong></p>' .
   143 							'<p>' . esc_html__( 'You need to enter an API key to activate the Akismet service on your site.' , 'akismet') . '</p>' .
   188 							'<p>' . esc_html__( 'You need to enter an API key to activate the Akismet service on your site.' , 'akismet') . '</p>' .
   144 							'<p>' . sprintf( __( 'Signup for an account on %s to get an API Key.' , 'akismet'), '<a href="https://akismet.com/plugin-signup/" target="_blank">Akismet.com</a>' ) . '</p>',
   189 							'<p>' . sprintf( __( 'Sign up for an account on %s to get an API Key.' , 'akismet'), '<a href="https://akismet.com/plugin-signup/" target="_blank">Akismet.com</a>' ) . '</p>',
   145 					)
   190 					)
   146 				);
   191 				);
   147 
   192 
   148 				$current_screen->add_help_tab(
   193 				$current_screen->add_help_tab(
   149 					array(
   194 					array(
   165 					array(
   210 					array(
   166 						'id'		=> 'overview',
   211 						'id'		=> 'overview',
   167 						'title'		=> __( 'Overview' , 'akismet'),
   212 						'title'		=> __( 'Overview' , 'akismet'),
   168 						'content'	=>
   213 						'content'	=>
   169 							'<p><strong>' . esc_html__( 'Akismet Stats' , 'akismet') . '</strong></p>' .
   214 							'<p><strong>' . esc_html__( 'Akismet Stats' , 'akismet') . '</strong></p>' .
   170 							'<p>' . esc_html__( 'Akismet filters out your comment and trackback spam for you, so you can focus on more important things.' , 'akismet') . '</p>' .
   215 							'<p>' . esc_html__( 'Akismet filters out spam, so you can focus on more important things.' , 'akismet') . '</p>' .
   171 							'<p>' . esc_html__( 'On this page, you are able to view stats on spam filtered on your site.' , 'akismet') . '</p>',
   216 							'<p>' . esc_html__( 'On this page, you are able to view stats on spam filtered on your site.' , 'akismet') . '</p>',
   172 					)
   217 					)
   173 				);
   218 				);
   174 			}
   219 			}
   175 			else {
   220 			else {
   178 					array(
   223 					array(
   179 						'id'		=> 'overview',
   224 						'id'		=> 'overview',
   180 						'title'		=> __( 'Overview' , 'akismet'),
   225 						'title'		=> __( 'Overview' , 'akismet'),
   181 						'content'	=>
   226 						'content'	=>
   182 							'<p><strong>' . esc_html__( 'Akismet Configuration' , 'akismet') . '</strong></p>' .
   227 							'<p><strong>' . esc_html__( 'Akismet Configuration' , 'akismet') . '</strong></p>' .
   183 							'<p>' . esc_html__( 'Akismet filters out your comment and trackback spam for you, so you can focus on more important things.' , 'akismet') . '</p>' .
   228 							'<p>' . esc_html__( 'Akismet filters out spam, so you can focus on more important things.' , 'akismet') . '</p>' .
   184 							'<p>' . esc_html__( 'On this page, you are able to enter/remove an API key, view account information and view spam stats.' , 'akismet') . '</p>',
   229 							'<p>' . esc_html__( 'On this page, you are able to update your Akismet settings and view spam stats.' , 'akismet') . '</p>',
   185 					)
   230 					)
   186 				);
   231 				);
   187 
   232 
   188 				$current_screen->add_help_tab(
   233 				$current_screen->add_help_tab(
   189 					array(
   234 					array(
   190 						'id'		=> 'settings',
   235 						'id'		=> 'settings',
   191 						'title'		=> __( 'Settings' , 'akismet'),
   236 						'title'		=> __( 'Settings' , 'akismet'),
   192 						'content'	=>
   237 						'content'	=>
   193 							'<p><strong>' . esc_html__( 'Akismet Configuration' , 'akismet') . '</strong></p>' .
   238 							'<p><strong>' . esc_html__( 'Akismet Configuration' , 'akismet') . '</strong></p>' .
   194 							'<p><strong>' . esc_html__( 'API Key' , 'akismet') . '</strong> - ' . esc_html__( 'Enter/remove an API key.' , 'akismet') . '</p>' .
   239 							( Akismet::predefined_api_key() ? '' : '<p><strong>' . esc_html__( 'API Key' , 'akismet') . '</strong> - ' . esc_html__( 'Enter/remove an API key.' , 'akismet') . '</p>' ) .
   195 							'<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>' .
   240 							'<p><strong>' . esc_html__( 'Comments' , 'akismet') . '</strong> - ' . esc_html__( 'Show the number of approved comments beside each comment author in the comments list page.' , 'akismet') . '</p>' .
   196 							'<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>',
   241 							'<p><strong>' . esc_html__( 'Strictness' , 'akismet') . '</strong> - ' . esc_html__( 'Choose to either discard the worst spam automatically or to always put all spam in spam folder.' , 'akismet') . '</p>',
   197 					)
   242 					)
   198 				);
   243 				);
   199 
   244 
   200 				$current_screen->add_help_tab(
   245 				if ( ! Akismet::predefined_api_key() ) {
   201 					array(
   246 					$current_screen->add_help_tab(
   202 						'id'		=> 'account',
   247 						array(
   203 						'title'		=> __( 'Account' , 'akismet'),
   248 							'id'		=> 'account',
   204 						'content'	=>
   249 							'title'		=> __( 'Account' , 'akismet'),
   205 							'<p><strong>' . esc_html__( 'Akismet Configuration' , 'akismet') . '</strong></p>' .
   250 							'content'	=>
   206 							'<p><strong>' . esc_html__( 'Subscription Type' , 'akismet') . '</strong> - ' . esc_html__( 'The Akismet subscription plan' , 'akismet') . '</p>' .
   251 								'<p><strong>' . esc_html__( 'Akismet Configuration' , 'akismet') . '</strong></p>' .
   207 							'<p><strong>' . esc_html__( 'Status' , 'akismet') . '</strong> - ' . esc_html__( 'The subscription status - active, cancelled or suspended' , 'akismet') . '</p>',
   252 								'<p><strong>' . esc_html__( 'Subscription Type' , 'akismet') . '</strong> - ' . esc_html__( 'The Akismet subscription plan' , 'akismet') . '</p>' .
   208 					)
   253 								'<p><strong>' . esc_html__( 'Status' , 'akismet') . '</strong> - ' . esc_html__( 'The subscription status - active, cancelled or suspended' , 'akismet') . '</p>',
   209 				);
   254 						)
       
   255 					);
       
   256 				}
   210 			}
   257 			}
   211 		}
   258 		}
   212 
   259 
   213 		// Help Sidebar
   260 		// Help Sidebar
   214 		$current_screen->set_help_sidebar(
   261 		$current_screen->set_help_sidebar(
   217 			'<p><a href="https://akismet.com/support/" target="_blank">' . esc_html__( 'Akismet Support' , 'akismet') . '</a></p>'
   264 			'<p><a href="https://akismet.com/support/" target="_blank">' . esc_html__( 'Akismet Support' , 'akismet') . '</a></p>'
   218 		);
   265 		);
   219 	}
   266 	}
   220 
   267 
   221 	public static function enter_api_key() {
   268 	public static function enter_api_key() {
   222 		if ( function_exists('current_user_can') && !current_user_can('manage_options') )
   269 		if ( ! current_user_can( 'manage_options' ) ) {
   223 			die(__('Cheatin&#8217; uh?', 'akismet'));
   270 			die( __( 'Cheatin&#8217; uh?', 'akismet' ) );
       
   271 		}
   224 
   272 
   225 		if ( !wp_verify_nonce( $_POST['_wpnonce'], self::NONCE ) )
   273 		if ( !wp_verify_nonce( $_POST['_wpnonce'], self::NONCE ) )
   226 			return false;
   274 			return false;
   227 
   275 
   228 		foreach( array( 'akismet_strictness', 'akismet_show_user_comments_approved' ) as $option ) {
   276 		foreach( array( 'akismet_strictness', 'akismet_show_user_comments_approved' ) as $option ) {
   229 			update_option( $option, isset( $_POST[$option] ) && (int) $_POST[$option] == 1 ? '1' : '0' );
   277 			update_option( $option, isset( $_POST[$option] ) && (int) $_POST[$option] == 1 ? '1' : '0' );
   230 		}
   278 		}
   231 
   279 
   232 		if ( defined( 'WPCOM_API_KEY' ) )
   280 		if ( ! empty( $_POST['akismet_comment_form_privacy_notice'] ) ) {
       
   281 			self::set_form_privacy_notice_option( $_POST['akismet_comment_form_privacy_notice'] );
       
   282 		} else {
       
   283 			self::set_form_privacy_notice_option( 'hide' );
       
   284 		}
       
   285 
       
   286 		if ( Akismet::predefined_api_key() ) {
   233 			return false; //shouldn't have option to save key if already defined
   287 			return false; //shouldn't have option to save key if already defined
   234 
   288 		}
       
   289 		
   235 		$new_key = preg_replace( '/[^a-f0-9]/i', '', $_POST['key'] );
   290 		$new_key = preg_replace( '/[^a-f0-9]/i', '', $_POST['key'] );
   236 		$old_key = Akismet::get_api_key();
   291 		$old_key = Akismet::get_api_key();
   237 
   292 
   238 		if ( empty( $new_key ) ) {
   293 		if ( empty( $new_key ) ) {
   239 			if ( !empty( $old_key ) ) {
   294 			if ( !empty( $old_key ) ) {
   256 			
   311 			
   257 			if ( $akismet_user ) {				
   312 			if ( $akismet_user ) {				
   258 				if ( in_array( $akismet_user->status, array( 'active', 'active-dunning', 'no-sub' ) ) )
   313 				if ( in_array( $akismet_user->status, array( 'active', 'active-dunning', 'no-sub' ) ) )
   259 					update_option( 'wordpress_api_key', $api_key );
   314 					update_option( 'wordpress_api_key', $api_key );
   260 				
   315 				
   261 				if (  $akismet_user->status == 'active' )
   316 				if ( $akismet_user->status == 'active' )
   262 					self::$notices['status'] = 'new-key-valid';
   317 					self::$notices['status'] = 'new-key-valid';
       
   318 				elseif ( $akismet_user->status == 'notice' )
       
   319 					self::$notices['status'] = $akismet_user;
   263 				else
   320 				else
   264 					self::$notices['status'] = $akismet_user->status;
   321 					self::$notices['status'] = $akismet_user->status;
   265 			}
   322 			}
   266 			else
   323 			else
   267 				self::$notices['status'] = 'new-key-invalid';
   324 				self::$notices['status'] = 'new-key-invalid';
   269 		elseif ( in_array( $key_status, array( 'invalid', 'failed' ) ) )
   326 		elseif ( in_array( $key_status, array( 'invalid', 'failed' ) ) )
   270 			self::$notices['status'] = 'new-key-'.$key_status;
   327 			self::$notices['status'] = 'new-key-'.$key_status;
   271 	}
   328 	}
   272 
   329 
   273 	public static function dashboard_stats() {
   330 	public static function dashboard_stats() {
   274 		if ( !function_exists('did_action') || did_action( 'rightnow_end' ) )
   331 		if ( did_action( 'rightnow_end' ) ) {
   275 			return; // We already displayed this info in the "Right Now" section
   332 			return; // We already displayed this info in the "Right Now" section
       
   333 		}
   276 
   334 
   277 		if ( !$count = get_option('akismet_spam_count') )
   335 		if ( !$count = get_option('akismet_spam_count') )
   278 			return;
   336 			return;
   279 
   337 
   280 		global $submenu;
   338 		global $submenu;
   322 		// not-yet-moderated comment.
   380 		// not-yet-moderated comment.
   323 		if ( 'all' != $comment_status && 'moderated' != $comment_status ) {
   381 		if ( 'all' != $comment_status && 'moderated' != $comment_status ) {
   324 			return;
   382 			return;
   325 		}
   383 		}
   326 
   384 
   327 		if ( function_exists('plugins_url') )
   385 		$link = add_query_arg( array( 'action' => 'akismet_recheck_queue' ), admin_url( 'admin.php' ) );
   328 			$link = add_query_arg( array( 'action' => 'akismet_recheck_queue' ), admin_url( 'admin.php' ) );
   386 
   329 		else
   387 		$comments_count = wp_count_comments();
   330 			$link = add_query_arg( array( 'page' => 'akismet-admin', 'recheckqueue' => 'true', 'noheader' => 'true' ), admin_url( 'edit-comments.php' ) );
   388 		
   331 
   389 		echo '</div>';
   332 		echo '</div><div class="alignleft"><a class="button-secondary checkforspam" href="' . esc_url( $link ) . '">' . esc_html__('Check for Spam', 'akismet') . '</a><span class="checkforspam-spinner"></span>';
   390 		echo '<div class="alignleft">';
       
   391 		echo '<a
       
   392 				class="button-secondary checkforspam"
       
   393 				href="' . esc_url( $link ) . '"
       
   394 				data-active-label="' . esc_attr( __( 'Checking for Spam', 'akismet' ) ) . '"
       
   395 				data-progress-label-format="' . esc_attr( __( '(%1$s%)', 'akismet' ) ) . '"
       
   396 				data-success-url="' . esc_attr( remove_query_arg( 'akismet_recheck', add_query_arg( array( 'akismet_recheck_complete' => 1, 'recheck_count' => urlencode( '__recheck_count__' ), 'spam_count' => urlencode( '__spam_count__' ) ) ) ) ) . '"
       
   397 				data-pending-comment-count="' . esc_attr( $comments_count->moderated ) . '"
       
   398 				>';
       
   399 			echo '<span class="akismet-label">' . esc_html__('Check for Spam', 'akismet') . '</span>';
       
   400 			echo '<span class="checkforspam-progress"></span>';
       
   401 		echo '</a>';
       
   402 		echo '<span class="checkforspam-spinner"></span>';
       
   403 
   333 	}
   404 	}
   334 
   405 
   335 	public static function recheck_queue() {
   406 	public static function recheck_queue() {
   336 		global $wpdb;
   407 		global $wpdb;
   337 
   408 
   338 		Akismet::fix_scheduled_recheck();
   409 		Akismet::fix_scheduled_recheck();
   339 
   410 
   340 		if ( ! ( isset( $_GET['recheckqueue'] ) || ( isset( $_REQUEST['action'] ) && 'akismet_recheck_queue' == $_REQUEST['action'] ) ) )
   411 		if ( ! ( isset( $_GET['recheckqueue'] ) || ( isset( $_REQUEST['action'] ) && 'akismet_recheck_queue' == $_REQUEST['action'] ) ) ) {
   341 			return;
   412 			return;
   342 
   413 		}
   343 		$paginate = '';
   414 
   344 		if ( isset( $_POST['limit'] ) && isset( $_POST['offset'] ) ) {
   415 		$result_counts = self::recheck_queue_portion( empty( $_POST['offset'] ) ? 0 : $_POST['offset'], empty( $_POST['limit'] ) ? 100 : $_POST['limit'] );
   345 			$paginate = $wpdb->prepare( " LIMIT %d OFFSET %d", array( $_POST['limit'], $_POST['offset'] ) );
   416 
   346 		}
       
   347 		$moderation = $wpdb->get_results( "SELECT * FROM {$wpdb->comments} WHERE comment_approved = '0'{$paginate}", ARRAY_A );
       
   348 
       
   349 		foreach ( (array) $moderation as $c ) {
       
   350 			$c['user_ip']      = $c['comment_author_IP'];
       
   351 			$c['user_agent']   = $c['comment_agent'];
       
   352 			$c['referrer']     = '';
       
   353 			$c['blog']         = get_bloginfo('url');
       
   354 			$c['blog_lang']    = get_locale();
       
   355 			$c['blog_charset'] = get_option('blog_charset');
       
   356 			$c['permalink']    = get_permalink($c['comment_post_ID']);
       
   357 
       
   358 			$c['user_role'] = '';
       
   359 			if ( isset( $c['user_ID'] ) )
       
   360 				$c['user_role'] = Akismet::get_user_roles($c['user_ID']);
       
   361 
       
   362 			if ( Akismet::is_test_mode() )
       
   363 				$c['is_test'] = 'true';
       
   364 
       
   365 			add_comment_meta( $c['comment_ID'], 'akismet_rechecking', true );
       
   366 
       
   367 			$response = Akismet::http_post( Akismet::build_query( $c ), 'comment-check' );
       
   368 			
       
   369 			if ( 'true' == $response[1] ) {
       
   370 				wp_set_comment_status( $c['comment_ID'], 'spam' );
       
   371 				update_comment_meta( $c['comment_ID'], 'akismet_result', 'true' );
       
   372 				delete_comment_meta( $c['comment_ID'], 'akismet_error' );
       
   373 				delete_comment_meta( $c['comment_ID'], 'akismet_delayed_moderation_email' );
       
   374 				Akismet::update_comment_history( $c['comment_ID'], '', 'recheck-spam' );
       
   375 
       
   376 			} elseif ( 'false' == $response[1] ) {
       
   377 				update_comment_meta( $c['comment_ID'], 'akismet_result', 'false' );
       
   378 				delete_comment_meta( $c['comment_ID'], 'akismet_error' );
       
   379 				delete_comment_meta( $c['comment_ID'], 'akismet_delayed_moderation_email' );
       
   380 				Akismet::update_comment_history( $c['comment_ID'], '', 'recheck-ham' );
       
   381 			// abnormal result: error
       
   382 			} else {
       
   383 				update_comment_meta( $c['comment_ID'], 'akismet_result', 'error' );
       
   384 				Akismet::update_comment_history(
       
   385 					$c['comment_ID'],
       
   386 					'',
       
   387 					'recheck-error',
       
   388 					array( 'response' => substr( $response[1], 0, 50 ) )
       
   389 				);
       
   390 			}
       
   391 
       
   392 			delete_comment_meta( $c['comment_ID'], 'akismet_rechecking' );
       
   393 		}
       
   394 		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
   417 		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
   395 			wp_send_json( array(
   418 			wp_send_json( array(
   396 				'processed' => count((array) $moderation),
   419 				'counts' => $result_counts,
   397 			));
   420 			));
   398 		}
   421 		}
   399 		else {
   422 		else {
   400 			$redirect_to = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : admin_url( 'edit-comments.php' );
   423 			$redirect_to = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : admin_url( 'edit-comments.php' );
   401 			wp_safe_redirect( $redirect_to );
   424 			wp_safe_redirect( $redirect_to );
   402 			exit;
   425 			exit;
   403 		}
   426 		}
   404 	}
   427 	}
       
   428 	
       
   429 	public static function recheck_queue_portion( $start = 0, $limit = 100 ) {
       
   430 		global $wpdb;
       
   431 		
       
   432 		$paginate = '';
       
   433 
       
   434 		if ( $limit <= 0 ) {
       
   435 			$limit = 100;
       
   436 		}
       
   437 
       
   438 		if ( $start < 0 ) {
       
   439 			$start = 0;
       
   440 		}
       
   441 
       
   442 		$moderation = $wpdb->get_col( $wpdb->prepare( "SELECT * FROM {$wpdb->comments} WHERE comment_approved = '0' LIMIT %d OFFSET %d", $limit, $start ) );
       
   443 
       
   444 		$result_counts = array(
       
   445 			'processed' => count( $moderation ),
       
   446 			'spam' => 0,
       
   447 			'ham' => 0,
       
   448 			'error' => 0,
       
   449 		);
       
   450 
       
   451 		foreach ( $moderation as $comment_id ) {
       
   452 			$api_response = Akismet::recheck_comment( $comment_id, 'recheck_queue' );
       
   453 
       
   454 			if ( 'true' === $api_response ) {
       
   455 				++$result_counts['spam'];
       
   456 			}
       
   457 			elseif ( 'false' === $api_response ) {
       
   458 				++$result_counts['ham'];
       
   459 			}
       
   460 			else {
       
   461 				++$result_counts['error'];
       
   462 			}
       
   463 		}
       
   464 
       
   465 		return $result_counts;
       
   466 	}
   405 
   467 
   406 	// Adds an 'x' link next to author URLs, clicking will remove the author URL and show an undo link
   468 	// Adds an 'x' link next to author URLs, clicking will remove the author URL and show an undo link
   407 	public static function remove_comment_author_url() {
   469 	public static function remove_comment_author_url() {
   408 		if ( !empty( $_POST['id'] ) && check_admin_referer( 'comment_author_url_nonce' ) ) {
   470 		if ( !empty( $_POST['id'] ) && check_admin_referer( 'comment_author_url_nonce' ) ) {
   409 			$comment = get_comment( intval( $_POST['id'] ), ARRAY_A );
   471 			$comment_id = intval( $_POST['id'] );
       
   472 			$comment = get_comment( $comment_id, ARRAY_A );
   410 			if ( $comment && current_user_can( 'edit_comment', $comment['comment_ID'] ) ) {
   473 			if ( $comment && current_user_can( 'edit_comment', $comment['comment_ID'] ) ) {
   411 				$comment['comment_author_url'] = '';
   474 				$comment['comment_author_url'] = '';
   412 				do_action( 'comment_remove_author_url' );
   475 				do_action( 'comment_remove_author_url' );
   413 				print( wp_update_comment( $comment ) );
   476 				print( wp_update_comment( $comment ) );
   414 				die();
   477 				die();
   416 		}
   479 		}
   417 	}
   480 	}
   418 
   481 
   419 	public static function add_comment_author_url() {
   482 	public static function add_comment_author_url() {
   420 		if ( !empty( $_POST['id'] ) && !empty( $_POST['url'] ) && check_admin_referer( 'comment_author_url_nonce' ) ) {
   483 		if ( !empty( $_POST['id'] ) && !empty( $_POST['url'] ) && check_admin_referer( 'comment_author_url_nonce' ) ) {
   421 			$comment = get_comment( intval( $_POST['id'] ), ARRAY_A );
   484 			$comment_id = intval( $_POST['id'] );
       
   485 			$comment = get_comment( $comment_id, ARRAY_A );
   422 			if ( $comment && current_user_can( 'edit_comment', $comment['comment_ID'] ) ) {
   486 			if ( $comment && current_user_can( 'edit_comment', $comment['comment_ID'] ) ) {
   423 				$comment['comment_author_url'] = esc_url( $_POST['url'] );
   487 				$comment['comment_author_url'] = esc_url( $_POST['url'] );
   424 				do_action( 'comment_add_author_url' );
   488 				do_action( 'comment_add_author_url' );
   425 				print( wp_update_comment( $comment ) );
   489 				print( wp_update_comment( $comment ) );
   426 				die();
   490 				die();
   427 			}
   491 			}
   428 		}
   492 		}
   429 	}
   493 	}
   430 
   494 
   431 	public static function comment_row_action( $a, $comment ) {
   495 	public static function comment_row_action( $a, $comment ) {
   432 
       
   433 		// failsafe for old WP versions
       
   434 		if ( !function_exists('add_comment_meta') )
       
   435 			return $a;
       
   436 
       
   437 		$akismet_result = get_comment_meta( $comment->comment_ID, 'akismet_result', true );
   496 		$akismet_result = get_comment_meta( $comment->comment_ID, 'akismet_result', true );
   438 		$akismet_error  = get_comment_meta( $comment->comment_ID, 'akismet_error', true );
   497 		$akismet_error  = get_comment_meta( $comment->comment_ID, 'akismet_error', true );
   439 		$user_result    = get_comment_meta( $comment->comment_ID, 'akismet_user_result', true);
   498 		$user_result    = get_comment_meta( $comment->comment_ID, 'akismet_user_result', true);
   440 		$comment_status = wp_get_comment_status( $comment->comment_ID );
   499 		$comment_status = wp_get_comment_status( $comment->comment_ID );
   441 		$desc = null;
   500 		$desc = null;
   460 			$b = array();
   519 			$b = array();
   461 			foreach ( $a as $k => $item ) {
   520 			foreach ( $a as $k => $item ) {
   462 				$b[ $k ] = $item;
   521 				$b[ $k ] = $item;
   463 				if (
   522 				if (
   464 					$k == 'edit'
   523 					$k == 'edit'
   465 					|| ( $k == 'unspam' && $GLOBALS['wp_version'] >= 3.4 )
   524 					|| $k == 'unspam'
   466 				) {
   525 				) {
   467 					$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>';
   526 					$b['history'] = '<a href="comment.php?action=editcomment&amp;c='.$comment->comment_ID.'#akismet-status" title="'. esc_attr__( 'View comment history' , 'akismet') . '"> '. esc_html__('History', 'akismet') . '</a>';
   468 				}
   527 				}
   469 			}
   528 			}
   470 
   529 
   472 		}
   531 		}
   473 
   532 
   474 		if ( $desc )
   533 		if ( $desc )
   475 			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>';
   534 			echo '<span class="akismet-status" commentid="'.$comment->comment_ID.'"><a href="comment.php?action=editcomment&amp;c='.$comment->comment_ID.'#akismet-status" title="' . esc_attr__( 'View comment history' , 'akismet') . '">'.esc_html( $desc ).'</a></span>';
   476 
   535 
   477 		$show_user_comments = apply_filters( 'akismet_show_user_comments_approved', get_option('akismet_show_user_comments_approved') );
   536 		$show_user_comments_option = get_option( 'akismet_show_user_comments_approved' );
       
   537 		
       
   538 		if ( $show_user_comments_option === false ) {
       
   539 			// Default to active if the user hasn't made a decision.
       
   540 			$show_user_comments_option = '1';
       
   541 		}
       
   542 		
       
   543 		$show_user_comments = apply_filters( 'akismet_show_user_comments_approved', $show_user_comments_option );
   478 		$show_user_comments = $show_user_comments === 'false' ? false : $show_user_comments; //option used to be saved as 'false' / 'true'
   544 		$show_user_comments = $show_user_comments === 'false' ? false : $show_user_comments; //option used to be saved as 'false' / 'true'
   479 		
   545 		
   480 		if ( $show_user_comments ) {
   546 		if ( $show_user_comments ) {
   481 			$comment_count = Akismet::get_user_comments_approved( $comment->user_id, $comment->comment_author_email, $comment->comment_author, $comment->comment_author_url );
   547 			$comment_count = Akismet::get_user_comments_approved( $comment->user_id, $comment->comment_author_email, $comment->comment_author, $comment->comment_author_url );
   482 			$comment_count = intval( $comment_count );
   548 			$comment_count = intval( $comment_count );
   583 			echo '</div>';
   649 			echo '</div>';
   584 		}
   650 		}
   585 	}
   651 	}
   586 
   652 
   587 	public static function plugin_action_links( $links, $file ) {
   653 	public static function plugin_action_links( $links, $file ) {
   588 		if ( $file == plugin_basename( AKISMET__PLUGIN_URL . '/akismet.php' ) ) {
   654 		if ( $file == plugin_basename( plugin_dir_url( __FILE__ ) . '/akismet.php' ) ) {
   589 			$links[] = '<a href="' . esc_url( self::get_page_url() ) . '">'.esc_html__( 'Settings' , 'akismet').'</a>';
   655 			$links[] = '<a href="' . esc_url( self::get_page_url() ) . '">'.esc_html__( 'Settings' , 'akismet').'</a>';
   590 		}
   656 		}
   591 
   657 
   592 		return $links;
   658 		return $links;
   593 	}
       
   594 
       
   595 	public static function text_add_link_callback( $m ) {
       
   596 		// bare link?
       
   597 		if ( $m[4] == $m[2] )
       
   598 			return '<a '.$m[1].' href="'.$m[2].'" '.$m[3].' class="comment-link">'.$m[4].'</a>';
       
   599 		else
       
   600 			return '<span title="'.$m[2].'" class="comment-link"><a '.$m[1].' href="'.$m[2].'" '.$m[3].' class="comment-link">'.$m[4].'</a></span>';
       
   601 	}
       
   602 
       
   603 	public static function text_add_link_class( $comment_text ) {
       
   604 		return preg_replace_callback( '#<a ([^>]*)href="([^"]+)"([^>]*)>(.*?)</a>#i', array( 'Akismet_Admin', 'text_add_link_callback' ), $comment_text );
       
   605 	}
   659 	}
   606 
   660 
   607 	// Total spam in queue
   661 	// Total spam in queue
   608 	// get_option( 'akismet_spam_count' ) is the total caught ever
   662 	// get_option( 'akismet_spam_count' ) is the total caught ever
   609 	public static function get_spam_count( $type = false ) {
   663 	public static function get_spam_count( $type = false ) {
   610 		global $wpdb;
   664 		global $wpdb;
   611 
   665 
   612 		if ( !$type ) { // total
   666 		if ( !$type ) { // total
   613 			$count = wp_cache_get( 'akismet_spam_count', 'widget' );
   667 			$count = wp_cache_get( 'akismet_spam_count', 'widget' );
   614 			if ( false === $count ) {
   668 			if ( false === $count ) {
   615 				if ( function_exists('wp_count_comments') ) {
   669 				$count = wp_count_comments();
   616 					$count = wp_count_comments();
   670 				$count = $count->spam;
   617 					$count = $count->spam;
       
   618 				} else {
       
   619 					$count = (int) $wpdb->get_var("SELECT COUNT(comment_ID) FROM {$wpdb->comments} WHERE comment_approved = 'spam'");
       
   620 				}
       
   621 				wp_cache_set( 'akismet_spam_count', $count, 'widget', 3600 );
   671 				wp_cache_set( 'akismet_spam_count', $count, 'widget', 3600 );
   622 			}
   672 			}
   623 			return $count;
   673 			return $count;
   624 		} elseif ( 'comments' == $type || 'comment' == $type ) { // comments
   674 		} elseif ( 'comments' == $type || 'comment' == $type ) { // comments
   625 			$type = '';
   675 			$type = '';
   670 		if ( (time() - get_option('akismet_connectivity_time') < $cache_timeout) && $servers !== false ) {
   720 		if ( (time() - get_option('akismet_connectivity_time') < $cache_timeout) && $servers !== false ) {
   671 			$servers = self::check_server_ip_connectivity();
   721 			$servers = self::check_server_ip_connectivity();
   672 			update_option('akismet_available_servers', $servers);
   722 			update_option('akismet_available_servers', $servers);
   673 			update_option('akismet_connectivity_time', time());
   723 			update_option('akismet_connectivity_time', time());
   674 		}
   724 		}
   675 			
   725 
   676 		$response = wp_remote_get( 'http://rest.akismet.com/1.1/test' );
   726 		if ( wp_http_supports( array( 'ssl' ) ) ) {
   677 		
   727 			$response = wp_remote_get( 'https://rest.akismet.com/1.1/test' );
       
   728 		}
       
   729 		else {
       
   730 			$response = wp_remote_get( 'http://rest.akismet.com/1.1/test' );
       
   731 		}
       
   732 
   678 		$debug[ 'gethostbynamel' ]  = function_exists('gethostbynamel') ? 'exists' : 'not here';
   733 		$debug[ 'gethostbynamel' ]  = function_exists('gethostbynamel') ? 'exists' : 'not here';
   679 		$debug[ 'Servers' ]         = $servers;
   734 		$debug[ 'Servers' ]         = $servers;
   680 		$debug[ 'Test Connection' ] = $response;
   735 		$debug[ 'Test Connection' ] = $response;
   681 		
   736 		
   682 		Akismet::log( $debug );
   737 		Akismet::log( $debug );
   690 	// Check the server connectivity and store the available servers in an option. 
   745 	// Check the server connectivity and store the available servers in an option. 
   691 	public static function get_server_connectivity($cache_timeout = 86400) {
   746 	public static function get_server_connectivity($cache_timeout = 86400) {
   692 		return self::check_server_connectivity( $cache_timeout );
   747 		return self::check_server_connectivity( $cache_timeout );
   693 	}
   748 	}
   694 
   749 
   695 	public static function get_number_spam_waiting() {
   750 	/**
   696 		global $wpdb;
   751 	 * Find out whether any comments in the Pending queue have not yet been checked by Akismet.
   697 		return (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->commentmeta} WHERE meta_key = 'akismet_error'" );
   752 	 *
       
   753 	 * @return bool
       
   754 	 */
       
   755 	public static function are_any_comments_waiting_to_be_checked() {
       
   756 		return !! get_comments( array(
       
   757 			// Exclude comments that are not pending. This would happen if someone manually approved or spammed a comment
       
   758 			// that was waiting to be checked. The akismet_error meta entry will eventually be removed by the cron recheck job.
       
   759 			'status' => 'hold',
       
   760 			
       
   761 			// This is the commentmeta that is saved when a comment couldn't be checked.
       
   762 			'meta_key' => 'akismet_error',
       
   763 			
       
   764 			// We only need to know whether at least one comment is waiting for a check.
       
   765 			'number' => 1,
       
   766 		) );
   698 	}
   767 	}
   699 
   768 
   700 	public static function get_page_url( $page = 'config' ) {
   769 	public static function get_page_url( $page = 'config' ) {
   701 
   770 
   702 		$args = array( 'page' => 'akismet-key-config' );
   771 		$args = array( 'page' => 'akismet-key-config' );
   710 
   779 
   711 		return $url;
   780 		return $url;
   712 	}
   781 	}
   713 	
   782 	
   714 	public static function get_akismet_user( $api_key ) {
   783 	public static function get_akismet_user( $api_key ) {
   715 		$akismet_user = Akismet::http_post( Akismet::build_query( array( 'key' => $api_key, 'blog' => get_bloginfo( 'url' ) ) ), 'get-subscription' );
   784 		$akismet_user = false;
   716 
   785 
   717 		if ( ! empty( $akismet_user[1] ) )
   786 		$subscription_verification = Akismet::http_post( Akismet::build_query( array( 'key' => $api_key, 'blog' => get_option( 'home' ) ) ), 'get-subscription' );
   718 			$akismet_user = json_decode( $akismet_user[1] );
   787 
   719 		else
   788 		if ( ! empty( $subscription_verification[1] ) ) {
   720 			$akismet_user = false;
   789 			if ( 'invalid' !== $subscription_verification[1] ) {
   721 			
   790 				$akismet_user = json_decode( $subscription_verification[1] );
       
   791 			}
       
   792 		}
       
   793 
   722 		return $akismet_user;
   794 		return $akismet_user;
   723 	}
   795 	}
   724 	
   796 	
   725 	public static function get_stats( $api_key ) {
   797 	public static function get_stats( $api_key ) {
   726 		$stat_totals = array();
   798 		$stat_totals = array();
   727 
   799 
   728 		foreach( array( '6-months', 'all' ) as $interval ) {
   800 		foreach( array( '6-months', 'all' ) as $interval ) {
   729 			$response = Akismet::http_post( Akismet::build_query( array( 'blog' => get_bloginfo( 'url' ), 'key' => $api_key, 'from' => $interval ) ), 'get-stats' );
   801 			$response = Akismet::http_post( Akismet::build_query( array( 'blog' => get_option( 'home' ), 'key' => $api_key, 'from' => $interval ) ), 'get-stats' );
   730 
   802 
   731 			if ( ! empty( $response[1] ) ) {
   803 			if ( ! empty( $response[1] ) ) {
   732 				$stat_totals[$interval] = json_decode( $response[1] );
   804 				$stat_totals[$interval] = json_decode( $response[1] );
   733 			}
   805 			}
   734 		}
   806 		}
   773 			'code' => (int) get_option( 'akismet_alert_code' ),
   845 			'code' => (int) get_option( 'akismet_alert_code' ),
   774 			'msg'  => get_option( 'akismet_alert_msg' )
   846 			'msg'  => get_option( 'akismet_alert_msg' )
   775 		) );
   847 		) );
   776 	}
   848 	}
   777 
   849 
       
   850 	public static function display_privacy_notice_control_warning() {
       
   851 		if ( !current_user_can( 'manage_options' ) )
       
   852 			return;
       
   853 		Akismet::view( 'notice', array(
       
   854 			'type' => 'privacy',
       
   855 		) );
       
   856 	}
       
   857 
   778 	public static function display_spam_check_warning() {
   858 	public static function display_spam_check_warning() {
   779 		Akismet::fix_scheduled_recheck();
   859 		Akismet::fix_scheduled_recheck();
   780 
   860 
   781 		if ( wp_next_scheduled('akismet_schedule_cron_recheck') > time() && self::get_number_spam_waiting() > 0 ) {
   861 		if ( wp_next_scheduled('akismet_schedule_cron_recheck') > time() && self::are_any_comments_waiting_to_be_checked() ) {
   782 			$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() ) ) );
   862 			$link_text = apply_filters( 'akismet_spam_check_warning_link_text', sprintf( __( 'Please check your <a href="%s">Akismet configuration</a> and contact your web host if problems persist.', 'akismet'), esc_url( self::get_page_url() ) ) );
   783 			Akismet::view( 'notice', array( 'type' => 'spam-check', 'link_text' => $link_text ) );
   863 			Akismet::view( 'notice', array( 'type' => 'spam-check', 'link_text' => $link_text ) );
   784 		}
   864 		}
   785 	}
       
   786 
       
   787 	public static function display_invalid_version() {
       
   788 		Akismet::view( 'notice', array( 'type' => 'version' ) );
       
   789 	}
   865 	}
   790 
   866 
   791 	public static function display_api_key_warning() {
   867 	public static function display_api_key_warning() {
   792 		Akismet::view( 'notice', array( 'type' => 'plugin' ) );
   868 		Akismet::view( 'notice', array( 'type' => 'plugin' ) );
   793 	}
   869 	}
   807 				if ( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], self::NONCE ) )
   883 				if ( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], self::NONCE ) )
   808 					delete_option( 'wordpress_api_key' );
   884 					delete_option( 'wordpress_api_key' );
   809 			}
   885 			}
   810 		}
   886 		}
   811 
   887 
   812 		if ( $api_key = Akismet::get_api_key() ) {
   888 		if ( $api_key = Akismet::get_api_key() && ( empty( self::$notices['status'] ) || 'existing-key-invalid' != self::$notices['status'] ) ) {
   813 			self::display_configuration_page();
   889 			self::display_configuration_page();
   814 			return;
   890 			return;
   815 		}
   891 		}
   816 		
   892 		
   817 		//the user can choose to auto connect their API key by clicking a button on the akismet done page
   893 		//the user can choose to auto connect their API key by clicking a button on the akismet done page
   827 			
   903 			
   828 		if ( isset( $_GET['action'] ) ) {
   904 		if ( isset( $_GET['action'] ) ) {
   829 			if ( $_GET['action'] == 'save-key' ) {
   905 			if ( $_GET['action'] == 'save-key' ) {
   830 				if ( is_object( $akismet_user ) ) {
   906 				if ( is_object( $akismet_user ) ) {
   831 					self::save_key( $akismet_user->api_key );
   907 					self::save_key( $akismet_user->api_key );
   832 					self::display_notice();
       
   833 					self::display_configuration_page();
   908 					self::display_configuration_page();
   834 					return;				
   909 					return;
   835 				}
   910 				}
   836 			}
   911 			}
   837 		}
   912 		}
   838 
       
   839 		echo '<h2 class="ak-header">'.esc_html__('Akismet', 'akismet').'</h2>';
       
   840 
       
   841 		self::display_status();
       
   842 
   913 
   843 		Akismet::view( 'start', compact( 'akismet_user' ) );
   914 		Akismet::view( 'start', compact( 'akismet_user' ) );
       
   915 
       
   916 		/*
       
   917 		// To see all variants when testing.
       
   918 		$akismet_user->status = 'no-sub';
       
   919 		Akismet::view( 'start', compact( 'akismet_user' ) );
       
   920 		$akismet_user->status = 'cancelled';
       
   921 		Akismet::view( 'start', compact( 'akismet_user' ) );
       
   922 		$akismet_user->status = 'suspended';
       
   923 		Akismet::view( 'start', compact( 'akismet_user' ) );
       
   924 		$akismet_user->status = 'other';
       
   925 		Akismet::view( 'start', compact( 'akismet_user' ) );
       
   926 		$akismet_user = false;
       
   927 		*/
   844 	}
   928 	}
   845 
   929 
   846 	public static function display_stats_page() {
   930 	public static function display_stats_page() {
   847 		Akismet::view( 'stats' );
   931 		Akismet::view( 'stats' );
   848 	}
   932 	}
   849 
   933 
   850 	public static function display_configuration_page() {
   934 	public static function display_configuration_page() {
   851 		$api_key      = Akismet::get_api_key();
   935 		$api_key      = Akismet::get_api_key();
   852 		$akismet_user = self::get_akismet_user( $api_key );
   936 		$akismet_user = self::get_akismet_user( $api_key );
       
   937 		
       
   938 		if ( ! $akismet_user ) {
       
   939 			// This could happen if the user's key became invalid after it was previously valid and successfully set up.
       
   940 			self::$notices['status'] = 'existing-key-invalid';
       
   941 			self::display_start_page();
       
   942 			return;
       
   943 		}
       
   944 
   853 		$stat_totals  = self::get_stats( $api_key );
   945 		$stat_totals  = self::get_stats( $api_key );
   854 		
   946 
   855 		// If unset, create the new strictness option using the old discard option to determine its default
   947 		// If unset, create the new strictness option using the old discard option to determine its default.
   856        	if ( get_option( 'akismet_strictness' ) === false )
   948 		// If the old option wasn't set, default to discarding the blatant spam.
   857         	add_option( 'akismet_strictness', (get_option('akismet_discard_month') === 'true' ? '1' : '0') );
   949 		if ( get_option( 'akismet_strictness' ) === false ) {
       
   950 			add_option( 'akismet_strictness', ( get_option( 'akismet_discard_month' ) === 'false' ? '0' : '1' ) );
       
   951 		}
       
   952 		
       
   953 		// Sync the local "Total spam blocked" count with the authoritative count from the server.
       
   954 		if ( isset( $stat_totals['all'], $stat_totals['all']->spam ) ) {
       
   955 			update_option( 'akismet_spam_count', $stat_totals['all']->spam );
       
   956 		}
       
   957 
       
   958 		$notices = array();
   858 
   959 
   859 		if ( empty( self::$notices ) ) {
   960 		if ( empty( self::$notices ) ) {
   860 			//show status
       
   861 			if ( ! empty( $stat_totals['all'] ) && isset( $stat_totals['all']->time_saved ) && $akismet_user->status == 'active' && $akismet_user->account_type == 'free-api-key' ) {
   961 			if ( ! empty( $stat_totals['all'] ) && isset( $stat_totals['all']->time_saved ) && $akismet_user->status == 'active' && $akismet_user->account_type == 'free-api-key' ) {
   862 
   962 
   863 				$time_saved = false;
   963 				$time_saved = false;
   864 
   964 
   865 				if ( $stat_totals['all']->time_saved > 1800 ) {
   965 				if ( $stat_totals['all']->time_saved > 1800 ) {
   867 					$total_in_hours   = round( $total_in_minutes / 60 );
   967 					$total_in_hours   = round( $total_in_minutes / 60 );
   868 					$total_in_days    = round( $total_in_hours / 8 );
   968 					$total_in_days    = round( $total_in_hours / 8 );
   869 					$cleaning_up      = __( 'Cleaning up spam takes time.' , 'akismet');
   969 					$cleaning_up      = __( 'Cleaning up spam takes time.' , 'akismet');
   870 
   970 
   871 					if ( $total_in_days > 1 )
   971 					if ( $total_in_days > 1 )
   872 						$time_saved = $cleaning_up . ' ' . sprintf( __( 'Since you joined us, Akismet has saved you %s days!' , 'akismet'), number_format_i18n( $total_in_days ) );
   972 						$time_saved = $cleaning_up . ' ' . sprintf( _n( 'Akismet has saved you %s day!', 'Akismet has saved you %s days!', $total_in_days, 'akismet' ), number_format_i18n( $total_in_days ) );
   873 					elseif ( $total_in_hours > 1 )
   973 					elseif ( $total_in_hours > 1 )
   874 						$time_saved = $cleaning_up . ' ' . sprintf( __( 'Since you joined us, Akismet has saved you %d hours!' , 'akismet'), $total_in_hours );
   974 						$time_saved = $cleaning_up . ' ' . sprintf( _n( 'Akismet has saved you %d hour!', 'Akismet has saved you %d hours!', $total_in_hours, 'akismet' ), $total_in_hours );
   875 					elseif ( $total_in_minutes >= 30 )
   975 					elseif ( $total_in_minutes >= 30 )
   876 						$time_saved = $cleaning_up . ' ' . sprintf( __( 'Since you joined us, Akismet has saved you %d minutes!' , 'akismet'), $total_in_minutes );
   976 						$time_saved = $cleaning_up . ' ' . sprintf( _n( 'Akismet has saved you %d minute!', 'Akismet has saved you %d minutes!', $total_in_minutes, 'akismet' ), $total_in_minutes );
   877 				}
   977 				}
   878 
   978 				
   879 				Akismet::view( 'notice', array( 'type' => 'active-notice', 'time_saved' => $time_saved ) );
   979 				$notices[] =  array( 'type' => 'active-notice', 'time_saved' => $time_saved );
   880 			}
   980 			}
   881 			
   981 			
   882 			if ( !empty( $akismet_user->limit_reached ) && in_array( $akismet_user->limit_reached, array( 'yellow', 'red' ) ) ) {
   982 			if ( !empty( $akismet_user->limit_reached ) && in_array( $akismet_user->limit_reached, array( 'yellow', 'red' ) ) ) {
   883 				Akismet::view( 'notice', array( 'type' => 'limit-reached', 'level' => $akismet_user->limit_reached ) );
   983 				$notices[] = array( 'type' => 'limit-reached', 'level' => $akismet_user->limit_reached );
   884 			}
   984 			}
   885 		}
   985 		}
   886 		
   986 		
   887 		if ( !isset( self::$notices['status'] ) && in_array( $akismet_user->status, array( 'cancelled', 'suspended', 'missing', 'no-sub' ) ) )	
   987 		if ( !isset( self::$notices['status'] ) && in_array( $akismet_user->status, array( 'cancelled', 'suspended', 'missing', 'no-sub' ) ) ) {
   888 			Akismet::view( 'notice', array( 'type' => $akismet_user->status ) );
   988 			$notices[] = array( 'type' => $akismet_user->status );
   889 
   989 		}
       
   990 
       
   991 		if ( false === get_option( 'akismet_comment_form_privacy_notice' ) ) {
       
   992 			$notices[] = array( 'type' => 'privacy' );
       
   993 		}
       
   994 
       
   995 		/*
       
   996 		// To see all variants when testing.
       
   997 		$notices[] = array( 'type' => 'active-notice', 'time_saved' => 'Cleaning up spam takes time. Akismet has saved you 1 minute!' );
       
   998 		$notices[] = array( 'type' => 'plugin' );
       
   999 		$notices[] = array( 'type' => 'spam-check', 'link_text' => 'Link text.' );
       
  1000 		$notices[] = array( 'type' => 'notice', 'notice_header' => 'This is the notice header.', 'notice_text' => 'This is the notice text.' );
       
  1001 		$notices[] = array( 'type' => 'missing-functions' );
       
  1002 		$notices[] = array( 'type' => 'servers-be-down' );
       
  1003 		$notices[] = array( 'type' => 'active-dunning' );
       
  1004 		$notices[] = array( 'type' => 'cancelled' );
       
  1005 		$notices[] = array( 'type' => 'suspended' );
       
  1006 		$notices[] = array( 'type' => 'missing' );
       
  1007 		$notices[] = array( 'type' => 'no-sub' );
       
  1008 		$notices[] = array( 'type' => 'new-key-valid' );
       
  1009 		$notices[] = array( 'type' => 'new-key-invalid' );
       
  1010 		$notices[] = array( 'type' => 'existing-key-invalid' );
       
  1011 		$notices[] = array( 'type' => 'new-key-failed' );
       
  1012 		$notices[] = array( 'type' => 'limit-reached', 'level' => 'yellow' );
       
  1013 		$notices[] = array( 'type' => 'limit-reached', 'level' => 'red' );
       
  1014 		*/
       
  1015 		
   890 		Akismet::log( compact( 'stat_totals', 'akismet_user' ) );
  1016 		Akismet::log( compact( 'stat_totals', 'akismet_user' ) );
   891 		Akismet::view( 'config', compact( 'api_key', 'akismet_user', 'stat_totals' ) );
  1017 		Akismet::view( 'config', compact( 'api_key', 'akismet_user', 'stat_totals', 'notices' ) );
   892 	}
  1018 	}
   893 
  1019 
   894 	public static function display_notice() {
  1020 	public static function display_notice() {
   895 		global $hook_suffix;
  1021 		global $hook_suffix;
   896 
  1022 
   897 		if ( in_array( $hook_suffix, array( 'jetpack_page_akismet-key-config', 'settings_page_akismet-key-config', 'edit-comments.php' ) ) && (int) get_option( 'akismet_alert_code' ) > 0 ) {
  1023 		if ( in_array( $hook_suffix, array( 'jetpack_page_akismet-key-config', 'settings_page_akismet-key-config' ) ) ) {
       
  1024 			// This page manages the notices and puts them inline where they make sense.
       
  1025 			return;
       
  1026 		}
       
  1027 
       
  1028 		if ( in_array( $hook_suffix, array( 'edit-comments.php' ) ) && (int) get_option( 'akismet_alert_code' ) > 0 ) {
   898 			Akismet::verify_key( Akismet::get_api_key() ); //verify that the key is still in alert state
  1029 			Akismet::verify_key( Akismet::get_api_key() ); //verify that the key is still in alert state
   899 			
  1030 			
   900 			if ( get_option( 'akismet_alert_code' ) > 0 )
  1031 			if ( get_option( 'akismet_alert_code' ) > 0 )
   901 				self::display_alert();
  1032 				self::display_alert();
   902 		}
  1033 		}
   904 			self::display_api_key_warning();
  1035 			self::display_api_key_warning();
   905 		}
  1036 		}
   906 		elseif ( $hook_suffix == 'edit-comments.php' && wp_next_scheduled( 'akismet_schedule_cron_recheck' ) ) {
  1037 		elseif ( $hook_suffix == 'edit-comments.php' && wp_next_scheduled( 'akismet_schedule_cron_recheck' ) ) {
   907 			self::display_spam_check_warning();
  1038 			self::display_spam_check_warning();
   908 		}
  1039 		}
   909 		elseif ( in_array( $hook_suffix, array( 'jetpack_page_akismet-key-config', 'settings_page_akismet-key-config' ) ) && Akismet::get_api_key() ) {
  1040 		else if ( isset( $_GET['akismet_recheck_complete'] ) ) {
   910 			self::display_status();
  1041 			$recheck_count = (int) $_GET['recheck_count'];
       
  1042 			$spam_count = (int) $_GET['spam_count'];
       
  1043 			
       
  1044 			if ( $recheck_count === 0 ) {
       
  1045 				$message = __( 'There were no comments to check. Akismet will only check comments in the Pending queue.', 'akismet' );
       
  1046 			}
       
  1047 			else {
       
  1048 				$message = sprintf( _n( 'Akismet checked %s comment.', 'Akismet checked %s comments.', $recheck_count, 'akismet' ), number_format( $recheck_count ) );
       
  1049 				$message .= ' ';
       
  1050 			
       
  1051 				if ( $spam_count === 0 ) {
       
  1052 					$message .= __( 'No comments were caught as spam.' );
       
  1053 				}
       
  1054 				else {
       
  1055 					$message .= sprintf( _n( '%s comment was caught as spam.', '%s comments were caught as spam.', $spam_count, 'akismet' ), number_format( $spam_count ) );
       
  1056 				}
       
  1057 			}
       
  1058 			
       
  1059 			echo '<div class="notice notice-success"><p>' . esc_html( $message ) . '</p></div>';
       
  1060 		}
       
  1061 
       
  1062 		$akismet_comment_form_privacy_notice_option = get_option( 'akismet_comment_form_privacy_notice' );
       
  1063 		if ( ! in_array( $akismet_comment_form_privacy_notice_option, array( 'hide', 'display' ) ) ) {
       
  1064 			$api_key = Akismet::get_api_key();
       
  1065 			if ( ! empty( $api_key ) ) {
       
  1066 				self::display_privacy_notice_control_warning();
       
  1067 			}
   911 		}
  1068 		}
   912 	}
  1069 	}
   913 
  1070 
   914 	public static function display_status() {
  1071 	public static function display_status() {
   915 		$type = '';
  1072 		if ( ! self::get_server_connectivity() ) {
   916 
  1073 			Akismet::view( 'notice', array( 'type' => 'servers-be-down' ) );
   917 		if ( !self::get_server_connectivity() )
  1074 		}
   918 			$type = 'servers-be-down';
  1075 		else if ( ! empty( self::$notices ) ) {
   919 
  1076 			foreach ( self::$notices as $index => $type ) {
   920 		if ( !empty( $type ) )
  1077 				if ( is_object( $type ) ) {
   921 			Akismet::view( 'notice', compact( 'type' ) );
  1078 					$notice_header = $notice_text = '';
   922 		elseif ( !empty( self::$notices ) ) {
  1079 					
   923 			foreach ( self::$notices as $type )
  1080 					if ( property_exists( $type, 'notice_header' ) ) {
   924 				Akismet::view( 'notice', compact( 'type' ) );
  1081 						$notice_header = wp_kses( $type->notice_header, self::$allowed );
       
  1082 					}
       
  1083 				
       
  1084 					if ( property_exists( $type, 'notice_text' ) ) {
       
  1085 						$notice_text = wp_kses( $type->notice_text, self::$allowed );
       
  1086 					}
       
  1087 					
       
  1088 					if ( property_exists( $type, 'status' ) ) {
       
  1089 						$type = wp_kses( $type->status, self::$allowed );
       
  1090 						Akismet::view( 'notice', compact( 'type', 'notice_header', 'notice_text' ) );
       
  1091 						
       
  1092 						unset( self::$notices[ $index ] );
       
  1093 					}
       
  1094 				}
       
  1095 				else {
       
  1096 					Akismet::view( 'notice', compact( 'type' ) );
       
  1097 					
       
  1098 					unset( self::$notices[ $index ] );
       
  1099 				}
       
  1100 			}
   925 		}
  1101 		}
   926 	}
  1102 	}
   927 
  1103 
   928 	private static function get_jetpack_user() {
  1104 	private static function get_jetpack_user() {
   929 		if ( !class_exists('Jetpack') )
  1105 		if ( !class_exists('Jetpack') )
   939 		Akismet::log( compact( 'xml' ) );
  1115 		Akismet::log( compact( 'xml' ) );
   940 
  1116 
   941 		if ( !$xml->isError() ) {
  1117 		if ( !$xml->isError() ) {
   942 			$responses = $xml->getResponse();
  1118 			$responses = $xml->getResponse();
   943 			if ( count( $responses ) > 1 ) {
  1119 			if ( count( $responses ) > 1 ) {
   944 				$api_key = array_shift( $responses[0] );
  1120 				// Due to a quirk in how Jetpack does multi-calls, the response order
   945 				$user_id = (int) array_shift( $responses[1] );
  1121 				// can't be trusted to match the call order. It's a good thing our
       
  1122 				// return values can be mostly differentiated from each other.
       
  1123 				$first_response_value = array_shift( $responses[0] );
       
  1124 				$second_response_value = array_shift( $responses[1] );
       
  1125 				
       
  1126 				// If WPCOM ever reaches 100 billion users, this will fail. :-)
       
  1127 				if ( preg_match( '/^[a-f0-9]{12}$/i', $first_response_value ) ) {
       
  1128 					$api_key = $first_response_value;
       
  1129 					$user_id = (int) $second_response_value;
       
  1130 				}
       
  1131 				else {
       
  1132 					$api_key = $second_response_value;
       
  1133 					$user_id = (int) $first_response_value;
       
  1134 				}
       
  1135 				
   946 				return compact( 'api_key', 'user_id' );
  1136 				return compact( 'api_key', 'user_id' );
   947 			}
  1137 			}
   948 		}
  1138 		}
   949 		return false;
  1139 		return false;
   950 	}
  1140 	}
   962 			return true;
  1152 			return true;
   963 		}
  1153 		}
   964 		
  1154 		
   965 		return $exclude;
  1155 		return $exclude;
   966 	}
  1156 	}
       
  1157 	
       
  1158 	/**
       
  1159 	 * When Akismet is active, remove the "Activate Akismet" step from the plugin description.
       
  1160 	 */
       
  1161 	public static function modify_plugin_description( $all_plugins ) {
       
  1162 		if ( isset( $all_plugins['akismet/akismet.php'] ) ) {
       
  1163 			if ( Akismet::get_api_key() ) {
       
  1164 				$all_plugins['akismet/akismet.php']['Description'] = __( 'Used by millions, Akismet is quite possibly the best way in the world to <strong>protect your blog from spam</strong>. Your site is fully configured and being protected, even while you sleep.', 'akismet' );
       
  1165 			}
       
  1166 			else {
       
  1167 				$all_plugins['akismet/akismet.php']['Description'] = __( 'Used by millions, Akismet is quite possibly the best way in the world to <strong>protect your blog from spam</strong>. It keeps your site protected even while you sleep. To get started, just go to <a href="admin.php?page=akismet-key-config">your Akismet Settings page</a> to set up your API key.', 'akismet' );
       
  1168 			}
       
  1169 		}
       
  1170 		
       
  1171 		return $all_plugins;
       
  1172 	}
       
  1173 
       
  1174 	private static function set_form_privacy_notice_option( $state ) {
       
  1175 		if ( in_array( $state, array( 'display', 'hide' ) ) ) {
       
  1176 			update_option( 'akismet_comment_form_privacy_notice', $state );
       
  1177 		}
       
  1178 	}
       
  1179 
       
  1180 	public static function jetpack_comment_form_privacy_notice_url( $url ) {
       
  1181 		return str_replace( 'options-general.php', 'admin.php', $url );
       
  1182 	}
   967 }
  1183 }