/bp-activity/bp-activity-functions.php

  1. <?php 
  2. /** 
  3. * BuddyPress Activity Functions. 
  4. * 
  5. * Functions for the Activity Streams component. 
  6. * 
  7. * @package BuddyPress 
  8. * @subpackage ActivityFunctions 
  9. * @since 1.5.0 
  10. */ 
  11.  
  12. // Exit if accessed directly. 
  13. defined( 'ABSPATH' ) || exit; 
  14.  
  15. /** 
  16. * Check whether the $bp global lists an activity directory page. 
  17. * 
  18. * @since 1.5.0 
  19. * 
  20. * @return bool True if activity directory page is found, otherwise false. 
  21. */ 
  22. function bp_activity_has_directory() { 
  23. return (bool) !empty( buddypress()->pages->activity->id ); 
  24.  
  25. /** 
  26. * Are mentions enabled or disabled? 
  27. * 
  28. * The Mentions feature does a number of things, all of which will be turned 
  29. * off if you disable mentions: 
  30. * - Detecting and auto-linking @username in all BP/WP content. 
  31. * - Sending BP notifications and emails to users when they are mentioned 
  32. * using the @username syntax. 
  33. * - The Public Message button on user profiles. 
  34. * 
  35. * Mentions are enabled by default. To disable, put the following line in 
  36. * bp-custom.php or your theme's functions.php file: 
  37. * 
  38. * add_filter( 'bp_activity_do_mentions', '__return_false' ); 
  39. * 
  40. * @since 1.8.0 
  41. * 
  42. * @return bool $retval True to enable mentions, false to disable. 
  43. */ 
  44. function bp_activity_do_mentions() { 
  45.  
  46. /** 
  47. * Filters whether or not mentions are enabled. 
  48. * 
  49. * @since 1.8.0 
  50. * 
  51. * @param bool $enabled True to enable mentions, false to disable. 
  52. */ 
  53. return (bool) apply_filters( 'bp_activity_do_mentions', true ); 
  54.  
  55. /** 
  56. * Should BuddyPress load the mentions scripts and related assets, including results to prime the 
  57. * mentions suggestions? 
  58. * 
  59. * @since 2.1.0 
  60. * 
  61. * @return bool True if mentions scripts should be loaded. 
  62. */ 
  63. function bp_activity_maybe_load_mentions_scripts() { 
  64. $mentions_enabled = bp_activity_do_mentions() && bp_is_user_active(); 
  65. $load_mentions = $mentions_enabled && ( bp_is_activity_component() || is_admin() ); 
  66.  
  67. /** 
  68. * Filters whether or not BuddyPress should load mentions scripts and assets. 
  69. * 
  70. * @since 2.1.0 
  71. * 
  72. * @param bool $load_mentions True to load mentions assets, false otherwise. 
  73. * @param bool $mentions_enabled True if mentions are enabled. 
  74. */ 
  75. return (bool) apply_filters( 'bp_activity_maybe_load_mentions_scripts', $load_mentions, $mentions_enabled ); 
  76.  
  77. /** 
  78. * Locate usernames in an activity content string, as designated by an @ sign. 
  79. * 
  80. * @since 1.5.0 
  81. * 
  82. * @param string $content The content of the activity, usually found in 
  83. * $activity->content. 
  84. * @return array|bool Associative array with user ID as key and username as 
  85. * value. Boolean false if no mentions found. 
  86. */ 
  87. function bp_activity_find_mentions( $content ) { 
  88.  
  89. $pattern = '/[@]+([A-Za-z0-9-_\.@]+)\b/'; 
  90. preg_match_all( $pattern, $content, $usernames ); 
  91.  
  92. // Make sure there's only one instance of each username. 
  93. $usernames = array_unique( $usernames[1] ); 
  94.  
  95. // Bail if no usernames. 
  96. if ( empty( $usernames ) ) { 
  97. return false; 
  98.  
  99. $mentioned_users = array(); 
  100.  
  101. // We've found some mentions! Check to see if users exist. 
  102. foreach( (array) array_values( $usernames ) as $username ) { 
  103. $user_id = bp_activity_get_userid_from_mentionname( $username ); 
  104.  
  105. // The user ID exists, so let's add it to our array. 
  106. if ( ! empty( $user_id ) ) { 
  107. $mentioned_users[ $user_id ] = $username; 
  108.  
  109. if ( empty( $mentioned_users ) ) { 
  110. return false; 
  111.  
  112. /** 
  113. * Filters the mentioned users. 
  114. * 
  115. * @since 2.5.0 
  116. * 
  117. * @param array $mentioned_users Associative array with user IDs as keys and usernames as values. 
  118. */ 
  119. return apply_filters( 'bp_activity_mentioned_users', $mentioned_users ); 
  120.  
  121. /** 
  122. * Reset a user's unread mentions list and count. 
  123. * 
  124. * @since 1.5.0 
  125. * 
  126. * @param int $user_id The id of the user whose unread mentions are being reset. 
  127. */ 
  128. function bp_activity_clear_new_mentions( $user_id ) { 
  129. bp_delete_user_meta( $user_id, 'bp_new_mention_count' ); 
  130. bp_delete_user_meta( $user_id, 'bp_new_mentions' ); 
  131.  
  132. /** 
  133. * Fires once mentions has been reset for a given user. 
  134. * 
  135. * @since 2.5.0 
  136. * 
  137. * @param int $user_id The id of the user whose unread mentions are being reset. 
  138. */ 
  139. do_action( 'bp_activity_clear_new_mentions', $user_id ); 
  140.  
  141. /** 
  142. * Adjusts mention count for mentioned users in activity items. 
  143. * 
  144. * This function is useful if you only have the activity ID handy and you 
  145. * haven't parsed an activity item for @mentions yet. 
  146. * 
  147. * Currently, only used in {@link bp_activity_delete()}. 
  148. * 
  149. * @since 1.5.0 
  150. * 
  151. * @param int $activity_id The unique id for the activity item. 
  152. * @param string $action Can be 'delete' or 'add'. Defaults to 'add'. 
  153. * @return bool 
  154. */ 
  155. function bp_activity_adjust_mention_count( $activity_id = 0, $action = 'add' ) { 
  156.  
  157. // Bail if no activity ID passed. 
  158. if ( empty( $activity_id ) ) { 
  159. return false; 
  160.  
  161. // Get activity object. 
  162. $activity = new BP_Activity_Activity( $activity_id ); 
  163.  
  164. // Try to find mentions. 
  165. $usernames = bp_activity_find_mentions( strip_tags( $activity->content ) ); 
  166.  
  167. // Still empty? Stop now. 
  168. if ( empty( $usernames ) ) { 
  169. return false; 
  170.  
  171. // Increment mention count foreach mentioned user. 
  172. foreach( (array) array_keys( $usernames ) as $user_id ) { 
  173. bp_activity_update_mention_count_for_user( $user_id, $activity_id, $action ); 
  174.  
  175. /** 
  176. * Update the mention count for a given user. 
  177. * 
  178. * This function should be used when you've already parsed your activity item 
  179. * for @mentions. 
  180. * 
  181. * @since 1.7.0 
  182. * 
  183. * @param int $user_id The user ID. 
  184. * @param int $activity_id The unique ID for the activity item. 
  185. * @param string $action 'delete' or 'add'. Default: 'add'. 
  186. * @return bool 
  187. */ 
  188. function bp_activity_update_mention_count_for_user( $user_id, $activity_id, $action = 'add' ) { 
  189.  
  190. if ( empty( $user_id ) || empty( $activity_id ) ) { 
  191. return false; 
  192.  
  193. // Adjust the mention list and count for the member. 
  194. $new_mention_count = (int) bp_get_user_meta( $user_id, 'bp_new_mention_count', true ); 
  195. $new_mentions = bp_get_user_meta( $user_id, 'bp_new_mentions', true ); 
  196.  
  197. // Make sure new mentions is an array. 
  198. if ( empty( $new_mentions ) ) { 
  199. $new_mentions = array(); 
  200.  
  201. switch ( $action ) { 
  202. case 'delete' : 
  203. $key = array_search( $activity_id, $new_mentions ); 
  204.  
  205. if ( $key !== false ) { 
  206. unset( $new_mentions[$key] ); 
  207.  
  208. break; 
  209.  
  210. case 'add' : 
  211. default : 
  212. if ( !in_array( $activity_id, $new_mentions ) ) { 
  213. $new_mentions[] = (int) $activity_id; 
  214.  
  215. break; 
  216.  
  217. // Get an updated mention count. 
  218. $new_mention_count = count( $new_mentions ); 
  219.  
  220. // Resave the user_meta. 
  221. bp_update_user_meta( $user_id, 'bp_new_mention_count', $new_mention_count ); 
  222. bp_update_user_meta( $user_id, 'bp_new_mentions', $new_mentions ); 
  223.  
  224. return true; 
  225.  
  226. /** 
  227. * Determine a user's "mentionname", the name used for that user in @-mentions. 
  228. * 
  229. * @since 1.9.0 
  230. * 
  231. * @param int|string $user_id ID of the user to get @-mention name for. 
  232. * @return string $mentionname User name appropriate for @-mentions. 
  233. */ 
  234. function bp_activity_get_user_mentionname( $user_id ) { 
  235. $mentionname = ''; 
  236.  
  237. $userdata = bp_core_get_core_userdata( $user_id ); 
  238.  
  239. if ( $userdata ) { 
  240. if ( bp_is_username_compatibility_mode() ) { 
  241. $mentionname = str_replace( ' ', '-', $userdata->user_login ); 
  242. } else { 
  243. $mentionname = $userdata->user_nicename; 
  244.  
  245. return $mentionname; 
  246.  
  247. /** 
  248. * Get a user ID from a "mentionname", the name used for a user in @-mentions. 
  249. * 
  250. * @since 1.9.0 
  251. * 
  252. * @param string $mentionname Username of user in @-mentions. 
  253. * @return int|bool ID of the user, if one is found. Otherwise false. 
  254. */ 
  255. function bp_activity_get_userid_from_mentionname( $mentionname ) { 
  256. $user_id = false; 
  257.  
  258. /** 
  259. * In username compatibility mode, hyphens are ambiguous between 
  260. * actual hyphens and converted spaces. 
  261. * 
  262. * @todo There is the potential for username clashes between 'foo bar' 
  263. * and 'foo-bar' in compatibility mode. Come up with a system for 
  264. * unique mentionnames. 
  265. */ 
  266. if ( bp_is_username_compatibility_mode() ) { 
  267. // First, try the raw username. 
  268. $userdata = get_user_by( 'login', $mentionname ); 
  269.  
  270. // Doing a direct query to use proper regex. Necessary to 
  271. // account for hyphens + spaces in the same user_login. 
  272. if ( empty( $userdata ) || ! is_a( $userdata, 'WP_User' ) ) { 
  273. global $wpdb; 
  274. $regex = esc_sql( str_replace( '-', '[ \-]', $mentionname ) ); 
  275. $user_id = $wpdb->get_var( "SELECT ID FROM {$wpdb->users} WHERE user_login REGEXP '{$regex}'" ); 
  276. } else { 
  277. $user_id = $userdata->ID; 
  278.  
  279. // When username compatibility mode is disabled, the mentionname is 
  280. // the same as the nicename. 
  281. } else { 
  282. $user_id = bp_core_get_userid_from_nicename( $mentionname ); 
  283.  
  284.  
  285. return $user_id; 
  286.  
  287. /** Actions ******************************************************************/ 
  288.  
  289. /** 
  290. * Register an activity 'type' and its action description/callback. 
  291. * 
  292. * Activity actions are strings used to describe items in the activity stream,  
  293. * such as 'Joe became a registered member' or 'Bill and Susie are now 
  294. * friends'. Each activity type (such as 'new_member' or 'friendship_created') 
  295. * used by a component should be registered using this function. 
  296. * 
  297. * While it's possible to post items to the activity stream whose types are 
  298. * not registered using bp_activity_set_action(), it is not recommended; 
  299. * unregistered types will not be displayed properly in the activity admin 
  300. * panel, and dynamic action generation (which is essential for multilingual 
  301. * sites, etc) will not work. 
  302. * 
  303. * @since 1.1.0 
  304. * 
  305. * @param string $component_id The unique string ID of the component. 
  306. * @param string $type The action type. 
  307. * @param string $description The action description. 
  308. * @param callable|bool $format_callback Callback for formatting the action string. 
  309. * @param string|bool $label String to describe this action in the activity stream filter dropdown. 
  310. * @param array $context Optional. Activity stream contexts where the filter should appear. 
  311. * Values: 'activity', 'member', 'member_groups', 'group'. 
  312. * @param int $position Optional. The position of the action when listed in dropdowns. 
  313. * @return bool False if any param is empty, otherwise true. 
  314. */ 
  315. function bp_activity_set_action( $component_id, $type, $description, $format_callback = false, $label = false, $context = array(), $position = 0 ) { 
  316. $bp = buddypress(); 
  317.  
  318. // Return false if any of the above values are not set. 
  319. if ( empty( $component_id ) || empty( $type ) || empty( $description ) ) { 
  320. return false; 
  321.  
  322. // Set activity action. 
  323. if ( ! isset( $bp->activity->actions ) || ! is_object( $bp->activity->actions ) ) { 
  324. $bp->activity->actions = new stdClass; 
  325.  
  326. // Verify callback. 
  327. if ( ! is_callable( $format_callback ) ) { 
  328. $format_callback = ''; 
  329.  
  330. if ( ! isset( $bp->activity->actions->{$component_id} ) || ! is_object( $bp->activity->actions->{$component_id} ) ) { 
  331. $bp->activity->actions->{$component_id} = new stdClass; 
  332.  
  333. /** 
  334. * Filters the action type being set for the current activity item. 
  335. * 
  336. * @since 1.1.0 
  337. * 
  338. * @param array $array Array of arguments for action type being set. 
  339. * @param string $component_id ID of the current component being set. 
  340. * @param string $type Action type being set. 
  341. * @param string $description Action description for action being set. 
  342. * @param callable $format_callback Callback for formatting the action string. 
  343. * @param string $label String to describe this action in the activity stream filter dropdown. 
  344. * @param array $context Activity stream contexts where the filter should appear. 'activity', 'member',  
  345. * 'member_groups', 'group'. 
  346. */ 
  347. $bp->activity->actions->{$component_id}->{$type} = apply_filters( 'bp_activity_set_action', array( 
  348. 'key' => $type,  
  349. 'value' => $description,  
  350. 'format_callback' => $format_callback,  
  351. 'label' => $label,  
  352. 'context' => $context,  
  353. 'position' => $position,  
  354. ), $component_id, $type, $description, $format_callback, $label, $context ); 
  355.  
  356. // Sort the actions of the affected component. 
  357. $action_array = (array) $bp->activity->actions->{$component_id}; 
  358. $action_array = bp_sort_by_key( $action_array, 'position', 'num' ); 
  359.  
  360. // Restore keys. 
  361. $bp->activity->actions->{$component_id} = new stdClass; 
  362. foreach ( $action_array as $key_ordered ) { 
  363. $bp->activity->actions->{$component_id}->{$key_ordered['key']} = $key_ordered; 
  364.  
  365. return true; 
  366.  
  367. /** 
  368. * Set tracking arguments for a given post type. 
  369. * 
  370. * @since 2.2.0 
  371. * 
  372. * @global $wp_post_types 
  373. * 
  374. * @param string $post_type The name of the post type, as registered with WordPress. Eg 'post' or 'page'. 
  375. * @param array $args { 
  376. * An associative array of tracking parameters. All items are optional. 
  377. * @type string $bp_activity_admin_filter String to use in the Dashboard > Activity dropdown. 
  378. * @type string $bp_activity_front_filter String to use in frontend dropdown. 
  379. * @type string $bp_activity_new_post String format to use for generating the activity action. Should be a 
  380. * translatable string where %1$s is replaced by a user link and %2$s is 
  381. * the URL of the newly created post. 
  382. * @type string $bp_activity_new_post_ms String format to use for generating the activity action on Multisite. 
  383. * Should be a translatable string where %1$s is replaced by a user link,  
  384. * %2$s is the URL of the newly created post, and %3$s is a link to 
  385. * the site. 
  386. * @type string $component_id ID of the BuddyPress component to associate the activity item. 
  387. * @type string $action_id Value for the 'type' param of the new activity item. 
  388. * @type callable $format_callback Callback for formatting the activity action string. 
  389. * Default: 'bp_activity_format_activity_action_custom_post_type_post'. 
  390. * @type array $contexts The directory contexts in which the filter will show. 
  391. * Default: array( 'activity' ). 
  392. * @type array $position Position of the item in filter dropdowns. 
  393. * @type string $singular Singular, translatable name of the post type item. If no value is 
  394. * provided, it's pulled from the 'singular_name' of the post type. 
  395. * @type bool $activity_comment Whether to allow comments on the activity items. Defaults to true if 
  396. * the post type does not natively support comments, otherwise false. 
  397. * } 
  398. * @return bool 
  399. */ 
  400. function bp_activity_set_post_type_tracking_args( $post_type = '', $args = array() ) { 
  401. global $wp_post_types; 
  402.  
  403. if ( empty( $wp_post_types[ $post_type ] ) || ! post_type_supports( $post_type, 'buddypress-activity' ) || ! is_array( $args ) ) { 
  404. return false; 
  405.  
  406. $activity_labels = array( 
  407. /** Post labels */ 
  408. 'bp_activity_admin_filter',  
  409. 'bp_activity_front_filter',  
  410. 'bp_activity_new_post',  
  411. 'bp_activity_new_post_ms',  
  412. /** Comment labels */ 
  413. 'bp_activity_comments_admin_filter',  
  414. 'bp_activity_comments_front_filter',  
  415. 'bp_activity_new_comment',  
  416. 'bp_activity_new_comment_ms' 
  417. ); 
  418.  
  419. // Labels are loaded into the post type object. 
  420. foreach ( $activity_labels as $label_type ) { 
  421. if ( ! empty( $args[ $label_type ] ) ) { 
  422. $wp_post_types[ $post_type ]->labels->{$label_type} = $args[ $label_type ]; 
  423. unset( $args[ $label_type ] ); 
  424.  
  425. // If there are any additional args, put them in the bp_activity attribute of the post type. 
  426. if ( ! empty( $args ) ) { 
  427. $wp_post_types[ $post_type ]->bp_activity = $args; 
  428.  
  429. /** 
  430. * Get tracking arguments for a specific post type. 
  431. * 
  432. * @since 2.2.0 
  433. * @since 2.5.0 Add post type comments tracking args 
  434. * 
  435. * @param string $post_type Name of the post type. 
  436. * @return object The tracking arguments of the post type. 
  437. */ 
  438. function bp_activity_get_post_type_tracking_args( $post_type ) { 
  439. if ( ! post_type_supports( $post_type, 'buddypress-activity' ) ) { 
  440. return false; 
  441.  
  442. $post_type_object = get_post_type_object( $post_type ); 
  443. $post_type_support_comments = post_type_supports( $post_type, 'comments' ); 
  444.  
  445. $post_type_activity = array( 
  446. 'component_id' => buddypress()->activity->id,  
  447. 'action_id' => 'new_' . $post_type,  
  448. 'format_callback' => 'bp_activity_format_activity_action_custom_post_type_post',  
  449. 'front_filter' => $post_type_object->labels->name,  
  450. 'contexts' => array( 'activity' ),  
  451. 'position' => 0,  
  452. 'singular' => strtolower( $post_type_object->labels->singular_name ),  
  453. 'activity_comment' => ! $post_type_support_comments,  
  454. 'comment_action_id' => false,  
  455. 'comment_format_callback' => 'bp_activity_format_activity_action_custom_post_type_comment',  
  456. ); 
  457.  
  458. if ( ! empty( $post_type_object->bp_activity ) ) { 
  459. $post_type_activity = bp_parse_args( (array) $post_type_object->bp_activity, $post_type_activity, $post_type . '_tracking_args' ); 
  460.  
  461. $post_type_activity = (object) $post_type_activity; 
  462.  
  463. // Try to get the admin filter from the post type labels. 
  464. if ( ! empty( $post_type_object->labels->bp_activity_admin_filter ) ) { 
  465. $post_type_activity->admin_filter = $post_type_object->labels->bp_activity_admin_filter; 
  466.  
  467. // Fall back to a generic name. 
  468. } else { 
  469. $post_type_activity->admin_filter = _x( 'New item published', 'Post Type generic activity post admin filter', 'buddypress' ); 
  470.  
  471. // Check for the front filter in the post type labels. 
  472. if ( ! empty( $post_type_object->labels->bp_activity_front_filter ) ) { 
  473. $post_type_activity->front_filter = $post_type_object->labels->bp_activity_front_filter; 
  474.  
  475. // Try to get the action for new post type action on non-multisite installations. 
  476. if ( ! empty( $post_type_object->labels->bp_activity_new_post ) ) { 
  477. $post_type_activity->new_post_type_action = $post_type_object->labels->bp_activity_new_post; 
  478.  
  479. // Try to get the action for new post type action on multisite installations. 
  480. if ( ! empty( $post_type_object->labels->bp_activity_new_post_ms ) ) { 
  481. $post_type_activity->new_post_type_action_ms = $post_type_object->labels->bp_activity_new_post_ms; 
  482.  
  483. // If the post type supports comments and has a comment action id, build the comments tracking args 
  484. if ( $post_type_support_comments && ! empty( $post_type_activity->comment_action_id ) ) { 
  485. // Init a new container for the activity type for comments 
  486. $post_type_activity->comments_tracking = new stdClass(); 
  487.  
  488. // Build the activity type for comments 
  489. $post_type_activity->comments_tracking->component_id = $post_type_activity->component_id; 
  490. $post_type_activity->comments_tracking->action_id = $post_type_activity->comment_action_id; 
  491.  
  492. // Try to get the comments admin filter from the post type labels. 
  493. if ( ! empty( $post_type_object->labels->bp_activity_comments_admin_filter ) ) { 
  494. $post_type_activity->comments_tracking->admin_filter = $post_type_object->labels->bp_activity_comments_admin_filter; 
  495.  
  496. // Fall back to a generic name. 
  497. } else { 
  498. $post_type_activity->comments_tracking->admin_filter = _x( 'New item comment posted', 'Post Type generic comments activity admin filter', 'buddypress' ); 
  499.  
  500. $post_type_activity->comments_tracking->format_callback = $post_type_activity->comment_format_callback; 
  501.  
  502. // Check for the comments front filter in the post type labels. 
  503. if ( ! empty( $post_type_object->labels->bp_activity_comments_front_filter ) ) { 
  504. $post_type_activity->comments_tracking->front_filter = $post_type_object->labels->bp_activity_comments_front_filter; 
  505.  
  506. // Fall back to a generic name. 
  507. } else { 
  508. $post_type_activity->comments_tracking->front_filter = _x( 'Item comments', 'Post Type generic comments activity front filter', 'buddypress' ); 
  509.  
  510. $post_type_activity->comments_tracking->contexts = $post_type_activity->contexts; 
  511. $post_type_activity->comments_tracking->position = (int) $post_type_activity->position + 1; 
  512.  
  513. // Try to get the action for new post type comment action on non-multisite installations. 
  514. if ( ! empty( $post_type_object->labels->bp_activity_new_comment ) ) { 
  515. $post_type_activity->comments_tracking->new_post_type_comment_action = $post_type_object->labels->bp_activity_new_comment; 
  516.  
  517. // Try to get the action for new post type comment action on multisite installations. 
  518. if ( ! empty( $post_type_object->labels->bp_activity_new_comment_ms ) ) { 
  519. $post_type_activity->comments_tracking->new_post_type_comment_action_ms = $post_type_object->labels->bp_activity_new_comment_ms; 
  520.  
  521. // Finally make sure we'll be able to find the post type this activity type is associated to. 
  522. $post_type_activity->post_type = $post_type; 
  523.  
  524. /** 
  525. * Filters tracking arguments for a specific post type. 
  526. * 
  527. * @since 2.2.0 
  528. * 
  529. * @param object $post_type_activity The tracking arguments of the post type. 
  530. * @param string $post_type Name of the post type. 
  531. */ 
  532. return apply_filters( 'bp_activity_get_post_type_tracking_args', $post_type_activity, $post_type ); 
  533.  
  534. /** 
  535. * Get tracking arguments for all post types. 
  536. * 
  537. * @since 2.2.0 
  538. * @since 2.5.0 Include post type comments tracking args if needed 
  539. * 
  540. * @return array List of post types with their tracking arguments. 
  541. */ 
  542. function bp_activity_get_post_types_tracking_args() { 
  543. // Fetch all public post types. 
  544. $post_types = get_post_types( array( 'public' => true ), 'names' ); 
  545.  
  546. $post_types_tracking_args = array(); 
  547.  
  548. foreach ( $post_types as $post_type ) { 
  549. $track_post_type = bp_activity_get_post_type_tracking_args( $post_type ); 
  550.  
  551. if ( ! empty( $track_post_type ) ) { 
  552. // Set the post type comments tracking args 
  553. if ( ! empty( $track_post_type->comments_tracking->action_id ) ) { 
  554. // Used to check support for comment tracking by activity type (new_post_type_comment) 
  555. $track_post_type->comments_tracking->comments_tracking = true; 
  556.  
  557. // Used to be able to find the post type this activity type is associated to. 
  558. $track_post_type->comments_tracking->post_type = $post_type; 
  559.  
  560. $post_types_tracking_args[ $track_post_type->comments_tracking->action_id ] = $track_post_type->comments_tracking; 
  561.  
  562. // Used to check support for comment tracking by activity type (new_post_type) 
  563. $track_post_type->comments_tracking = true; 
  564.  
  565. $post_types_tracking_args[ $track_post_type->action_id ] = $track_post_type; 
  566.  
  567.  
  568. /** 
  569. * Filters tracking arguments for all post types. 
  570. * 
  571. * @since 2.2.0 
  572. * 
  573. * @param array $post_types_tracking_args Array of post types with 
  574. * their tracking arguments. 
  575. */ 
  576. return apply_filters( 'bp_activity_get_post_types_tracking_args', $post_types_tracking_args ); 
  577.  
  578. /** 
  579. * Check if the *Post Type* activity supports a specific feature. 
  580. * 
  581. * @since 2.5.0 
  582. * 
  583. * @param string $activity_type The activity type to check. 
  584. * @param string $feature The feature to check. Currently supports: 
  585. * 'post-type-comment-tracking', 'post-type-comment-reply' & 'comment-reply'. 
  586. * See inline doc for more info. 
  587. * @return bool 
  588. */ 
  589. function bp_activity_type_supports( $activity_type = '', $feature = '' ) { 
  590. $retval = false; 
  591.  
  592. $bp = buddypress(); 
  593.  
  594. switch ( $feature ) { 
  595. /** 
  596. * Does this activity type support comment tracking? 
  597. * 
  598. * eg. 'new_blog_post' and 'new_blog_comment' will both return true. 
  599. */ 
  600. case 'post-type-comment-tracking' : 
  601. // Set the activity track global if not set yet 
  602. if ( empty( $bp->activity->track ) ) { 
  603. $bp->activity->track = bp_activity_get_post_types_tracking_args(); 
  604.  
  605. if ( ! empty( $bp->activity->track[ $activity_type ]->comments_tracking ) ) { 
  606. $retval = true; 
  607. break; 
  608.  
  609. /** 
  610. * Is this a parent activity type that support post comments? 
  611. * 
  612. * eg. 'new_blog_post' will return true; 'new_blog_comment' will return false. 
  613. */ 
  614. case 'post-type-comment-reply' : 
  615. // Set the activity track global if not set yet
  616. if ( empty( $bp->activity->track ) ) { 
  617. $bp->activity->track = bp_activity_get_post_types_tracking_args(); 
  618.  
  619. if ( ! empty( $bp->activity->track[ $activity_type ]->comments_tracking ) && ! empty( $bp->activity->track[ $activity_type ]->comment_action_id ) ) { 
  620. $retval = true; 
  621. break; 
  622.  
  623. /** 
  624. * Does this activity type support comment & reply? 
  625. */ 
  626. case 'comment-reply' : 
  627. // Set the activity track global if not set yet
  628. if ( empty( $bp->activity->track ) ) { 
  629. $bp->activity->track = bp_activity_get_post_types_tracking_args(); 
  630.  
  631. // Post Type activities 
  632. if ( ! empty( $bp->activity->track[ $activity_type ] ) ) { 
  633. if ( isset( $bp->activity->track[ $activity_type ]->activity_comment ) ) { 
  634. $retval = $bp->activity->track[ $activity_type ]->activity_comment; 
  635.  
  636. // Eventually override with comment synchronization feature. 
  637. if ( isset( $bp->activity->track[ $activity_type ]->comments_tracking ) ) { 
  638. $retval = $bp->activity->track[ $activity_type ]->comments_tracking && ! bp_disable_blogforum_comments(); 
  639.  
  640. // Retired Forums component 
  641. } elseif ( 'new_forum_topic' === $activity_type || 'new_forum_post' === $activity_type ) { 
  642. $retval = ! bp_disable_blogforum_comments(); 
  643.  
  644. // By Default, all other activity types are supporting comments. 
  645. } else { 
  646. $retval = true; 
  647. break; 
  648.  
  649. return $retval; 
  650.  
  651. /** 
  652. * Get a specific tracking argument for a given activity type 
  653. * 
  654. * @since 2.5.0 
  655. * 
  656. * @param string $activity_type the activity type. 
  657. * @param string $arg the key of the tracking argument. 
  658. * @return mixed the value of the tracking arg, false if not found. 
  659. */ 
  660. function bp_activity_post_type_get_tracking_arg( $activity_type, $arg = '' ) { 
  661. if ( empty( $activity_type ) || empty( $arg ) ) { 
  662. return false; 
  663.  
  664. $bp = buddypress(); 
  665.  
  666. // Set the activity track global if not set yet 
  667. if ( empty( $bp->activity->track ) ) { 
  668. $bp->activity->track = bp_activity_get_post_types_tracking_args(); 
  669.  
  670. if ( isset( $bp->activity->track[ $activity_type ]->{$arg} ) ) { 
  671. return $bp->activity->track[ $activity_type ]->{$arg}; 
  672. } else { 
  673. return false; 
  674.  
  675. /** 
  676. * Get all components' activity actions, sorted by their position attribute. 
  677. * 
  678. * @since 2.2.0 
  679. * 
  680. * @return object Actions ordered by their position. 
  681. */ 
  682. function bp_activity_get_actions() { 
  683. $bp = buddypress(); 
  684.  
  685. $post_types = bp_activity_get_post_types_tracking_args(); 
  686.  
  687. // Create the actions for the post types, if they haven't already been created. 
  688. if ( ! empty( $post_types ) ) { 
  689. foreach ( $post_types as $post_type ) { 
  690. if ( isset( $bp->activity->actions->{$post_type->component_id}->{$post_type->action_id} ) ) { 
  691. continue; 
  692.  
  693. bp_activity_set_action( 
  694. $post_type->component_id,  
  695. $post_type->action_id,  
  696. $post_type->admin_filter,  
  697. $post_type->format_callback,  
  698. $post_type->front_filter,  
  699. $post_type->contexts,  
  700. $post_type->position 
  701. ); 
  702.  
  703. return $bp->activity->actions; 
  704.  
  705. /** 
  706. * Retrieve the current action from a component and key. 
  707. * 
  708. * @since 1.1.0 
  709. * 
  710. * @param string $component_id The unique string ID of the component. 
  711. * @param string $key The action key. 
  712. * @return string|bool Action value if found, otherwise false. 
  713. */ 
  714. function bp_activity_get_action( $component_id, $key ) { 
  715.  
  716. // Return false if any of the above values are not set. 
  717. if ( empty( $component_id ) || empty( $key ) ) { 
  718. return false; 
  719.  
  720. $actions = bp_activity_get_actions(); 
  721. $retval = false; 
  722.  
  723. if ( isset( $actions->{$component_id}->{$key} ) ) { 
  724. $retval = $actions->{$component_id}->{$key}; 
  725.  
  726. /** 
  727. * Filters the current action by component and key. 
  728. * 
  729. * @since 1.1.0 
  730. * 
  731. * @param string|bool $retval The action key. 
  732. * @param string $component_id The unique string ID of the component. 
  733. * @param string $key The action key. 
  734. */ 
  735. return apply_filters( 'bp_activity_get_action', $retval, $component_id, $key ); 
  736.  
  737. /** 
  738. * Fetch details of all registered activity types. 
  739. * 
  740. * @since 1.7.0 
  741. * 
  742. * @return array array( type => description ), ... 
  743. */ 
  744. function bp_activity_get_types() { 
  745. $actions = array(); 
  746.  
  747. // Walk through the registered actions, and build an array of actions/values. 
  748. foreach ( bp_activity_get_actions() as $action ) { 
  749. $action = array_values( (array) $action ); 
  750.  
  751. for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ ) { 
  752. $actions[ $action[$i]['key'] ] = $action[$i]['value']; 
  753.  
  754. // This was a mis-named activity type from before BP 1.6. 
  755. unset( $actions['friends_register_activity_action'] ); 
  756.  
  757. /** 
  758. * Filters the available activity types. 
  759. * 
  760. * @since 1.7.0 
  761. * 
  762. * @param array $actions Array of registered activity types. 
  763. */ 
  764. return apply_filters( 'bp_activity_get_types', $actions ); 
  765.  
  766. /** Favorites ****************************************************************/ 
  767.  
  768. /** 
  769. * Get a users favorite activity stream items. 
  770. * 
  771. * @since 1.2.0 
  772. * 
  773. * @param int $user_id ID of the user whose favorites are being queried. 
  774. * @return array IDs of the user's favorite activity items. 
  775. */ 
  776. function bp_activity_get_user_favorites( $user_id = 0 ) { 
  777.  
  778. // Fallback to logged in user if no user_id is passed. 
  779. if ( empty( $user_id ) ) { 
  780. $user_id = bp_displayed_user_id(); 
  781.  
  782. // Get favorites for user. 
  783. $favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true ); 
  784.  
  785. /** 
  786. * Filters the favorited activity items for a specified user. 
  787. * 
  788. * @since 1.2.0 
  789. * 
  790. * @param array $favs Array of user's favorited activity items. 
  791. */ 
  792. return apply_filters( 'bp_activity_get_user_favorites', $favs ); 
  793.  
  794. /** 
  795. * Add an activity stream item as a favorite for a user. 
  796. * 
  797. * @since 1.2.0 
  798. * 
  799. * @param int $activity_id ID of the activity item being favorited. 
  800. * @param int $user_id ID of the user favoriting the activity item. 
  801. * @return bool True on success, false on failure. 
  802. */ 
  803. function bp_activity_add_user_favorite( $activity_id, $user_id = 0 ) { 
  804.  
  805. // Favorite activity stream items are for logged in users only. 
  806. if ( ! is_user_logged_in() ) { 
  807. return false; 
  808.  
  809. // Fallback to logged in user if no user_id is passed. 
  810. if ( empty( $user_id ) ) { 
  811. $user_id = bp_loggedin_user_id(); 
  812.  
  813. $my_favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true ); 
  814. if ( empty( $my_favs ) || ! is_array( $my_favs ) ) { 
  815. $my_favs = array(); 
  816.  
  817. // Bail if the user has already favorited this activity item. 
  818. if ( in_array( $activity_id, $my_favs ) ) { 
  819. return false; 
  820.  
  821. // Add to user's favorites. 
  822. $my_favs[] = $activity_id; 
  823.  
  824. // Update the total number of users who have favorited this activity. 
  825. $fav_count = bp_activity_get_meta( $activity_id, 'favorite_count' ); 
  826. $fav_count = !empty( $fav_count ) ? (int) $fav_count + 1 : 1; 
  827.  
  828. // Update user meta. 
  829. bp_update_user_meta( $user_id, 'bp_favorite_activities', $my_favs ); 
  830.  
  831. // Update activity meta counts. 
  832. if ( bp_activity_update_meta( $activity_id, 'favorite_count', $fav_count ) ) { 
  833.  
  834. /** 
  835. * Fires if bp_activity_update_meta() for favorite_count is successful and before returning a true value for success. 
  836. * 
  837. * @since 1.2.1 
  838. * 
  839. * @param int $activity_id ID of the activity item being favorited. 
  840. * @param int $user_id ID of the user doing the favoriting. 
  841. */ 
  842. do_action( 'bp_activity_add_user_favorite', $activity_id, $user_id ); 
  843.  
  844. // Success. 
  845. return true; 
  846.  
  847. // Saving meta was unsuccessful for an unknown reason. 
  848. } else { 
  849.  
  850. /** 
  851. * Fires if bp_activity_update_meta() for favorite_count is unsuccessful and before returning a false value for failure. 
  852. * 
  853. * @since 1.5.0 
  854. * 
  855. * @param int $activity_id ID of the activity item being favorited. 
  856. * @param int $user_id ID of the user doing the favoriting. 
  857. */ 
  858. do_action( 'bp_activity_add_user_favorite_fail', $activity_id, $user_id ); 
  859.  
  860. return false; 
  861.  
  862. /** 
  863. * Remove an activity stream item as a favorite for a user. 
  864. * 
  865. * @since 1.2.0 
  866. * 
  867. * @param int $activity_id ID of the activity item being unfavorited. 
  868. * @param int $user_id ID of the user unfavoriting the activity item. 
  869. * @return bool True on success, false on failure. 
  870. */ 
  871. function bp_activity_remove_user_favorite( $activity_id, $user_id = 0 ) { 
  872.  
  873. // Favorite activity stream items are for logged in users only. 
  874. if ( ! is_user_logged_in() ) { 
  875. return false; 
  876.  
  877. // Fallback to logged in user if no user_id is passed. 
  878. if ( empty( $user_id ) ) { 
  879. $user_id = bp_loggedin_user_id(); 
  880.  
  881. $my_favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true ); 
  882. $my_favs = array_flip( (array) $my_favs ); 
  883.  
  884. // Bail if the user has not previously favorited the item. 
  885. if ( ! isset( $my_favs[ $activity_id ] ) ) { 
  886. return false; 
  887.  
  888. // Remove the fav from the user's favs. 
  889. unset( $my_favs[$activity_id] ); 
  890. $my_favs = array_unique( array_flip( $my_favs ) ); 
  891.  
  892. // Update the total number of users who have favorited this activity. 
  893. $fav_count = bp_activity_get_meta( $activity_id, 'favorite_count' ); 
  894. if ( ! empty( $fav_count ) ) { 
  895.  
  896. // Deduct from total favorites. 
  897. if ( bp_activity_update_meta( $activity_id, 'favorite_count', (int) $fav_count - 1 ) ) { 
  898.  
  899. // Update users favorites. 
  900. if ( bp_update_user_meta( $user_id, 'bp_favorite_activities', $my_favs ) ) { 
  901.  
  902. /** 
  903. * Fires if bp_update_user_meta() is successful and before returning a true value for success. 
  904. * 
  905. * @since 1.2.1 
  906. * 
  907. * @param int $activity_id ID of the activity item being unfavorited. 
  908. * @param int $user_id ID of the user doing the unfavoriting. 
  909. */ 
  910. do_action( 'bp_activity_remove_user_favorite', $activity_id, $user_id ); 
  911.  
  912. // Success. 
  913. return true; 
  914.  
  915. // Error updating. 
  916. } else { 
  917. return false; 
  918.  
  919. // Error updating favorite count. 
  920. } else { 
  921. return false; 
  922.  
  923. // Error getting favorite count. 
  924. } else { 
  925. return false; 
  926.  
  927. /** 
  928. * Check whether an activity item exists with a given content string. 
  929. * 
  930. * @since 1.1.0 
  931. * 
  932. * @param string $content The content to filter by. 
  933. * @return int|null The ID of the located activity item. Null if none is found. 
  934. */ 
  935. function bp_activity_check_exists_by_content( $content ) { 
  936.  
  937. /** 
  938. * Filters the results of the check for whether an activity item exists by specified content. 
  939. * 
  940. * @since 1.1.0 
  941. * 
  942. * @param BP_Activity_Activity $value ID of the activity if found, else null. 
  943. */ 
  944. return apply_filters( 'bp_activity_check_exists_by_content', BP_Activity_Activity::check_exists_by_content( $content ) ); 
  945.  
  946. /** 
  947. * Retrieve the last time activity was updated. 
  948. * 
  949. * @since 1.0.0 
  950. * 
  951. * @return string Date last updated. 
  952. */ 
  953. function bp_activity_get_last_updated() { 
  954.  
  955. /** 
  956. * Filters the value for the last updated time for an activity item. 
  957. * 
  958. * @since 1.1.0 
  959. * 
  960. * @param BP_Activity_Activity $last_updated Date last updated. 
  961. */ 
  962. return apply_filters( 'bp_activity_get_last_updated', BP_Activity_Activity::get_last_updated() ); 
  963.  
  964. /** 
  965. * Retrieve the number of favorite activity stream items a user has. 
  966. * 
  967. * @since 1.2.0 
  968. * 
  969. * @param int $user_id ID of the user whose favorite count is being requested. 
  970. * @return int Total favorite count for the user. 
  971. */ 
  972. function bp_activity_total_favorites_for_user( $user_id = 0 ) { 
  973.  
  974. // Fallback on displayed user, and then logged in user. 
  975. if ( empty( $user_id ) ) { 
  976. $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id(); 
  977.  
  978. return BP_Activity_Activity::total_favorite_count( $user_id ); 
  979.  
  980. /** Meta *********************************************************************/ 
  981.  
  982. /** 
  983. * Delete a meta entry from the DB for an activity stream item. 
  984. * 
  985. * @since 1.2.0 
  986. * 
  987. * @global object $wpdb WordPress database access object. 
  988. * 
  989. * @param int $activity_id ID of the activity item whose metadata is being deleted. 
  990. * @param string $meta_key Optional. The key of the metadata being deleted. If 
  991. * omitted, all metadata associated with the activity 
  992. * item will be deleted. 
  993. * @param string $meta_value Optional. If present, the metadata will only be 
  994. * deleted if the meta_value matches this parameter. 
  995. * @param bool $delete_all Optional. If true, delete matching metadata entries 
  996. * for all objects, ignoring the specified object_id. Otherwise,  
  997. * only delete matching metadata entries for the specified 
  998. * activity item. Default: false. 
  999. * @return bool True on success, false on failure. 
  1000. */ 
  1001. function bp_activity_delete_meta( $activity_id, $meta_key = '', $meta_value = '', $delete_all = false ) { 
  1002.  
  1003. // Legacy - if no meta_key is passed, delete all for the item. 
  1004. if ( empty( $meta_key ) ) { 
  1005. $all_meta = bp_activity_get_meta( $activity_id ); 
  1006. $keys = ! empty( $all_meta ) ? array_keys( $all_meta ) : array(); 
  1007.  
  1008. // With no meta_key, ignore $delete_all. 
  1009. $delete_all = false; 
  1010. } else { 
  1011. $keys = array( $meta_key ); 
  1012.  
  1013. $retval = true; 
  1014.  
  1015. add_filter( 'query', 'bp_filter_metaid_column_name' ); 
  1016. foreach ( $keys as $key ) { 
  1017. $retval = delete_metadata( 'activity', $activity_id, $key, $meta_value, $delete_all ); 
  1018. remove_filter( 'query', 'bp_filter_metaid_column_name' ); 
  1019.  
  1020. return $retval; 
  1021.  
  1022. /** 
  1023. * Get metadata for a given activity item. 
  1024. * 
  1025. * @since 1.2.0 
  1026. * 
  1027. * @param int $activity_id ID of the activity item whose metadata is being requested. 
  1028. * @param string $meta_key Optional. If present, only the metadata matching 
  1029. * that meta key will be returned. Otherwise, all metadata for the 
  1030. * activity item will be fetched. 
  1031. * @param bool $single Optional. If true, return only the first value of the 
  1032. * specified meta_key. This parameter has no effect if meta_key is not 
  1033. * specified. Default: true. 
  1034. * @return mixed The meta value(s) being requested. 
  1035. */ 
  1036. function bp_activity_get_meta( $activity_id = 0, $meta_key = '', $single = true ) { 
  1037. add_filter( 'query', 'bp_filter_metaid_column_name' ); 
  1038. $retval = get_metadata( 'activity', $activity_id, $meta_key, $single ); 
  1039. remove_filter( 'query', 'bp_filter_metaid_column_name' ); 
  1040.  
  1041. /** 
  1042. * Filters the metadata for a specified activity item. 
  1043. * 
  1044. * @since 1.5.0 
  1045. * 
  1046. * @param mixed $retval The meta values for the activity item. 
  1047. * @param int $activity_id ID of the activity item. 
  1048. * @param string $meta_key Meta key for the value being requested. 
  1049. * @param bool $single Whether to return one matched meta key row or all. 
  1050. */ 
  1051. return apply_filters( 'bp_activity_get_meta', $retval, $activity_id, $meta_key, $single ); 
  1052.  
  1053. /** 
  1054. * Update a piece of activity meta. 
  1055. * 
  1056. * @since 1.2.0 
  1057. * 
  1058. * @param int $activity_id ID of the activity item whose metadata is being updated. 
  1059. * @param string $meta_key Key of the metadata being updated. 
  1060. * @param mixed $meta_value Value to be set. 
  1061. * @param mixed $prev_value Optional. If specified, only update existing metadata entries 
  1062. * with the specified value. Otherwise, update all entries. 
  1063. * @return bool|int Returns false on failure. On successful update of existing 
  1064. * metadata, returns true. On successful creation of new metadata,  
  1065. * returns the integer ID of the new metadata row. 
  1066. */ 
  1067. function bp_activity_update_meta( $activity_id, $meta_key, $meta_value, $prev_value = '' ) { 
  1068. add_filter( 'query', 'bp_filter_metaid_column_name' ); 
  1069. $retval = update_metadata( 'activity', $activity_id, $meta_key, $meta_value, $prev_value ); 
  1070. remove_filter( 'query', 'bp_filter_metaid_column_name' ); 
  1071.  
  1072. return $retval; 
  1073.  
  1074. /** 
  1075. * Add a piece of activity metadata. 
  1076. * 
  1077. * @since 2.0.0 
  1078. * 
  1079. * @param int $activity_id ID of the activity item. 
  1080. * @param string $meta_key Metadata key. 
  1081. * @param mixed $meta_value Metadata value. 
  1082. * @param bool $unique Optional. Whether to enforce a single metadata value for the 
  1083. * given key. If true, and the object already has a value for 
  1084. * the key, no change will be made. Default: false. 
  1085. * @return int|bool The meta ID on successful update, false on failure. 
  1086. */ 
  1087. function bp_activity_add_meta( $activity_id, $meta_key, $meta_value, $unique = false ) { 
  1088. add_filter( 'query', 'bp_filter_metaid_column_name' ); 
  1089. $retval = add_metadata( 'activity', $activity_id, $meta_key, $meta_value, $unique ); 
  1090. remove_filter( 'query', 'bp_filter_metaid_column_name' ); 
  1091.  
  1092. return $retval; 
  1093.  
  1094. /** Clean up *****************************************************************/ 
  1095.  
  1096. /** 
  1097. * Completely remove a user's activity data. 
  1098. * 
  1099. * @since 1.5.0 
  1100. * 
  1101. * @param int $user_id ID of the user whose activity is being deleted. 
  1102. * @return bool 
  1103. */ 
  1104. function bp_activity_remove_all_user_data( $user_id = 0 ) { 
  1105.  
  1106. // Do not delete user data unless a logged in user says so. 
  1107. if ( empty( $user_id ) || ! is_user_logged_in() ) { 
  1108. return false; 
  1109.  
  1110. // Clear the user's activity from the sitewide stream and clear their activity tables. 
  1111. bp_activity_delete( array( 'user_id' => $user_id ) ); 
  1112.  
  1113. // Remove any usermeta. 
  1114. bp_delete_user_meta( $user_id, 'bp_latest_update' ); 
  1115. bp_delete_user_meta( $user_id, 'bp_favorite_activities' ); 
  1116.  
  1117. // Execute additional code 
  1118. do_action( 'bp_activity_remove_data', $user_id ); // Deprecated! Do not use! 
  1119.  
  1120. /** 
  1121. * Fires after the removal of all of a user's activity data. 
  1122. * 
  1123. * @since 1.5.0 
  1124. * 
  1125. * @param int $user_id ID of the user being deleted. 
  1126. */ 
  1127. do_action( 'bp_activity_remove_all_user_data', $user_id ); 
  1128. add_action( 'wpmu_delete_user', 'bp_activity_remove_all_user_data' ); 
  1129. add_action( 'delete_user', 'bp_activity_remove_all_user_data' ); 
  1130.  
  1131. /** 
  1132. * Mark all of the user's activity as spam. 
  1133. * 
  1134. * @since 1.6.0 
  1135. * 
  1136. * @global object $wpdb WordPress database access object. 
  1137. * 
  1138. * @param int $user_id ID of the user whose activity is being spammed. 
  1139. * @return bool 
  1140. */ 
  1141. function bp_activity_spam_all_user_data( $user_id = 0 ) { 
  1142. global $wpdb; 
  1143.  
  1144. // Do not delete user data unless a logged in user says so. 
  1145. if ( empty( $user_id ) || ! is_user_logged_in() ) { 
  1146. return false; 
  1147.  
  1148. // Get all the user's activities. 
  1149. $activities = bp_activity_get( array( 
  1150. 'display_comments' => 'stream',  
  1151. 'filter' => array( 'user_id' => $user_id ),  
  1152. 'show_hidden' => true 
  1153. ) ); 
  1154.  
  1155. $bp = buddypress(); 
  1156.  
  1157. // Mark each as spam. 
  1158. foreach ( (array) $activities['activities'] as $activity ) { 
  1159.  
  1160. // Create an activity object. 
  1161. $activity_obj = new BP_Activity_Activity; 
  1162. foreach ( $activity as $k => $v ) { 
  1163. $activity_obj->$k = $v; 
  1164.  
  1165. // Mark as spam. 
  1166. bp_activity_mark_as_spam( $activity_obj ); 
  1167.  
  1168. /** 
  1169. * If Akismet is present, update the activity history meta. 
  1170. * 
  1171. * This is usually taken care of when BP_Activity_Activity::save() happens, but 
  1172. * as we're going to be updating all the activity statuses directly, for efficiency,  
  1173. * we need to update manually. 
  1174. */ 
  1175. if ( ! empty( $bp->activity->akismet ) ) { 
  1176. $bp->activity->akismet->update_activity_spam_meta( $activity_obj ); 
  1177.  
  1178. // Tidy up. 
  1179. unset( $activity_obj ); 
  1180.  
  1181. // Mark all of this user's activities as spam. 
  1182. $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET is_spam = 1 WHERE user_id = %d", $user_id ) ); 
  1183.  
  1184. /** 
  1185. * Fires after all activity data from a user has been marked as spam. 
  1186. * 
  1187. * @since 1.6.0 
  1188. * 
  1189. * @param int $user_id ID of the user whose activity is being marked as spam. 
  1190. * @param array $activities Array of activity items being marked as spam. 
  1191. */ 
  1192. do_action( 'bp_activity_spam_all_user_data', $user_id, $activities['activities'] ); 
  1193. add_action( 'bp_make_spam_user', 'bp_activity_spam_all_user_data' ); 
  1194.  
  1195. /** 
  1196. * Mark all of the user's activity as ham (not spam). 
  1197. * 
  1198. * @since 1.6.0 
  1199. * 
  1200. * @global object $wpdb WordPress database access object. 
  1201. * 
  1202. * @param int $user_id ID of the user whose activity is being hammed. 
  1203. * @return bool 
  1204. */ 
  1205. function bp_activity_ham_all_user_data( $user_id = 0 ) { 
  1206. global $wpdb; 
  1207.  
  1208. // Do not delete user data unless a logged in user says so. 
  1209. if ( empty( $user_id ) || ! is_user_logged_in() ) { 
  1210. return false; 
  1211.  
  1212. // Get all the user's activities. 
  1213. $activities = bp_activity_get( array( 
  1214. 'display_comments' => 'stream',  
  1215. 'filter' => array( 'user_id' => $user_id ),  
  1216. 'show_hidden' => true,  
  1217. 'spam' => 'all' 
  1218. ) ); 
  1219.  
  1220. $bp = buddypress(); 
  1221.  
  1222. // Mark each as not spam. 
  1223. foreach ( (array) $activities['activities'] as $activity ) { 
  1224.  
  1225. // Create an activity object. 
  1226. $activity_obj = new BP_Activity_Activity; 
  1227. foreach ( $activity as $k => $v ) { 
  1228. $activity_obj->$k = $v; 
  1229.  
  1230. // Mark as not spam. 
  1231. bp_activity_mark_as_ham( $activity_obj ); 
  1232.  
  1233. /** 
  1234. * If Akismet is present, update the activity history meta. 
  1235. * 
  1236. * This is usually taken care of when BP_Activity_Activity::save() happens, but 
  1237. * as we're going to be updating all the activity statuses directly, for efficiency,  
  1238. * we need to update manually. 
  1239. */ 
  1240. if ( ! empty( $bp->activity->akismet ) ) { 
  1241. $bp->activity->akismet->update_activity_ham_meta( $activity_obj ); 
  1242.  
  1243. // Tidy up. 
  1244. unset( $activity_obj ); 
  1245.  
  1246. // Mark all of this user's activities as not spam. 
  1247. $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET is_spam = 0 WHERE user_id = %d", $user_id ) ); 
  1248.  
  1249. /** 
  1250. * Fires after all activity data from a user has been marked as ham. 
  1251. * 
  1252. * @since 1.6.0 
  1253. * 
  1254. * @param int $user_id ID of the user whose activity is being marked as ham. 
  1255. * @param array $activities Array of activity items being marked as ham. 
  1256. */ 
  1257. do_action( 'bp_activity_ham_all_user_data', $user_id, $activities['activities'] ); 
  1258. add_action( 'bp_make_ham_user', 'bp_activity_ham_all_user_data' ); 
  1259.  
  1260. /** 
  1261. * Register the activity stream actions for updates. 
  1262. * 
  1263. * @since 1.6.0 
  1264. */ 
  1265. function bp_activity_register_activity_actions() { 
  1266. $bp = buddypress(); 
  1267.  
  1268. bp_activity_set_action( 
  1269. $bp->activity->id,  
  1270. 'activity_update',  
  1271. __( 'Posted a status update', 'buddypress' ),  
  1272. 'bp_activity_format_activity_action_activity_update',  
  1273. __( 'Updates', 'buddypress' ),  
  1274. array( 'activity', 'group', 'member', 'member_groups' ) 
  1275. ); 
  1276.  
  1277. bp_activity_set_action( 
  1278. $bp->activity->id,  
  1279. 'activity_comment',  
  1280. __( 'Replied to a status update', 'buddypress' ),  
  1281. 'bp_activity_format_activity_action_activity_comment',  
  1282. __( 'Activity Comments', 'buddypress' ) 
  1283. ); 
  1284.  
  1285. /** 
  1286. * Fires at the end of the activity actions registration. 
  1287. * 
  1288. * Allows plugin authors to add their own activity actions alongside the core actions. 
  1289. * 
  1290. * @since 1.6.0 
  1291. */ 
  1292. do_action( 'bp_activity_register_activity_actions' ); 
  1293.  
  1294. // Backpat. Don't use this. 
  1295. do_action( 'updates_register_activity_actions' ); 
  1296. add_action( 'bp_register_activity_actions', 'bp_activity_register_activity_actions' ); 
  1297.  
  1298. /** 
  1299. * Generate an activity action string for an activity item. 
  1300. * 
  1301. * @since 2.0.0 
  1302. * 
  1303. * @param object $activity Activity data object. 
  1304. * @return string|bool Returns false if no callback is found, otherwise returns 
  1305. * the formatted action string. 
  1306. */ 
  1307. function bp_activity_generate_action_string( $activity ) { 
  1308.  
  1309. // Check for valid input. 
  1310. if ( empty( $activity->component ) || empty( $activity->type ) ) { 
  1311. return false; 
  1312.  
  1313. // Check for registered format callback. 
  1314. $actions = bp_activity_get_actions(); 
  1315. if ( empty( $actions->{$activity->component}->{$activity->type}['format_callback'] ) ) { 
  1316. return false; 
  1317.  
  1318. // We apply the format_callback as a filter. 
  1319. add_filter( 'bp_activity_generate_action_string', $actions->{$activity->component}->{$activity->type}['format_callback'], 10, 2 ); 
  1320.  
  1321. /** 
  1322. * Filters the string for the activity action being returned. 
  1323. * 
  1324. * @since 2.0.0 
  1325. * 
  1326. * @param BP_Activity_Activity $action Action string being requested. 
  1327. * @param BP_Activity_Activity $activity Activity item object. 
  1328. */ 
  1329. $action = apply_filters( 'bp_activity_generate_action_string', $activity->action, $activity ); 
  1330.  
  1331. // Remove the filter for future activity items. 
  1332. remove_filter( 'bp_activity_generate_action_string', $actions->{$activity->component}->{$activity->type}['format_callback'], 10, 2 ); 
  1333.  
  1334. return $action; 
  1335.  
  1336. /** 
  1337. * Format 'activity_update' activity actions. 
  1338. * 
  1339. * @since 2.0.0 
  1340. * 
  1341. * @param string $action Static activity action. 
  1342. * @param object $activity Activity data object. 
  1343. * @return string $action 
  1344. */ 
  1345. function bp_activity_format_activity_action_activity_update( $action, $activity ) { 
  1346. $action = sprintf( __( '%s posted an update', 'buddypress' ), bp_core_get_userlink( $activity->user_id ) ); 
  1347.  
  1348. /** 
  1349. * Filters the formatted activity action update string. 
  1350. * 
  1351. * @since 1.2.0 
  1352. * 
  1353. * @param string $action Activity action string value. 
  1354. * @param BP_Activity_Activity $activity Activity item object. 
  1355. */ 
  1356. return apply_filters( 'bp_activity_new_update_action', $action, $activity ); 
  1357.  
  1358. /** 
  1359. * Format 'activity_comment' activity actions. 
  1360. * 
  1361. * @since 2.0.0 
  1362. * 
  1363. * @param string $action Static activity action. 
  1364. * @param object $activity Activity data object. 
  1365. * @return string $action 
  1366. */ 
  1367. function bp_activity_format_activity_action_activity_comment( $action, $activity ) { 
  1368. $action = sprintf( __( '%s posted a new activity comment', 'buddypress' ), bp_core_get_userlink( $activity->user_id ) ); 
  1369.  
  1370. /** 
  1371. * Filters the formatted activity action comment string. 
  1372. * 
  1373. * @since 1.2.0 
  1374. * 
  1375. * @param string $action Activity action string value. 
  1376. * @param BP_Activity_Activity $activity Activity item object. 
  1377. */ 
  1378. return apply_filters( 'bp_activity_comment_action', $action, $activity ); 
  1379.  
  1380. /** 
  1381. * Format activity action strings for custom post types. 
  1382. * 
  1383. * @since 2.2.0 
  1384. * 
  1385. * @param string $action Static activity action. 
  1386. * @param object $activity Activity data object. 
  1387. * @return string $action 
  1388. */ 
  1389. function bp_activity_format_activity_action_custom_post_type_post( $action, $activity ) { 
  1390. $bp = buddypress(); 
  1391.  
  1392. // Fetch all the tracked post types once. 
  1393. if ( empty( $bp->activity->track ) ) { 
  1394. $bp->activity->track = bp_activity_get_post_types_tracking_args(); 
  1395.  
  1396. if ( empty( $activity->type ) || empty( $bp->activity->track[ $activity->type ] ) ) { 
  1397. return $action; 
  1398.  
  1399. $user_link = bp_core_get_userlink( $activity->user_id ); 
  1400. $blog_url = get_home_url( $activity->item_id ); 
  1401.  
  1402. if ( empty( $activity->post_url ) ) { 
  1403. $post_url = add_query_arg( 'p', $activity->secondary_item_id, trailingslashit( $blog_url ) ); 
  1404. } else { 
  1405. $post_url = $activity->post_url; 
  1406.  
  1407. if ( is_multisite() ) { 
  1408. $blog_link = '<a href="' . esc_url( $blog_url ) . '">' . get_blog_option( $activity->item_id, 'blogname' ) . '</a>'; 
  1409.  
  1410. if ( ! empty( $bp->activity->track[ $activity->type ]->new_post_type_action_ms ) ) { 
  1411. $action = sprintf( $bp->activity->track[ $activity->type ]->new_post_type_action_ms, $user_link, $post_url, $blog_link ); 
  1412. } else { 
  1413. $action = sprintf( _x( '%1$s wrote a new <a href="%2$s">item</a>, on the site %3$s', 'Activity Custom Post Type post action', 'buddypress' ), $user_link, esc_url( $post_url ), $blog_link ); 
  1414. } else { 
  1415. if ( ! empty( $bp->activity->track[ $activity->type ]->new_post_type_action ) ) { 
  1416. $action = sprintf( $bp->activity->track[ $activity->type ]->new_post_type_action, $user_link, $post_url ); 
  1417. } else { 
  1418. $action = sprintf( _x( '%1$s wrote a new <a href="%2$s">item</a>', 'Activity Custom Post Type post action', 'buddypress' ), $user_link, esc_url( $post_url ) ); 
  1419.  
  1420. /** 
  1421. * Filters the formatted custom post type activity post action string. 
  1422. * 
  1423. * @since 2.2.0 
  1424. * 
  1425. * @param string $action Activity action string value. 
  1426. * @param BP_Activity_Activity $activity Activity item object. 
  1427. */ 
  1428. return apply_filters( 'bp_activity_custom_post_type_post_action', $action, $activity ); 
  1429.  
  1430. /** 
  1431. * Format activity action strings for custom post types comments. 
  1432. * 
  1433. * @since 2.5.0 
  1434. * 
  1435. * @param string $action Static activity action. 
  1436. * @param object $activity Activity data object. 
  1437. * 
  1438. * @return string 
  1439. */ 
  1440. function bp_activity_format_activity_action_custom_post_type_comment( $action, $activity ) { 
  1441. $bp = buddypress(); 
  1442.  
  1443. // Fetch all the tracked post types once. 
  1444. if ( empty( $bp->activity->track ) ) { 
  1445. $bp->activity->track = bp_activity_get_post_types_tracking_args(); 
  1446.  
  1447. if ( empty( $activity->type ) || empty( $bp->activity->track[ $activity->type ] ) ) { 
  1448. return $action; 
  1449.  
  1450. $user_link = bp_core_get_userlink( $activity->user_id ); 
  1451.  
  1452. if ( is_multisite() ) { 
  1453. $blog_link = '<a href="' . esc_url( get_home_url( $activity->item_id ) ) . '">' . get_blog_option( $activity->item_id, 'blogname' ) . '</a>'; 
  1454.  
  1455. if ( ! empty( $bp->activity->track[ $activity->type ]->new_post_type_comment_action_ms ) ) { 
  1456. $action = sprintf( $bp->activity->track[ $activity->type ]->new_post_type_comment_action_ms, $user_link, $activity->primary_link, $blog_link ); 
  1457. } else { 
  1458. $action = sprintf( _x( '%1$s commented on the <a href="%2$s">item</a>, on the site %3$s', 'Activity Custom Post Type comment action', 'buddypress' ), $user_link, $activity->primary_link, $blog_link ); 
  1459. } else { 
  1460. if ( ! empty( $bp->activity->track[ $activity->type ]->new_post_type_comment_action ) ) { 
  1461. $action = sprintf( $bp->activity->track[ $activity->type ]->new_post_type_comment_action, $user_link, $activity->primary_link ); 
  1462. } else { 
  1463. $action = sprintf( _x( '%1$s commented on the <a href="%2$s">item</a>', 'Activity Custom Post Type post comment action', 'buddypress' ), $user_link, $activity->primary_link ); 
  1464.  
  1465. /** 
  1466. * Filters the formatted custom post type activity comment action string. 
  1467. * 
  1468. * @since 2.5.0 
  1469. * 
  1470. * @param string $action Activity action string value. 
  1471. * @param BP_Activity_Activity $activity Activity item object. 
  1472. */ 
  1473. return apply_filters( 'bp_activity_custom_post_type_comment_action', $action, $activity ); 
  1474.  
  1475. /** 
  1476. * Business functions are where all the magic happens in BuddyPress. They will 
  1477. * handle the actual saving or manipulation of information. Usually they will 
  1478. * hand off to a database class for data access, then return 
  1479. * true or false on success or failure. 
  1480. */ 
  1481.  
  1482. /** 
  1483. * Retrieve an activity or activities. 
  1484. * 
  1485. * The bp_activity_get() function shares all arguments with BP_Activity_Activity::get(). 
  1486. * The following is a list of bp_activity_get() parameters that have different 
  1487. * default values from BP_Activity_Activity::get() (value in parentheses is 
  1488. * the default for the bp_activity_get()). 
  1489. * - 'per_page' (false) 
  1490. * 
  1491. * @since 1.2.0 
  1492. * @since 2.4.0 Introduced the `$fields` parameter. 
  1493. * 
  1494. * @see BP_Activity_Activity::get() For more information on accepted arguments 
  1495. * and the format of the returned value. 
  1496. * 
  1497. * @param array|string $args See BP_Activity_Activity::get() for description. 
  1498. * @return array $activity See BP_Activity_Activity::get() for description. 
  1499. */ 
  1500. function bp_activity_get( $args = '' ) { 
  1501.  
  1502. $r = bp_parse_args( $args, array( 
  1503. 'max' => false, // Maximum number of results to return. 
  1504. 'fields' => 'all',  
  1505. 'page' => 1, // Page 1 without a per_page will result in no pagination. 
  1506. 'per_page' => false, // results per page 
  1507. 'sort' => 'DESC', // sort ASC or DESC 
  1508. 'display_comments' => false, // False for no comments. 'stream' for within stream display, 'threaded' for below each activity item. 
  1509.  
  1510. 'search_terms' => false, // Pass search terms as a string 
  1511. 'meta_query' => false, // Filter by activity meta. See WP_Meta_Query for format 
  1512. 'date_query' => false, // Filter by date. See first parameter of WP_Date_Query for format. 
  1513. 'filter_query' => false,  
  1514. 'show_hidden' => false, // Show activity items that are hidden site-wide? 
  1515. 'exclude' => false, // Comma-separated list of activity IDs to exclude. 
  1516. 'in' => false, // Comma-separated list or array of activity IDs to which you 
  1517. // want to limit the query. 
  1518. 'spam' => 'ham_only', // 'ham_only' (default), 'spam_only' or 'all'. 
  1519. 'update_meta_cache' => true,  
  1520. 'count_total' => false,  
  1521. 'scope' => false,  
  1522.  
  1523. /** 
  1524. * Pass filters as an array -- all filter items can be multiple values comma separated: 
  1525. * array( 
  1526. * 'user_id' => false, // User ID to filter on. 
  1527. * 'object' => false, // Object to filter on e.g. groups, profile, status, friends. 
  1528. * 'action' => false, // Action to filter on e.g. activity_update, profile_updated. 
  1529. * 'primary_id' => false, // Object ID to filter on e.g. a group_id or forum_id or blog_id etc. 
  1530. * 'secondary_id' => false, // Secondary object ID to filter on e.g. a post_id. 
  1531. * ); 
  1532. */ 
  1533. 'filter' => array() 
  1534. ), 'activity_get' ); 
  1535.  
  1536. $activity = BP_Activity_Activity::get( array( 
  1537. 'page' => $r['page'],  
  1538. 'per_page' => $r['per_page'],  
  1539. 'max' => $r['max'],  
  1540. 'sort' => $r['sort'],  
  1541. 'search_terms' => $r['search_terms'],  
  1542. 'meta_query' => $r['meta_query'],  
  1543. 'date_query' => $r['date_query'],  
  1544. 'filter_query' => $r['filter_query'],  
  1545. 'filter' => $r['filter'],  
  1546. 'scope' => $r['scope'],  
  1547. 'display_comments' => $r['display_comments'],  
  1548. 'show_hidden' => $r['show_hidden'],  
  1549. 'exclude' => $r['exclude'],  
  1550. 'in' => $r['in'],  
  1551. 'spam' => $r['spam'],  
  1552. 'update_meta_cache' => $r['update_meta_cache'],  
  1553. 'count_total' => $r['count_total'],  
  1554. 'fields' => $r['fields'],  
  1555. ) ); 
  1556.  
  1557. /** 
  1558. * Filters the requested activity item(s). 
  1559. * 
  1560. * @since 1.2.0 
  1561. * 
  1562. * @param BP_Activity_Activity $activity Requested activity object. 
  1563. * @param array $r Arguments used for the activity query. 
  1564. */ 
  1565. return apply_filters_ref_array( 'bp_activity_get', array( &$activity, &$r ) ); 
  1566.  
  1567. /** 
  1568. * Fetch specific activity items. 
  1569. * 
  1570. * @since 1.2.0 
  1571. * 
  1572. * @see BP_Activity_Activity::get() For more information on accepted arguments. 
  1573. * 
  1574. * @param array|string $args { 
  1575. * All arguments and defaults are shared with BP_Activity_Activity::get(),  
  1576. * except for the following: 
  1577. * @type string|int|array Single activity ID, comma-separated list of IDs,  
  1578. * or array of IDs. 
  1579. * } 
  1580. * @return array $activity See BP_Activity_Activity::get() for description. 
  1581. */ 
  1582. function bp_activity_get_specific( $args = '' ) { 
  1583.  
  1584. $r = bp_parse_args( $args, array( 
  1585. 'activity_ids' => false, // A single activity_id or array of IDs. 
  1586. 'display_comments' => false, // True or false to display threaded comments for these specific activity items. 
  1587. 'max' => false, // Maximum number of results to return. 
  1588. 'page' => 1, // Page 1 without a per_page will result in no pagination. 
  1589. 'per_page' => false, // Results per page. 
  1590. 'show_hidden' => true, // When fetching specific items, show all. 
  1591. 'sort' => 'DESC', // Sort ASC or DESC 
  1592. 'spam' => 'ham_only', // Retrieve items marked as spam. 
  1593. 'update_meta_cache' => true,  
  1594. ) ); 
  1595.  
  1596. $get_args = array( 
  1597. 'display_comments' => $r['display_comments'],  
  1598. 'in' => $r['activity_ids'],  
  1599. 'max' => $r['max'],  
  1600. 'page' => $r['page'],  
  1601. 'per_page' => $r['per_page'],  
  1602. 'show_hidden' => $r['show_hidden'],  
  1603. 'sort' => $r['sort'],  
  1604. 'spam' => $r['spam'],  
  1605. 'update_meta_cache' => $r['update_meta_cache'],  
  1606. ); 
  1607.  
  1608. /** 
  1609. * Filters the requested specific activity item. 
  1610. * 
  1611. * @since 1.2.0 
  1612. * 
  1613. * @param BP_Activity_Activity $activity Requested activity object. 
  1614. * @param array $args Original passed in arguments. 
  1615. * @param array $get_args Constructed arguments used with request. 
  1616. */ 
  1617. return apply_filters( 'bp_activity_get_specific', BP_Activity_Activity::get( $get_args ), $args, $get_args ); 
  1618.  
  1619. /** 
  1620. * Add an activity item. 
  1621. * 
  1622. * @since 1.1.0 
  1623. * @since 2.6.0 Added 'error_type' parameter to $args. 
  1624. * 
  1625. * @param array|string $args { 
  1626. * An array of arguments. 
  1627. * @type int|bool $id Pass an activity ID to update an existing item, or 
  1628. * false to create a new item. Default: false. 
  1629. * @type string $action Optional. The activity action/description, typically 
  1630. * something like "Joe posted an update". Values passed to this param 
  1631. * will be stored in the database and used as a fallback for when the 
  1632. * activity item's format_callback cannot be found (eg, when the 
  1633. * component is disabled). As long as you have registered a 
  1634. * format_callback for your $type, it is unnecessary to include this 
  1635. * argument - BP will generate it automatically. 
  1636. * See {@link bp_activity_set_action()}. 
  1637. * @type string $content Optional. The content of the activity item. 
  1638. * @type string $component The unique name of the component associated with 
  1639. * the activity item - 'groups', 'profile', etc. 
  1640. * @type string $type The specific activity type, used for directory 
  1641. * filtering. 'new_blog_post', 'activity_update', etc. 
  1642. * @type string $primary_link Optional. The URL for this item, as used in 
  1643. * RSS feeds. Defaults to the URL for this activity 
  1644. * item's permalink page. 
  1645. * @type int|bool $user_id Optional. The ID of the user associated with the activity 
  1646. * item. May be set to false or 0 if the item is not related 
  1647. * to any user. Default: the ID of the currently logged-in user. 
  1648. * @type int $item_id Optional. The ID of the associated item. 
  1649. * @type int $secondary_item_id Optional. The ID of a secondary associated item. 
  1650. * @type string $date_recorded Optional. The GMT time, in Y-m-d h:i:s format, when 
  1651. * the item was recorded. Defaults to the current time. 
  1652. * @type bool $hide_sitewide Should the item be hidden on sitewide streams? 
  1653. * Default: false. 
  1654. * @type bool $is_spam Should the item be marked as spam? Default: false. 
  1655. * @type string $error_type Optional. Error type. Either 'bool' or 'wp_error'. Default: 'bool'. 
  1656. * } 
  1657. * @return int|bool The ID of the activity on success. False on error. 
  1658. */ 
  1659. function bp_activity_add( $args = '' ) { 
  1660.  
  1661. $r = bp_parse_args( $args, array( 
  1662. 'id' => false, // Pass an existing activity ID to update an existing entry. 
  1663. 'action' => '', // The activity action - e.g. "Jon Doe posted an update" 
  1664. 'content' => '', // Optional: The content of the activity item e.g. "BuddyPress is awesome guys!" 
  1665. 'component' => false, // The name/ID of the component e.g. groups, profile, mycomponent. 
  1666. 'type' => false, // The activity type e.g. activity_update, profile_updated. 
  1667. 'primary_link' => '', // Optional: The primary URL for this item in RSS feeds (defaults to activity permalink). 
  1668. 'user_id' => bp_loggedin_user_id(), // Optional: The user to record the activity for, can be false if this activity is not for a user. 
  1669. 'item_id' => false, // Optional: The ID of the specific item being recorded, e.g. a blog_id. 
  1670. 'secondary_item_id' => false, // Optional: A second ID used to further filter e.g. a comment_id. 
  1671. 'recorded_time' => bp_core_current_time(), // The GMT time that this activity was recorded. 
  1672. 'hide_sitewide' => false, // Should this be hidden on the sitewide activity stream? 
  1673. 'is_spam' => false, // Is this activity item to be marked as spam? 
  1674. 'error_type' => 'bool' 
  1675. ), 'activity_add' ); 
  1676.  
  1677. // Make sure we are backwards compatible. 
  1678. if ( empty( $r['component'] ) && !empty( $r['component_name'] ) ) { 
  1679. $r['component'] = $r['component_name']; 
  1680.  
  1681. if ( empty( $r['type'] ) && !empty( $r['component_action'] ) ) { 
  1682. $r['type'] = $r['component_action']; 
  1683.  
  1684. // Setup activity to be added. 
  1685. $activity = new BP_Activity_Activity( $r['id'] ); 
  1686. $activity->user_id = $r['user_id']; 
  1687. $activity->component = $r['component']; 
  1688. $activity->type = $r['type']; 
  1689. $activity->content = $r['content']; 
  1690. $activity->primary_link = $r['primary_link']; 
  1691. $activity->item_id = $r['item_id']; 
  1692. $activity->secondary_item_id = $r['secondary_item_id']; 
  1693. $activity->date_recorded = $r['recorded_time']; 
  1694. $activity->hide_sitewide = $r['hide_sitewide']; 
  1695. $activity->is_spam = $r['is_spam']; 
  1696. $activity->error_type = $r['error_type']; 
  1697. $activity->action = ! empty( $r['action'] ) 
  1698. ? $r['action'] 
  1699. : bp_activity_generate_action_string( $activity ); 
  1700.  
  1701. $save = $activity->save(); 
  1702.  
  1703. if ( 'wp_error' === $r['error_type'] && is_wp_error( $save ) ) { 
  1704. return $save; 
  1705. } elseif ('bool' === $r['error_type'] && false === $save ) { 
  1706. return false; 
  1707.  
  1708. // If this is an activity comment, rebuild the tree. 
  1709. if ( 'activity_comment' === $activity->type ) { 
  1710. // Also clear the comment cache for the parent activity ID. 
  1711. wp_cache_delete( $activity->item_id, 'bp_activity_comments' ); 
  1712.  
  1713. BP_Activity_Activity::rebuild_activity_comment_tree( $activity->item_id ); 
  1714.  
  1715. wp_cache_delete( 'bp_activity_sitewide_front', 'bp' ); 
  1716.  
  1717. /** 
  1718. * Fires at the end of the execution of adding a new activity item, before returning the new activity item ID. 
  1719. * 
  1720. * @since 1.1.0 
  1721. * 
  1722. * @param array $r Array of parsed arguments for the activity item being added. 
  1723. */ 
  1724. do_action( 'bp_activity_add', $r ); 
  1725.  
  1726. return $activity->id; 
  1727.  
  1728. /** 
  1729. * Post an activity update. 
  1730. * 
  1731. * @since 1.2.0 
  1732. * 
  1733. * @param array|string $args { 
  1734. * @type string $content The content of the activity update. 
  1735. * @type int $user_id Optional. Defaults to the logged-in user. 
  1736. * @type string $error_type Optional. Error type to return. Either 'bool' or 'wp_error'. Defaults to 
  1737. * 'bool' for boolean. 'wp_error' will return a WP_Error object. 
  1738. * } 
  1739. * @return int|bool|WP_Error $activity_id The activity id on success. On failure, either boolean false or WP_Error 
  1740. * object depending on the 'error_type' $args parameter. 
  1741. */ 
  1742. function bp_activity_post_update( $args = '' ) { 
  1743.  
  1744. $r = wp_parse_args( $args, array( 
  1745. 'content' => false,  
  1746. 'user_id' => bp_loggedin_user_id(),  
  1747. 'error_type' => 'bool',  
  1748. ) ); 
  1749.  
  1750. if ( empty( $r['content'] ) || !strlen( trim( $r['content'] ) ) ) { 
  1751. return false; 
  1752.  
  1753. if ( bp_is_user_inactive( $r['user_id'] ) ) { 
  1754. return false; 
  1755.  
  1756. // Record this on the user's profile. 
  1757. $activity_content = $r['content']; 
  1758. $primary_link = bp_core_get_userlink( $r['user_id'], false, true ); 
  1759.  
  1760. /** 
  1761. * Filters the new activity content for current activity item. 
  1762. * 
  1763. * @since 1.2.0 
  1764. * 
  1765. * @param string $activity_content Activity content posted by user. 
  1766. */ 
  1767. $add_content = apply_filters( 'bp_activity_new_update_content', $activity_content ); 
  1768.  
  1769. /** 
  1770. * Filters the activity primary link for current activity item. 
  1771. * 
  1772. * @since 1.2.0 
  1773. * 
  1774. * @param string $primary_link Link to the profile for the user who posted the activity. 
  1775. */ 
  1776. $add_primary_link = apply_filters( 'bp_activity_new_update_primary_link', $primary_link ); 
  1777.  
  1778. // Now write the values. 
  1779. $activity_id = bp_activity_add( array( 
  1780. 'user_id' => $r['user_id'],  
  1781. 'content' => $add_content,  
  1782. 'primary_link' => $add_primary_link,  
  1783. 'component' => buddypress()->activity->id,  
  1784. 'type' => 'activity_update',  
  1785. 'error_type' => $r['error_type'] 
  1786. ) ); 
  1787.  
  1788. // Bail on failure. 
  1789. if ( false === $activity_id || is_wp_error( $activity_id ) ) { 
  1790. return $activity_id; 
  1791.  
  1792. /** 
  1793. * Filters the latest update content for the activity item. 
  1794. * 
  1795. * @since 1.6.0 
  1796. * 
  1797. * @param string $r Content of the activity update. 
  1798. * @param string $activity_content Content of the activity update. 
  1799. */ 
  1800. $activity_content = apply_filters( 'bp_activity_latest_update_content', $r['content'], $activity_content ); 
  1801.  
  1802. // Add this update to the "latest update" usermeta so it can be fetched anywhere. 
  1803. bp_update_user_meta( bp_loggedin_user_id(), 'bp_latest_update', array( 
  1804. 'id' => $activity_id,  
  1805. 'content' => $activity_content 
  1806. ) ); 
  1807.  
  1808. /** 
  1809. * Fires at the end of an activity post update, before returning the updated activity item ID. 
  1810. * 
  1811. * @since 1.2.0 
  1812. * 
  1813. * @param string $content Content of the activity post update. 
  1814. * @param int $user_id ID of the user posting the activity update. 
  1815. * @param int $activity_id ID of the activity item being updated. 
  1816. */ 
  1817. do_action( 'bp_activity_posted_update', $r['content'], $r['user_id'], $activity_id ); 
  1818.  
  1819. return $activity_id; 
  1820.  
  1821. /** 
  1822. * Create an activity item for a newly published post type post. 
  1823. * 
  1824. * @since 2.2.0 
  1825. * 
  1826. * @param int $post_id ID of the new post. 
  1827. * @param WP_Post|null $post Post object. 
  1828. * @param int $user_id ID of the post author. 
  1829. * @return int|bool The ID of the activity on success. False on error. 
  1830. */ 
  1831. function bp_activity_post_type_publish( $post_id = 0, $post = null, $user_id = 0 ) { 
  1832.  
  1833. if ( ! is_a( $post, 'WP_Post' ) ) { 
  1834. return; 
  1835.  
  1836. // Get the post type tracking args. 
  1837. $activity_post_object = bp_activity_get_post_type_tracking_args( $post->post_type ); 
  1838.  
  1839. if ( 'publish' != $post->post_status || ! empty( $post->post_password ) || empty( $activity_post_object->action_id ) ) { 
  1840. return; 
  1841.  
  1842. if ( empty( $post_id ) ) { 
  1843. $post_id = $post->ID; 
  1844.  
  1845. $blog_id = get_current_blog_id(); 
  1846.  
  1847. if ( empty( $user_id ) ) { 
  1848. $user_id = (int) $post->post_author; 
  1849.  
  1850. // Bail if an activity item already exists for this post. 
  1851. $existing = bp_activity_get( array( 
  1852. 'filter' => array( 
  1853. 'action' => $activity_post_object->action_id,  
  1854. 'primary_id' => $blog_id,  
  1855. 'secondary_id' => $post_id,  
  1856. ) ); 
  1857.  
  1858. if ( ! empty( $existing['activities'] ) ) { 
  1859. return; 
  1860.  
  1861. /** 
  1862. * Filters whether or not to post the activity. 
  1863. * 
  1864. * This is a variable filter, dependent on the post type,  
  1865. * that lets components or plugins bail early if needed. 
  1866. * 
  1867. * @since 2.2.0 
  1868. * 
  1869. * @param bool $value Whether or not to continue. 
  1870. * @param int $blog_id ID of the current site. 
  1871. * @param int $post_id ID of the current post being published. 
  1872. * @param int $user_id ID of the current user or post author. 
  1873. */ 
  1874. if ( false === apply_filters( "bp_activity_{$post->post_type}_pre_publish", true, $blog_id, $post_id, $user_id ) ) { 
  1875. return; 
  1876.  
  1877. // Record this in activity streams. 
  1878. $blog_url = get_home_url( $blog_id ); 
  1879. $post_url = add_query_arg( 
  1880. 'p',  
  1881. $post_id,  
  1882. trailingslashit( $blog_url ) 
  1883. ); 
  1884.  
  1885. // Backward compatibility filters for the 'blogs' component. 
  1886. if ( 'blogs' == $activity_post_object->component_id ) { 
  1887. $activity_content = apply_filters( 'bp_blogs_activity_new_post_content', $post->post_content, $post, $post_url, $post->post_type ); 
  1888. $activity_primary_link = apply_filters( 'bp_blogs_activity_new_post_primary_link', $post_url, $post_id, $post->post_type ); 
  1889. } else { 
  1890. $activity_content = $post->post_content; 
  1891. $activity_primary_link = $post_url; 
  1892.  
  1893. $activity_args = array( 
  1894. 'user_id' => $user_id,  
  1895. 'content' => $activity_content,  
  1896. 'primary_link' => $activity_primary_link,  
  1897. 'component' => $activity_post_object->component_id,  
  1898. 'type' => $activity_post_object->action_id,  
  1899. 'item_id' => $blog_id,  
  1900. 'secondary_item_id' => $post_id,  
  1901. 'recorded_time' => $post->post_date_gmt,  
  1902. ); 
  1903.  
  1904. if ( ! empty( $activity_args['content'] ) ) { 
  1905. // Create the excerpt. 
  1906. $activity_summary = bp_activity_create_summary( $activity_args['content'], $activity_args ); 
  1907.  
  1908. // Backward compatibility filter for blog posts. 
  1909. if ( 'blogs' == $activity_post_object->component_id ) { 
  1910. $activity_args['content'] = apply_filters( 'bp_blogs_record_activity_content', $activity_summary, $activity_args['content'], $activity_args, $post->post_type ); 
  1911. } else { 
  1912. $activity_args['content'] = $activity_summary; 
  1913.  
  1914. // Set up the action by using the format functions. 
  1915. $action_args = array_merge( $activity_args, array( 
  1916. 'post_title' => $post->post_title,  
  1917. 'post_url' => $post_url,  
  1918. ) ); 
  1919.  
  1920. $activity_args['action'] = call_user_func_array( $activity_post_object->format_callback, array( '', (object) $action_args ) ); 
  1921.  
  1922. // Make sure the action is set. 
  1923. if ( empty( $activity_args['action'] ) ) { 
  1924. return; 
  1925. } else { 
  1926. // Backward compatibility filter for the blogs component. 
  1927. if ( 'blogs' == $activity_post_object->component_id ) { 
  1928. $activity_args['action'] = apply_filters( 'bp_blogs_record_activity_action', $activity_args['action'] ); 
  1929.  
  1930. $activity_id = bp_activity_add( $activity_args ); 
  1931.  
  1932. /** 
  1933. * Fires after the publishing of an activity item for a newly published post type post. 
  1934. * 
  1935. * @since 2.2.0 
  1936. * 
  1937. * @param int $activity_id ID of the newly published activity item. 
  1938. * @param WP_Post $post Post object. 
  1939. * @param array $activity_args Array of activity arguments. 
  1940. */ 
  1941. do_action( 'bp_activity_post_type_published', $activity_id, $post, $activity_args ); 
  1942.  
  1943. return $activity_id; 
  1944.  
  1945. /** 
  1946. * Update the activity item for a custom post type entry. 
  1947. * 
  1948. * @since 2.2.0 
  1949. * 
  1950. * @param WP_Post|null $post Post item. 
  1951. * @return bool True on success, false on failure. 
  1952. */ 
  1953. function bp_activity_post_type_update( $post = null ) { 
  1954.  
  1955. if ( ! is_a( $post, 'WP_Post' ) ) { 
  1956. return; 
  1957.  
  1958. // Get the post type tracking args. 
  1959. $activity_post_object = bp_activity_get_post_type_tracking_args( $post->post_type ); 
  1960.  
  1961. if ( empty( $activity_post_object->action_id ) ) { 
  1962. return; 
  1963.  
  1964. $activity_id = bp_activity_get_activity_id( array( 
  1965. 'component' => $activity_post_object->component_id,  
  1966. 'item_id' => get_current_blog_id(),  
  1967. 'secondary_item_id' => $post->ID,  
  1968. 'type' => $activity_post_object->action_id,  
  1969. ) ); 
  1970.  
  1971. // Activity ID doesn't exist, so stop! 
  1972. if ( empty( $activity_id ) ) { 
  1973. return; 
  1974.  
  1975. // Delete the activity if the post was updated with a password. 
  1976. if ( ! empty( $post->post_password ) ) { 
  1977. bp_activity_delete( array( 'id' => $activity_id ) ); 
  1978.  
  1979. // Update the activity entry. 
  1980. $activity = new BP_Activity_Activity( $activity_id ); 
  1981.  
  1982. if ( ! empty( $post->post_content ) ) { 
  1983. $activity_summary = bp_activity_create_summary( $post->post_content, (array) $activity ); 
  1984.  
  1985. // Backward compatibility filter for the blogs component. 
  1986. if ( 'blogs' == $activity_post_object->component_id ) { 
  1987. $activity->content = apply_filters( 'bp_blogs_record_activity_content', $activity_summary, $post->post_content, (array) $activity, $post->post_type ); 
  1988. } else { 
  1989. $activity->content = $activity_summary; 
  1990.  
  1991. // Save the updated activity. 
  1992. $updated = $activity->save(); 
  1993.  
  1994. /** 
  1995. * Fires after the updating of an activity item for a custom post type entry. 
  1996. * 
  1997. * @since 2.2.0 
  1998. * @since 2.5.0 Add the post type tracking args parameter 
  1999. * 
  2000. * @param WP_Post $post Post object. 
  2001. * @param BP_Activity_Activity $activity Activity object. 
  2002. * @param object $activity_post_object The post type tracking args object. 
  2003. */ 
  2004. do_action( 'bp_activity_post_type_updated', $post, $activity, $activity_post_object ); 
  2005.  
  2006. return $updated; 
  2007.  
  2008. /** 
  2009. * Unpublish an activity for the custom post type. 
  2010. * 
  2011. * @since 2.2.0 
  2012. * 
  2013. * @param int $post_id ID of the post being unpublished. 
  2014. * @param WP_Post|null $post Post object. 
  2015. * @return bool True on success, false on failure. 
  2016. */ 
  2017. function bp_activity_post_type_unpublish( $post_id = 0, $post = null ) { 
  2018.  
  2019. if ( ! is_a( $post, 'WP_Post' ) ) { 
  2020. return; 
  2021.  
  2022. // Get the post type tracking args. 
  2023. $activity_post_object = bp_activity_get_post_type_tracking_args( $post->post_type ); 
  2024.  
  2025. if ( empty( $activity_post_object->action_id ) ) { 
  2026. return; 
  2027.  
  2028. if ( empty( $post_id ) ) { 
  2029. $post_id = $post->ID; 
  2030.  
  2031. $delete_activity_args = array( 
  2032. 'item_id' => get_current_blog_id(),  
  2033. 'secondary_item_id' => $post_id,  
  2034. 'component' => $activity_post_object->component_id,  
  2035. 'type' => $activity_post_object->action_id,  
  2036. 'user_id' => false,  
  2037. ); 
  2038.  
  2039. $deleted = bp_activity_delete_by_item_id( $delete_activity_args ); 
  2040.  
  2041. /** 
  2042. * Fires after the unpublishing for the custom post type. 
  2043. * 
  2044. * @since 2.2.0 
  2045. * 
  2046. * @param array $delete_activity_args Array of arguments for activity deletion. 
  2047. * @param WP_Post $post Post object. 
  2048. * @param bool $activity Whether or not the activity was successfully deleted. 
  2049. */ 
  2050. do_action( 'bp_activity_post_type_unpublished', $delete_activity_args, $post, $deleted ); 
  2051.  
  2052. return $deleted; 
  2053.  
  2054. /** 
  2055. * Create an activity item for a newly posted post type comment. 
  2056. * 
  2057. * @since 2.5.0 
  2058. * 
  2059. * @param int $comment_id ID of the comment. 
  2060. * @param bool $is_approved Whether the comment is approved or not. 
  2061. * @param object|null $activity_post_object The post type tracking args object. 
  2062. * @return int|bool The ID of the activity on success. False on error. 
  2063. */ 
  2064. function bp_activity_post_type_comment( $comment_id = 0, $is_approved = true, $activity_post_object = null ) { 
  2065. // Get the users comment 
  2066. $post_type_comment = get_comment( $comment_id ); 
  2067.  
  2068. // Don't record activity if the comment hasn't been approved 
  2069. if ( empty( $is_approved ) ) { 
  2070. return false; 
  2071.  
  2072. // Don't record activity if no email address has been included 
  2073. if ( empty( $post_type_comment->comment_author_email ) ) { 
  2074. return false; 
  2075.  
  2076. // Don't record activity if the comment has already been marked as spam 
  2077. if ( 'spam' === $is_approved ) { 
  2078. return false; 
  2079.  
  2080. // Get the user by the comment author email. 
  2081. $user = get_user_by( 'email', $post_type_comment->comment_author_email ); 
  2082.  
  2083. // If user isn't registered, don't record activity 
  2084. if ( empty( $user ) ) { 
  2085. return false; 
  2086.  
  2087. // Get the user_id 
  2088. $user_id = (int) $user->ID; 
  2089.  
  2090. // Get blog and post data 
  2091. $blog_id = get_current_blog_id(); 
  2092.  
  2093. // Get the post 
  2094. $post_type_comment->post = get_post( $post_type_comment->comment_post_ID ); 
  2095.  
  2096. if ( ! is_a( $post_type_comment->post, 'WP_Post' ) ) { 
  2097. return false; 
  2098.  
  2099. /** 
  2100. * Filters whether to publish activities about the comment regarding the post status 
  2101. * 
  2102. * @since 2.5.0 
  2103. * 
  2104. * @param bool true to bail, false otherwise. 
  2105. */ 
  2106. $is_post_status_not_allowed = (bool) apply_filters( 'bp_activity_post_type_is_post_status_allowed', 'publish' !== $post_type_comment->post->post_status || ! empty( $post_type_comment->post->post_password ) ); 
  2107.  
  2108. // If this is a password protected post, or not a public post don't record the comment 
  2109. if ( $is_post_status_not_allowed ) { 
  2110. return false; 
  2111.  
  2112. // Set post type 
  2113. $post_type = $post_type_comment->post->post_type; 
  2114.  
  2115. if ( empty( $activity_post_object ) ) { 
  2116. // Get the post type tracking args. 
  2117. $activity_post_object = bp_activity_get_post_type_tracking_args( $post_type ); 
  2118.  
  2119. // Bail if the activity type does not exist 
  2120. if ( empty( $activity_post_object->comments_tracking->action_id ) ) { 
  2121. return false; 
  2122.  
  2123. // Set the $activity_comment_object 
  2124. $activity_comment_object = $activity_post_object->comments_tracking; 
  2125.  
  2126. /** 
  2127. * Filters whether or not to post the activity about the comment. 
  2128. * 
  2129. * This is a variable filter, dependent on the post type,  
  2130. * that lets components or plugins bail early if needed. 
  2131. * 
  2132. * @since 2.5.0 
  2133. * 
  2134. * @param bool $value Whether or not to continue. 
  2135. * @param int $blog_id ID of the current site. 
  2136. * @param int $post_id ID of the current post being commented. 
  2137. * @param int $user_id ID of the current user. 
  2138. * @param int $comment_id ID of the current comment being posted. 
  2139. */ 
  2140. if ( false === apply_filters( "bp_activity_{$post_type}_pre_comment", true, $blog_id, $post_type_comment->post->ID, $user_id, $comment_id ) ) { 
  2141. return false; 
  2142.  
  2143. // Is this an update ? 
  2144. $activity_id = bp_activity_get_activity_id( array( 
  2145. 'user_id' => $user_id,  
  2146. 'component' => $activity_comment_object->component_id,  
  2147. 'type' => $activity_comment_object->action_id,  
  2148. 'item_id' => $blog_id,  
  2149. 'secondary_item_id' => $comment_id,  
  2150. ) ); 
  2151.  
  2152. // Record this in activity streams. 
  2153. $comment_link = get_comment_link( $post_type_comment->comment_ID ); 
  2154.  
  2155. // Backward compatibility filters for the 'blogs' component. 
  2156. if ( 'blogs' == $activity_comment_object->component_id ) { 
  2157. $activity_content = apply_filters_ref_array( 'bp_blogs_activity_new_comment_content', array( $post_type_comment->comment_content, &$post_type_comment, $comment_link ) ); 
  2158. $activity_primary_link = apply_filters_ref_array( 'bp_blogs_activity_new_comment_primary_link', array( $comment_link, &$post_type_comment ) ); 
  2159. } else { 
  2160. $activity_content = $post_type_comment->comment_content; 
  2161. $activity_primary_link = $comment_link; 
  2162.  
  2163. $activity_args = array( 
  2164. 'id' => $activity_id,  
  2165. 'user_id' => $user_id,  
  2166. 'content' => $activity_content,  
  2167. 'primary_link' => $activity_primary_link,  
  2168. 'component' => $activity_comment_object->component_id,  
  2169. 'recorded_time' => $post_type_comment->comment_date_gmt,  
  2170. ); 
  2171.  
  2172. if ( bp_disable_blogforum_comments() ) { 
  2173. $blog_url = get_home_url( $blog_id ); 
  2174. $post_url = add_query_arg( 
  2175. 'p',  
  2176. $post_type_comment->post->ID,  
  2177. trailingslashit( $blog_url ) 
  2178. ); 
  2179.  
  2180. $activity_args['type'] = $activity_comment_object->action_id; 
  2181. $activity_args['item_id'] = $blog_id; 
  2182. $activity_args['secondary_item_id'] = $post_type_comment->comment_ID; 
  2183.  
  2184. if ( ! empty( $activity_args['content'] ) ) { 
  2185. // Create the excerpt. 
  2186. $activity_summary = bp_activity_create_summary( $activity_args['content'], $activity_args ); 
  2187.  
  2188. // Backward compatibility filter for blog comments. 
  2189. if ( 'blogs' == $activity_post_object->component_id ) { 
  2190. $activity_args['content'] = apply_filters( 'bp_blogs_record_activity_content', $activity_summary, $activity_args['content'], $activity_args, $post_type ); 
  2191. } else { 
  2192. $activity_args['content'] = $activity_summary; 
  2193.  
  2194. // Set up the action by using the format functions. 
  2195. $action_args = array_merge( $activity_args, array( 
  2196. 'post_title' => $post_type_comment->post->post_title,  
  2197. 'post_url' => $post_url,  
  2198. 'blog_url' => $blog_url,  
  2199. 'blog_name' => get_blog_option( $blog_id, 'blogname' ),  
  2200. ) ); 
  2201.  
  2202. $activity_args['action'] = call_user_func_array( $activity_comment_object->format_callback, array( '', (object) $action_args ) ); 
  2203.  
  2204. // Make sure the action is set. 
  2205. if ( empty( $activity_args['action'] ) ) { 
  2206. return; 
  2207. } else { 
  2208. // Backward compatibility filter for the blogs component. 
  2209. if ( 'blogs' === $activity_post_object->component_id ) { 
  2210. $activity_args['action'] = apply_filters( 'bp_blogs_record_activity_action', $activity_args['action'] ); 
  2211.  
  2212. $activity_id = bp_activity_add( $activity_args ); 
  2213.  
  2214. /** 
  2215. * Fires after the publishing of an activity item for a newly published post type post. 
  2216. * 
  2217. * @since 2.5.0 
  2218. * 
  2219. * @param int $activity_id ID of the newly published activity item. 
  2220. * @param WP_Comment $post_type_comment Comment object. 
  2221. * @param array $activity_args Array of activity arguments. 
  2222. * @param object $activity_post_object the post type tracking args object. 
  2223. */ 
  2224. do_action_ref_array( 'bp_activity_post_type_comment', array( &$activity_id, $post_type_comment, $activity_args, $activity_post_object ) ); 
  2225.  
  2226. return $activity_id; 
  2227. add_action( 'comment_post', 'bp_activity_post_type_comment', 10, 2 ); 
  2228. add_action( 'edit_comment', 'bp_activity_post_type_comment', 10 ); 
  2229.  
  2230. /** 
  2231. * Remove an activity item when a comment about a post type is deleted. 
  2232. * 
  2233. * @since 2.5.0 
  2234. * 
  2235. * @param int $comment_id ID of the comment. 
  2236. * @param object|null $activity_post_object The post type tracking args object. 
  2237. * @return bool True on success. False on error. 
  2238. */ 
  2239. function bp_activity_post_type_remove_comment( $comment_id = 0, $activity_post_object = null ) { 
  2240. if ( empty( $activity_post_object ) ) { 
  2241. $comment = get_comment( $comment_id ); 
  2242. if ( ! $comment ) { 
  2243. return; 
  2244.  
  2245. $post_type = get_post_type( $comment->comment_post_ID ); 
  2246. if ( ! $post_type ) { 
  2247. return; 
  2248.  
  2249. // Get the post type tracking args. 
  2250. $activity_post_object = bp_activity_get_post_type_tracking_args( $post_type ); 
  2251.  
  2252. // Bail if the activity type does not exist 
  2253. if ( empty( $activity_post_object->comments_tracking->action_id ) ) { 
  2254. return false; 
  2255.  
  2256. // Set the $activity_comment_object 
  2257. $activity_comment_object = $activity_post_object->comments_tracking; 
  2258.  
  2259. if ( empty( $activity_comment_object->action_id ) ) { 
  2260. return false; 
  2261.  
  2262. $deleted = false; 
  2263.  
  2264. if ( bp_disable_blogforum_comments() ) { 
  2265. $deleted = bp_activity_delete_by_item_id( array( 
  2266. 'item_id' => get_current_blog_id(),  
  2267. 'secondary_item_id' => $comment_id,  
  2268. 'component' => $activity_comment_object->component_id,  
  2269. 'type' => $activity_comment_object->action_id,  
  2270. 'user_id' => false,  
  2271. ) ); 
  2272.  
  2273. /** 
  2274. * Fires after the custom post type comment activity was removed. 
  2275. * 
  2276. * @since 2.5.0 
  2277. * 
  2278. * @param bool $deleted True if the activity was deleted false otherwise 
  2279. * @param WP_Comment $comment Comment object. 
  2280. * @param object $activity_post_object The post type tracking args object. 
  2281. * @param string $value The post type comment activity type. 
  2282. */ 
  2283. do_action( 'bp_activity_post_type_remove_comment', $deleted, $comment_id, $activity_post_object, $activity_comment_object->action_id ); 
  2284.  
  2285. return $deleted; 
  2286. add_action( 'delete_comment', 'bp_activity_post_type_remove_comment', 10, 1 ); 
  2287.  
  2288. /** 
  2289. * Add an activity comment. 
  2290. * 
  2291. * @since 1.2.0 
  2292. * @since 2.5.0 Add a new possible parameter $skip_notification for the array of arguments. 
  2293. * Add the $primary_link parameter for the array of arguments. 
  2294. * @since 2.6.0 Added 'error_type' parameter to $args. 
  2295. * 
  2296. * @param array|string $args { 
  2297. * An array of arguments. 
  2298. * @type int $id Optional. Pass an ID to update an existing comment. 
  2299. * @type string $content The content of the comment. 
  2300. * @type int $user_id Optional. The ID of the user making the comment. 
  2301. * Defaults to the ID of the logged-in user. 
  2302. * @type int $activity_id The ID of the "root" activity item, ie the oldest 
  2303. * ancestor of the comment. 
  2304. * @type int $parent_id Optional. The ID of the parent activity item, ie the item to 
  2305. * which the comment is an immediate reply. If not provided,  
  2306. * this value defaults to the $activity_id. 
  2307. * @type string $primary_link Optional. the primary link for the comment. 
  2308. * Defaults to an empty string. 
  2309. * @type bool $skip_notification Optional. false to send a comment notification, false otherwise. 
  2310. * Defaults to false. 
  2311. * @type string $error_type Optional. Error type. Either 'bool' or 'wp_error'. Default: 'bool'. 
  2312. * } 
  2313. * @return int|bool The ID of the comment on success, otherwise false. 
  2314. */ 
  2315. function bp_activity_new_comment( $args = '' ) { 
  2316. $bp = buddypress(); 
  2317.  
  2318. $r = wp_parse_args( $args, array( 
  2319. 'id' => false,  
  2320. 'content' => false,  
  2321. 'user_id' => bp_loggedin_user_id(),  
  2322. 'activity_id' => false, // ID of the root activity item. 
  2323. 'parent_id' => false, // ID of a parent comment (optional). 
  2324. 'primary_link' => '',  
  2325. 'skip_notification' => false,  
  2326. 'error_type' => 'bool' 
  2327. ) ); 
  2328.  
  2329. // Error type is boolean; need to initialize some variables for backpat. 
  2330. if ( 'bool' === $r['error_type'] ) { 
  2331. if ( empty( $bp->activity->errors ) ) { 
  2332. $bp->activity->errors = array(); 
  2333.  
  2334. // Default error message. 
  2335. $feedback = __( 'There was an error posting your reply. Please try again.', 'buddypress' ); 
  2336.  
  2337. // Bail if missing necessary data. 
  2338. if ( empty( $r['content'] ) || empty( $r['user_id'] ) || empty( $r['activity_id'] ) ) { 
  2339. $error = new WP_Error( 'missing_data', $feedback ); 
  2340.  
  2341. if ( 'wp_error' === $r['error_type'] ) { 
  2342. return $error; 
  2343.  
  2344. // Backpat. 
  2345. } else { 
  2346. $bp->activity->errors['new_comment'] = $error; 
  2347. return false; 
  2348.  
  2349. // Maybe set current activity ID as the parent. 
  2350. if ( empty( $r['parent_id'] ) ) { 
  2351. $r['parent_id'] = $r['activity_id']; 
  2352.  
  2353. $activity_id = $r['activity_id']; 
  2354.  
  2355. // Get the parent activity. 
  2356. $activity = new BP_Activity_Activity( $activity_id ); 
  2357.  
  2358. // Bail if the parent activity does not exist. 
  2359. if ( empty( $activity->date_recorded ) ) { 
  2360. $error = new WP_Error( 'missing_activity', __( 'The item you were replying to no longer exists.', 'buddypress' ) ); 
  2361.  
  2362. if ( 'wp_error' === $r['error_type'] ) { 
  2363. return $error; 
  2364.  
  2365. // Backpat. 
  2366. } else { 
  2367. $bp->activity->errors['new_comment'] = $error; 
  2368. return false; 
  2369.  
  2370.  
  2371. // Check to see if the parent activity is hidden, and if so, hide this comment publicly. 
  2372. $is_hidden = $activity->hide_sitewide ? 1 : 0; 
  2373.  
  2374. /** 
  2375. * Filters the content of a new comment. 
  2376. * 
  2377. * @since 1.2.0 
  2378. * 
  2379. * @param string $r Content for the newly posted comment. 
  2380. */ 
  2381. $comment_content = apply_filters( 'bp_activity_comment_content', $r['content'] ); 
  2382.  
  2383. // Insert the activity comment. 
  2384. $comment_id = bp_activity_add( array( 
  2385. 'id' => $r['id'],  
  2386. 'content' => $comment_content,  
  2387. 'component' => buddypress()->activity->id,  
  2388. 'type' => 'activity_comment',  
  2389. 'primary_link' => $r['primary_link'],  
  2390. 'user_id' => $r['user_id'],  
  2391. 'item_id' => $activity_id,  
  2392. 'secondary_item_id' => $r['parent_id'],  
  2393. 'hide_sitewide' => $is_hidden,  
  2394. 'error_type' => $r['error_type'] 
  2395. ) ); 
  2396.  
  2397. // Bail on failure. 
  2398. if ( false === $comment_id || is_wp_error( $comment_id ) ) { 
  2399. return $comment_id; 
  2400.  
  2401. // Comment caches are stored only with the top-level item. 
  2402. wp_cache_delete( $activity_id, 'bp_activity_comments' ); 
  2403.  
  2404. // Walk the tree to clear caches for all parent items. 
  2405. $clear_id = $r['parent_id']; 
  2406. while ( $clear_id != $activity_id ) { 
  2407. $clear_object = new BP_Activity_Activity( $clear_id ); 
  2408. wp_cache_delete( $clear_id, 'bp_activity' ); 
  2409. $clear_id = intval( $clear_object->secondary_item_id ); 
  2410. wp_cache_delete( $activity_id, 'bp_activity' ); 
  2411.  
  2412. if ( empty( $r[ 'skip_notification' ] ) ) { 
  2413. /** 
  2414. * Fires near the end of an activity comment posting, before the returning of the comment ID. 
  2415. * Sends a notification to the user @see bp_activity_new_comment_notification_helper(). 
  2416. * 
  2417. * @since 1.2.0 
  2418. * 
  2419. * @param int $comment_id ID of the newly posted activity comment. 
  2420. * @param array $r Array of parsed comment arguments. 
  2421. * @param int $activity ID of the activity item being commented on. 
  2422. */ 
  2423. do_action( 'bp_activity_comment_posted', $comment_id, $r, $activity ); 
  2424. } else { 
  2425. /** 
  2426. * Fires near the end of an activity comment posting, before the returning of the comment ID. 
  2427. * without sending a notification to the user 
  2428. * 
  2429. * @since 2.5.0 
  2430. * 
  2431. * @param int $comment_id ID of the newly posted activity comment. 
  2432. * @param array $r Array of parsed comment arguments. 
  2433. * @param int $activity ID of the activity item being commented on. 
  2434. */ 
  2435. do_action( 'bp_activity_comment_posted_notification_skipped', $comment_id, $r, $activity ); 
  2436.  
  2437. if ( empty( $comment_id ) ) { 
  2438. $error = new WP_Error( 'comment_failed', $feedback ); 
  2439.  
  2440. if ( 'wp_error' === $r['error_type'] ) { 
  2441. return $error; 
  2442.  
  2443. // Backpat. 
  2444. } else { 
  2445. $bp->activity->errors['new_comment'] = $error; 
  2446.  
  2447. return $comment_id; 
  2448.  
  2449. /** 
  2450. * Fetch the activity_id for an existing activity entry in the DB. 
  2451. * 
  2452. * @since 1.2.0 
  2453. * 
  2454. * @see BP_Activity_Activity::get() For more information on accepted arguments. 
  2455. * 
  2456. * @param array|string $args See BP_Activity_Activity::get() for description. 
  2457. * @return int $activity_id The ID of the activity item found. 
  2458. */ 
  2459. function bp_activity_get_activity_id( $args = '' ) { 
  2460.  
  2461. $r = bp_parse_args( $args, array( 
  2462. 'user_id' => false,  
  2463. 'component' => false,  
  2464. 'type' => false,  
  2465. 'item_id' => false,  
  2466. 'secondary_item_id' => false,  
  2467. 'action' => false,  
  2468. 'content' => false,  
  2469. 'date_recorded' => false,  
  2470. ) ); 
  2471.  
  2472. /** 
  2473. * Filters the activity ID being requested. 
  2474. * 
  2475. * @since 1.2.0 
  2476. * @since 2.5.0 Added the `$r` and `$args` parameters. 
  2477. * 
  2478. * @param BP_Activity_Activity $value ID returned by BP_Activity_Activity get_id() method with provided arguments. 
  2479. * @param array $r Parsed function arguments. 
  2480. * @param array $args Arguments passed to the function. 
  2481. */ 
  2482. return apply_filters( 'bp_activity_get_activity_id', BP_Activity_Activity::get_id( 
  2483. $r['user_id'],  
  2484. $r['component'],  
  2485. $r['type'],  
  2486. $r['item_id'],  
  2487. $r['secondary_item_id'],  
  2488. $r['action'],  
  2489. $r['content'],  
  2490. $r['date_recorded'] 
  2491. ), $r, $args ); 
  2492.  
  2493. /** 
  2494. * Delete activity item(s). 
  2495. * 
  2496. * If you're looking to hook into one action that provides the ID(s) of 
  2497. * the activity/activities deleted, then use: 
  2498. * 
  2499. * add_action( 'bp_activity_deleted_activities', 'my_function' ); 
  2500. * 
  2501. * The action passes one parameter that is a single activity ID or an 
  2502. * array of activity IDs depending on the number deleted. 
  2503. * 
  2504. * If you are deleting an activity comment please use bp_activity_delete_comment(); 
  2505. * 
  2506. * @since 1.0.0 
  2507. * 
  2508. * @see BP_Activity_Activity::get() For more information on accepted arguments. 
  2509. * 
  2510. * @param array|string $args To delete specific activity items, use 
  2511. * $args = array( 'id' => $ids ); Otherwise, to use 
  2512. * filters for item deletion, the argument format is 
  2513. * the same as BP_Activity_Activity::get(). 
  2514. * See that method for a description. 
  2515. * @return bool True on success, false on failure. 
  2516. */ 
  2517. function bp_activity_delete( $args = '' ) { 
  2518.  
  2519. // Pass one or more the of following variables to delete by those variables. 
  2520. $args = bp_parse_args( $args, array( 
  2521. 'id' => false,  
  2522. 'action' => false,  
  2523. 'content' => false,  
  2524. 'component' => false,  
  2525. 'type' => false,  
  2526. 'primary_link' => false,  
  2527. 'user_id' => false,  
  2528. 'item_id' => false,  
  2529. 'secondary_item_id' => false,  
  2530. 'date_recorded' => false,  
  2531. 'hide_sitewide' => false 
  2532. ) ); 
  2533.  
  2534. /** 
  2535. * Fires before an activity item proceeds to be deleted. 
  2536. * 
  2537. * @since 1.5.0 
  2538. * 
  2539. * @param array $args Array of arguments to be used with the activity deletion. 
  2540. */ 
  2541. do_action( 'bp_before_activity_delete', $args ); 
  2542.  
  2543. // Adjust the new mention count of any mentioned member. 
  2544. bp_activity_adjust_mention_count( $args['id'], 'delete' ); 
  2545.  
  2546. $activity_ids_deleted = BP_Activity_Activity::delete( $args ); 
  2547. if ( empty( $activity_ids_deleted ) ) { 
  2548. return false; 
  2549.  
  2550. // Check if the user's latest update has been deleted. 
  2551. $user_id = empty( $args['user_id'] ) 
  2552. ? bp_loggedin_user_id() 
  2553. : $args['user_id']; 
  2554.  
  2555. $latest_update = bp_get_user_meta( $user_id, 'bp_latest_update', true ); 
  2556. if ( !empty( $latest_update ) ) { 
  2557. if ( in_array( (int) $latest_update['id'], (array) $activity_ids_deleted ) ) { 
  2558. bp_delete_user_meta( $user_id, 'bp_latest_update' ); 
  2559.  
  2560. /** 
  2561. * Fires after the activity item has been deleted. 
  2562. * 
  2563. * @since 1.0.0 
  2564. * 
  2565. * @param array $args Array of arguments used with the activity deletion. 
  2566. */ 
  2567. do_action( 'bp_activity_delete', $args ); 
  2568.  
  2569. /** 
  2570. * Fires after the activity item has been deleted. 
  2571. * 
  2572. * @since 1.2.0 
  2573. * 
  2574. * @param array $activity_ids_deleted Array of affected activity item IDs. 
  2575. */ 
  2576. do_action( 'bp_activity_deleted_activities', $activity_ids_deleted ); 
  2577.  
  2578. wp_cache_delete( 'bp_activity_sitewide_front', 'bp' ); 
  2579.  
  2580. return true; 
  2581.  
  2582. /** 
  2583. * Delete an activity item by activity id. 
  2584. * 
  2585. * You should use bp_activity_delete() instead. 
  2586. * 
  2587. * @since 1.1.0 
  2588. * @deprecated 1.2.0 
  2589. * 
  2590. * 
  2591. * @param array|string $args See BP_Activity_Activity::get for a 
  2592. * description of accepted arguments. 
  2593. * @return bool True on success, false on failure. 
  2594. */ 
  2595. function bp_activity_delete_by_item_id( $args = '' ) { 
  2596.  
  2597. $r = bp_parse_args( $args, array( 
  2598. 'item_id' => false,  
  2599. 'component' => false,  
  2600. 'type' => false,  
  2601. 'user_id' => false,  
  2602. 'secondary_item_id' => false 
  2603. ) ); 
  2604.  
  2605. return bp_activity_delete( $r ); 
  2606.  
  2607. /** 
  2608. * Delete an activity item by activity id. 
  2609. * 
  2610. * @since 1.1.0 
  2611. * 
  2612. * 
  2613. * @param int $activity_id ID of the activity item to be deleted. 
  2614. * @return bool True on success, false on failure. 
  2615. */ 
  2616. function bp_activity_delete_by_activity_id( $activity_id ) { 
  2617. return bp_activity_delete( array( 'id' => $activity_id ) ); 
  2618.  
  2619. /** 
  2620. * Delete an activity item by its content. 
  2621. * 
  2622. * You should use bp_activity_delete() instead. 
  2623. * 
  2624. * @since 1.1.0 
  2625. * @deprecated 1.2.0 
  2626. * 
  2627. * 
  2628. * @param int $user_id The user id. 
  2629. * @param string $content The activity id. 
  2630. * @param string $component The activity component. 
  2631. * @param string $type The activity type. 
  2632. * @return bool True on success, false on failure. 
  2633. */ 
  2634. function bp_activity_delete_by_content( $user_id, $content, $component, $type ) { 
  2635. return bp_activity_delete( array( 
  2636. 'user_id' => $user_id,  
  2637. 'content' => $content,  
  2638. 'component' => $component,  
  2639. 'type' => $type 
  2640. ) ); 
  2641.  
  2642. /** 
  2643. * Delete a user's activity for a component. 
  2644. * 
  2645. * You should use bp_activity_delete() instead. 
  2646. * 
  2647. * @since 1.1.0 
  2648. * @deprecated 1.2.0 
  2649. * 
  2650. * 
  2651. * @param int $user_id The user id. 
  2652. * @param string $component The activity component. 
  2653. * @return bool True on success, false on failure. 
  2654. */ 
  2655. function bp_activity_delete_for_user_by_component( $user_id, $component ) { 
  2656. return bp_activity_delete( array( 
  2657. 'user_id' => $user_id,  
  2658. 'component' => $component 
  2659. ) ); 
  2660.  
  2661. /** 
  2662. * Delete an activity comment. 
  2663. * 
  2664. * @since 1.2.0 
  2665. * 
  2666. * @todo Why is an activity id required? We could look this up. 
  2667. * @todo Why do we encourage users to call this function directly? We could just 
  2668. * as easily examine the activity type in bp_activity_delete() and then 
  2669. * call this function with the proper arguments if necessary. 
  2670. * 
  2671. * @param int $activity_id The ID of the "root" activity, ie the comment's 
  2672. * oldest ancestor. 
  2673. * @param int $comment_id The ID of the comment to be deleted. 
  2674. * @return bool True on success, false on failure. 
  2675. */ 
  2676. function bp_activity_delete_comment( $activity_id, $comment_id ) { 
  2677. $deleted = false; 
  2678.  
  2679. /** 
  2680. * Filters whether BuddyPress should delete an activity comment or not. 
  2681. * 
  2682. * You may want to hook into this filter if you want to override this function and 
  2683. * handle the deletion of child comments differently. Make sure you return false. 
  2684. * 
  2685. * @since 1.2.0 
  2686. * @since 2.5.0 Add the deleted parameter (passed by reference) 
  2687. * 
  2688. * @param bool $value Whether BuddyPress should continue or not. 
  2689. * @param int $activity_id ID of the root activity item being deleted. 
  2690. * @param int $comment_id ID of the comment being deleted. 
  2691. * @param bool $deleted Whether the activity comment has been deleted or not. 
  2692. */ 
  2693. if ( ! apply_filters_ref_array( 'bp_activity_delete_comment_pre', array( true, $activity_id, $comment_id, &$deleted ) ) ) { 
  2694. return $deleted; 
  2695.  
  2696. // Delete any children of this comment. 
  2697. bp_activity_delete_children( $activity_id, $comment_id ); 
  2698.  
  2699. // Delete the actual comment. 
  2700. if ( ! bp_activity_delete( array( 'id' => $comment_id, 'type' => 'activity_comment' ) ) ) { 
  2701. return false; 
  2702. } else { 
  2703. $deleted = true; 
  2704.  
  2705. // Purge comment cache for the root activity update. 
  2706. wp_cache_delete( $activity_id, 'bp_activity_comments' ); 
  2707.  
  2708. // Recalculate the comment tree. 
  2709. BP_Activity_Activity::rebuild_activity_comment_tree( $activity_id ); 
  2710.  
  2711. /** 
  2712. * Fires at the end of the deletion of an activity comment, before returning success. 
  2713. * 
  2714. * @since 1.2.0 
  2715. * 
  2716. * @param int $activity_id ID of the activity that has had a comment deleted from. 
  2717. * @param int $comment_id ID of the comment that was deleted. 
  2718. */ 
  2719. do_action( 'bp_activity_delete_comment', $activity_id, $comment_id ); 
  2720.  
  2721. return $deleted; 
  2722.  
  2723. /** 
  2724. * Delete an activity comment's children. 
  2725. * 
  2726. * @since 1.2.0 
  2727. * 
  2728. * 
  2729. * @param int $activity_id The ID of the "root" activity, ie the 
  2730. * comment's oldest ancestor. 
  2731. * @param int $comment_id The ID of the comment to be deleted. 
  2732. */ 
  2733. function bp_activity_delete_children( $activity_id, $comment_id ) { 
  2734.  
  2735. // Get activity children to delete. 
  2736. $children = BP_Activity_Activity::get_child_comments( $comment_id ); 
  2737.  
  2738. // Recursively delete all children of this comment. 
  2739. if ( ! empty( $children ) ) { 
  2740. foreach( (array) $children as $child ) { 
  2741. bp_activity_delete_children( $activity_id, $child->id ); 
  2742.  
  2743. // Delete the comment itself. 
  2744. bp_activity_delete( array( 
  2745. 'secondary_item_id' => $comment_id,  
  2746. 'type' => 'activity_comment',  
  2747. 'item_id' => $activity_id 
  2748. ) ); 
  2749.  
  2750. /** 
  2751. * Get the permalink for a single activity item. 
  2752. * 
  2753. * When only the $activity_id param is passed, BP has to instantiate a new 
  2754. * BP_Activity_Activity object. To save yourself some processing overhead,  
  2755. * be sure to pass the full $activity_obj parameter as well, if you already 
  2756. * have it available. 
  2757. * 
  2758. * @since 1.2.0 
  2759. * 
  2760. * @param int $activity_id The unique id of the activity object. 
  2761. * @param object|bool $activity_obj Optional. The activity object. 
  2762. * @return string $link Permalink for the activity item. 
  2763. */ 
  2764. function bp_activity_get_permalink( $activity_id, $activity_obj = false ) { 
  2765. $bp = buddypress(); 
  2766.  
  2767. if ( empty( $activity_obj ) ) { 
  2768. $activity_obj = new BP_Activity_Activity( $activity_id ); 
  2769.  
  2770. if ( isset( $activity_obj->current_comment ) ) { 
  2771. $activity_obj = $activity_obj->current_comment; 
  2772.  
  2773. $use_primary_links = array( 
  2774. 'new_blog_post',  
  2775. 'new_blog_comment',  
  2776. 'new_forum_topic',  
  2777. 'new_forum_post',  
  2778. ); 
  2779.  
  2780. if ( ! empty( $bp->activity->track ) ) { 
  2781. $use_primary_links = array_merge( $use_primary_links, array_keys( $bp->activity->track ) ); 
  2782.  
  2783. if ( false !== array_search( $activity_obj->type, $use_primary_links ) ) { 
  2784. $link = $activity_obj->primary_link; 
  2785. } else { 
  2786. if ( 'activity_comment' == $activity_obj->type ) { 
  2787. $link = bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/p/' . $activity_obj->item_id . '/#acomment-' . $activity_obj->id; 
  2788. } else { 
  2789. $link = bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/p/' . $activity_obj->id . '/'; 
  2790.  
  2791. /** 
  2792. * Filters the activity permalink for the specified activity item. 
  2793. * 
  2794. * @since 1.2.0 
  2795. * 
  2796. * @param array $array Array holding activity permalink and activity item object. 
  2797. */ 
  2798. return apply_filters_ref_array( 'bp_activity_get_permalink', array( $link, &$activity_obj ) ); 
  2799.  
  2800. /** 
  2801. * Hide a user's activity. 
  2802. * 
  2803. * @since 1.2.0 
  2804. * 
  2805. * @param int $user_id The ID of the user whose activity is being hidden. 
  2806. * @return bool True on success, false on failure. 
  2807. */ 
  2808. function bp_activity_hide_user_activity( $user_id ) { 
  2809. return BP_Activity_Activity::hide_all_for_user( $user_id ); 
  2810.  
  2811. /** 
  2812. * Take content, remove images, and replace them with a single thumbnail image. 
  2813. * 
  2814. * The format of items in the activity stream is such that we do not want to 
  2815. * allow an arbitrary number of arbitrarily large images to be rendered. 
  2816. * However, the activity stream is built to elegantly display a single 
  2817. * thumbnail corresponding to the activity comment. This function looks 
  2818. * through the content, grabs the first image and converts it to a thumbnail,  
  2819. * and removes the rest of the images from the string. 
  2820. * 
  2821. * As of BuddyPress 2.3, this function is no longer in use. 
  2822. * 
  2823. * @since 1.2.0 
  2824. * 
  2825. * @param string $content The content of the activity item. 
  2826. * @param string|bool $link Optional. The unescaped URL that the image should link 
  2827. * to. If absent, the image will not be a link. 
  2828. * @param array|bool $args Optional. The args passed to the activity 
  2829. * creation function (eg bp_blogs_record_activity()). 
  2830. * @return string $content The content with images stripped and replaced with a 
  2831. * single thumb. 
  2832. */ 
  2833. function bp_activity_thumbnail_content_images( $content, $link = false, $args = false ) { 
  2834.  
  2835. preg_match_all( '/<img[^>]*>/Ui', $content, $matches ); 
  2836.  
  2837. // Remove <img> tags. Also remove caption shortcodes and caption text if present. 
  2838. $content = preg_replace('|(\[caption(.*?)\])?<img[^>]*>([^\[\[]*\[\/caption\])?|', '', $content ); 
  2839.  
  2840. if ( !empty( $matches ) && !empty( $matches[0] ) ) { 
  2841.  
  2842. // Get the SRC value. 
  2843. preg_match( '/<img.*?(src\=[\'|"]{0, 1}.*?[\'|"]{0, 1})[\s|>]{1}/i', $matches[0][0], $src ); 
  2844.  
  2845. // Get the width and height. 
  2846. preg_match( '/<img.*?(height\=[\'|"]{0, 1}.*?[\'|"]{0, 1})[\s|>]{1}/i', $matches[0][0], $height ); 
  2847. preg_match( '/<img.*?(width\=[\'|"]{0, 1}.*?[\'|"]{0, 1})[\s|>]{1}/i', $matches[0][0], $width ); 
  2848.  
  2849. if ( ! empty( $src ) ) { 
  2850. $src = substr( substr( str_replace( 'src=', '', $src[1] ), 0, -1 ), 1 ); 
  2851.  
  2852. if ( isset( $width[1] ) ) { 
  2853. $width = substr( substr( str_replace( 'width=', '', $width[1] ), 0, -1 ), 1 ); 
  2854.  
  2855. if ( isset( $height[1] ) ) { 
  2856. $height = substr( substr( str_replace( 'height=', '', $height[1] ), 0, -1 ), 1 ); 
  2857.  
  2858. if ( empty( $width ) || empty( $height ) ) { 
  2859. $width = 100; 
  2860. $height = 100; 
  2861.  
  2862. $ratio = (int) $width / (int) $height; 
  2863. $new_height = (int) $height >= 100 ? 100 : $height; 
  2864. $new_width = $new_height * $ratio; 
  2865. $image = '<img src="' . esc_url( $src ) . '" width="' . absint( $new_width ) . '" height="' . absint( $new_height ) . '" alt="' . __( 'Thumbnail', 'buddypress' ) . '" class="align-left thumbnail" />'; 
  2866.  
  2867. if ( !empty( $link ) ) { 
  2868. $image = '<a href="' . esc_url( $link ) . '">' . $image . '</a>'; 
  2869.  
  2870. $content = $image . $content; 
  2871.  
  2872. /** 
  2873. * Filters the activity content that had a thumbnail replace images. 
  2874. * 
  2875. * @since 1.2.0 
  2876. * 
  2877. * @param string $content Activity content that had images replaced in. 
  2878. * @param array $matches Array of all image tags found in the posted content. 
  2879. * @param array $args Arguments passed into function creating the activity update. 
  2880. */ 
  2881. return apply_filters( 'bp_activity_thumbnail_content_images', $content, $matches, $args ); 
  2882.  
  2883. /** 
  2884. * Create a rich summary of an activity item for the activity stream. 
  2885. * 
  2886. * More than just a simple excerpt, the summary could contain oEmbeds and other types of media. 
  2887. * Currently, it's only used for blog post items, but it will probably be used for all types of 
  2888. * activity in the future. 
  2889. * 
  2890. * @since 2.3.0 
  2891. * 
  2892. * @param string $content The content of the activity item. 
  2893. * @param array $activity The data passed to bp_activity_add() or the values 
  2894. * from an Activity obj. 
  2895. * @return string $summary 
  2896. */ 
  2897. function bp_activity_create_summary( $content, $activity ) { 
  2898. $args = array( 
  2899. 'width' => isset( $GLOBALS['content_width'] ) ? (int) $GLOBALS['content_width'] : 'medium',  
  2900. ); 
  2901.  
  2902. // Get the WP_Post object if this activity type is a blog post. 
  2903. if ( $activity['type'] === 'new_blog_post' ) { 
  2904. $content = get_post( $activity['secondary_item_id'] ); 
  2905.  
  2906. /** 
  2907. * Filter the class name of the media extractor when creating an Activity summary. 
  2908. * 
  2909. * Use this filter to change the media extractor used to extract media info for the activity item. 
  2910. * 
  2911. * @since 2.3.0 
  2912. * 
  2913. * @param string $extractor Class name. 
  2914. * @param string $content The content of the activity item. 
  2915. * @param array $activity The data passed to bp_activity_add() or the values from an Activity obj. 
  2916. */ 
  2917. $extractor = apply_filters( 'bp_activity_create_summary_extractor_class', 'BP_Media_Extractor', $content, $activity ); 
  2918. $extractor = new $extractor; 
  2919.  
  2920. /** 
  2921. * Filter the arguments passed to the media extractor when creating an Activity summary. 
  2922. * 
  2923. * @since 2.3.0 
  2924. * 
  2925. * @param array $args Array of bespoke data for the media extractor. 
  2926. * @param string $content The content of the activity item. 
  2927. * @param array $activity The data passed to bp_activity_add() or the values from an Activity obj. 
  2928. * @param BP_Media_Extractor $extractor The media extractor object. 
  2929. */ 
  2930. $args = apply_filters( 'bp_activity_create_summary_extractor_args', $args, $content, $activity, $extractor ); 
  2931.  
  2932.  
  2933. // Extract media information from the $content. 
  2934. $media = $extractor->extract( $content, BP_Media_Extractor::ALL, $args ); 
  2935.  
  2936. // If we converted $content to an object earlier, flip it back to a string. 
  2937. if ( is_a( $content, 'WP_Post' ) ) { 
  2938. $content = $content->post_content; 
  2939.  
  2940. $para_count = substr_count( strtolower( wpautop( $content ) ), '<p>' ); 
  2941. $has_audio = ! empty( $media['has']['audio'] ) && $media['has']['audio']; 
  2942. $has_videos = ! empty( $media['has']['videos'] ) && $media['has']['videos']; 
  2943. $has_feat_image = ! empty( $media['has']['featured_images'] ) && $media['has']['featured_images']; 
  2944. $has_galleries = ! empty( $media['has']['galleries'] ) && $media['has']['galleries']; 
  2945. $has_images = ! empty( $media['has']['images'] ) && $media['has']['images']; 
  2946. $has_embeds = false; 
  2947.  
  2948. // Embeds must be subtracted from the paragraph count. 
  2949. if ( ! empty( $media['has']['embeds'] ) ) { 
  2950. $has_embeds = $media['has']['embeds'] > 0; 
  2951. $para_count -= count( $media['has']['embeds'] ); 
  2952.  
  2953. $extracted_media = array(); 
  2954. $use_media_type = ''; 
  2955. $image_source = ''; 
  2956.  
  2957. // If it's a short article and there's an embed/audio/video, use it. 
  2958. if ( $para_count <= 3 ) { 
  2959. if ( $has_embeds ) { 
  2960. $use_media_type = 'embeds'; 
  2961. } elseif ( $has_audio ) { 
  2962. $use_media_type = 'audio'; 
  2963. } elseif ( $has_videos ) { 
  2964. $use_media_type = 'videos'; 
  2965.  
  2966. // If not, or in any other situation, try to use an image. 
  2967. if ( ! $use_media_type && $has_images ) { 
  2968. $use_media_type = 'images'; 
  2969. $image_source = 'html'; 
  2970.  
  2971. // Featured Image > Galleries > inline <img>. 
  2972. if ( $has_feat_image ) { 
  2973. $image_source = 'featured_images'; 
  2974.  
  2975. } elseif ( $has_galleries ) { 
  2976. $image_source = 'galleries'; 
  2977.  
  2978. // Extract an item from the $media results. 
  2979. if ( $use_media_type ) { 
  2980. if ( $use_media_type === 'images' ) { 
  2981. $extracted_media = wp_list_filter( $media[ $use_media_type ], array( 'source' => $image_source ) ); 
  2982. $extracted_media = array_shift( $extracted_media ); 
  2983. } else { 
  2984. $extracted_media = array_shift( $media[ $use_media_type ] ); 
  2985.  
  2986. /** 
  2987. * Filter the results of the media extractor when creating an Activity summary. 
  2988. * 
  2989. * @since 2.3.0 
  2990. * 
  2991. * @param array $extracted_media Extracted media item. See {@link BP_Media_Extractor::extract()} for format. 
  2992. * @param string $content Content of the activity item. 
  2993. * @param array $activity The data passed to bp_activity_add() or the values from an Activity obj. 
  2994. * @param array $media All results from the media extraction. 
  2995. * See {@link BP_Media_Extractor::extract()} for format. 
  2996. * @param string $use_media_type The kind of media item that was preferentially extracted. 
  2997. * @param string $image_source If $use_media_type was "images", the preferential source of the image. 
  2998. * Otherwise empty. 
  2999. */ 
  3000. $extracted_media = apply_filters( 
  3001. 'bp_activity_create_summary_extractor_result',  
  3002. $extracted_media,  
  3003. $content,  
  3004. $activity,  
  3005. $media,  
  3006. $use_media_type,  
  3007. $image_source 
  3008. ); 
  3009.  
  3010. // Generate a text excerpt for this activity item (and remove any oEmbeds URLs). 
  3011. $summary = bp_create_excerpt( html_entity_decode( $content ), 225, array( 
  3012. 'html' => false,  
  3013. 'filter_shortcodes' => true,  
  3014. 'strip_tags' => true,  
  3015. 'remove_links' => true 
  3016. ) ); 
  3017.  
  3018. if ( $use_media_type === 'embeds' ) { 
  3019. $summary .= PHP_EOL . PHP_EOL . $extracted_media['url']; 
  3020. } elseif ( $use_media_type === 'images' ) { 
  3021. $summary .= sprintf( ' <img src="%s">', esc_url( $extracted_media['url'] ) ); 
  3022. } elseif ( in_array( $use_media_type, array( 'audio', 'videos' ), true ) ) { 
  3023. $summary .= PHP_EOL . PHP_EOL . $extracted_media['original']; // Full shortcode. 
  3024.  
  3025. /** 
  3026. * Filters the newly-generated summary for the activity item. 
  3027. * 
  3028. * @since 2.3.0 
  3029. * 
  3030. * @param string $summary Activity summary HTML. 
  3031. * @param string $content Content of the activity item. 
  3032. * @param array $activity The data passed to bp_activity_add() or the values from an Activity obj. 
  3033. * @param array $extracted_media Media item extracted. See {@link BP_Media_Extractor::extract()} for format. 
  3034. */ 
  3035. return apply_filters( 'bp_activity_create_summary', $summary, $content, $activity, $extracted_media ); 
  3036.  
  3037. /** 
  3038. * Fetch whether the current user is allowed to mark items as spam. 
  3039. * 
  3040. * @since 1.6.0 
  3041. * 
  3042. * @return bool True if user is allowed to mark activity items as spam. 
  3043. */ 
  3044. function bp_activity_user_can_mark_spam() { 
  3045.  
  3046. /** 
  3047. * Filters whether the current user should be able to mark items as spam. 
  3048. * 
  3049. * @since 1.6.0 
  3050. * 
  3051. * @param bool $moderate Whether or not the current user has bp_moderate capability. 
  3052. */ 
  3053. return apply_filters( 'bp_activity_user_can_mark_spam', bp_current_user_can( 'bp_moderate' ) ); 
  3054.  
  3055. /** 
  3056. * Mark an activity item as spam. 
  3057. * 
  3058. * @since 1.6.0 
  3059. * 
  3060. * @todo We should probably save $source to activity meta. 
  3061. * 
  3062. * @param BP_Activity_Activity $activity The activity item to be spammed. 
  3063. * @param string $source Optional. Default is "by_a_person" (ie, a person has 
  3064. * manually marked the activity as spam). BP core also 
  3065. * accepts 'by_akismet'. 
  3066. */ 
  3067. function bp_activity_mark_as_spam( &$activity, $source = 'by_a_person' ) { 
  3068. $bp = buddypress(); 
  3069.  
  3070. $activity->is_spam = 1; 
  3071.  
  3072. // Clear the activity stream first page cache. 
  3073. wp_cache_delete( 'bp_activity_sitewide_front', 'bp' ); 
  3074.  
  3075. // Clear the activity comment cache for this activity item. 
  3076. wp_cache_delete( $activity->id, 'bp_activity_comments' ); 
  3077.  
  3078. // If Akismet is active, and this was a manual spam/ham request, stop Akismet checking the activity. 
  3079. if ( 'by_a_person' == $source && !empty( $bp->activity->akismet ) ) { 
  3080. remove_action( 'bp_activity_before_save', array( $bp->activity->akismet, 'check_activity' ), 4, 1 ); 
  3081.  
  3082. // Build data package for Akismet. 
  3083. $activity_data = BP_Akismet::build_akismet_data_package( $activity ); 
  3084.  
  3085. // Tell Akismet this is spam. 
  3086. $activity_data = $bp->activity->akismet->send_akismet_request( $activity_data, 'submit', 'spam' ); 
  3087.  
  3088. // Update meta. 
  3089. add_action( 'bp_activity_after_save', array( $bp->activity->akismet, 'update_activity_spam_meta' ), 1, 1 ); 
  3090.  
  3091. /** 
  3092. * Fires at the end of the process to mark an activity item as spam. 
  3093. * 
  3094. * @since 1.6.0 
  3095. * 
  3096. * @param BP_Activity_Activity $activity Activity item being marked as spam. 
  3097. * @param string $source Source of determination of spam status. For example 
  3098. * "by_a_person" or "by_akismet". 
  3099. */ 
  3100. do_action( 'bp_activity_mark_as_spam', $activity, $source ); 
  3101.  
  3102. /** 
  3103. * Mark an activity item as ham. 
  3104. * 
  3105. * @since 1.6.0 
  3106. * 
  3107. * @param BP_Activity_Activity $activity The activity item to be hammed. Passed by reference. 
  3108. * @param string $source Optional. Default is "by_a_person" (ie, a person has 
  3109. * manually marked the activity as spam). BP core also accepts 
  3110. * 'by_akismet'. 
  3111. */ 
  3112. function bp_activity_mark_as_ham( &$activity, $source = 'by_a_person' ) { 
  3113. $bp = buddypress(); 
  3114.  
  3115. $activity->is_spam = 0; 
  3116.  
  3117. // Clear the activity stream first page cache. 
  3118. wp_cache_delete( 'bp_activity_sitewide_front', 'bp' ); 
  3119.  
  3120. // Clear the activity comment cache for this activity item. 
  3121. wp_cache_delete( $activity->id, 'bp_activity_comments' ); 
  3122.  
  3123. // If Akismet is active, and this was a manual spam/ham request, stop Akismet checking the activity. 
  3124. if ( 'by_a_person' == $source && !empty( $bp->activity->akismet ) ) { 
  3125. remove_action( 'bp_activity_before_save', array( $bp->activity->akismet, 'check_activity' ), 4, 1 ); 
  3126.  
  3127. // Build data package for Akismet. 
  3128. $activity_data = BP_Akismet::build_akismet_data_package( $activity ); 
  3129.  
  3130. // Tell Akismet this is spam. 
  3131. $activity_data = $bp->activity->akismet->send_akismet_request( $activity_data, 'submit', 'ham' ); 
  3132.  
  3133. // Update meta. 
  3134. add_action( 'bp_activity_after_save', array( $bp->activity->akismet, 'update_activity_ham_meta' ), 1, 1 ); 
  3135.  
  3136. /** 
  3137. * Fires at the end of the process to mark an activity item as ham. 
  3138. * 
  3139. * @since 1.6.0 
  3140. * 
  3141. * @param BP_Activity_Activity $activity Activity item being marked as ham. 
  3142. * @param string $source Source of determination of ham status. For example 
  3143. * "by_a_person" or "by_akismet". 
  3144. */ 
  3145. do_action( 'bp_activity_mark_as_ham', $activity, $source ); 
  3146.  
  3147. /** Emails *********************************************************************/ 
  3148.  
  3149. /** 
  3150. * Send email and BP notifications when a user is mentioned in an update. 
  3151. * 
  3152. * @since 1.2.0 
  3153. * 
  3154. * @param int $activity_id The ID of the activity update. 
  3155. * @param int $receiver_user_id The ID of the user who is receiving the update. 
  3156. */ 
  3157. function bp_activity_at_message_notification( $activity_id, $receiver_user_id ) { 
  3158. $notifications = BP_Core_Notification::get_all_for_user( $receiver_user_id, 'all' ); 
  3159.  
  3160. // Don't leave multiple notifications for the same activity item. 
  3161. foreach( $notifications as $notification ) { 
  3162. if ( $activity_id == $notification->item_id ) { 
  3163. return; 
  3164.  
  3165. $activity = new BP_Activity_Activity( $activity_id ); 
  3166. $email_type = 'activity-at-message'; 
  3167. $group_name = ''; 
  3168. $message_link = bp_activity_get_permalink( $activity_id ); 
  3169. $poster_name = bp_core_get_user_displayname( $activity->user_id ); 
  3170.  
  3171. remove_filter( 'bp_get_activity_content_body', 'convert_smilies' ); 
  3172. remove_filter( 'bp_get_activity_content_body', 'wpautop' ); 
  3173. remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 ); 
  3174.  
  3175. /** This filter is documented in bp-activity/bp-activity-template.php */ 
  3176. $content = apply_filters( 'bp_get_activity_content_body', $activity->content ); 
  3177.  
  3178. add_filter( 'bp_get_activity_content_body', 'convert_smilies' ); 
  3179. add_filter( 'bp_get_activity_content_body', 'wpautop' ); 
  3180. add_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 ); 
  3181.  
  3182. // Now email the user with the contents of the message (if they have enabled email notifications). 
  3183. if ( 'no' != bp_get_user_meta( $receiver_user_id, 'notification_activity_new_mention', true ) ) { 
  3184. if ( bp_is_active( 'groups' ) && bp_is_group() ) { 
  3185. $email_type = 'groups-at-message'; 
  3186. $group_name = bp_get_current_group_name(); 
  3187.  
  3188. $unsubscribe_args = array( 
  3189. 'user_id' => $receiver_user_id,  
  3190. 'notification_type' => $email_type,  
  3191. ); 
  3192.  
  3193. $args = array( 
  3194. 'tokens' => array( 
  3195. 'activity' => $activity,  
  3196. 'usermessage' => wp_strip_all_tags( $content ),  
  3197. 'group.name' => $group_name,  
  3198. 'mentioned.url' => $message_link,  
  3199. 'poster.name' => $poster_name,  
  3200. 'receiver-user.id' => $receiver_user_id,  
  3201. 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),  
  3202. ),  
  3203. ); 
  3204.  
  3205. bp_send_email( $email_type, $receiver_user_id, $args ); 
  3206.  
  3207. /** 
  3208. * Fires after the sending of an @mention email notification. 
  3209. * 
  3210. * @since 1.5.0 
  3211. * @since 2.5.0 $subject, $message, $content arguments unset and deprecated. 
  3212. * 
  3213. * @param BP_Activity_Activity $activity Activity Item object. 
  3214. * @param string $deprecated Removed in 2.5; now an empty string. 
  3215. * @param string $deprecated Removed in 2.5; now an empty string. 
  3216. * @param string $deprecated Removed in 2.5; now an empty string. 
  3217. * @param int $receiver_user_id The ID of the user who is receiving the update. 
  3218. */ 
  3219. do_action( 'bp_activity_sent_mention_email', $activity, '', '', '', $receiver_user_id ); 
  3220.  
  3221. /** 
  3222. * Send email and BP notifications when an activity item receives a comment. 
  3223. * 
  3224. * @since 1.2.0 
  3225. * @since 2.5.0 Updated to use new email APIs. 
  3226. * 
  3227. * @param int $comment_id The comment id. 
  3228. * @param int $commenter_id The ID of the user who posted the comment. 
  3229. * @param array $params {@link bp_activity_new_comment()}. 
  3230. */ 
  3231. function bp_activity_new_comment_notification( $comment_id = 0, $commenter_id = 0, $params = array() ) { 
  3232. $original_activity = new BP_Activity_Activity( $params['activity_id'] ); 
  3233. $poster_name = bp_core_get_user_displayname( $commenter_id ); 
  3234. $thread_link = bp_activity_get_permalink( $params['activity_id'] ); 
  3235.  
  3236. remove_filter( 'bp_get_activity_content_body', 'convert_smilies' ); 
  3237. remove_filter( 'bp_get_activity_content_body', 'wpautop' ); 
  3238. remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 ); 
  3239.  
  3240. /** This filter is documented in bp-activity/bp-activity-template.php */ 
  3241. $content = apply_filters( 'bp_get_activity_content_body', $params['content'] ); 
  3242.  
  3243. add_filter( 'bp_get_activity_content_body', 'convert_smilies' ); 
  3244. add_filter( 'bp_get_activity_content_body', 'wpautop' ); 
  3245. add_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 ); 
  3246.  
  3247. if ( $original_activity->user_id != $commenter_id ) { 
  3248.  
  3249. // Send an email if the user hasn't opted-out. 
  3250. if ( 'no' != bp_get_user_meta( $original_activity->user_id, 'notification_activity_new_reply', true ) ) { 
  3251.  
  3252. $unsubscribe_args = array( 
  3253. 'user_id' => $original_activity->user_id,  
  3254. 'notification_type' => 'activity-comment',  
  3255. ); 
  3256.  
  3257. $args = array( 
  3258. 'tokens' => array( 
  3259. 'comment.id' => $comment_id,  
  3260. 'commenter.id' => $commenter_id,  
  3261. 'usermessage' => wp_strip_all_tags( $content ),  
  3262. 'original_activity.user_id' => $original_activity->user_id,  
  3263. 'poster.name' => $poster_name,  
  3264. 'thread.url' => esc_url( $thread_link ),  
  3265. 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),  
  3266. ),  
  3267. ); 
  3268.  
  3269. bp_send_email( 'activity-comment', $original_activity->user_id, $args ); 
  3270.  
  3271. /** 
  3272. * Fires at the point that notifications should be sent for activity comments. 
  3273. * 
  3274. * @since 2.6.0 
  3275. * 
  3276. * @param BP_Activity_Activity $original_activity The original activity. 
  3277. * @param int $comment_id ID for the newly received comment. 
  3278. * @param int $commenter_id ID of the user who made the comment. 
  3279. * @param array $params Arguments used with the original activity comment. 
  3280. */ 
  3281. do_action( 'bp_activity_sent_reply_to_update_notification', $original_activity, $comment_id, $commenter_id, $params ); 
  3282.  
  3283.  
  3284. /** 
  3285. * If this is a reply to another comment, send an email notification to the 
  3286. * author of the immediate parent comment. 
  3287. */ 
  3288. if ( empty( $params['parent_id'] ) || ( $params['activity_id'] == $params['parent_id'] ) ) { 
  3289. return; 
  3290.  
  3291. $parent_comment = new BP_Activity_Activity( $params['parent_id'] ); 
  3292.  
  3293. if ( $parent_comment->user_id != $commenter_id && $original_activity->user_id != $parent_comment->user_id ) { 
  3294.  
  3295. // Send an email if the user hasn't opted-out. 
  3296. if ( 'no' != bp_get_user_meta( $parent_comment->user_id, 'notification_activity_new_reply', true ) ) { 
  3297.  
  3298. $unsubscribe_args = array( 
  3299. 'user_id' => $parent_comment->user_id,  
  3300. 'notification_type' => 'activity-comment-author',  
  3301. ); 
  3302.  
  3303. $args = array( 
  3304. 'tokens' => array( 
  3305. 'comment.id' => $comment_id,  
  3306. 'commenter.id' => $commenter_id,  
  3307. 'usermessage' => wp_strip_all_tags( $content ),  
  3308. 'parent-comment-user.id' => $parent_comment->user_id,  
  3309. 'poster.name' => $poster_name,  
  3310. 'thread.url' => esc_url( $thread_link ),  
  3311. 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),  
  3312. ),  
  3313. ); 
  3314.  
  3315. bp_send_email( 'activity-comment-author', $parent_comment->user_id, $args ); 
  3316.  
  3317. /** 
  3318. * Fires at the point that notifications should be sent for comments on activity replies. 
  3319. * 
  3320. * @since 2.6.0 
  3321. * 
  3322. * @param BP_Activity_Activity $parent_comment The parent activity. 
  3323. * @param int $comment_id ID for the newly received comment. 
  3324. * @param int $commenter_id ID of the user who made the comment. 
  3325. * @param array $params Arguments used with the original activity comment. 
  3326. */ 
  3327. do_action( 'bp_activity_sent_reply_to_reply_notification', $parent_comment, $comment_id, $commenter_id, $params ); 
  3328.  
  3329. /** 
  3330. * Helper method to map action arguments to function parameters. 
  3331. * 
  3332. * @since 1.9.0 
  3333. * 
  3334. * @param int $comment_id ID of the comment being notified about. 
  3335. * @param array $params Parameters to use with notification. 
  3336. */ 
  3337. function bp_activity_new_comment_notification_helper( $comment_id, $params ) { 
  3338. bp_activity_new_comment_notification( $comment_id, $params['user_id'], $params ); 
  3339. add_action( 'bp_activity_comment_posted', 'bp_activity_new_comment_notification_helper', 10, 2 ); 
  3340.  
  3341. /** Embeds *******************************************************************/ 
  3342.  
  3343. /** 
  3344. * Set up activity oEmbed cache during the activity loop. 
  3345. * 
  3346. * During an activity loop, this function sets up the hooks necessary to grab 
  3347. * each item's embeds from the cache, or put them in the cache if they are 
  3348. * not there yet. 
  3349. * 
  3350. * This does not cover recursive activity comments, as they do not use a real loop. 
  3351. * For that, see {@link bp_activity_comment_embed()}. 
  3352. * 
  3353. * @since 1.5.0 
  3354. * 
  3355. * @see BP_Embed 
  3356. * @see bp_embed_activity_cache() 
  3357. * @see bp_embed_activity_save_cache() 
  3358. * 
  3359. */ 
  3360. function bp_activity_embed() { 
  3361. add_filter( 'embed_post_id', 'bp_get_activity_id' ); 
  3362. add_filter( 'oembed_dataparse', 'bp_activity_oembed_dataparse', 10, 2 ); 
  3363. add_filter( 'bp_embed_get_cache', 'bp_embed_activity_cache', 10, 3 ); 
  3364. add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 ); 
  3365. add_action( 'activity_loop_start', 'bp_activity_embed' ); 
  3366.  
  3367. /** 
  3368. * Cache full oEmbed response from oEmbed. 
  3369. * 
  3370. * @since 2.6.0 
  3371. * 
  3372. * @param string $retval Current oEmbed result. 
  3373. * @param object $data Full oEmbed response. 
  3374. * @param string $url URL used for the oEmbed request. 
  3375. * @return string 
  3376. */ 
  3377. function bp_activity_oembed_dataparse( $retval, $data ) { 
  3378. buddypress()->activity->oembed_response = $data; 
  3379.  
  3380. return $retval; 
  3381.  
  3382. /** 
  3383. * Set up activity oEmbed cache while recursing through activity comments. 
  3384. * 
  3385. * While crawling through an activity comment tree 
  3386. * ({@link bp_activity_recurse_comments}), this function sets up the hooks 
  3387. * necessary to grab each comment's embeds from the cache, or put them in 
  3388. * the cache if they are not there yet. 
  3389. * 
  3390. * @since 1.5.0 
  3391. * 
  3392. * @see BP_Embed 
  3393. * @see bp_embed_activity_cache() 
  3394. * @see bp_embed_activity_save_cache() 
  3395. * 
  3396. */ 
  3397. function bp_activity_comment_embed() { 
  3398. add_filter( 'embed_post_id', 'bp_get_activity_comment_id' ); 
  3399. add_filter( 'bp_embed_get_cache', 'bp_embed_activity_cache', 10, 3 ); 
  3400. add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 ); 
  3401. add_action( 'bp_before_activity_comment', 'bp_activity_comment_embed' ); 
  3402.  
  3403. /** 
  3404. * When a user clicks on a "Read More" item, make sure embeds are correctly parsed and shown for the expanded content. 
  3405. * 
  3406. * @since 1.5.0 
  3407. * 
  3408. * @see BP_Embed 
  3409. * 
  3410. * @param object $activity The activity that is being expanded. 
  3411. */ 
  3412. function bp_dtheme_embed_read_more( $activity ) { 
  3413. buddypress()->activity->read_more_id = $activity->id; 
  3414.  
  3415. add_filter( 'embed_post_id', create_function( '', 'return buddypress()->activity->read_more_id;' ) ); 
  3416. add_filter( 'bp_embed_get_cache', 'bp_embed_activity_cache', 10, 3 ); 
  3417. add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 ); 
  3418. add_action( 'bp_dtheme_get_single_activity_content', 'bp_dtheme_embed_read_more' ); 
  3419. add_action( 'bp_legacy_theme_get_single_activity_content', 'bp_dtheme_embed_read_more' ); 
  3420.  
  3421. /** 
  3422. * Clean up 'embed_post_id' filter after comment recursion. 
  3423. * 
  3424. * This filter must be removed so that the non-comment filters take over again 
  3425. * once the comments are done being processed. 
  3426. * 
  3427. * @since 1.5.0 
  3428. * 
  3429. * @see bp_activity_comment_embed() 
  3430. */ 
  3431. function bp_activity_comment_embed_after_recurse() { 
  3432. remove_filter( 'embed_post_id', 'bp_get_activity_comment_id' ); 
  3433. add_action( 'bp_after_activity_comment', 'bp_activity_comment_embed_after_recurse' ); 
  3434.  
  3435. /** 
  3436. * Fetch an activity item's cached embeds. 
  3437. * 
  3438. * Used during {@link BP_Embed::parse_oembed()} via {@link bp_activity_embed()}. 
  3439. * 
  3440. * @since 1.5.0 
  3441. * 
  3442. * @see BP_Embed::parse_oembed() 
  3443. * 
  3444. * @param string $cache An empty string passed by BP_Embed::parse_oembed() for 
  3445. * functions like this one to filter. 
  3446. * @param int $id The ID of the activity item. 
  3447. * @param string $cachekey The cache key generated in BP_Embed::parse_oembed(). 
  3448. * @return mixed The cached embeds for this activity item. 
  3449. */ 
  3450. function bp_embed_activity_cache( $cache, $id, $cachekey ) { 
  3451. return bp_activity_get_meta( $id, $cachekey ); 
  3452.  
  3453. /** 
  3454. * Set an activity item's embed cache. 
  3455. * 
  3456. * Used during {@link BP_Embed::parse_oembed()} via {@link bp_activity_embed()}. 
  3457. * 
  3458. * @since 1.5.0 
  3459. * 
  3460. * @see BP_Embed::parse_oembed() 
  3461. * 
  3462. * @param string $cache An empty string passed by BP_Embed::parse_oembed() for 
  3463. * functions like this one to filter. 
  3464. * @param string $cachekey The cache key generated in BP_Embed::parse_oembed(). 
  3465. * @param int $id The ID of the activity item. 
  3466. */ 
  3467. function bp_embed_activity_save_cache( $cache, $cachekey, $id ) { 
  3468. bp_activity_update_meta( $id, $cachekey, $cache ); 
  3469.  
  3470. // Cache full oEmbed response. 
  3471. if ( true === isset( buddypress()->activity->oembed_response ) ) { 
  3472. $cachekey = str_replace( '_oembed', '_oembed_response', $cachekey ); 
  3473. bp_activity_update_meta( $id, $cachekey, buddypress()->activity->oembed_response ); 
  3474.  
  3475. /** 
  3476. * Should we use Heartbeat to refresh activities? 
  3477. * 
  3478. * @since 2.0.0 
  3479. * 
  3480. * directory. 
  3481. * is the group activities. 
  3482. * 
  3483. * @return bool True if activity heartbeat is enabled, otherwise false. 
  3484. */ 
  3485. function bp_activity_do_heartbeat() { 
  3486. $retval = false; 
  3487.  
  3488. if ( ! bp_is_activity_heartbeat_active() ) { 
  3489. return $retval; 
  3490.  
  3491. if ( bp_is_activity_directory() || bp_is_group_activity() ) { 
  3492. $retval = true; 
  3493.  
  3494. return $retval; 
.