/bp-activity/classes/class-bp-akismet.php

  1. <?php 
  2. /** 
  3. * Akismet support for BuddyPress' Activity Stream. 
  4. * 
  5. * @package BuddyPress 
  6. * @subpackage ActivityAkismet 
  7. * @since 1.6.0 
  8. */ 
  9.  
  10. // Exit if accessed directly. 
  11. defined( 'ABSPATH' ) || exit; 
  12.  
  13. /** 
  14. * Akismet support for the Activity component. 
  15. * 
  16. * @since 1.6.0 
  17. * @since 2.3.0 We only support Akismet 3+. 
  18. */ 
  19. class BP_Akismet { 
  20.  
  21. /** 
  22. * The activity last marked as spam. 
  23. * 
  24. * @since 1.6.0 
  25. * @var BP_Activity_Activity 
  26. */ 
  27. protected $last_activity = null; 
  28.  
  29. /** 
  30. * Constructor. 
  31. * 
  32. * @since 1.6.0 
  33. */ 
  34. public function __construct() { 
  35. $this->setup_actions(); 
  36.  
  37. /** 
  38. * Hook Akismet into the activity stream. 
  39. * 
  40. * @since 1.6.0 
  41. */ 
  42. protected function setup_actions() { 
  43. // Add nonces to activity stream lists. 
  44. add_action( 'bp_after_activity_post_form', array( $this, 'add_activity_stream_nonce' ) ); 
  45. add_action( 'bp_activity_entry_comments', array( $this, 'add_activity_stream_nonce' ) ); 
  46.  
  47. // Add a "mark as spam" button to individual activity items. 
  48. add_action( 'bp_activity_entry_meta', array( $this, 'add_activity_spam_button' ) ); 
  49. add_action( 'bp_activity_comment_options', array( $this, 'add_activity_comment_spam_button' ) ); 
  50.  
  51. // Check activity for spam. 
  52. add_action( 'bp_activity_before_save', array( $this, 'check_activity' ), 4, 1 ); 
  53.  
  54. // Tidy up member's latest (activity) update. 
  55. add_action( 'bp_activity_posted_update', array( $this, 'check_member_activity_update' ), 1, 3 ); 
  56.  
  57. // Hooks to extend Activity core spam/ham functions for Akismet. 
  58. add_action( 'bp_activity_mark_as_spam', array( $this, 'mark_as_spam' ), 10, 2 ); 
  59. add_action( 'bp_activity_mark_as_ham', array( $this, 'mark_as_ham' ), 10, 2 ); 
  60.  
  61. // Hook into the Activity wp-admin screen. 
  62. add_action( 'bp_activity_admin_comment_row_actions', array( $this, 'comment_row_action' ), 10, 2 ); 
  63. add_action( 'bp_activity_admin_load', array( $this, 'add_history_metabox' ) ); 
  64.  
  65. /** 
  66. * Add a history item to the hover links in an activity's row. 
  67. * 
  68. * This function lifted with love from the Akismet WordPress plugin's 
  69. * akismet_comment_row_action() function. Thanks! 
  70. * 
  71. * @since 1.6.0 
  72. * 
  73. * @param array $actions The hover links. 
  74. * @param array $activity The activity for the current row being processed. 
  75. * @return array The hover links. 
  76. */ 
  77. function comment_row_action( $actions, $activity ) { 
  78. $akismet_result = bp_activity_get_meta( $activity['id'], '_bp_akismet_result' ); 
  79. $user_result = bp_activity_get_meta( $activity['id'], '_bp_akismet_user_result' ); 
  80. $desc = ''; 
  81.  
  82. if ( !$user_result || $user_result == $akismet_result ) { 
  83. // Show the original Akismet result if the user hasn't overridden it, or if their decision was the same. 
  84. if ( 'true' == $akismet_result && $activity['is_spam'] ) 
  85. $desc = __( 'Flagged as spam by Akismet', 'buddypress' ); 
  86.  
  87. elseif ( 'false' == $akismet_result && !$activity['is_spam'] ) 
  88. $desc = __( 'Cleared by Akismet', 'buddypress' ); 
  89.  
  90. } else { 
  91. $who = bp_activity_get_meta( $activity['id'], '_bp_akismet_user' ); 
  92.  
  93. if ( 'true' == $user_result ) 
  94. $desc = sprintf( __( 'Flagged as spam by %s', 'buddypress' ), $who ); 
  95. else 
  96. $desc = sprintf( __( 'Un-spammed by %s', 'buddypress' ), $who ); 
  97.  
  98. // Add a History item to the hover links, just after Edit. 
  99. if ( $akismet_result ) { 
  100. $b = array(); 
  101. foreach ( $actions as $k => $item ) { 
  102. $b[ $k ] = $item; 
  103. if ( $k == 'edit' ) 
  104. $b['history'] = '<a href="' . esc_url( bp_get_admin_url( 'admin.php?page=bp-activity&action=edit&aid=' . $activity['id'] ) ) . '#bp_activity_history"> '. __( 'History', 'buddypress' ) . '</a>'; 
  105.  
  106. $actions = $b; 
  107.  
  108. if ( $desc ) 
  109. echo '<span class="akismet-status"><a href="' . esc_url( bp_get_admin_url( 'admin.php?page=bp-activity&action=edit&aid=' . $activity['id'] ) ) . '#bp_activity_history">' . htmlspecialchars( $desc ) . '</a></span>'; 
  110.  
  111. /** 
  112. * Filters the list of actions for the current activity's row. 
  113. * 
  114. * @since 1.6.0 
  115. * 
  116. * @param array $actions Array of available actions for the current activity item's row. 
  117. */ 
  118. return apply_filters( 'bp_akismet_comment_row_action', $actions ); 
  119.  
  120. /** 
  121. * Generate nonces for activity forms. 
  122. * 
  123. * These nonces appear in the member profile status form, as well as in 
  124. * the reply form of each activity item. The nonces are, in turn, used 
  125. * by Akismet to help detect spam activity. 
  126. * 
  127. * @since 1.6.0 
  128. * 
  129. * @see https://plugins.trac.wordpress.org/ticket/1232 
  130. */ 
  131. public function add_activity_stream_nonce() { 
  132. $form_id = '_bp_as_nonce'; 
  133. $value = '_bp_as_nonce_' . bp_loggedin_user_id(); 
  134.  
  135. // If we're in the activity stream loop, we can use the current item's ID to make the nonce unique. 
  136. if ( 'bp_activity_entry_comments' == current_filter() ) { 
  137. $form_id .= '_' . bp_get_activity_id(); 
  138. $value .= '_' . bp_get_activity_id(); 
  139.  
  140. wp_nonce_field( $value, $form_id, false ); 
  141.  
  142. /** 
  143. * Clean up the bp_latest_update usermeta in case of spamming. 
  144. * 
  145. * Run just after an update is posted, this method check to see whether 
  146. * the newly created update has been marked as spam by Akismet. If so,  
  147. * the cached update is cleared from the user's 'bp_latest_update' 
  148. * usermeta, ensuring that it won't appear in the member header and 
  149. * elsewhere in the theme. 
  150. * 
  151. * This can't be done in BP_Akismet::check_activity() due to the 
  152. * default AJAX implementation; see bp_dtheme_post_update(). 
  153. * 
  154. * @since 1.6.0 
  155. * 
  156. * @see bp_dtheme_post_update() 
  157. * 
  158. * @param string $content Activity update text. 
  159. * @param int $user_id User ID. 
  160. * @param int $activity_id Activity ID. 
  161. */ 
  162. public function check_member_activity_update( $content, $user_id, $activity_id ) { 
  163. // By default, only handle activity updates and activity comments. 
  164. if ( empty( $this->last_activity ) || !in_array( $this->last_activity->type, BP_Akismet::get_activity_types() ) ) 
  165. return; 
  166.  
  167. // Was this $activity_id just marked as spam? If not, bail out. 
  168. if ( !$this->last_activity->id || $activity_id != $this->last_activity->id || 'false' == $this->last_activity->akismet_submission['bp_as_result'] ) 
  169. return; 
  170.  
  171. // It was, so delete the member's latest activity update. 
  172. bp_delete_user_meta( $user_id, 'bp_latest_update' ); 
  173.  
  174. /** 
  175. * Adds a "mark as spam" button to each activity item for site admins. 
  176. * 
  177. * This function is intended to be used inside the activity stream loop. 
  178. * 
  179. * @since 1.6.0 
  180. */ 
  181. public function add_activity_spam_button() { 
  182. if ( !bp_activity_user_can_mark_spam() ) 
  183. return; 
  184.  
  185. // By default, only handle activity updates and activity comments. 
  186. if ( !in_array( bp_get_activity_type(), BP_Akismet::get_activity_types() ) ) 
  187. return; 
  188.  
  189. bp_button( 
  190. array( 
  191. 'block_self' => false,  
  192. 'component' => 'activity',  
  193. 'id' => 'activity_make_spam_' . bp_get_activity_id(),  
  194. 'link_class' => 'bp-secondary-action spam-activity confirm button item-button',  
  195. 'link_href' => wp_nonce_url( bp_get_root_domain() . '/' . bp_get_activity_slug() . '/spam/' . bp_get_activity_id() . '/', 'bp_activity_akismet_spam_' . bp_get_activity_id() ),  
  196. 'link_text' => __( 'Spam', 'buddypress' ),  
  197. 'wrapper' => false,  
  198. ); 
  199.  
  200. /** 
  201. * Adds a "mark as spam" button to each activity COMMENT item for site admins. 
  202. * 
  203. * This function is intended to be used inside the activity stream loop. 
  204. * 
  205. * @since 1.6.0 
  206. */ 
  207. public function add_activity_comment_spam_button() { 
  208. if ( !bp_activity_user_can_mark_spam() ) 
  209. return; 
  210.  
  211. // By default, only handle activity updates and activity comments. 
  212. $current_comment = bp_activity_current_comment(); 
  213. if ( empty( $current_comment ) || !in_array( $current_comment->type, BP_Akismet::get_activity_types() ) ) 
  214. return; 
  215.  
  216. bp_button( 
  217. array( 
  218. 'block_self' => false,  
  219. 'component' => 'activity',  
  220. 'id' => 'activity_make_spam_' . bp_get_activity_comment_id(),  
  221. 'link_class' => 'bp-secondary-action spam-activity-comment confirm',  
  222. 'link_href' => wp_nonce_url( bp_get_root_domain() . '/' . bp_get_activity_slug() . '/spam/' . bp_get_activity_comment_id() . '/?cid=' . bp_get_activity_comment_id(), 'bp_activity_akismet_spam_' . bp_get_activity_comment_id() ),  
  223. 'link_text' => __( 'Spam', 'buddypress' ),  
  224. 'wrapper' => false,  
  225. ); 
  226.  
  227. /** 
  228. * Get a filterable list of activity types that Akismet should automatically check for spam. 
  229. * 
  230. * @since 1.6.0 
  231. * 
  232. * @static 
  233. * 
  234. * @return array $value List of activity types. 
  235. */ 
  236. public static function get_activity_types() { 
  237.  
  238. /** 
  239. * Filters the list of activity types that Akismet should automatically check for spam. 
  240. * 
  241. * @since 1.6.0 
  242. * 
  243. * @param array $value Array of default activity types for Akismet to check. 
  244. */ 
  245. return apply_filters( 'bp_akismet_get_activity_types', array( 'activity_comment', 'activity_update' ) ); 
  246.  
  247. /** 
  248. * Mark activity item as spam. 
  249. * 
  250. * @since 1.6.0 
  251. * 
  252. * @param BP_Activity_Activity $activity Activity item being spammed. 
  253. * @param string $source Either "by_a_person" (e.g. a person has 
  254. * manually marked the activity as spam) or 
  255. * "by_akismet" (automatically spammed). 
  256. */ 
  257. public function mark_as_spam( $activity, $source ) { 
  258. // Record this item so we can do some tidyup in BP_Akismet::check_member_activity_update(). 
  259. $this->last_activity = $activity; 
  260.  
  261. /** 
  262. * Fires after marking an activity item has been marked as spam. 
  263. * 
  264. * @since 1.6.0 
  265. * 
  266. * @param BP_Activity_Activity $activity Activity object being marked as spam. 
  267. * @param string $source Source of the whom marked as spam. 
  268. * Either "by_a_person" (e.g. a person has 
  269. * manually marked the activity as spam) 
  270. * or "by_akismet". 
  271. */ 
  272. do_action( 'bp_activity_akismet_mark_as_spam', $activity, $source ); 
  273.  
  274. /** 
  275. * Mark activity item as ham. 
  276. * 
  277. * @since 1.6.0 
  278. * 
  279. * @param BP_Activity_Activity $activity Activity item being hammed. 
  280. * @param string $source Either "by_a_person" (e.g. a person has 
  281. * manually marked the activity as ham) or 
  282. * "by_akismet" (automatically hammed). 
  283. */ 
  284. public function mark_as_ham( $activity, $source ) { 
  285. // If the activity was, originally, automatically marked as spam by Akismet, run the @mentions filter as it would have been skipped. 
  286. if ( 'true' == bp_activity_get_meta( $activity->id, '_bp_akismet_result' ) && !bp_activity_get_meta( $activity->id, '_bp_akismet_user_result' ) ) 
  287. $activity->content = bp_activity_at_name_filter( $activity->content, $activity->id ); 
  288.  
  289. /** 
  290. * Fires after marking an activity item has been marked as ham. 
  291. * 
  292. * @since 1.6.0 
  293. * 
  294. * @param BP_Activity_Activity $activity Activity object being marked as ham. 
  295. * @param string $source Source of the whom marked as ham. 
  296. * Either "by_a_person" (e.g. a person has 
  297. * manually marked the activity as ham) or 
  298. * "by_akismet" (automatically hammed). 
  299. */ 
  300. do_action( 'bp_activity_akismet_mark_as_ham', $activity, $source ); 
  301.  
  302. /** 
  303. * Build a data package for the Akismet service to inspect. 
  304. * 
  305. * @since 1.6.0 
  306. * 
  307. * @see http://akismet.com/development/api/#comment-check 
  308. * @static 
  309. * 
  310. * @param BP_Activity_Activity $activity Activity item data. 
  311. * @return array $activity_data 
  312. */ 
  313. public static function build_akismet_data_package( $activity ) { 
  314. $userdata = get_userdata( $activity->user_id ); 
  315.  
  316. $activity_data = array(); 
  317. $activity_data['akismet_comment_nonce'] = 'inactive'; 
  318. $activity_data['comment_author'] = $userdata->display_name; 
  319. $activity_data['comment_author_email'] = $userdata->user_email; 
  320. $activity_data['comment_author_url'] = bp_core_get_userlink( $userdata->ID, false, true); 
  321. $activity_data['comment_content'] = $activity->content; 
  322. $activity_data['comment_type'] = $activity->type; 
  323. $activity_data['permalink'] = bp_activity_get_permalink( $activity->id, $activity ); 
  324. $activity_data['user_ID'] = $userdata->ID; 
  325. $activity_data['user_role'] = Akismet::get_user_roles( $userdata->ID ); 
  326.  
  327. /** 
  328. * Get the nonce if the new activity was submitted through the "what's up, Paul?" form. 
  329. * This helps Akismet ensure that the update was a valid form submission. 
  330. */ 
  331. if ( !empty( $_POST['_bp_as_nonce'] ) ) 
  332. $activity_data['akismet_comment_nonce'] = wp_verify_nonce( $_POST['_bp_as_nonce'], "_bp_as_nonce_{$userdata->ID}" ) ? 'passed' : 'failed'; 
  333.  
  334. /** 
  335. * If the new activity was a reply to an existing item, check the nonce with the activity parent ID. 
  336. * This helps Akismet ensure that the update was a valid form submission. 
  337. */ 
  338. elseif ( !empty( $activity->secondary_item_id ) && !empty( $_POST['_bp_as_nonce_' . $activity->secondary_item_id] ) ) 
  339. $activity_data['akismet_comment_nonce'] = wp_verify_nonce( $_POST["_bp_as_nonce_{$activity->secondary_item_id}"], "_bp_as_nonce_{$userdata->ID}_{$activity->secondary_item_id}" ) ? 'passed' : 'failed'; 
  340.  
  341. /** 
  342. * Filters activity data before being sent to Akismet to inspect. 
  343. * 
  344. * @since 1.6.0 
  345. * 
  346. * @param array $activity_data Array of activity data for Akismet to inspect. 
  347. * @param BP_Activity_Activity $activity Activity item data. 
  348. */ 
  349. return apply_filters( 'bp_akismet_build_akismet_data_package', $activity_data, $activity ); 
  350.  
  351. /** 
  352. * Check if the activity item is spam or ham. 
  353. * 
  354. * @since 1.6.0 
  355. * 
  356. * @see http://akismet.com/development/api/ 
  357. * @todo Spam counter? 
  358. * @todo Auto-delete old spam? 
  359. * 
  360. * @param BP_Activity_Activity $activity The activity item to check. 
  361. */ 
  362. public function check_activity( $activity ) { 
  363. // By default, only handle activity updates and activity comments. 
  364. if ( !in_array( $activity->type, BP_Akismet::get_activity_types() ) ) 
  365. return; 
  366.  
  367. // Make sure last_activity is clear to avoid any confusion. 
  368. $this->last_activity = null; 
  369.  
  370. // Build data package for Akismet. 
  371. $activity_data = BP_Akismet::build_akismet_data_package( $activity ); 
  372.  
  373. // Check with Akismet to see if this is spam. 
  374. $activity_data = $this->send_akismet_request( $activity_data, 'check', 'spam' ); 
  375.  
  376. // Record this item. 
  377. $this->last_activity = $activity; 
  378.  
  379. // Store a copy of the data that was submitted to Akismet. 
  380. $this->last_activity->akismet_submission = $activity_data; 
  381.  
  382. // Spam. 
  383. if ( 'true' == $activity_data['bp_as_result'] ) { 
  384. /** 
  385. * Fires after an activity item has been proven to be spam, but before officially being marked as spam. 
  386. * 
  387. * @since 1.6.0 
  388. * 
  389. * @param BP_Activity_Activity $activity The activity item proven to be spam. 
  390. * @param array $activity_data Array of activity data for item including 
  391. * Akismet check results data. 
  392. */ 
  393. do_action_ref_array( 'bp_activity_akismet_spam_caught', array( &$activity, $activity_data ) ); 
  394.  
  395. // Mark as spam. 
  396. bp_activity_mark_as_spam( $activity, 'by_akismet' ); 
  397.  
  398. // Update activity meta after a spam check. 
  399. add_action( 'bp_activity_after_save', array( $this, 'update_activity_akismet_meta' ), 1, 1 ); 
  400.  
  401. /** 
  402. * Update activity meta after a manual spam change (user-initiated). 
  403. * 
  404. * @since 1.6.0 
  405. * 
  406. * @param BP_Activity_Activity $activity The activity to check. 
  407. */ 
  408. public function update_activity_spam_meta( $activity ) { 
  409. // By default, only handle activity updates and activity comments. 
  410. if ( !in_array( $activity->type, BP_Akismet::get_activity_types() ) ) 
  411. return; 
  412.  
  413. $this->update_activity_history( $activity->id, sprintf( __( '%s reported this activity as spam', 'buddypress' ), bp_get_loggedin_user_username() ), 'report-spam' ); 
  414. bp_activity_update_meta( $activity->id, '_bp_akismet_user_result', 'true' ); 
  415. bp_activity_update_meta( $activity->id, '_bp_akismet_user', bp_get_loggedin_user_username() ); 
  416.  
  417. /** 
  418. * Update activity meta after a manual ham change (user-initiated). 
  419. * 
  420. * @since 1.6.0 
  421. * 
  422. * @param BP_Activity_Activity $activity The activity to check. 
  423. */ 
  424. public function update_activity_ham_meta( $activity ) { 
  425. // By default, only handle activity updates and activity comments. 
  426. if ( !in_array( $activity->type, BP_Akismet::get_activity_types() ) ) 
  427. return; 
  428.  
  429. $this->update_activity_history( $activity->id, sprintf( __( '%s reported this activity as not spam', 'buddypress' ), bp_get_loggedin_user_username() ), 'report-ham' ); 
  430. bp_activity_update_meta( $activity->id, '_bp_akismet_user_result', 'false' ); 
  431. bp_activity_update_meta( $activity->id, '_bp_akismet_user', bp_get_loggedin_user_username() ); 
  432.  
  433. /** 
  434. * Update activity meta after an automatic spam check (not user-initiated). 
  435. * 
  436. * @since 1.6.0 
  437. * 
  438. * @param BP_Activity_Activity $activity The activity to check. 
  439. */ 
  440. public function update_activity_akismet_meta( $activity ) { 
  441. // Check we're dealing with what was last updated by Akismet. 
  442. if ( empty( $this->last_activity ) || !empty( $this->last_activity ) && $activity->id != $this->last_activity->id ) 
  443. return; 
  444.  
  445. // By default, only handle activity updates and activity comments. 
  446. if ( !in_array( $this->last_activity->type, BP_Akismet::get_activity_types() ) ) 
  447. return; 
  448.  
  449. // Spam. 
  450. if ( 'true' == $this->last_activity->akismet_submission['bp_as_result'] ) { 
  451. bp_activity_update_meta( $activity->id, '_bp_akismet_result', 'true' ); 
  452. $this->update_activity_history( $activity->id, __( 'Akismet caught this item as spam', 'buddypress' ), 'check-spam' ); 
  453.  
  454. // Not spam. 
  455. } elseif ( 'false' == $this->last_activity->akismet_submission['bp_as_result'] ) { 
  456. bp_activity_update_meta( $activity->id, '_bp_akismet_result', 'false' ); 
  457. $this->update_activity_history( $activity->id, __( 'Akismet cleared this item', 'buddypress' ), 'check-ham' ); 
  458.  
  459. // Uh oh, something's gone horribly wrong. Unexpected result. 
  460. } else { 
  461. bp_activity_update_meta( $activity->id, '_bp_akismet_error', bp_core_current_time() ); 
  462. $this->update_activity_history( $activity->id, sprintf( __( 'Akismet was unable to check this item (response: %s), will automatically retry again later.', 'buddypress' ), $this->last_activity->akismet_submission['bp_as_result'] ), 'check-error' ); 
  463.  
  464. // Record the original data which was submitted to Akismet for checking. 
  465. bp_activity_update_meta( $activity->id, '_bp_akismet_submission', $this->last_activity->akismet_submission ); 
  466.  
  467. /** 
  468. * Contact Akismet to check if this is spam or ham. 
  469. * 
  470. * Props to WordPress core Akismet plugin for a lot of this. 
  471. * 
  472. * @since 1.6.0 
  473. * 
  474. * @param array $activity_data Packet of information to submit to Akismet. 
  475. * @param string $check "check" or "submit". 
  476. * @param string $spam "spam" or "ham". 
  477. * @return array $activity_data Activity data, with Akismet data added. 
  478. */ 
  479. public function send_akismet_request( $activity_data, $check = 'check', $spam = 'spam' ) { 
  480. $query_string = $path = ''; 
  481.  
  482. $activity_data['blog'] = bp_get_option( 'home' ); 
  483. $activity_data['blog_charset'] = bp_get_option( 'blog_charset' ); 
  484. $activity_data['blog_lang'] = get_locale(); 
  485. $activity_data['referrer'] = $_SERVER['HTTP_REFERER']; 
  486. $activity_data['user_agent'] = bp_core_current_user_ua(); 
  487. $activity_data['user_ip'] = bp_core_current_user_ip(); 
  488.  
  489. if ( Akismet::is_test_mode() ) 
  490. $activity_data['is_test'] = 'true'; 
  491.  
  492. // Loop through _POST args and rekey strings. 
  493. foreach ( $_POST as $key => $value ) 
  494. if ( is_string( $value ) && 'cookie' != $key ) 
  495. $activity_data['POST_' . $key] = $value; 
  496.  
  497. // Keys to ignore. 
  498. $ignore = array( 'HTTP_COOKIE', 'HTTP_COOKIE2', 'PHP_AUTH_PW' ); 
  499.  
  500. // Loop through _SERVER args and remove whitelisted keys. 
  501. foreach ( $_SERVER as $key => $value ) { 
  502.  
  503. // Key should not be ignored. 
  504. if ( !in_array( $key, $ignore ) && is_string( $value ) ) { 
  505. $activity_data[$key] = $value; 
  506.  
  507. // Key should be ignored. 
  508. } else { 
  509. $activity_data[$key] = ''; 
  510.  
  511. foreach ( $activity_data as $key => $data ) 
  512. $query_string .= $key . '=' . urlencode( stripslashes( $data ) ) . '&'; 
  513.  
  514. if ( 'check' == $check ) 
  515. $path = 'comment-check'; 
  516. elseif ( 'submit' == $check ) 
  517. $path = 'submit-' . $spam; 
  518.  
  519. // Send to Akismet. 
  520. add_filter( 'akismet_ua', array( $this, 'buddypress_ua' ) ); 
  521. $response = Akismet::http_post( $query_string, $path ); 
  522. remove_filter( 'akismet_ua', array( $this, 'buddypress_ua' ) ); 
  523.  
  524. // Get the response. 
  525. if ( ! empty( $response[1] ) && ! is_wp_error( $response[1] ) ) 
  526. $activity_data['bp_as_result'] = $response[1]; 
  527. else 
  528. $activity_data['bp_as_result'] = false; 
  529.  
  530. // Perform a daily tidy up. 
  531. if ( ! wp_next_scheduled( 'bp_activity_akismet_delete_old_metadata' ) ) 
  532. wp_schedule_event( time(), 'daily', 'bp_activity_akismet_delete_old_metadata' ); 
  533.  
  534. return $activity_data; 
  535.  
  536. /** 
  537. * Filters user agent when sending to Akismet to add BuddyPress info. 
  538. * 
  539. * @since 1.6.0 
  540. * 
  541. * @param string $user_agent User agent string, as generated by Akismet. 
  542. * @return string $user_agent Modified user agent string. 
  543. */ 
  544. public function buddypress_ua( $user_agent ) { 
  545. $user_agent = 'BuddyPress/' . bp_get_version() . ' | Akismet/'. constant( 'AKISMET_VERSION' ); 
  546. return $user_agent; 
  547.  
  548. /** 
  549. * Adds a "History" meta box to the activity edit screen. 
  550. * 
  551. * @since 1.6.0 
  552. * 
  553. * @param string $screen_action The type of screen that has been requested. 
  554. */ 
  555. function add_history_metabox( $screen_action ) { 
  556. // Only proceed if we're on the edit screen. 
  557. if ( 'edit' != $screen_action ) 
  558. return; 
  559.  
  560. // Display meta box with a low priority (low position on screen by default). 
  561. add_meta_box( 'bp_activity_history', __( 'Activity History', 'buddypress' ), array( $this, 'history_metabox' ), get_current_screen()->id, 'normal', 'low' ); 
  562.  
  563. /** 
  564. * History meta box for the Activity admin edit screen. 
  565. * 
  566. * @since 1.6.0 
  567. * 
  568. * @see https://buddypress.trac.wordpress.org/ticket/3907 
  569. * @todo Update activity meta to allow >1 record with the same key (iterate through $history). 
  570. * 
  571. * @param object $item Activity item. 
  572. */ 
  573. function history_metabox( $item ) { 
  574. $history = BP_Akismet::get_activity_history( $item->id ); 
  575.  
  576. if ( empty( $history ) ) 
  577. return; 
  578.  
  579. echo '<div class="akismet-history"><div>'; 
  580. printf( _x( '%1$s — %2$s', 'x hours ago - akismet cleared this item', 'buddypress' ), '<span>' . bp_core_time_since( $history[2] ) . '</span>', esc_html( $history[1] ) ); 
  581. echo '</div></div>'; 
  582.  
  583. /** 
  584. * Update an activity item's Akismet history. 
  585. * 
  586. * @since 1.6.0 
  587. * 
  588. * @param int $activity_id Activity item ID. 
  589. * @param string $message Human-readable description of what's changed. 
  590. * @param string $event The type of check we were carrying out. 
  591. */ 
  592. public function update_activity_history( $activity_id = 0, $message = '', $event = '' ) { 
  593. $event = array( 
  594. 'event' => $event,  
  595. 'message' => $message,  
  596. 'time' => Akismet::_get_microtime(),  
  597. 'user' => bp_loggedin_user_id(),  
  598. ); 
  599.  
  600. // Save the history data. 
  601. bp_activity_update_meta( $activity_id, '_bp_akismet_history', $event ); 
  602.  
  603. /** 
  604. * Get an activity item's Akismet history. 
  605. * 
  606. * @since 1.6.0 
  607. * 
  608. * @param int $activity_id Activity item ID. 
  609. * @return array The activity item's Akismet history. 
  610. */ 
  611. public function get_activity_history( $activity_id = 0 ) { 
  612. $history = bp_activity_get_meta( $activity_id, '_bp_akismet_history' ); 
  613. if ( $history === false ) 
  614. $history = array(); 
  615.  
  616. // Sort it by the time recorded. 
  617. usort( $history, 'akismet_cmp_time' ); 
  618.  
  619. return $history; 
.