/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 the front-end 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. /** 
  767. * Gets the current activity context. 
  768. * 
  769. * The "context" is the current view type, corresponding roughly to the 
  770. * current component. Use this context to determine which activity actions 
  771. * should be whitelisted for the filter dropdown. 
  772. * 
  773. * @since 2.8.0 
  774. * 
  775. * @return string Activity context. 'member', 'member_groups', 'group', 'activity'. 
  776. */ 
  777. function bp_activity_get_current_context() { 
  778. // On member pages, default to 'member', unless this is a user's Groups activity. 
  779. if ( bp_is_user() ) { 
  780. if ( bp_is_active( 'groups' ) && bp_is_current_action( bp_get_groups_slug() ) ) { 
  781. $context = 'member_groups'; 
  782. } else { 
  783. $context = 'member'; 
  784.  
  785. // On individual group pages, default to 'group'. 
  786. } elseif ( bp_is_active( 'groups' ) && bp_is_group() ) { 
  787. $context = 'group'; 
  788.  
  789. // 'activity' everywhere else. 
  790. } else { 
  791. $context = 'activity'; 
  792.  
  793. return $context; 
  794.  
  795. /** 
  796. * Gets a flat list of activity actions compatible with a given context. 
  797. * 
  798. * @since 2.8.0 
  799. * 
  800. * @param string $context Optional. Name of the context. Defaults to the current context. 
  801. * @return array 
  802. */ 
  803. function bp_activity_get_actions_for_context( $context = '' ) { 
  804. if ( ! $context ) { 
  805. $context = bp_activity_get_current_context(); 
  806.  
  807. $actions = array(); 
  808. foreach ( bp_activity_get_actions() as $component_actions ) { 
  809. foreach ( $component_actions as $component_action ) { 
  810. if ( in_array( $context, (array) $component_action['context'], true ) ) { 
  811. $actions[] = $component_action; 
  812.  
  813. return $actions; 
  814.  
  815. /** Favorites ****************************************************************/ 
  816.  
  817. /** 
  818. * Get a users favorite activity stream items. 
  819. * 
  820. * @since 1.2.0 
  821. * 
  822. * @param int $user_id ID of the user whose favorites are being queried. 
  823. * @return array IDs of the user's favorite activity items. 
  824. */ 
  825. function bp_activity_get_user_favorites( $user_id = 0 ) { 
  826.  
  827. // Fallback to logged in user if no user_id is passed. 
  828. if ( empty( $user_id ) ) { 
  829. $user_id = bp_displayed_user_id(); 
  830.  
  831. // Get favorites for user. 
  832. $favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true ); 
  833.  
  834. /** 
  835. * Filters the favorited activity items for a specified user. 
  836. * 
  837. * @since 1.2.0 
  838. * 
  839. * @param array $favs Array of user's favorited activity items. 
  840. */ 
  841. return apply_filters( 'bp_activity_get_user_favorites', $favs ); 
  842.  
  843. /** 
  844. * Add an activity stream item as a favorite for a user. 
  845. * 
  846. * @since 1.2.0 
  847. * 
  848. * @param int $activity_id ID of the activity item being favorited. 
  849. * @param int $user_id ID of the user favoriting the activity item. 
  850. * @return bool True on success, false on failure. 
  851. */ 
  852. function bp_activity_add_user_favorite( $activity_id, $user_id = 0 ) { 
  853.  
  854. // Favorite activity stream items are for logged in users only. 
  855. if ( ! is_user_logged_in() ) { 
  856. return false; 
  857.  
  858. // Fallback to logged in user if no user_id is passed. 
  859. if ( empty( $user_id ) ) { 
  860. $user_id = bp_loggedin_user_id(); 
  861.  
  862. $my_favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true ); 
  863. if ( empty( $my_favs ) || ! is_array( $my_favs ) ) { 
  864. $my_favs = array(); 
  865.  
  866. // Bail if the user has already favorited this activity item. 
  867. if ( in_array( $activity_id, $my_favs ) ) { 
  868. return false; 
  869.  
  870. // Add to user's favorites. 
  871. $my_favs[] = $activity_id; 
  872.  
  873. // Update the total number of users who have favorited this activity. 
  874. $fav_count = bp_activity_get_meta( $activity_id, 'favorite_count' ); 
  875. $fav_count = !empty( $fav_count ) ? (int) $fav_count + 1 : 1; 
  876.  
  877. // Update user meta. 
  878. bp_update_user_meta( $user_id, 'bp_favorite_activities', $my_favs ); 
  879.  
  880. // Update activity meta counts. 
  881. if ( bp_activity_update_meta( $activity_id, 'favorite_count', $fav_count ) ) { 
  882.  
  883. /** 
  884. * Fires if bp_activity_update_meta() for favorite_count is successful and before returning a true value for success. 
  885. * 
  886. * @since 1.2.1 
  887. * 
  888. * @param int $activity_id ID of the activity item being favorited. 
  889. * @param int $user_id ID of the user doing the favoriting. 
  890. */ 
  891. do_action( 'bp_activity_add_user_favorite', $activity_id, $user_id ); 
  892.  
  893. // Success. 
  894. return true; 
  895.  
  896. // Saving meta was unsuccessful for an unknown reason. 
  897. } else { 
  898.  
  899. /** 
  900. * Fires if bp_activity_update_meta() for favorite_count is unsuccessful and before returning a false value for failure. 
  901. * 
  902. * @since 1.5.0 
  903. * 
  904. * @param int $activity_id ID of the activity item being favorited. 
  905. * @param int $user_id ID of the user doing the favoriting. 
  906. */ 
  907. do_action( 'bp_activity_add_user_favorite_fail', $activity_id, $user_id ); 
  908.  
  909. return false; 
  910.  
  911. /** 
  912. * Remove an activity stream item as a favorite for a user. 
  913. * 
  914. * @since 1.2.0 
  915. * 
  916. * @param int $activity_id ID of the activity item being unfavorited. 
  917. * @param int $user_id ID of the user unfavoriting the activity item. 
  918. * @return bool True on success, false on failure. 
  919. */ 
  920. function bp_activity_remove_user_favorite( $activity_id, $user_id = 0 ) { 
  921.  
  922. // Favorite activity stream items are for logged in users only. 
  923. if ( ! is_user_logged_in() ) { 
  924. return false; 
  925.  
  926. // Fallback to logged in user if no user_id is passed. 
  927. if ( empty( $user_id ) ) { 
  928. $user_id = bp_loggedin_user_id(); 
  929.  
  930. $my_favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true ); 
  931. $my_favs = array_flip( (array) $my_favs ); 
  932.  
  933. // Bail if the user has not previously favorited the item. 
  934. if ( ! isset( $my_favs[ $activity_id ] ) ) { 
  935. return false; 
  936.  
  937. // Remove the fav from the user's favs. 
  938. unset( $my_favs[$activity_id] ); 
  939. $my_favs = array_unique( array_flip( $my_favs ) ); 
  940.  
  941. // Update the total number of users who have favorited this activity. 
  942. $fav_count = bp_activity_get_meta( $activity_id, 'favorite_count' ); 
  943. if ( ! empty( $fav_count ) ) { 
  944.  
  945. // Deduct from total favorites. 
  946. if ( bp_activity_update_meta( $activity_id, 'favorite_count', (int) $fav_count - 1 ) ) { 
  947.  
  948. // Update users favorites. 
  949. if ( bp_update_user_meta( $user_id, 'bp_favorite_activities', $my_favs ) ) { 
  950.  
  951. /** 
  952. * Fires if bp_update_user_meta() is successful and before returning a true value for success. 
  953. * 
  954. * @since 1.2.1 
  955. * 
  956. * @param int $activity_id ID of the activity item being unfavorited. 
  957. * @param int $user_id ID of the user doing the unfavoriting. 
  958. */ 
  959. do_action( 'bp_activity_remove_user_favorite', $activity_id, $user_id ); 
  960.  
  961. // Success. 
  962. return true; 
  963.  
  964. // Error updating. 
  965. } else { 
  966. return false; 
  967.  
  968. // Error updating favorite count. 
  969. } else { 
  970. return false; 
  971.  
  972. // Error getting favorite count. 
  973. } else { 
  974. return false; 
  975.  
  976. /** 
  977. * Check whether an activity item exists with a given content string. 
  978. * 
  979. * @since 1.1.0 
  980. * 
  981. * @param string $content The content to filter by. 
  982. * @return int|null The ID of the located activity item. Null if none is found. 
  983. */ 
  984. function bp_activity_check_exists_by_content( $content ) { 
  985.  
  986. /** 
  987. * Filters the results of the check for whether an activity item exists by specified content. 
  988. * 
  989. * @since 1.1.0 
  990. * 
  991. * @param BP_Activity_Activity $value ID of the activity if found, else null. 
  992. */ 
  993. return apply_filters( 'bp_activity_check_exists_by_content', BP_Activity_Activity::check_exists_by_content( $content ) ); 
  994.  
  995. /** 
  996. * Retrieve the last time activity was updated. 
  997. * 
  998. * @since 1.0.0 
  999. * 
  1000. * @return string Date last updated. 
  1001. */ 
  1002. function bp_activity_get_last_updated() { 
  1003.  
  1004. /** 
  1005. * Filters the value for the last updated time for an activity item. 
  1006. * 
  1007. * @since 1.1.0 
  1008. * 
  1009. * @param BP_Activity_Activity $last_updated Date last updated. 
  1010. */ 
  1011. return apply_filters( 'bp_activity_get_last_updated', BP_Activity_Activity::get_last_updated() ); 
  1012.  
  1013. /** 
  1014. * Retrieve the number of favorite activity stream items a user has. 
  1015. * 
  1016. * @since 1.2.0 
  1017. * 
  1018. * @param int $user_id ID of the user whose favorite count is being requested. 
  1019. * @return int Total favorite count for the user. 
  1020. */ 
  1021. function bp_activity_total_favorites_for_user( $user_id = 0 ) { 
  1022.  
  1023. // Fallback on displayed user, and then logged in user. 
  1024. if ( empty( $user_id ) ) { 
  1025. $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id(); 
  1026.  
  1027. return BP_Activity_Activity::total_favorite_count( $user_id ); 
  1028.  
  1029. /** Meta *********************************************************************/ 
  1030.  
  1031. /** 
  1032. * Delete a meta entry from the DB for an activity stream item. 
  1033. * 
  1034. * @since 1.2.0 
  1035. * 
  1036. * @global object $wpdb WordPress database access object. 
  1037. * 
  1038. * @param int $activity_id ID of the activity item whose metadata is being deleted. 
  1039. * @param string $meta_key Optional. The key of the metadata being deleted. If 
  1040. * omitted, all metadata associated with the activity 
  1041. * item will be deleted. 
  1042. * @param string $meta_value Optional. If present, the metadata will only be 
  1043. * deleted if the meta_value matches this parameter. 
  1044. * @param bool $delete_all Optional. If true, delete matching metadata entries 
  1045. * for all objects, ignoring the specified object_id. Otherwise,  
  1046. * only delete matching metadata entries for the specified 
  1047. * activity item. Default: false. 
  1048. * @return bool True on success, false on failure. 
  1049. */ 
  1050. function bp_activity_delete_meta( $activity_id, $meta_key = '', $meta_value = '', $delete_all = false ) { 
  1051.  
  1052. // Legacy - if no meta_key is passed, delete all for the item. 
  1053. if ( empty( $meta_key ) ) { 
  1054. $all_meta = bp_activity_get_meta( $activity_id ); 
  1055. $keys = ! empty( $all_meta ) ? array_keys( $all_meta ) : array(); 
  1056.  
  1057. // With no meta_key, ignore $delete_all. 
  1058. $delete_all = false; 
  1059. } else { 
  1060. $keys = array( $meta_key ); 
  1061.  
  1062. $retval = true; 
  1063.  
  1064. add_filter( 'query', 'bp_filter_metaid_column_name' ); 
  1065. foreach ( $keys as $key ) { 
  1066. $retval = delete_metadata( 'activity', $activity_id, $key, $meta_value, $delete_all ); 
  1067. remove_filter( 'query', 'bp_filter_metaid_column_name' ); 
  1068.  
  1069. return $retval; 
  1070.  
  1071. /** 
  1072. * Get metadata for a given activity item. 
  1073. * 
  1074. * @since 1.2.0 
  1075. * 
  1076. * @param int $activity_id ID of the activity item whose metadata is being requested. 
  1077. * @param string $meta_key Optional. If present, only the metadata matching 
  1078. * that meta key will be returned. Otherwise, all metadata for the 
  1079. * activity item will be fetched. 
  1080. * @param bool $single Optional. If true, return only the first value of the 
  1081. * specified meta_key. This parameter has no effect if meta_key is not 
  1082. * specified. Default: true. 
  1083. * @return mixed The meta value(s) being requested. 
  1084. */ 
  1085. function bp_activity_get_meta( $activity_id = 0, $meta_key = '', $single = true ) { 
  1086. add_filter( 'query', 'bp_filter_metaid_column_name' ); 
  1087. $retval = get_metadata( 'activity', $activity_id, $meta_key, $single ); 
  1088. remove_filter( 'query', 'bp_filter_metaid_column_name' ); 
  1089.  
  1090. /** 
  1091. * Filters the metadata for a specified activity item. 
  1092. * 
  1093. * @since 1.5.0 
  1094. * 
  1095. * @param mixed $retval The meta values for the activity item. 
  1096. * @param int $activity_id ID of the activity item. 
  1097. * @param string $meta_key Meta key for the value being requested. 
  1098. * @param bool $single Whether to return one matched meta key row or all. 
  1099. */ 
  1100. return apply_filters( 'bp_activity_get_meta', $retval, $activity_id, $meta_key, $single ); 
  1101.  
  1102. /** 
  1103. * Update a piece of activity meta. 
  1104. * 
  1105. * @since 1.2.0 
  1106. * 
  1107. * @param int $activity_id ID of the activity item whose metadata is being updated. 
  1108. * @param string $meta_key Key of the metadata being updated. 
  1109. * @param mixed $meta_value Value to be set. 
  1110. * @param mixed $prev_value Optional. If specified, only update existing metadata entries 
  1111. * with the specified value. Otherwise, update all entries. 
  1112. * @return bool|int Returns false on failure. On successful update of existing 
  1113. * metadata, returns true. On successful creation of new metadata,  
  1114. * returns the integer ID of the new metadata row. 
  1115. */ 
  1116. function bp_activity_update_meta( $activity_id, $meta_key, $meta_value, $prev_value = '' ) { 
  1117. add_filter( 'query', 'bp_filter_metaid_column_name' ); 
  1118. $retval = update_metadata( 'activity', $activity_id, $meta_key, $meta_value, $prev_value ); 
  1119. remove_filter( 'query', 'bp_filter_metaid_column_name' ); 
  1120.  
  1121. return $retval; 
  1122.  
  1123. /** 
  1124. * Add a piece of activity metadata. 
  1125. * 
  1126. * @since 2.0.0 
  1127. * 
  1128. * @param int $activity_id ID of the activity item. 
  1129. * @param string $meta_key Metadata key. 
  1130. * @param mixed $meta_value Metadata value. 
  1131. * @param bool $unique Optional. Whether to enforce a single metadata value for the 
  1132. * given key. If true, and the object already has a value for 
  1133. * the key, no change will be made. Default: false. 
  1134. * @return int|bool The meta ID on successful update, false on failure. 
  1135. */ 
  1136. function bp_activity_add_meta( $activity_id, $meta_key, $meta_value, $unique = false ) { 
  1137. add_filter( 'query', 'bp_filter_metaid_column_name' ); 
  1138. $retval = add_metadata( 'activity', $activity_id, $meta_key, $meta_value, $unique ); 
  1139. remove_filter( 'query', 'bp_filter_metaid_column_name' ); 
  1140.  
  1141. return $retval; 
  1142.  
  1143. /** Clean up *****************************************************************/ 
  1144.  
  1145. /** 
  1146. * Completely remove a user's activity data. 
  1147. * 
  1148. * @since 1.5.0 
  1149. * 
  1150. * @param int $user_id ID of the user whose activity is being deleted. 
  1151. * @return bool 
  1152. */ 
  1153. function bp_activity_remove_all_user_data( $user_id = 0 ) { 
  1154.  
  1155. // Do not delete user data unless a logged in user says so. 
  1156. if ( empty( $user_id ) || ! is_user_logged_in() ) { 
  1157. return false; 
  1158.  
  1159. // Clear the user's activity from the sitewide stream and clear their activity tables. 
  1160. bp_activity_delete( array( 'user_id' => $user_id ) ); 
  1161.  
  1162. // Remove any usermeta. 
  1163. bp_delete_user_meta( $user_id, 'bp_latest_update' ); 
  1164. bp_delete_user_meta( $user_id, 'bp_favorite_activities' ); 
  1165.  
  1166. // Execute additional code 
  1167. do_action( 'bp_activity_remove_data', $user_id ); // Deprecated! Do not use! 
  1168.  
  1169. /** 
  1170. * Fires after the removal of all of a user's activity data. 
  1171. * 
  1172. * @since 1.5.0 
  1173. * 
  1174. * @param int $user_id ID of the user being deleted. 
  1175. */ 
  1176. do_action( 'bp_activity_remove_all_user_data', $user_id ); 
  1177. add_action( 'wpmu_delete_user', 'bp_activity_remove_all_user_data' ); 
  1178. add_action( 'delete_user', 'bp_activity_remove_all_user_data' ); 
  1179.  
  1180. /** 
  1181. * Mark all of the user's activity as spam. 
  1182. * 
  1183. * @since 1.6.0 
  1184. * 
  1185. * @global object $wpdb WordPress database access object. 
  1186. * 
  1187. * @param int $user_id ID of the user whose activity is being spammed. 
  1188. * @return bool 
  1189. */ 
  1190. function bp_activity_spam_all_user_data( $user_id = 0 ) { 
  1191. global $wpdb; 
  1192.  
  1193. // Do not delete user data unless a logged in user says so. 
  1194. if ( empty( $user_id ) || ! is_user_logged_in() ) { 
  1195. return false; 
  1196.  
  1197. // Get all the user's activities. 
  1198. $activities = bp_activity_get( array( 
  1199. 'display_comments' => 'stream',  
  1200. 'filter' => array( 'user_id' => $user_id ),  
  1201. 'show_hidden' => true 
  1202. ) ); 
  1203.  
  1204. $bp = buddypress(); 
  1205.  
  1206. // Mark each as spam. 
  1207. foreach ( (array) $activities['activities'] as $activity ) { 
  1208.  
  1209. // Create an activity object. 
  1210. $activity_obj = new BP_Activity_Activity; 
  1211. foreach ( $activity as $k => $v ) { 
  1212. $activity_obj->$k = $v; 
  1213.  
  1214. // Mark as spam. 
  1215. bp_activity_mark_as_spam( $activity_obj ); 
  1216.  
  1217. /** 
  1218. * If Akismet is present, update the activity history meta. 
  1219. * 
  1220. * This is usually taken care of when BP_Activity_Activity::save() happens, but 
  1221. * as we're going to be updating all the activity statuses directly, for efficiency,  
  1222. * we need to update manually. 
  1223. */ 
  1224. if ( ! empty( $bp->activity->akismet ) ) { 
  1225. $bp->activity->akismet->update_activity_spam_meta( $activity_obj ); 
  1226.  
  1227. // Tidy up. 
  1228. unset( $activity_obj ); 
  1229.  
  1230. // Mark all of this user's activities as spam. 
  1231. $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET is_spam = 1 WHERE user_id = %d", $user_id ) ); 
  1232.  
  1233. /** 
  1234. * Fires after all activity data from a user has been marked as spam. 
  1235. * 
  1236. * @since 1.6.0 
  1237. * 
  1238. * @param int $user_id ID of the user whose activity is being marked as spam. 
  1239. * @param array $activities Array of activity items being marked as spam. 
  1240. */ 
  1241. do_action( 'bp_activity_spam_all_user_data', $user_id, $activities['activities'] ); 
  1242. add_action( 'bp_make_spam_user', 'bp_activity_spam_all_user_data' ); 
  1243.  
  1244. /** 
  1245. * Mark all of the user's activity as ham (not spam). 
  1246. * 
  1247. * @since 1.6.0 
  1248. * 
  1249. * @global object $wpdb WordPress database access object. 
  1250. * 
  1251. * @param int $user_id ID of the user whose activity is being hammed. 
  1252. * @return bool 
  1253. */ 
  1254. function bp_activity_ham_all_user_data( $user_id = 0 ) { 
  1255. global $wpdb; 
  1256.  
  1257. // Do not delete user data unless a logged in user says so. 
  1258. if ( empty( $user_id ) || ! is_user_logged_in() ) { 
  1259. return false; 
  1260.  
  1261. // Get all the user's activities. 
  1262. $activities = bp_activity_get( array( 
  1263. 'display_comments' => 'stream',  
  1264. 'filter' => array( 'user_id' => $user_id ),  
  1265. 'show_hidden' => true,  
  1266. 'spam' => 'all' 
  1267. ) ); 
  1268.  
  1269. $bp = buddypress(); 
  1270.  
  1271. // Mark each as not spam. 
  1272. foreach ( (array) $activities['activities'] as $activity ) { 
  1273.  
  1274. // Create an activity object. 
  1275. $activity_obj = new BP_Activity_Activity; 
  1276. foreach ( $activity as $k => $v ) { 
  1277. $activity_obj->$k = $v; 
  1278.  
  1279. // Mark as not spam. 
  1280. bp_activity_mark_as_ham( $activity_obj ); 
  1281.  
  1282. /** 
  1283. * If Akismet is present, update the activity history meta. 
  1284. * 
  1285. * This is usually taken care of when BP_Activity_Activity::save() happens, but 
  1286. * as we're going to be updating all the activity statuses directly, for efficiency,  
  1287. * we need to update manually. 
  1288. */ 
  1289. if ( ! empty( $bp->activity->akismet ) ) { 
  1290. $bp->activity->akismet->update_activity_ham_meta( $activity_obj ); 
  1291.  
  1292. // Tidy up. 
  1293. unset( $activity_obj ); 
  1294.  
  1295. // Mark all of this user's activities as not spam. 
  1296. $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET is_spam = 0 WHERE user_id = %d", $user_id ) ); 
  1297.  
  1298. /** 
  1299. * Fires after all activity data from a user has been marked as ham. 
  1300. * 
  1301. * @since 1.6.0 
  1302. * 
  1303. * @param int $user_id ID of the user whose activity is being marked as ham. 
  1304. * @param array $activities Array of activity items being marked as ham. 
  1305. */ 
  1306. do_action( 'bp_activity_ham_all_user_data', $user_id, $activities['activities'] ); 
  1307. add_action( 'bp_make_ham_user', 'bp_activity_ham_all_user_data' ); 
  1308.  
  1309. /** 
  1310. * Register the activity stream actions for updates. 
  1311. * 
  1312. * @since 1.6.0 
  1313. */ 
  1314. function bp_activity_register_activity_actions() { 
  1315. $bp = buddypress(); 
  1316.  
  1317. bp_activity_set_action( 
  1318. $bp->activity->id,  
  1319. 'activity_update',  
  1320. __( 'Posted a status update', 'buddypress' ),  
  1321. 'bp_activity_format_activity_action_activity_update',  
  1322. __( 'Updates', 'buddypress' ),  
  1323. array( 'activity', 'group', 'member', 'member_groups' ) 
  1324. ); 
  1325.  
  1326. bp_activity_set_action( 
  1327. $bp->activity->id,  
  1328. 'activity_comment',  
  1329. __( 'Replied to a status update', 'buddypress' ),  
  1330. 'bp_activity_format_activity_action_activity_comment',  
  1331. __( 'Activity Comments', 'buddypress' ) 
  1332. ); 
  1333.  
  1334. /** 
  1335. * Fires at the end of the activity actions registration. 
  1336. * 
  1337. * Allows plugin authors to add their own activity actions alongside the core actions. 
  1338. * 
  1339. * @since 1.6.0 
  1340. */ 
  1341. do_action( 'bp_activity_register_activity_actions' ); 
  1342.  
  1343. // Backpat. Don't use this. 
  1344. do_action( 'updates_register_activity_actions' ); 
  1345. add_action( 'bp_register_activity_actions', 'bp_activity_register_activity_actions' ); 
  1346.  
  1347. /** 
  1348. * Generate an activity action string for an activity item. 
  1349. * 
  1350. * @since 2.0.0 
  1351. * 
  1352. * @param object $activity Activity data object. 
  1353. * @return string|bool Returns false if no callback is found, otherwise returns 
  1354. * the formatted action string. 
  1355. */ 
  1356. function bp_activity_generate_action_string( $activity ) { 
  1357.  
  1358. // Check for valid input. 
  1359. if ( empty( $activity->component ) || empty( $activity->type ) ) { 
  1360. return false; 
  1361.  
  1362. // Check for registered format callback. 
  1363. $actions = bp_activity_get_actions(); 
  1364. if ( empty( $actions->{$activity->component}->{$activity->type}['format_callback'] ) ) { 
  1365. return false; 
  1366.  
  1367. // We apply the format_callback as a filter. 
  1368. add_filter( 'bp_activity_generate_action_string', $actions->{$activity->component}->{$activity->type}['format_callback'], 10, 2 ); 
  1369.  
  1370. /** 
  1371. * Filters the string for the activity action being returned. 
  1372. * 
  1373. * @since 2.0.0 
  1374. * 
  1375. * @param BP_Activity_Activity $action Action string being requested. 
  1376. * @param BP_Activity_Activity $activity Activity item object. 
  1377. */ 
  1378. $action = apply_filters( 'bp_activity_generate_action_string', $activity->action, $activity ); 
  1379.  
  1380. // Remove the filter for future activity items. 
  1381. remove_filter( 'bp_activity_generate_action_string', $actions->{$activity->component}->{$activity->type}['format_callback'], 10 ); 
  1382.  
  1383. return $action; 
  1384.  
  1385. /** 
  1386. * Format 'activity_update' activity actions. 
  1387. * 
  1388. * @since 2.0.0 
  1389. * 
  1390. * @param string $action Static activity action. 
  1391. * @param object $activity Activity data object. 
  1392. * @return string $action 
  1393. */ 
  1394. function bp_activity_format_activity_action_activity_update( $action, $activity ) { 
  1395. $action = sprintf( __( '%s posted an update', 'buddypress' ), bp_core_get_userlink( $activity->user_id ) ); 
  1396.  
  1397. /** 
  1398. * Filters the formatted activity action update string. 
  1399. * 
  1400. * @since 1.2.0 
  1401. * 
  1402. * @param string $action Activity action string value. 
  1403. * @param BP_Activity_Activity $activity Activity item object. 
  1404. */ 
  1405. return apply_filters( 'bp_activity_new_update_action', $action, $activity ); 
  1406.  
  1407. /** 
  1408. * Format 'activity_comment' activity actions. 
  1409. * 
  1410. * @since 2.0.0 
  1411. * 
  1412. * @param string $action Static activity action. 
  1413. * @param object $activity Activity data object. 
  1414. * @return string $action 
  1415. */ 
  1416. function bp_activity_format_activity_action_activity_comment( $action, $activity ) { 
  1417. $action = sprintf( __( '%s posted a new activity comment', 'buddypress' ), bp_core_get_userlink( $activity->user_id ) ); 
  1418.  
  1419. /** 
  1420. * Filters the formatted activity action comment string. 
  1421. * 
  1422. * @since 1.2.0 
  1423. * 
  1424. * @param string $action Activity action string value. 
  1425. * @param BP_Activity_Activity $activity Activity item object. 
  1426. */ 
  1427. return apply_filters( 'bp_activity_comment_action', $action, $activity ); 
  1428.  
  1429. /** 
  1430. * Format activity action strings for custom post types. 
  1431. * 
  1432. * @since 2.2.0 
  1433. * 
  1434. * @param string $action Static activity action. 
  1435. * @param object $activity Activity data object. 
  1436. * @return string $action 
  1437. */ 
  1438. function bp_activity_format_activity_action_custom_post_type_post( $action, $activity ) { 
  1439. $bp = buddypress(); 
  1440.  
  1441. // Fetch all the tracked post types once. 
  1442. if ( empty( $bp->activity->track ) ) { 
  1443. $bp->activity->track = bp_activity_get_post_types_tracking_args(); 
  1444.  
  1445. if ( empty( $activity->type ) || empty( $bp->activity->track[ $activity->type ] ) ) { 
  1446. return $action; 
  1447.  
  1448. $user_link = bp_core_get_userlink( $activity->user_id ); 
  1449. $blog_url = get_home_url( $activity->item_id ); 
  1450.  
  1451. if ( empty( $activity->post_url ) ) { 
  1452. $post_url = add_query_arg( 'p', $activity->secondary_item_id, trailingslashit( $blog_url ) ); 
  1453. } else { 
  1454. $post_url = $activity->post_url; 
  1455.  
  1456. if ( is_multisite() ) { 
  1457. $blog_link = '<a href="' . esc_url( $blog_url ) . '">' . get_blog_option( $activity->item_id, 'blogname' ) . '</a>'; 
  1458.  
  1459. if ( ! empty( $bp->activity->track[ $activity->type ]->new_post_type_action_ms ) ) { 
  1460. $action = sprintf( $bp->activity->track[ $activity->type ]->new_post_type_action_ms, $user_link, $post_url, $blog_link ); 
  1461. } else { 
  1462. $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 ); 
  1463. } else { 
  1464. if ( ! empty( $bp->activity->track[ $activity->type ]->new_post_type_action ) ) { 
  1465. $action = sprintf( $bp->activity->track[ $activity->type ]->new_post_type_action, $user_link, $post_url ); 
  1466. } else { 
  1467. $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 ) ); 
  1468.  
  1469. /** 
  1470. * Filters the formatted custom post type activity post action string. 
  1471. * 
  1472. * @since 2.2.0 
  1473. * 
  1474. * @param string $action Activity action string value. 
  1475. * @param BP_Activity_Activity $activity Activity item object. 
  1476. */ 
  1477. return apply_filters( 'bp_activity_custom_post_type_post_action', $action, $activity ); 
  1478.  
  1479. /** 
  1480. * Format activity action strings for custom post types comments. 
  1481. * 
  1482. * @since 2.5.0 
  1483. * 
  1484. * @param string $action Static activity action. 
  1485. * @param object $activity Activity data object. 
  1486. * 
  1487. * @return string 
  1488. */ 
  1489. function bp_activity_format_activity_action_custom_post_type_comment( $action, $activity ) { 
  1490. $bp = buddypress(); 
  1491.  
  1492. // Fetch all the tracked post types once. 
  1493. if ( empty( $bp->activity->track ) ) { 
  1494. $bp->activity->track = bp_activity_get_post_types_tracking_args(); 
  1495.  
  1496. if ( empty( $activity->type ) || empty( $bp->activity->track[ $activity->type ] ) ) { 
  1497. return $action; 
  1498.  
  1499. $user_link = bp_core_get_userlink( $activity->user_id ); 
  1500.  
  1501. if ( is_multisite() ) { 
  1502. $blog_link = '<a href="' . esc_url( get_home_url( $activity->item_id ) ) . '">' . get_blog_option( $activity->item_id, 'blogname' ) . '</a>'; 
  1503.  
  1504. if ( ! empty( $bp->activity->track[ $activity->type ]->new_post_type_comment_action_ms ) ) { 
  1505. $action = sprintf( $bp->activity->track[ $activity->type ]->new_post_type_comment_action_ms, $user_link, $activity->primary_link, $blog_link ); 
  1506. } else { 
  1507. $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 ); 
  1508. } else { 
  1509. if ( ! empty( $bp->activity->track[ $activity->type ]->new_post_type_comment_action ) ) { 
  1510. $action = sprintf( $bp->activity->track[ $activity->type ]->new_post_type_comment_action, $user_link, $activity->primary_link ); 
  1511. } else { 
  1512. $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 ); 
  1513.  
  1514. /** 
  1515. * Filters the formatted custom post type activity comment action string. 
  1516. * 
  1517. * @since 2.5.0 
  1518. * 
  1519. * @param string $action Activity action string value. 
  1520. * @param BP_Activity_Activity $activity Activity item object. 
  1521. */ 
  1522. return apply_filters( 'bp_activity_custom_post_type_comment_action', $action, $activity ); 
  1523.  
  1524. /** 
  1525. * Business functions are where all the magic happens in BuddyPress. They will 
  1526. * handle the actual saving or manipulation of information. Usually they will 
  1527. * hand off to a database class for data access, then return 
  1528. * true or false on success or failure. 
  1529. */ 
  1530.  
  1531. /** 
  1532. * Retrieve an activity or activities. 
  1533. * 
  1534. * The bp_activity_get() function shares all arguments with BP_Activity_Activity::get(). 
  1535. * The following is a list of bp_activity_get() parameters that have different 
  1536. * default values from BP_Activity_Activity::get() (value in parentheses is 
  1537. * the default for the bp_activity_get()). 
  1538. * - 'per_page' (false) 
  1539. * 
  1540. * @since 1.2.0 
  1541. * @since 2.4.0 Introduced the `$fields` parameter. 
  1542. * 
  1543. * @see BP_Activity_Activity::get() For more information on accepted arguments 
  1544. * and the format of the returned value. 
  1545. * 
  1546. * @param array|string $args See BP_Activity_Activity::get() for description. 
  1547. * @return array $activity See BP_Activity_Activity::get() for description. 
  1548. */ 
  1549. function bp_activity_get( $args = '' ) { 
  1550.  
  1551. $r = bp_parse_args( $args, array( 
  1552. 'max' => false, // Maximum number of results to return. 
  1553. 'fields' => 'all',  
  1554. 'page' => 1, // Page 1 without a per_page will result in no pagination. 
  1555. 'per_page' => false, // results per page 
  1556. 'sort' => 'DESC', // sort ASC or DESC 
  1557. 'display_comments' => false, // False for no comments. 'stream' for within stream display, 'threaded' for below each activity item. 
  1558.  
  1559. 'search_terms' => false, // Pass search terms as a string 
  1560. 'meta_query' => false, // Filter by activity meta. See WP_Meta_Query for format 
  1561. 'date_query' => false, // Filter by date. See first parameter of WP_Date_Query for format. 
  1562. 'filter_query' => false,  
  1563. 'show_hidden' => false, // Show activity items that are hidden site-wide? 
  1564. 'exclude' => false, // Comma-separated list of activity IDs to exclude. 
  1565. 'in' => false, // Comma-separated list or array of activity IDs to which you 
  1566. // want to limit the query. 
  1567. 'spam' => 'ham_only', // 'ham_only' (default), 'spam_only' or 'all'. 
  1568. 'update_meta_cache' => true,  
  1569. 'count_total' => false,  
  1570. 'scope' => false,  
  1571.  
  1572. /** 
  1573. * Pass filters as an array -- all filter items can be multiple values comma separated: 
  1574. * array( 
  1575. * 'user_id' => false, // User ID to filter on. 
  1576. * 'object' => false, // Object to filter on e.g. groups, profile, status, friends. 
  1577. * 'action' => false, // Action to filter on e.g. activity_update, profile_updated. 
  1578. * 'primary_id' => false, // Object ID to filter on e.g. a group_id or forum_id or blog_id etc. 
  1579. * 'secondary_id' => false, // Secondary object ID to filter on e.g. a post_id. 
  1580. * ); 
  1581. */ 
  1582. 'filter' => array() 
  1583. ), 'activity_get' ); 
  1584.  
  1585. $activity = BP_Activity_Activity::get( array( 
  1586. 'page' => $r['page'],  
  1587. 'per_page' => $r['per_page'],  
  1588. 'max' => $r['max'],  
  1589. 'sort' => $r['sort'],  
  1590. 'search_terms' => $r['search_terms'],  
  1591. 'meta_query' => $r['meta_query'],  
  1592. 'date_query' => $r['date_query'],  
  1593. 'filter_query' => $r['filter_query'],  
  1594. 'filter' => $r['filter'],  
  1595. 'scope' => $r['scope'],  
  1596. 'display_comments' => $r['display_comments'],  
  1597. 'show_hidden' => $r['show_hidden'],  
  1598. 'exclude' => $r['exclude'],  
  1599. 'in' => $r['in'],  
  1600. 'spam' => $r['spam'],  
  1601. 'update_meta_cache' => $r['update_meta_cache'],  
  1602. 'count_total' => $r['count_total'],  
  1603. 'fields' => $r['fields'],  
  1604. ) ); 
  1605.  
  1606. /** 
  1607. * Filters the requested activity item(s). 
  1608. * 
  1609. * @since 1.2.0 
  1610. * 
  1611. * @param BP_Activity_Activity $activity Requested activity object. 
  1612. * @param array $r Arguments used for the activity query. 
  1613. */ 
  1614. return apply_filters_ref_array( 'bp_activity_get', array( &$activity, &$r ) ); 
  1615.  
  1616. /** 
  1617. * Fetch specific activity items. 
  1618. * 
  1619. * @since 1.2.0 
  1620. * 
  1621. * @see BP_Activity_Activity::get() For more information on accepted arguments. 
  1622. * 
  1623. * @param array|string $args { 
  1624. * All arguments and defaults are shared with BP_Activity_Activity::get(),  
  1625. * except for the following: 
  1626. * @type string|int|array Single activity ID, comma-separated list of IDs,  
  1627. * or array of IDs. 
  1628. * } 
  1629. * @return array $activity See BP_Activity_Activity::get() for description. 
  1630. */ 
  1631. function bp_activity_get_specific( $args = '' ) { 
  1632.  
  1633. $r = bp_parse_args( $args, array( 
  1634. 'activity_ids' => false, // A single activity_id or array of IDs. 
  1635. 'display_comments' => false, // True or false to display threaded comments for these specific activity items. 
  1636. 'max' => false, // Maximum number of results to return. 
  1637. 'page' => 1, // Page 1 without a per_page will result in no pagination. 
  1638. 'per_page' => false, // Results per page. 
  1639. 'show_hidden' => true, // When fetching specific items, show all. 
  1640. 'sort' => 'DESC', // Sort ASC or DESC 
  1641. 'spam' => 'ham_only', // Retrieve items marked as spam. 
  1642. 'update_meta_cache' => true,  
  1643. ), 'activity_get_specific' ); 
  1644.  
  1645. $get_args = array( 
  1646. 'display_comments' => $r['display_comments'],  
  1647. 'in' => $r['activity_ids'],  
  1648. 'max' => $r['max'],  
  1649. 'page' => $r['page'],  
  1650. 'per_page' => $r['per_page'],  
  1651. 'show_hidden' => $r['show_hidden'],  
  1652. 'sort' => $r['sort'],  
  1653. 'spam' => $r['spam'],  
  1654. 'update_meta_cache' => $r['update_meta_cache'],  
  1655. ); 
  1656.  
  1657. /** 
  1658. * Filters the requested specific activity item. 
  1659. * 
  1660. * @since 1.2.0 
  1661. * 
  1662. * @param BP_Activity_Activity $activity Requested activity object. 
  1663. * @param array $args Original passed in arguments. 
  1664. * @param array $get_args Constructed arguments used with request. 
  1665. */ 
  1666. return apply_filters( 'bp_activity_get_specific', BP_Activity_Activity::get( $get_args ), $args, $get_args ); 
  1667.  
  1668. /** 
  1669. * Add an activity item. 
  1670. * 
  1671. * @since 1.1.0 
  1672. * @since 2.6.0 Added 'error_type' parameter to $args. 
  1673. * 
  1674. * @param array|string $args { 
  1675. * An array of arguments. 
  1676. * @type int|bool $id Pass an activity ID to update an existing item, or 
  1677. * false to create a new item. Default: false. 
  1678. * @type string $action Optional. The activity action/description, typically 
  1679. * something like "Joe posted an update". Values passed to this param 
  1680. * will be stored in the database and used as a fallback for when the 
  1681. * activity item's format_callback cannot be found (eg, when the 
  1682. * component is disabled). As long as you have registered a 
  1683. * format_callback for your $type, it is unnecessary to include this 
  1684. * argument - BP will generate it automatically. 
  1685. * See {@link bp_activity_set_action()}. 
  1686. * @type string $content Optional. The content of the activity item. 
  1687. * @type string $component The unique name of the component associated with 
  1688. * the activity item - 'groups', 'profile', etc. 
  1689. * @type string $type The specific activity type, used for directory 
  1690. * filtering. 'new_blog_post', 'activity_update', etc. 
  1691. * @type string $primary_link Optional. The URL for this item, as used in 
  1692. * RSS feeds. Defaults to the URL for this activity 
  1693. * item's permalink page. 
  1694. * @type int|bool $user_id Optional. The ID of the user associated with the activity 
  1695. * item. May be set to false or 0 if the item is not related 
  1696. * to any user. Default: the ID of the currently logged-in user. 
  1697. * @type int $item_id Optional. The ID of the associated item. 
  1698. * @type int $secondary_item_id Optional. The ID of a secondary associated item. 
  1699. * @type string $date_recorded Optional. The GMT time, in Y-m-d h:i:s format, when 
  1700. * the item was recorded. Defaults to the current time. 
  1701. * @type bool $hide_sitewide Should the item be hidden on sitewide streams? 
  1702. * Default: false. 
  1703. * @type bool $is_spam Should the item be marked as spam? Default: false. 
  1704. * @type string $error_type Optional. Error type. Either 'bool' or 'wp_error'. Default: 'bool'. 
  1705. * } 
  1706. * @return int|bool The ID of the activity on success. False on error. 
  1707. */ 
  1708. function bp_activity_add( $args = '' ) { 
  1709.  
  1710. $r = bp_parse_args( $args, array( 
  1711. 'id' => false, // Pass an existing activity ID to update an existing entry. 
  1712. 'action' => '', // The activity action - e.g. "Jon Doe posted an update" 
  1713. 'content' => '', // Optional: The content of the activity item e.g. "BuddyPress is awesome guys!" 
  1714. 'component' => false, // The name/ID of the component e.g. groups, profile, mycomponent. 
  1715. 'type' => false, // The activity type e.g. activity_update, profile_updated. 
  1716. 'primary_link' => '', // Optional: The primary URL for this item in RSS feeds (defaults to activity permalink). 
  1717. '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. 
  1718. 'item_id' => false, // Optional: The ID of the specific item being recorded, e.g. a blog_id. 
  1719. 'secondary_item_id' => false, // Optional: A second ID used to further filter e.g. a comment_id. 
  1720. 'recorded_time' => bp_core_current_time(), // The GMT time that this activity was recorded. 
  1721. 'hide_sitewide' => false, // Should this be hidden on the sitewide activity stream? 
  1722. 'is_spam' => false, // Is this activity item to be marked as spam? 
  1723. 'error_type' => 'bool' 
  1724. ), 'activity_add' ); 
  1725.  
  1726. // Make sure we are backwards compatible. 
  1727. if ( empty( $r['component'] ) && !empty( $r['component_name'] ) ) { 
  1728. $r['component'] = $r['component_name']; 
  1729.  
  1730. if ( empty( $r['type'] ) && !empty( $r['component_action'] ) ) { 
  1731. $r['type'] = $r['component_action']; 
  1732.  
  1733. // Setup activity to be added. 
  1734. $activity = new BP_Activity_Activity( $r['id'] ); 
  1735. $activity->user_id = $r['user_id']; 
  1736. $activity->component = $r['component']; 
  1737. $activity->type = $r['type']; 
  1738. $activity->content = $r['content']; 
  1739. $activity->primary_link = $r['primary_link']; 
  1740. $activity->item_id = $r['item_id']; 
  1741. $activity->secondary_item_id = $r['secondary_item_id']; 
  1742. $activity->date_recorded = $r['recorded_time']; 
  1743. $activity->hide_sitewide = $r['hide_sitewide']; 
  1744. $activity->is_spam = $r['is_spam']; 
  1745. $activity->error_type = $r['error_type']; 
  1746. $activity->action = ! empty( $r['action'] ) 
  1747. ? $r['action'] 
  1748. : bp_activity_generate_action_string( $activity ); 
  1749.  
  1750. $save = $activity->save(); 
  1751.  
  1752. if ( 'wp_error' === $r['error_type'] && is_wp_error( $save ) ) { 
  1753. return $save; 
  1754. } elseif ('bool' === $r['error_type'] && false === $save ) { 
  1755. return false; 
  1756.  
  1757. // If this is an activity comment, rebuild the tree. 
  1758. if ( 'activity_comment' === $activity->type ) { 
  1759. // Also clear the comment cache for the parent activity ID. 
  1760. wp_cache_delete( $activity->item_id, 'bp_activity_comments' ); 
  1761.  
  1762. BP_Activity_Activity::rebuild_activity_comment_tree( $activity->item_id ); 
  1763.  
  1764. wp_cache_delete( 'bp_activity_sitewide_front', 'bp' ); 
  1765.  
  1766. /** 
  1767. * Fires at the end of the execution of adding a new activity item, before returning the new activity item ID. 
  1768. * 
  1769. * @since 1.1.0 
  1770. * 
  1771. * @param array $r Array of parsed arguments for the activity item being added. 
  1772. */ 
  1773. do_action( 'bp_activity_add', $r ); 
  1774.  
  1775. return $activity->id; 
  1776.  
  1777. /** 
  1778. * Post an activity update. 
  1779. * 
  1780. * @since 1.2.0 
  1781. * 
  1782. * @param array|string $args { 
  1783. * @type string $content The content of the activity update. 
  1784. * @type int $user_id Optional. Defaults to the logged-in user. 
  1785. * @type string $error_type Optional. Error type to return. Either 'bool' or 'wp_error'. Defaults to 
  1786. * 'bool' for boolean. 'wp_error' will return a WP_Error object. 
  1787. * } 
  1788. * @return int|bool|WP_Error $activity_id The activity id on success. On failure, either boolean false or WP_Error 
  1789. * object depending on the 'error_type' $args parameter. 
  1790. */ 
  1791. function bp_activity_post_update( $args = '' ) { 
  1792.  
  1793. $r = wp_parse_args( $args, array( 
  1794. 'content' => false,  
  1795. 'user_id' => bp_loggedin_user_id(),  
  1796. 'error_type' => 'bool',  
  1797. ) ); 
  1798.  
  1799. if ( empty( $r['content'] ) || !strlen( trim( $r['content'] ) ) ) { 
  1800. return false; 
  1801.  
  1802. if ( bp_is_user_inactive( $r['user_id'] ) ) { 
  1803. return false; 
  1804.  
  1805. // Record this on the user's profile. 
  1806. $activity_content = $r['content']; 
  1807. $primary_link = bp_core_get_userlink( $r['user_id'], false, true ); 
  1808.  
  1809. /** 
  1810. * Filters the new activity content for current activity item. 
  1811. * 
  1812. * @since 1.2.0 
  1813. * 
  1814. * @param string $activity_content Activity content posted by user. 
  1815. */ 
  1816. $add_content = apply_filters( 'bp_activity_new_update_content', $activity_content ); 
  1817.  
  1818. /** 
  1819. * Filters the activity primary link for current activity item. 
  1820. * 
  1821. * @since 1.2.0 
  1822. * 
  1823. * @param string $primary_link Link to the profile for the user who posted the activity. 
  1824. */ 
  1825. $add_primary_link = apply_filters( 'bp_activity_new_update_primary_link', $primary_link ); 
  1826.  
  1827. // Now write the values. 
  1828. $activity_id = bp_activity_add( array( 
  1829. 'user_id' => $r['user_id'],  
  1830. 'content' => $add_content,  
  1831. 'primary_link' => $add_primary_link,  
  1832. 'component' => buddypress()->activity->id,  
  1833. 'type' => 'activity_update',  
  1834. 'error_type' => $r['error_type'] 
  1835. ) ); 
  1836.  
  1837. // Bail on failure. 
  1838. if ( false === $activity_id || is_wp_error( $activity_id ) ) { 
  1839. return $activity_id; 
  1840.  
  1841. /** 
  1842. * Filters the latest update content for the activity item. 
  1843. * 
  1844. * @since 1.6.0 
  1845. * 
  1846. * @param string $r Content of the activity update. 
  1847. * @param string $activity_content Content of the activity update. 
  1848. */ 
  1849. $activity_content = apply_filters( 'bp_activity_latest_update_content', $r['content'], $activity_content ); 
  1850.  
  1851. // Add this update to the "latest update" usermeta so it can be fetched anywhere. 
  1852. bp_update_user_meta( bp_loggedin_user_id(), 'bp_latest_update', array( 
  1853. 'id' => $activity_id,  
  1854. 'content' => $activity_content 
  1855. ) ); 
  1856.  
  1857. /** 
  1858. * Fires at the end of an activity post update, before returning the updated activity item ID. 
  1859. * 
  1860. * @since 1.2.0 
  1861. * 
  1862. * @param string $content Content of the activity post update. 
  1863. * @param int $user_id ID of the user posting the activity update. 
  1864. * @param int $activity_id ID of the activity item being updated. 
  1865. */ 
  1866. do_action( 'bp_activity_posted_update', $r['content'], $r['user_id'], $activity_id ); 
  1867.  
  1868. return $activity_id; 
  1869.  
  1870. /** 
  1871. * Create an activity item for a newly published post type post. 
  1872. * 
  1873. * @since 2.2.0 
  1874. * 
  1875. * @param int $post_id ID of the new post. 
  1876. * @param WP_Post|null $post Post object. 
  1877. * @param int $user_id ID of the post author. 
  1878. * @return int|bool The ID of the activity on success. False on error. 
  1879. */ 
  1880. function bp_activity_post_type_publish( $post_id = 0, $post = null, $user_id = 0 ) { 
  1881.  
  1882. if ( ! is_a( $post, 'WP_Post' ) ) { 
  1883. return; 
  1884.  
  1885. // Get the post type tracking args. 
  1886. $activity_post_object = bp_activity_get_post_type_tracking_args( $post->post_type ); 
  1887.  
  1888. if ( 'publish' != $post->post_status || ! empty( $post->post_password ) || empty( $activity_post_object->action_id ) ) { 
  1889. return; 
  1890.  
  1891. if ( empty( $post_id ) ) { 
  1892. $post_id = $post->ID; 
  1893.  
  1894. $blog_id = get_current_blog_id(); 
  1895.  
  1896. if ( empty( $user_id ) ) { 
  1897. $user_id = (int) $post->post_author; 
  1898.  
  1899. // Bail if an activity item already exists for this post. 
  1900. $existing = bp_activity_get( array( 
  1901. 'filter' => array( 
  1902. 'action' => $activity_post_object->action_id,  
  1903. 'primary_id' => $blog_id,  
  1904. 'secondary_id' => $post_id,  
  1905. ) ); 
  1906.  
  1907. if ( ! empty( $existing['activities'] ) ) { 
  1908. return; 
  1909.  
  1910. /** 
  1911. * Filters whether or not to post the activity. 
  1912. * 
  1913. * This is a variable filter, dependent on the post type,  
  1914. * that lets components or plugins bail early if needed. 
  1915. * 
  1916. * @since 2.2.0 
  1917. * 
  1918. * @param bool $value Whether or not to continue. 
  1919. * @param int $blog_id ID of the current site. 
  1920. * @param int $post_id ID of the current post being published. 
  1921. * @param int $user_id ID of the current user or post author. 
  1922. */ 
  1923. if ( false === apply_filters( "bp_activity_{$post->post_type}_pre_publish", true, $blog_id, $post_id, $user_id ) ) { 
  1924. return; 
  1925.  
  1926. // Record this in activity streams. 
  1927. $blog_url = get_home_url( $blog_id ); 
  1928. $post_url = add_query_arg( 
  1929. 'p',  
  1930. $post_id,  
  1931. trailingslashit( $blog_url ) 
  1932. ); 
  1933.  
  1934. // Backward compatibility filters for the 'blogs' component. 
  1935. if ( 'blogs' == $activity_post_object->component_id ) { 
  1936. $activity_content = apply_filters( 'bp_blogs_activity_new_post_content', $post->post_content, $post, $post_url, $post->post_type ); 
  1937. $activity_primary_link = apply_filters( 'bp_blogs_activity_new_post_primary_link', $post_url, $post_id, $post->post_type ); 
  1938. } else { 
  1939. $activity_content = $post->post_content; 
  1940. $activity_primary_link = $post_url; 
  1941.  
  1942. $activity_args = array( 
  1943. 'user_id' => $user_id,  
  1944. 'content' => $activity_content,  
  1945. 'primary_link' => $activity_primary_link,  
  1946. 'component' => $activity_post_object->component_id,  
  1947. 'type' => $activity_post_object->action_id,  
  1948. 'item_id' => $blog_id,  
  1949. 'secondary_item_id' => $post_id,  
  1950. 'recorded_time' => $post->post_date_gmt,  
  1951. ); 
  1952.  
  1953. if ( ! empty( $activity_args['content'] ) ) { 
  1954. // Create the excerpt. 
  1955. $activity_summary = bp_activity_create_summary( $activity_args['content'], $activity_args ); 
  1956.  
  1957. // Backward compatibility filter for blog posts. 
  1958. if ( 'blogs' == $activity_post_object->component_id ) { 
  1959. $activity_args['content'] = apply_filters( 'bp_blogs_record_activity_content', $activity_summary, $activity_args['content'], $activity_args, $post->post_type ); 
  1960. } else { 
  1961. $activity_args['content'] = $activity_summary; 
  1962.  
  1963. // Set up the action by using the format functions. 
  1964. $action_args = array_merge( $activity_args, array( 
  1965. 'post_title' => $post->post_title,  
  1966. 'post_url' => $post_url,  
  1967. ) ); 
  1968.  
  1969. $activity_args['action'] = call_user_func_array( $activity_post_object->format_callback, array( '', (object) $action_args ) ); 
  1970.  
  1971. // Make sure the action is set. 
  1972. if ( empty( $activity_args['action'] ) ) { 
  1973. return; 
  1974. } else { 
  1975. // Backward compatibility filter for the blogs component. 
  1976. if ( 'blogs' == $activity_post_object->component_id ) { 
  1977. $activity_args['action'] = apply_filters( 'bp_blogs_record_activity_action', $activity_args['action'] ); 
  1978.  
  1979. $activity_id = bp_activity_add( $activity_args ); 
  1980.  
  1981. /** 
  1982. * Fires after the publishing of an activity item for a newly published post type post. 
  1983. * 
  1984. * @since 2.2.0 
  1985. * 
  1986. * @param int $activity_id ID of the newly published activity item. 
  1987. * @param WP_Post $post Post object. 
  1988. * @param array $activity_args Array of activity arguments. 
  1989. */ 
  1990. do_action( 'bp_activity_post_type_published', $activity_id, $post, $activity_args ); 
  1991.  
  1992. return $activity_id; 
  1993.  
  1994. /** 
  1995. * Update the activity item for a custom post type entry. 
  1996. * 
  1997. * @since 2.2.0 
  1998. * 
  1999. * @param WP_Post|null $post Post item. 
  2000. * @return bool True on success, false on failure. 
  2001. */ 
  2002. function bp_activity_post_type_update( $post = null ) { 
  2003.  
  2004. if ( ! is_a( $post, 'WP_Post' ) ) { 
  2005. return; 
  2006.  
  2007. // Get the post type tracking args. 
  2008. $activity_post_object = bp_activity_get_post_type_tracking_args( $post->post_type ); 
  2009.  
  2010. if ( empty( $activity_post_object->action_id ) ) { 
  2011. return; 
  2012.  
  2013. $activity_id = bp_activity_get_activity_id( array( 
  2014. 'component' => $activity_post_object->component_id,  
  2015. 'item_id' => get_current_blog_id(),  
  2016. 'secondary_item_id' => $post->ID,  
  2017. 'type' => $activity_post_object->action_id,  
  2018. ) ); 
  2019.  
  2020. // Activity ID doesn't exist, so stop! 
  2021. if ( empty( $activity_id ) ) { 
  2022. return; 
  2023.  
  2024. // Delete the activity if the post was updated with a password. 
  2025. if ( ! empty( $post->post_password ) ) { 
  2026. bp_activity_delete( array( 'id' => $activity_id ) ); 
  2027.  
  2028. // Update the activity entry. 
  2029. $activity = new BP_Activity_Activity( $activity_id ); 
  2030.  
  2031. if ( ! empty( $post->post_content ) ) { 
  2032. $activity_summary = bp_activity_create_summary( $post->post_content, (array) $activity ); 
  2033.  
  2034. // Backward compatibility filter for the blogs component. 
  2035. if ( 'blogs' == $activity_post_object->component_id ) { 
  2036. $activity->content = apply_filters( 'bp_blogs_record_activity_content', $activity_summary, $post->post_content, (array) $activity, $post->post_type ); 
  2037. } else { 
  2038. $activity->content = $activity_summary; 
  2039.  
  2040. // Save the updated activity. 
  2041. $updated = $activity->save(); 
  2042.  
  2043. /** 
  2044. * Fires after the updating of an activity item for a custom post type entry. 
  2045. * 
  2046. * @since 2.2.0 
  2047. * @since 2.5.0 Add the post type tracking args parameter 
  2048. * 
  2049. * @param WP_Post $post Post object. 
  2050. * @param BP_Activity_Activity $activity Activity object. 
  2051. * @param object $activity_post_object The post type tracking args object. 
  2052. */ 
  2053. do_action( 'bp_activity_post_type_updated', $post, $activity, $activity_post_object ); 
  2054.  
  2055. return $updated; 
  2056.  
  2057. /** 
  2058. * Unpublish an activity for the custom post type. 
  2059. * 
  2060. * @since 2.2.0 
  2061. * 
  2062. * @param int $post_id ID of the post being unpublished. 
  2063. * @param WP_Post|null $post Post object. 
  2064. * @return bool True on success, false on failure. 
  2065. */ 
  2066. function bp_activity_post_type_unpublish( $post_id = 0, $post = null ) { 
  2067.  
  2068. if ( ! is_a( $post, 'WP_Post' ) ) { 
  2069. return; 
  2070.  
  2071. // Get the post type tracking args. 
  2072. $activity_post_object = bp_activity_get_post_type_tracking_args( $post->post_type ); 
  2073.  
  2074. if ( empty( $activity_post_object->action_id ) ) { 
  2075. return; 
  2076.  
  2077. if ( empty( $post_id ) ) { 
  2078. $post_id = $post->ID; 
  2079.  
  2080. $delete_activity_args = array( 
  2081. 'item_id' => get_current_blog_id(),  
  2082. 'secondary_item_id' => $post_id,  
  2083. 'component' => $activity_post_object->component_id,  
  2084. 'type' => $activity_post_object->action_id,  
  2085. 'user_id' => false,  
  2086. ); 
  2087.  
  2088. $deleted = bp_activity_delete_by_item_id( $delete_activity_args ); 
  2089.  
  2090. /** 
  2091. * Fires after the unpublishing for the custom post type. 
  2092. * 
  2093. * @since 2.2.0 
  2094. * 
  2095. * @param array $delete_activity_args Array of arguments for activity deletion. 
  2096. * @param WP_Post $post Post object. 
  2097. * @param bool $activity Whether or not the activity was successfully deleted. 
  2098. */ 
  2099. do_action( 'bp_activity_post_type_unpublished', $delete_activity_args, $post, $deleted ); 
  2100.  
  2101. return $deleted; 
  2102.  
  2103. /** 
  2104. * Create an activity item for a newly posted post type comment. 
  2105. * 
  2106. * @since 2.5.0 
  2107. * 
  2108. * @param int $comment_id ID of the comment. 
  2109. * @param bool $is_approved Whether the comment is approved or not. 
  2110. * @param object|null $activity_post_object The post type tracking args object. 
  2111. * @return int|bool The ID of the activity on success. False on error. 
  2112. */ 
  2113. function bp_activity_post_type_comment( $comment_id = 0, $is_approved = true, $activity_post_object = null ) { 
  2114. // Get the users comment 
  2115. $post_type_comment = get_comment( $comment_id ); 
  2116.  
  2117. // Don't record activity if the comment hasn't been approved 
  2118. if ( empty( $is_approved ) ) { 
  2119. return false; 
  2120.  
  2121. // Don't record activity if no email address has been included 
  2122. if ( empty( $post_type_comment->comment_author_email ) ) { 
  2123. return false; 
  2124.  
  2125. // Don't record activity if the comment has already been marked as spam 
  2126. if ( 'spam' === $is_approved ) { 
  2127. return false; 
  2128.  
  2129. // Get the user by the comment author email. 
  2130. $user = get_user_by( 'email', $post_type_comment->comment_author_email ); 
  2131.  
  2132. // If user isn't registered, don't record activity 
  2133. if ( empty( $user ) ) { 
  2134. return false; 
  2135.  
  2136. // Get the user_id 
  2137. $user_id = (int) $user->ID; 
  2138.  
  2139. // Get blog and post data 
  2140. $blog_id = get_current_blog_id(); 
  2141.  
  2142. // Get the post 
  2143. $post_type_comment->post = get_post( $post_type_comment->comment_post_ID ); 
  2144.  
  2145. if ( ! is_a( $post_type_comment->post, 'WP_Post' ) ) { 
  2146. return false; 
  2147.  
  2148. /** 
  2149. * Filters whether to publish activities about the comment regarding the post status 
  2150. * 
  2151. * @since 2.5.0 
  2152. * 
  2153. * @param bool true to bail, false otherwise. 
  2154. */ 
  2155. $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 ) ); 
  2156.  
  2157. // If this is a password protected post, or not a public post don't record the comment 
  2158. if ( $is_post_status_not_allowed ) { 
  2159. return false; 
  2160.  
  2161. // Set post type 
  2162. $post_type = $post_type_comment->post->post_type; 
  2163.  
  2164. if ( empty( $activity_post_object ) ) { 
  2165. // Get the post type tracking args. 
  2166. $activity_post_object = bp_activity_get_post_type_tracking_args( $post_type ); 
  2167.  
  2168. // Bail if the activity type does not exist 
  2169. if ( empty( $activity_post_object->comments_tracking->action_id ) ) { 
  2170. return false; 
  2171.  
  2172. // Set the $activity_comment_object 
  2173. $activity_comment_object = $activity_post_object->comments_tracking; 
  2174.  
  2175. /** 
  2176. * Filters whether or not to post the activity about the comment. 
  2177. * 
  2178. * This is a variable filter, dependent on the post type,  
  2179. * that lets components or plugins bail early if needed. 
  2180. * 
  2181. * @since 2.5.0 
  2182. * 
  2183. * @param bool $value Whether or not to continue. 
  2184. * @param int $blog_id ID of the current site. 
  2185. * @param int $post_id ID of the current post being commented. 
  2186. * @param int $user_id ID of the current user. 
  2187. * @param int $comment_id ID of the current comment being posted. 
  2188. */ 
  2189. if ( false === apply_filters( "bp_activity_{$post_type}_pre_comment", true, $blog_id, $post_type_comment->post->ID, $user_id, $comment_id ) ) { 
  2190. return false; 
  2191.  
  2192. // Is this an update ? 
  2193. $activity_id = bp_activity_get_activity_id( array( 
  2194. 'user_id' => $user_id,  
  2195. 'component' => $activity_comment_object->component_id,  
  2196. 'type' => $activity_comment_object->action_id,  
  2197. 'item_id' => $blog_id,  
  2198. 'secondary_item_id' => $comment_id,  
  2199. ) ); 
  2200.  
  2201. // Record this in activity streams. 
  2202. $comment_link = get_comment_link( $post_type_comment->comment_ID ); 
  2203.  
  2204. // Backward compatibility filters for the 'blogs' component. 
  2205. if ( 'blogs' == $activity_comment_object->component_id ) { 
  2206. $activity_content = apply_filters_ref_array( 'bp_blogs_activity_new_comment_content', array( $post_type_comment->comment_content, &$post_type_comment, $comment_link ) ); 
  2207. $activity_primary_link = apply_filters_ref_array( 'bp_blogs_activity_new_comment_primary_link', array( $comment_link, &$post_type_comment ) ); 
  2208. } else { 
  2209. $activity_content = $post_type_comment->comment_content; 
  2210. $activity_primary_link = $comment_link; 
  2211.  
  2212. $activity_args = array( 
  2213. 'id' => $activity_id,  
  2214. 'user_id' => $user_id,  
  2215. 'content' => $activity_content,  
  2216. 'primary_link' => $activity_primary_link,  
  2217. 'component' => $activity_comment_object->component_id,  
  2218. 'recorded_time' => $post_type_comment->comment_date_gmt,  
  2219. ); 
  2220.  
  2221. if ( bp_disable_blogforum_comments() ) { 
  2222. $blog_url = get_home_url( $blog_id ); 
  2223. $post_url = add_query_arg( 
  2224. 'p',  
  2225. $post_type_comment->post->ID,  
  2226. trailingslashit( $blog_url ) 
  2227. ); 
  2228.  
  2229. $activity_args['type'] = $activity_comment_object->action_id; 
  2230. $activity_args['item_id'] = $blog_id; 
  2231. $activity_args['secondary_item_id'] = $post_type_comment->comment_ID; 
  2232.  
  2233. if ( ! empty( $activity_args['content'] ) ) { 
  2234. // Create the excerpt. 
  2235. $activity_summary = bp_activity_create_summary( $activity_args['content'], $activity_args ); 
  2236.  
  2237. // Backward compatibility filter for blog comments. 
  2238. if ( 'blogs' == $activity_post_object->component_id ) { 
  2239. $activity_args['content'] = apply_filters( 'bp_blogs_record_activity_content', $activity_summary, $activity_args['content'], $activity_args, $post_type ); 
  2240. } else { 
  2241. $activity_args['content'] = $activity_summary; 
  2242.  
  2243. // Set up the action by using the format functions. 
  2244. $action_args = array_merge( $activity_args, array( 
  2245. 'post_title' => $post_type_comment->post->post_title,  
  2246. 'post_url' => $post_url,  
  2247. 'blog_url' => $blog_url,  
  2248. 'blog_name' => get_blog_option( $blog_id, 'blogname' ),  
  2249. ) ); 
  2250.  
  2251. $activity_args['action'] = call_user_func_array( $activity_comment_object->format_callback, array( '', (object) $action_args ) ); 
  2252.  
  2253. // Make sure the action is set. 
  2254. if ( empty( $activity_args['action'] ) ) { 
  2255. return; 
  2256. } else { 
  2257. // Backward compatibility filter for the blogs component. 
  2258. if ( 'blogs' === $activity_post_object->component_id ) { 
  2259. $activity_args['action'] = apply_filters( 'bp_blogs_record_activity_action', $activity_args['action'] ); 
  2260.  
  2261. $activity_id = bp_activity_add( $activity_args ); 
  2262.  
  2263. /** 
  2264. * Fires after the publishing of an activity item for a newly published post type post. 
  2265. * 
  2266. * @since 2.5.0 
  2267. * 
  2268. * @param int $activity_id ID of the newly published activity item. 
  2269. * @param WP_Comment $post_type_comment Comment object. 
  2270. * @param array $activity_args Array of activity arguments. 
  2271. * @param object $activity_post_object the post type tracking args object. 
  2272. */ 
  2273. do_action_ref_array( 'bp_activity_post_type_comment', array( &$activity_id, $post_type_comment, $activity_args, $activity_post_object ) ); 
  2274.  
  2275. return $activity_id; 
  2276. add_action( 'comment_post', 'bp_activity_post_type_comment', 10, 2 ); 
  2277. add_action( 'edit_comment', 'bp_activity_post_type_comment', 10 ); 
  2278.  
  2279. /** 
  2280. * Remove an activity item when a comment about a post type is deleted. 
  2281. * 
  2282. * @since 2.5.0 
  2283. * 
  2284. * @param int $comment_id ID of the comment. 
  2285. * @param object|null $activity_post_object The post type tracking args object. 
  2286. * @return bool True on success. False on error. 
  2287. */ 
  2288. function bp_activity_post_type_remove_comment( $comment_id = 0, $activity_post_object = null ) { 
  2289. if ( empty( $activity_post_object ) ) { 
  2290. $comment = get_comment( $comment_id ); 
  2291. if ( ! $comment ) { 
  2292. return; 
  2293.  
  2294. $post_type = get_post_type( $comment->comment_post_ID ); 
  2295. if ( ! $post_type ) { 
  2296. return; 
  2297.  
  2298. // Get the post type tracking args. 
  2299. $activity_post_object = bp_activity_get_post_type_tracking_args( $post_type ); 
  2300.  
  2301. // Bail if the activity type does not exist 
  2302. if ( empty( $activity_post_object->comments_tracking->action_id ) ) { 
  2303. return false; 
  2304.  
  2305. // Set the $activity_comment_object 
  2306. $activity_comment_object = $activity_post_object->comments_tracking; 
  2307.  
  2308. if ( empty( $activity_comment_object->action_id ) ) { 
  2309. return false; 
  2310.  
  2311. $deleted = false; 
  2312.  
  2313. if ( bp_disable_blogforum_comments() ) { 
  2314. $deleted = bp_activity_delete_by_item_id( array( 
  2315. 'item_id' => get_current_blog_id(),  
  2316. 'secondary_item_id' => $comment_id,  
  2317. 'component' => $activity_comment_object->component_id,  
  2318. 'type' => $activity_comment_object->action_id,  
  2319. 'user_id' => false,  
  2320. ) ); 
  2321.  
  2322. /** 
  2323. * Fires after the custom post type comment activity was removed. 
  2324. * 
  2325. * @since 2.5.0 
  2326. * 
  2327. * @param bool $deleted True if the activity was deleted false otherwise 
  2328. * @param WP_Comment $comment Comment object. 
  2329. * @param object $activity_post_object The post type tracking args object. 
  2330. * @param string $value The post type comment activity type. 
  2331. */ 
  2332. do_action( 'bp_activity_post_type_remove_comment', $deleted, $comment_id, $activity_post_object, $activity_comment_object->action_id ); 
  2333.  
  2334. return $deleted; 
  2335. add_action( 'delete_comment', 'bp_activity_post_type_remove_comment', 10, 1 ); 
  2336.  
  2337. /** 
  2338. * Add an activity comment. 
  2339. * 
  2340. * @since 1.2.0 
  2341. * @since 2.5.0 Add a new possible parameter $skip_notification for the array of arguments. 
  2342. * Add the $primary_link parameter for the array of arguments. 
  2343. * @since 2.6.0 Added 'error_type' parameter to $args. 
  2344. * 
  2345. * @param array|string $args { 
  2346. * An array of arguments. 
  2347. * @type int $id Optional. Pass an ID to update an existing comment. 
  2348. * @type string $content The content of the comment. 
  2349. * @type int $user_id Optional. The ID of the user making the comment. 
  2350. * Defaults to the ID of the logged-in user. 
  2351. * @type int $activity_id The ID of the "root" activity item, ie the oldest 
  2352. * ancestor of the comment. 
  2353. * @type int $parent_id Optional. The ID of the parent activity item, ie the item to 
  2354. * which the comment is an immediate reply. If not provided,  
  2355. * this value defaults to the $activity_id. 
  2356. * @type string $primary_link Optional. the primary link for the comment. 
  2357. * Defaults to an empty string. 
  2358. * @type bool $skip_notification Optional. false to send a comment notification, false otherwise. 
  2359. * Defaults to false. 
  2360. * @type string $error_type Optional. Error type. Either 'bool' or 'wp_error'. Default: 'bool'. 
  2361. * } 
  2362. * @return int|bool The ID of the comment on success, otherwise false. 
  2363. */ 
  2364. function bp_activity_new_comment( $args = '' ) { 
  2365. $bp = buddypress(); 
  2366.  
  2367. $r = wp_parse_args( $args, array( 
  2368. 'id' => false,  
  2369. 'content' => false,  
  2370. 'user_id' => bp_loggedin_user_id(),  
  2371. 'activity_id' => false, // ID of the root activity item. 
  2372. 'parent_id' => false, // ID of a parent comment (optional). 
  2373. 'primary_link' => '',  
  2374. 'skip_notification' => false,  
  2375. 'error_type' => 'bool' 
  2376. ) ); 
  2377.  
  2378. // Error type is boolean; need to initialize some variables for backpat. 
  2379. if ( 'bool' === $r['error_type'] ) { 
  2380. if ( empty( $bp->activity->errors ) ) { 
  2381. $bp->activity->errors = array(); 
  2382.  
  2383. // Default error message. 
  2384. $feedback = __( 'There was an error posting your reply. Please try again.', 'buddypress' ); 
  2385.  
  2386. // Bail if missing necessary data. 
  2387. if ( empty( $r['content'] ) || empty( $r['user_id'] ) || empty( $r['activity_id'] ) ) { 
  2388. $error = new WP_Error( 'missing_data', $feedback ); 
  2389.  
  2390. if ( 'wp_error' === $r['error_type'] ) { 
  2391. return $error; 
  2392.  
  2393. // Backpat. 
  2394. } else { 
  2395. $bp->activity->errors['new_comment'] = $error; 
  2396. return false; 
  2397.  
  2398. // Maybe set current activity ID as the parent. 
  2399. if ( empty( $r['parent_id'] ) ) { 
  2400. $r['parent_id'] = $r['activity_id']; 
  2401.  
  2402. $activity_id = $r['activity_id']; 
  2403.  
  2404. // Get the parent activity. 
  2405. $activity = new BP_Activity_Activity( $activity_id ); 
  2406.  
  2407. // Bail if the parent activity does not exist. 
  2408. if ( empty( $activity->date_recorded ) ) { 
  2409. $error = new WP_Error( 'missing_activity', __( 'The item you were replying to no longer exists.', 'buddypress' ) ); 
  2410.  
  2411. if ( 'wp_error' === $r['error_type'] ) { 
  2412. return $error; 
  2413.  
  2414. // Backpat. 
  2415. } else { 
  2416. $bp->activity->errors['new_comment'] = $error; 
  2417. return false; 
  2418.  
  2419.  
  2420. // Check to see if the parent activity is hidden, and if so, hide this comment publicly. 
  2421. $is_hidden = $activity->hide_sitewide ? 1 : 0; 
  2422.  
  2423. /** 
  2424. * Filters the content of a new comment. 
  2425. * 
  2426. * @since 1.2.0 
  2427. * 
  2428. * @param string $r Content for the newly posted comment. 
  2429. */ 
  2430. $comment_content = apply_filters( 'bp_activity_comment_content', $r['content'] ); 
  2431.  
  2432. // Insert the activity comment. 
  2433. $comment_id = bp_activity_add( array( 
  2434. 'id' => $r['id'],  
  2435. 'content' => $comment_content,  
  2436. 'component' => buddypress()->activity->id,  
  2437. 'type' => 'activity_comment',  
  2438. 'primary_link' => $r['primary_link'],  
  2439. 'user_id' => $r['user_id'],  
  2440. 'item_id' => $activity_id,  
  2441. 'secondary_item_id' => $r['parent_id'],  
  2442. 'hide_sitewide' => $is_hidden,  
  2443. 'error_type' => $r['error_type'] 
  2444. ) ); 
  2445.  
  2446. // Bail on failure. 
  2447. if ( false === $comment_id || is_wp_error( $comment_id ) ) { 
  2448. return $comment_id; 
  2449.  
  2450. // Comment caches are stored only with the top-level item. 
  2451. wp_cache_delete( $activity_id, 'bp_activity_comments' ); 
  2452.  
  2453. // Walk the tree to clear caches for all parent items. 
  2454. $clear_id = $r['parent_id']; 
  2455. while ( $clear_id != $activity_id ) { 
  2456. $clear_object = new BP_Activity_Activity( $clear_id ); 
  2457. wp_cache_delete( $clear_id, 'bp_activity' ); 
  2458. $clear_id = intval( $clear_object->secondary_item_id ); 
  2459. wp_cache_delete( $activity_id, 'bp_activity' ); 
  2460.  
  2461. if ( empty( $r[ 'skip_notification' ] ) ) { 
  2462. /** 
  2463. * Fires near the end of an activity comment posting, before the returning of the comment ID. 
  2464. * Sends a notification to the user @see bp_activity_new_comment_notification_helper(). 
  2465. * 
  2466. * @since 1.2.0 
  2467. * 
  2468. * @param int $comment_id ID of the newly posted activity comment. 
  2469. * @param array $r Array of parsed comment arguments. 
  2470. * @param BP_Activity_Activity $activity Activity item being commented on. 
  2471. */ 
  2472. do_action( 'bp_activity_comment_posted', $comment_id, $r, $activity ); 
  2473. } else { 
  2474. /** 
  2475. * Fires near the end of an activity comment posting, before the returning of the comment ID. 
  2476. * without sending a notification to the user 
  2477. * 
  2478. * @since 2.5.0 
  2479. * 
  2480. * @param int $comment_id ID of the newly posted activity comment. 
  2481. * @param array $r Array of parsed comment arguments. 
  2482. * @param BP_Activity_Activity $activity Activity item being commented on. 
  2483. */ 
  2484. do_action( 'bp_activity_comment_posted_notification_skipped', $comment_id, $r, $activity ); 
  2485.  
  2486. if ( empty( $comment_id ) ) { 
  2487. $error = new WP_Error( 'comment_failed', $feedback ); 
  2488.  
  2489. if ( 'wp_error' === $r['error_type'] ) { 
  2490. return $error; 
  2491.  
  2492. // Backpat. 
  2493. } else { 
  2494. $bp->activity->errors['new_comment'] = $error; 
  2495.  
  2496. return $comment_id; 
  2497.  
  2498. /** 
  2499. * Fetch the activity_id for an existing activity entry in the DB. 
  2500. * 
  2501. * @since 1.2.0 
  2502. * 
  2503. * @see BP_Activity_Activity::get() For more information on accepted arguments. 
  2504. * 
  2505. * @param array|string $args See BP_Activity_Activity::get() for description. 
  2506. * @return int $activity_id The ID of the activity item found. 
  2507. */ 
  2508. function bp_activity_get_activity_id( $args = '' ) { 
  2509.  
  2510. $r = bp_parse_args( $args, array( 
  2511. 'user_id' => false,  
  2512. 'component' => false,  
  2513. 'type' => false,  
  2514. 'item_id' => false,  
  2515. 'secondary_item_id' => false,  
  2516. 'action' => false,  
  2517. 'content' => false,  
  2518. 'date_recorded' => false,  
  2519. ) ); 
  2520.  
  2521. /** 
  2522. * Filters the activity ID being requested. 
  2523. * 
  2524. * @since 1.2.0 
  2525. * @since 2.5.0 Added the `$r` and `$args` parameters. 
  2526. * 
  2527. * @param BP_Activity_Activity $value ID returned by BP_Activity_Activity get_id() method with provided arguments. 
  2528. * @param array $r Parsed function arguments. 
  2529. * @param array $args Arguments passed to the function. 
  2530. */ 
  2531. return apply_filters( 'bp_activity_get_activity_id', BP_Activity_Activity::get_id( 
  2532. $r['user_id'],  
  2533. $r['component'],  
  2534. $r['type'],  
  2535. $r['item_id'],  
  2536. $r['secondary_item_id'],  
  2537. $r['action'],  
  2538. $r['content'],  
  2539. $r['date_recorded'] 
  2540. ), $r, $args ); 
  2541.  
  2542. /** 
  2543. * Delete activity item(s). 
  2544. * 
  2545. * If you're looking to hook into one action that provides the ID(s) of 
  2546. * the activity/activities deleted, then use: 
  2547. * 
  2548. * add_action( 'bp_activity_deleted_activities', 'my_function' ); 
  2549. * 
  2550. * The action passes one parameter that is a single activity ID or an 
  2551. * array of activity IDs depending on the number deleted. 
  2552. * 
  2553. * If you are deleting an activity comment please use bp_activity_delete_comment(); 
  2554. * 
  2555. * @since 1.0.0 
  2556. * 
  2557. * @see BP_Activity_Activity::get() For more information on accepted arguments. 
  2558. * 
  2559. * @param array|string $args To delete specific activity items, use 
  2560. * $args = array( 'id' => $ids ); Otherwise, to use 
  2561. * filters for item deletion, the argument format is 
  2562. * the same as BP_Activity_Activity::get(). 
  2563. * See that method for a description. 
  2564. * @return bool True on success, false on failure. 
  2565. */ 
  2566. function bp_activity_delete( $args = '' ) { 
  2567.  
  2568. // Pass one or more the of following variables to delete by those variables. 
  2569. $args = bp_parse_args( $args, array( 
  2570. 'id' => false,  
  2571. 'action' => false,  
  2572. 'content' => false,  
  2573. 'component' => false,  
  2574. 'type' => false,  
  2575. 'primary_link' => false,  
  2576. 'user_id' => false,  
  2577. 'item_id' => false,  
  2578. 'secondary_item_id' => false,  
  2579. 'date_recorded' => false,  
  2580. 'hide_sitewide' => false 
  2581. ) ); 
  2582.  
  2583. /** 
  2584. * Fires before an activity item proceeds to be deleted. 
  2585. * 
  2586. * @since 1.5.0 
  2587. * 
  2588. * @param array $args Array of arguments to be used with the activity deletion. 
  2589. */ 
  2590. do_action( 'bp_before_activity_delete', $args ); 
  2591.  
  2592. // Adjust the new mention count of any mentioned member. 
  2593. bp_activity_adjust_mention_count( $args['id'], 'delete' ); 
  2594.  
  2595. $activity_ids_deleted = BP_Activity_Activity::delete( $args ); 
  2596. if ( empty( $activity_ids_deleted ) ) { 
  2597. return false; 
  2598.  
  2599. // Check if the user's latest update has been deleted. 
  2600. $user_id = empty( $args['user_id'] ) 
  2601. ? bp_loggedin_user_id() 
  2602. : $args['user_id']; 
  2603.  
  2604. $latest_update = bp_get_user_meta( $user_id, 'bp_latest_update', true ); 
  2605. if ( !empty( $latest_update ) ) { 
  2606. if ( in_array( (int) $latest_update['id'], (array) $activity_ids_deleted ) ) { 
  2607. bp_delete_user_meta( $user_id, 'bp_latest_update' ); 
  2608.  
  2609. /** 
  2610. * Fires after the activity item has been deleted. 
  2611. * 
  2612. * @since 1.0.0 
  2613. * 
  2614. * @param array $args Array of arguments used with the activity deletion. 
  2615. */ 
  2616. do_action( 'bp_activity_delete', $args ); 
  2617.  
  2618. /** 
  2619. * Fires after the activity item has been deleted. 
  2620. * 
  2621. * @since 1.2.0 
  2622. * 
  2623. * @param array $activity_ids_deleted Array of affected activity item IDs. 
  2624. */ 
  2625. do_action( 'bp_activity_deleted_activities', $activity_ids_deleted ); 
  2626.  
  2627. wp_cache_delete( 'bp_activity_sitewide_front', 'bp' ); 
  2628.  
  2629. return true; 
  2630.  
  2631. /** 
  2632. * Delete an activity item by activity id. 
  2633. * 
  2634. * You should use bp_activity_delete() instead. 
  2635. * 
  2636. * @since 1.1.0 
  2637. * @deprecated 1.2.0 
  2638. * 
  2639. * 
  2640. * @param array|string $args See BP_Activity_Activity::get for a 
  2641. * description of accepted arguments. 
  2642. * @return bool True on success, false on failure. 
  2643. */ 
  2644. function bp_activity_delete_by_item_id( $args = '' ) { 
  2645.  
  2646. $r = bp_parse_args( $args, array( 
  2647. 'item_id' => false,  
  2648. 'component' => false,  
  2649. 'type' => false,  
  2650. 'user_id' => false,  
  2651. 'secondary_item_id' => false 
  2652. ) ); 
  2653.  
  2654. return bp_activity_delete( $r ); 
  2655.  
  2656. /** 
  2657. * Delete an activity item by activity id. 
  2658. * 
  2659. * @since 1.1.0 
  2660. * 
  2661. * 
  2662. * @param int $activity_id ID of the activity item to be deleted. 
  2663. * @return bool True on success, false on failure. 
  2664. */ 
  2665. function bp_activity_delete_by_activity_id( $activity_id ) { 
  2666. return bp_activity_delete( array( 'id' => $activity_id ) ); 
  2667.  
  2668. /** 
  2669. * Delete an activity item by its content. 
  2670. * 
  2671. * You should use bp_activity_delete() instead. 
  2672. * 
  2673. * @since 1.1.0 
  2674. * @deprecated 1.2.0 
  2675. * 
  2676. * 
  2677. * @param int $user_id The user id. 
  2678. * @param string $content The activity id. 
  2679. * @param string $component The activity component. 
  2680. * @param string $type The activity type. 
  2681. * @return bool True on success, false on failure. 
  2682. */ 
  2683. function bp_activity_delete_by_content( $user_id, $content, $component, $type ) { 
  2684. return bp_activity_delete( array( 
  2685. 'user_id' => $user_id,  
  2686. 'content' => $content,  
  2687. 'component' => $component,  
  2688. 'type' => $type 
  2689. ) ); 
  2690.  
  2691. /** 
  2692. * Delete a user's activity for a component. 
  2693. * 
  2694. * You should use bp_activity_delete() instead. 
  2695. * 
  2696. * @since 1.1.0 
  2697. * @deprecated 1.2.0 
  2698. * 
  2699. * 
  2700. * @param int $user_id The user id. 
  2701. * @param string $component The activity component. 
  2702. * @return bool True on success, false on failure. 
  2703. */ 
  2704. function bp_activity_delete_for_user_by_component( $user_id, $component ) { 
  2705. return bp_activity_delete( array( 
  2706. 'user_id' => $user_id,  
  2707. 'component' => $component 
  2708. ) ); 
  2709.  
  2710. /** 
  2711. * Delete an activity comment. 
  2712. * 
  2713. * @since 1.2.0 
  2714. * 
  2715. * @todo Why is an activity id required? We could look this up. 
  2716. * @todo Why do we encourage users to call this function directly? We could just 
  2717. * as easily examine the activity type in bp_activity_delete() and then 
  2718. * call this function with the proper arguments if necessary. 
  2719. * 
  2720. * @param int $activity_id The ID of the "root" activity, ie the comment's 
  2721. * oldest ancestor. 
  2722. * @param int $comment_id The ID of the comment to be deleted. 
  2723. * @return bool True on success, false on failure. 
  2724. */ 
  2725. function bp_activity_delete_comment( $activity_id, $comment_id ) { 
  2726. $deleted = false; 
  2727.  
  2728. /** 
  2729. * Filters whether BuddyPress should delete an activity comment or not. 
  2730. * 
  2731. * You may want to hook into this filter if you want to override this function and 
  2732. * handle the deletion of child comments differently. Make sure you return false. 
  2733. * 
  2734. * @since 1.2.0 
  2735. * @since 2.5.0 Add the deleted parameter (passed by reference) 
  2736. * 
  2737. * @param bool $value Whether BuddyPress should continue or not. 
  2738. * @param int $activity_id ID of the root activity item being deleted. 
  2739. * @param int $comment_id ID of the comment being deleted. 
  2740. * @param bool $deleted Whether the activity comment has been deleted or not. 
  2741. */ 
  2742. if ( ! apply_filters_ref_array( 'bp_activity_delete_comment_pre', array( true, $activity_id, $comment_id, &$deleted ) ) ) { 
  2743. return $deleted; 
  2744.  
  2745. // Delete any children of this comment. 
  2746. bp_activity_delete_children( $activity_id, $comment_id ); 
  2747.  
  2748. // Delete the actual comment. 
  2749. if ( ! bp_activity_delete( array( 'id' => $comment_id, 'type' => 'activity_comment' ) ) ) { 
  2750. return false; 
  2751. } else { 
  2752. $deleted = true; 
  2753.  
  2754. // Purge comment cache for the root activity update. 
  2755. wp_cache_delete( $activity_id, 'bp_activity_comments' ); 
  2756.  
  2757. // Recalculate the comment tree. 
  2758. BP_Activity_Activity::rebuild_activity_comment_tree( $activity_id ); 
  2759.  
  2760. /** 
  2761. * Fires at the end of the deletion of an activity comment, before returning success. 
  2762. * 
  2763. * @since 1.2.0 
  2764. * 
  2765. * @param int $activity_id ID of the activity that has had a comment deleted from. 
  2766. * @param int $comment_id ID of the comment that was deleted. 
  2767. */ 
  2768. do_action( 'bp_activity_delete_comment', $activity_id, $comment_id ); 
  2769.  
  2770. return $deleted; 
  2771.  
  2772. /** 
  2773. * Delete an activity comment's children. 
  2774. * 
  2775. * @since 1.2.0 
  2776. * 
  2777. * 
  2778. * @param int $activity_id The ID of the "root" activity, ie the 
  2779. * comment's oldest ancestor. 
  2780. * @param int $comment_id The ID of the comment to be deleted. 
  2781. */ 
  2782. function bp_activity_delete_children( $activity_id, $comment_id ) { 
  2783.  
  2784. // Get activity children to delete. 
  2785. $children = BP_Activity_Activity::get_child_comments( $comment_id ); 
  2786.  
  2787. // Recursively delete all children of this comment. 
  2788. if ( ! empty( $children ) ) { 
  2789. foreach( (array) $children as $child ) { 
  2790. bp_activity_delete_children( $activity_id, $child->id ); 
  2791.  
  2792. // Delete the comment itself. 
  2793. bp_activity_delete( array( 
  2794. 'secondary_item_id' => $comment_id,  
  2795. 'type' => 'activity_comment',  
  2796. 'item_id' => $activity_id 
  2797. ) ); 
  2798.  
  2799. /** 
  2800. * Get the permalink for a single activity item. 
  2801. * 
  2802. * When only the $activity_id param is passed, BP has to instantiate a new 
  2803. * BP_Activity_Activity object. To save yourself some processing overhead,  
  2804. * be sure to pass the full $activity_obj parameter as well, if you already 
  2805. * have it available. 
  2806. * 
  2807. * @since 1.2.0 
  2808. * 
  2809. * @param int $activity_id The unique id of the activity object. 
  2810. * @param object|bool $activity_obj Optional. The activity object. 
  2811. * @return string $link Permalink for the activity item. 
  2812. */ 
  2813. function bp_activity_get_permalink( $activity_id, $activity_obj = false ) { 
  2814. $bp = buddypress(); 
  2815.  
  2816. if ( empty( $activity_obj ) ) { 
  2817. $activity_obj = new BP_Activity_Activity( $activity_id ); 
  2818.  
  2819. if ( isset( $activity_obj->current_comment ) ) { 
  2820. $activity_obj = $activity_obj->current_comment; 
  2821.  
  2822. $use_primary_links = array( 
  2823. 'new_blog_post',  
  2824. 'new_blog_comment',  
  2825. 'new_forum_topic',  
  2826. 'new_forum_post',  
  2827. ); 
  2828.  
  2829. if ( ! empty( $bp->activity->track ) ) { 
  2830. $use_primary_links = array_merge( $use_primary_links, array_keys( $bp->activity->track ) ); 
  2831.  
  2832. if ( false !== array_search( $activity_obj->type, $use_primary_links ) ) { 
  2833. $link = $activity_obj->primary_link; 
  2834. } else { 
  2835. if ( 'activity_comment' == $activity_obj->type ) { 
  2836. $link = bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/p/' . $activity_obj->item_id . '/#acomment-' . $activity_obj->id; 
  2837. } else { 
  2838. $link = bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/p/' . $activity_obj->id . '/'; 
  2839.  
  2840. /** 
  2841. * Filters the activity permalink for the specified activity item. 
  2842. * 
  2843. * @since 1.2.0 
  2844. * 
  2845. * @param array $array Array holding activity permalink and activity item object. 
  2846. */ 
  2847. return apply_filters_ref_array( 'bp_activity_get_permalink', array( $link, &$activity_obj ) ); 
  2848.  
  2849. /** 
  2850. * Hide a user's activity. 
  2851. * 
  2852. * @since 1.2.0 
  2853. * 
  2854. * @param int $user_id The ID of the user whose activity is being hidden. 
  2855. * @return bool True on success, false on failure. 
  2856. */ 
  2857. function bp_activity_hide_user_activity( $user_id ) { 
  2858. return BP_Activity_Activity::hide_all_for_user( $user_id ); 
  2859.  
  2860. /** 
  2861. * Take content, remove images, and replace them with a single thumbnail image. 
  2862. * 
  2863. * The format of items in the activity stream is such that we do not want to 
  2864. * allow an arbitrary number of arbitrarily large images to be rendered. 
  2865. * However, the activity stream is built to elegantly display a single 
  2866. * thumbnail corresponding to the activity comment. This function looks 
  2867. * through the content, grabs the first image and converts it to a thumbnail,  
  2868. * and removes the rest of the images from the string. 
  2869. * 
  2870. * As of BuddyPress 2.3, this function is no longer in use. 
  2871. * 
  2872. * @since 1.2.0 
  2873. * 
  2874. * @param string $content The content of the activity item. 
  2875. * @param string|bool $link Optional. The unescaped URL that the image should link 
  2876. * to. If absent, the image will not be a link. 
  2877. * @param array|bool $args Optional. The args passed to the activity 
  2878. * creation function (eg bp_blogs_record_activity()). 
  2879. * @return string $content The content with images stripped and replaced with a 
  2880. * single thumb. 
  2881. */ 
  2882. function bp_activity_thumbnail_content_images( $content, $link = false, $args = false ) { 
  2883.  
  2884. preg_match_all( '/<img[^>]*>/Ui', $content, $matches ); 
  2885.  
  2886. // Remove <img> tags. Also remove caption shortcodes and caption text if present. 
  2887. $content = preg_replace('|(\[caption(.*?)\])?<img[^>]*>([^\[\[]*\[\/caption\])?|', '', $content ); 
  2888.  
  2889. if ( !empty( $matches ) && !empty( $matches[0] ) ) { 
  2890.  
  2891. // Get the SRC value. 
  2892. preg_match( '/<img.*?(src\=[\'|"]{0, 1}.*?[\'|"]{0, 1})[\s|>]{1}/i', $matches[0][0], $src ); 
  2893.  
  2894. // Get the width and height. 
  2895. preg_match( '/<img.*?(height\=[\'|"]{0, 1}.*?[\'|"]{0, 1})[\s|>]{1}/i', $matches[0][0], $height ); 
  2896. preg_match( '/<img.*?(width\=[\'|"]{0, 1}.*?[\'|"]{0, 1})[\s|>]{1}/i', $matches[0][0], $width ); 
  2897.  
  2898. if ( ! empty( $src ) ) { 
  2899. $src = substr( substr( str_replace( 'src=', '', $src[1] ), 0, -1 ), 1 ); 
  2900.  
  2901. if ( isset( $width[1] ) ) { 
  2902. $width = substr( substr( str_replace( 'width=', '', $width[1] ), 0, -1 ), 1 ); 
  2903.  
  2904. if ( isset( $height[1] ) ) { 
  2905. $height = substr( substr( str_replace( 'height=', '', $height[1] ), 0, -1 ), 1 ); 
  2906.  
  2907. if ( empty( $width ) || empty( $height ) ) { 
  2908. $width = 100; 
  2909. $height = 100; 
  2910.  
  2911. $ratio = (int) $width / (int) $height; 
  2912. $new_height = (int) $height >= 100 ? 100 : $height; 
  2913. $new_width = $new_height * $ratio; 
  2914. $image = '<img src="' . esc_url( $src ) . '" width="' . absint( $new_width ) . '" height="' . absint( $new_height ) . '" alt="' . __( 'Thumbnail', 'buddypress' ) . '" class="align-left thumbnail" />'; 
  2915.  
  2916. if ( !empty( $link ) ) { 
  2917. $image = '<a href="' . esc_url( $link ) . '">' . $image . '</a>'; 
  2918.  
  2919. $content = $image . $content; 
  2920.  
  2921. /** 
  2922. * Filters the activity content that had a thumbnail replace images. 
  2923. * 
  2924. * @since 1.2.0 
  2925. * 
  2926. * @param string $content Activity content that had images replaced in. 
  2927. * @param array $matches Array of all image tags found in the posted content. 
  2928. * @param array $args Arguments passed into function creating the activity update. 
  2929. */ 
  2930. return apply_filters( 'bp_activity_thumbnail_content_images', $content, $matches, $args ); 
  2931.  
  2932. /** 
  2933. * Gets the excerpt length for activity items. 
  2934. * 
  2935. * @since 2.8.0 
  2936. * 
  2937. * @return int Character length for activity excerpts. 
  2938. */ 
  2939. function bp_activity_get_excerpt_length() { 
  2940. /** 
  2941. * Filters the excerpt length for the activity excerpt. 
  2942. * 
  2943. * @since 1.5.0 
  2944. * 
  2945. * @param int Character length for activity excerpts. 
  2946. */ 
  2947. return (int) apply_filters( 'bp_activity_excerpt_length', 358 ); 
  2948.  
  2949. /** 
  2950. * Create a rich summary of an activity item for the activity stream. 
  2951. * 
  2952. * More than just a simple excerpt, the summary could contain oEmbeds and other types of media. 
  2953. * Currently, it's only used for blog post items, but it will probably be used for all types of 
  2954. * activity in the future. 
  2955. * 
  2956. * @since 2.3.0 
  2957. * 
  2958. * @param string $content The content of the activity item. 
  2959. * @param array $activity The data passed to bp_activity_add() or the values 
  2960. * from an Activity obj. 
  2961. * @return string $summary 
  2962. */ 
  2963. function bp_activity_create_summary( $content, $activity ) { 
  2964. $args = array( 
  2965. 'width' => isset( $GLOBALS['content_width'] ) ? (int) $GLOBALS['content_width'] : 'medium',  
  2966. ); 
  2967.  
  2968. // Get the WP_Post object if this activity type is a blog post. 
  2969. if ( $activity['type'] === 'new_blog_post' ) { 
  2970. $content = get_post( $activity['secondary_item_id'] ); 
  2971.  
  2972. /** 
  2973. * Filter the class name of the media extractor when creating an Activity summary. 
  2974. * 
  2975. * Use this filter to change the media extractor used to extract media info for the activity item. 
  2976. * 
  2977. * @since 2.3.0 
  2978. * 
  2979. * @param string $extractor Class name. 
  2980. * @param string $content The content of the activity item. 
  2981. * @param array $activity The data passed to bp_activity_add() or the values from an Activity obj. 
  2982. */ 
  2983. $extractor = apply_filters( 'bp_activity_create_summary_extractor_class', 'BP_Media_Extractor', $content, $activity ); 
  2984. $extractor = new $extractor; 
  2985.  
  2986. /** 
  2987. * Filter the arguments passed to the media extractor when creating an Activity summary. 
  2988. * 
  2989. * @since 2.3.0 
  2990. * 
  2991. * @param array $args Array of bespoke data for the media extractor. 
  2992. * @param string $content The 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 BP_Media_Extractor $extractor The media extractor object. 
  2995. */ 
  2996. $args = apply_filters( 'bp_activity_create_summary_extractor_args', $args, $content, $activity, $extractor ); 
  2997.  
  2998.  
  2999. // Extract media information from the $content. 
  3000. $media = $extractor->extract( $content, BP_Media_Extractor::ALL, $args ); 
  3001.  
  3002. // If we converted $content to an object earlier, flip it back to a string. 
  3003. if ( is_a( $content, 'WP_Post' ) ) { 
  3004. $content = $content->post_content; 
  3005.  
  3006. $para_count = substr_count( strtolower( wpautop( $content ) ), '<p>' ); 
  3007. $has_audio = ! empty( $media['has']['audio'] ) && $media['has']['audio']; 
  3008. $has_videos = ! empty( $media['has']['videos'] ) && $media['has']['videos']; 
  3009. $has_feat_image = ! empty( $media['has']['featured_images'] ) && $media['has']['featured_images']; 
  3010. $has_galleries = ! empty( $media['has']['galleries'] ) && $media['has']['galleries']; 
  3011. $has_images = ! empty( $media['has']['images'] ) && $media['has']['images']; 
  3012. $has_embeds = false; 
  3013.  
  3014. // Embeds must be subtracted from the paragraph count. 
  3015. if ( ! empty( $media['has']['embeds'] ) ) { 
  3016. $has_embeds = $media['has']['embeds'] > 0; 
  3017. $para_count -= count( $media['has']['embeds'] ); 
  3018.  
  3019. $extracted_media = array(); 
  3020. $use_media_type = ''; 
  3021. $image_source = ''; 
  3022.  
  3023. // If it's a short article and there's an embed/audio/video, use it. 
  3024. if ( $para_count <= 3 ) { 
  3025. if ( $has_embeds ) { 
  3026. $use_media_type = 'embeds'; 
  3027. } elseif ( $has_audio ) { 
  3028. $use_media_type = 'audio'; 
  3029. } elseif ( $has_videos ) { 
  3030. $use_media_type = 'videos'; 
  3031.  
  3032. // If not, or in any other situation, try to use an image. 
  3033. if ( ! $use_media_type && $has_images ) { 
  3034. $use_media_type = 'images'; 
  3035. $image_source = 'html'; 
  3036.  
  3037. // Featured Image > Galleries > inline <img>. 
  3038. if ( $has_feat_image ) { 
  3039. $image_source = 'featured_images'; 
  3040.  
  3041. } elseif ( $has_galleries ) { 
  3042. $image_source = 'galleries'; 
  3043.  
  3044. // Extract an item from the $media results. 
  3045. if ( $use_media_type ) { 
  3046. if ( $use_media_type === 'images' ) { 
  3047. $extracted_media = wp_list_filter( $media[ $use_media_type ], array( 'source' => $image_source ) ); 
  3048. $extracted_media = array_shift( $extracted_media ); 
  3049. } else { 
  3050. $extracted_media = array_shift( $media[ $use_media_type ] ); 
  3051.  
  3052. /** 
  3053. * Filter the results of the media extractor when creating an Activity summary. 
  3054. * 
  3055. * @since 2.3.0 
  3056. * 
  3057. * @param array $extracted_media Extracted media item. See {@link BP_Media_Extractor::extract()} for format. 
  3058. * @param string $content Content of the activity item. 
  3059. * @param array $activity The data passed to bp_activity_add() or the values from an Activity obj. 
  3060. * @param array $media All results from the media extraction. 
  3061. * See {@link BP_Media_Extractor::extract()} for format. 
  3062. * @param string $use_media_type The kind of media item that was preferentially extracted. 
  3063. * @param string $image_source If $use_media_type was "images", the preferential source of the image. 
  3064. * Otherwise empty. 
  3065. */ 
  3066. $extracted_media = apply_filters( 
  3067. 'bp_activity_create_summary_extractor_result',  
  3068. $extracted_media,  
  3069. $content,  
  3070. $activity,  
  3071. $media,  
  3072. $use_media_type,  
  3073. $image_source 
  3074. ); 
  3075.  
  3076. // Generate a text excerpt for this activity item (and remove any oEmbeds URLs). 
  3077. $summary = bp_create_excerpt( html_entity_decode( $content ), 225, array( 
  3078. 'html' => false,  
  3079. 'filter_shortcodes' => true,  
  3080. 'strip_tags' => true,  
  3081. 'remove_links' => true 
  3082. ) ); 
  3083.  
  3084. if ( $use_media_type === 'embeds' ) { 
  3085. $summary .= PHP_EOL . PHP_EOL . $extracted_media['url']; 
  3086. } elseif ( $use_media_type === 'images' ) { 
  3087. $summary .= sprintf( ' <img src="%s">', esc_url( $extracted_media['url'] ) ); 
  3088. } elseif ( in_array( $use_media_type, array( 'audio', 'videos' ), true ) ) { 
  3089. $summary .= PHP_EOL . PHP_EOL . $extracted_media['original']; // Full shortcode. 
  3090.  
  3091. /** 
  3092. * Filters the newly-generated summary for the activity item. 
  3093. * 
  3094. * @since 2.3.0 
  3095. * 
  3096. * @param string $summary Activity summary HTML. 
  3097. * @param string $content Content of the activity item. 
  3098. * @param array $activity The data passed to bp_activity_add() or the values from an Activity obj. 
  3099. * @param array $extracted_media Media item extracted. See {@link BP_Media_Extractor::extract()} for format. 
  3100. */ 
  3101. return apply_filters( 'bp_activity_create_summary', $summary, $content, $activity, $extracted_media ); 
  3102.  
  3103. /** 
  3104. * Fetch whether the current user is allowed to mark items as spam. 
  3105. * 
  3106. * @since 1.6.0 
  3107. * 
  3108. * @return bool True if user is allowed to mark activity items as spam. 
  3109. */ 
  3110. function bp_activity_user_can_mark_spam() { 
  3111.  
  3112. /** 
  3113. * Filters whether the current user should be able to mark items as spam. 
  3114. * 
  3115. * @since 1.6.0 
  3116. * 
  3117. * @param bool $moderate Whether or not the current user has bp_moderate capability. 
  3118. */ 
  3119. return apply_filters( 'bp_activity_user_can_mark_spam', bp_current_user_can( 'bp_moderate' ) ); 
  3120.  
  3121. /** 
  3122. * Mark an activity item as spam. 
  3123. * 
  3124. * @since 1.6.0 
  3125. * 
  3126. * @todo We should probably save $source to activity meta. 
  3127. * 
  3128. * @param BP_Activity_Activity $activity The activity item to be spammed. 
  3129. * @param string $source Optional. Default is "by_a_person" (ie, a person has 
  3130. * manually marked the activity as spam). BP core also 
  3131. * accepts 'by_akismet'. 
  3132. */ 
  3133. function bp_activity_mark_as_spam( &$activity, $source = 'by_a_person' ) { 
  3134. $bp = buddypress(); 
  3135.  
  3136. $activity->is_spam = 1; 
  3137.  
  3138. // Clear the activity stream first page cache. 
  3139. wp_cache_delete( 'bp_activity_sitewide_front', 'bp' ); 
  3140.  
  3141. // Clear the activity comment cache for this activity item. 
  3142. wp_cache_delete( $activity->id, 'bp_activity_comments' ); 
  3143.  
  3144. // If Akismet is active, and this was a manual spam/ham request, stop Akismet checking the activity. 
  3145. if ( 'by_a_person' == $source && !empty( $bp->activity->akismet ) ) { 
  3146. remove_action( 'bp_activity_before_save', array( $bp->activity->akismet, 'check_activity' ), 4 ); 
  3147.  
  3148. // Build data package for Akismet. 
  3149. $activity_data = BP_Akismet::build_akismet_data_package( $activity ); 
  3150.  
  3151. // Tell Akismet this is spam. 
  3152. $activity_data = $bp->activity->akismet->send_akismet_request( $activity_data, 'submit', 'spam' ); 
  3153.  
  3154. // Update meta. 
  3155. add_action( 'bp_activity_after_save', array( $bp->activity->akismet, 'update_activity_spam_meta' ), 1, 1 ); 
  3156.  
  3157. /** 
  3158. * Fires at the end of the process to mark an activity item as spam. 
  3159. * 
  3160. * @since 1.6.0 
  3161. * 
  3162. * @param BP_Activity_Activity $activity Activity item being marked as spam. 
  3163. * @param string $source Source of determination of spam status. For example 
  3164. * "by_a_person" or "by_akismet". 
  3165. */ 
  3166. do_action( 'bp_activity_mark_as_spam', $activity, $source ); 
  3167.  
  3168. /** 
  3169. * Mark an activity item as ham. 
  3170. * 
  3171. * @since 1.6.0 
  3172. * 
  3173. * @param BP_Activity_Activity $activity The activity item to be hammed. Passed by reference. 
  3174. * @param string $source Optional. Default is "by_a_person" (ie, a person has 
  3175. * manually marked the activity as spam). BP core also accepts 
  3176. * 'by_akismet'. 
  3177. */ 
  3178. function bp_activity_mark_as_ham( &$activity, $source = 'by_a_person' ) { 
  3179. $bp = buddypress(); 
  3180.  
  3181. $activity->is_spam = 0; 
  3182.  
  3183. // Clear the activity stream first page cache. 
  3184. wp_cache_delete( 'bp_activity_sitewide_front', 'bp' ); 
  3185.  
  3186. // Clear the activity comment cache for this activity item. 
  3187. wp_cache_delete( $activity->id, 'bp_activity_comments' ); 
  3188.  
  3189. // If Akismet is active, and this was a manual spam/ham request, stop Akismet checking the activity. 
  3190. if ( 'by_a_person' == $source && !empty( $bp->activity->akismet ) ) { 
  3191. remove_action( 'bp_activity_before_save', array( $bp->activity->akismet, 'check_activity' ), 4 ); 
  3192.  
  3193. // Build data package for Akismet. 
  3194. $activity_data = BP_Akismet::build_akismet_data_package( $activity ); 
  3195.  
  3196. // Tell Akismet this is spam. 
  3197. $activity_data = $bp->activity->akismet->send_akismet_request( $activity_data, 'submit', 'ham' ); 
  3198.  
  3199. // Update meta. 
  3200. add_action( 'bp_activity_after_save', array( $bp->activity->akismet, 'update_activity_ham_meta' ), 1, 1 ); 
  3201.  
  3202. /** 
  3203. * Fires at the end of the process to mark an activity item as ham. 
  3204. * 
  3205. * @since 1.6.0 
  3206. * 
  3207. * @param BP_Activity_Activity $activity Activity item being marked as ham. 
  3208. * @param string $source Source of determination of ham status. For example 
  3209. * "by_a_person" or "by_akismet". 
  3210. */ 
  3211. do_action( 'bp_activity_mark_as_ham', $activity, $source ); 
  3212.  
  3213. /** Emails *********************************************************************/ 
  3214.  
  3215. /** 
  3216. * Send email and BP notifications when a user is mentioned in an update. 
  3217. * 
  3218. * @since 1.2.0 
  3219. * 
  3220. * @param int $activity_id The ID of the activity update. 
  3221. * @param int $receiver_user_id The ID of the user who is receiving the update. 
  3222. */ 
  3223. function bp_activity_at_message_notification( $activity_id, $receiver_user_id ) { 
  3224. $notifications = BP_Core_Notification::get_all_for_user( $receiver_user_id, 'all' ); 
  3225.  
  3226. // Don't leave multiple notifications for the same activity item. 
  3227. foreach( $notifications as $notification ) { 
  3228. if ( $activity_id == $notification->item_id ) { 
  3229. return; 
  3230.  
  3231. $activity = new BP_Activity_Activity( $activity_id ); 
  3232. $email_type = 'activity-at-message'; 
  3233. $group_name = ''; 
  3234. $message_link = bp_activity_get_permalink( $activity_id ); 
  3235. $poster_name = bp_core_get_user_displayname( $activity->user_id ); 
  3236.  
  3237. remove_filter( 'bp_get_activity_content_body', 'convert_smilies' ); 
  3238. remove_filter( 'bp_get_activity_content_body', 'wpautop' ); 
  3239. remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 ); 
  3240.  
  3241. /** This filter is documented in bp-activity/bp-activity-template.php */ 
  3242. $content = apply_filters_ref_array( 'bp_get_activity_content_body', array( $activity->content, &$activity ) ); 
  3243.  
  3244. add_filter( 'bp_get_activity_content_body', 'convert_smilies' ); 
  3245. add_filter( 'bp_get_activity_content_body', 'wpautop' ); 
  3246. add_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 ); 
  3247.  
  3248. // Now email the user with the contents of the message (if they have enabled email notifications). 
  3249. if ( 'no' != bp_get_user_meta( $receiver_user_id, 'notification_activity_new_mention', true ) ) { 
  3250. if ( bp_is_active( 'groups' ) && bp_is_group() ) { 
  3251. $email_type = 'groups-at-message'; 
  3252. $group_name = bp_get_current_group_name(); 
  3253.  
  3254. $unsubscribe_args = array( 
  3255. 'user_id' => $receiver_user_id,  
  3256. 'notification_type' => $email_type,  
  3257. ); 
  3258.  
  3259. $args = array( 
  3260. 'tokens' => array( 
  3261. 'activity' => $activity,  
  3262. 'usermessage' => wp_strip_all_tags( $content ),  
  3263. 'group.name' => $group_name,  
  3264. 'mentioned.url' => $message_link,  
  3265. 'poster.name' => $poster_name,  
  3266. 'receiver-user.id' => $receiver_user_id,  
  3267. 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),  
  3268. ),  
  3269. ); 
  3270.  
  3271. bp_send_email( $email_type, $receiver_user_id, $args ); 
  3272.  
  3273. /** 
  3274. * Fires after the sending of an @mention email notification. 
  3275. * 
  3276. * @since 1.5.0 
  3277. * @since 2.5.0 $subject, $message, $content arguments unset and deprecated. 
  3278. * 
  3279. * @param BP_Activity_Activity $activity Activity Item object. 
  3280. * @param string $deprecated Removed in 2.5; now an empty string. 
  3281. * @param string $deprecated Removed in 2.5; now an empty string. 
  3282. * @param string $deprecated Removed in 2.5; now an empty string. 
  3283. * @param int $receiver_user_id The ID of the user who is receiving the update. 
  3284. */ 
  3285. do_action( 'bp_activity_sent_mention_email', $activity, '', '', '', $receiver_user_id ); 
  3286.  
  3287. /** 
  3288. * Send email and BP notifications when an activity item receives a comment. 
  3289. * 
  3290. * @since 1.2.0 
  3291. * @since 2.5.0 Updated to use new email APIs. 
  3292. * 
  3293. * @param int $comment_id The comment id. 
  3294. * @param int $commenter_id The ID of the user who posted the comment. 
  3295. * @param array $params {@link bp_activity_new_comment()}. 
  3296. */ 
  3297. function bp_activity_new_comment_notification( $comment_id = 0, $commenter_id = 0, $params = array() ) { 
  3298. $original_activity = new BP_Activity_Activity( $params['activity_id'] ); 
  3299. $poster_name = bp_core_get_user_displayname( $commenter_id ); 
  3300. $thread_link = bp_activity_get_permalink( $params['activity_id'] ); 
  3301.  
  3302. remove_filter( 'bp_get_activity_content_body', 'convert_smilies' ); 
  3303. remove_filter( 'bp_get_activity_content_body', 'wpautop' ); 
  3304. remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 ); 
  3305.  
  3306. /** This filter is documented in bp-activity/bp-activity-template.php */ 
  3307. $content = apply_filters_ref_array( 'bp_get_activity_content_body', array( $params['content'], &$original_activity ) ); 
  3308.  
  3309. add_filter( 'bp_get_activity_content_body', 'convert_smilies' ); 
  3310. add_filter( 'bp_get_activity_content_body', 'wpautop' ); 
  3311. add_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 ); 
  3312.  
  3313. if ( $original_activity->user_id != $commenter_id ) { 
  3314.  
  3315. // Send an email if the user hasn't opted-out. 
  3316. if ( 'no' != bp_get_user_meta( $original_activity->user_id, 'notification_activity_new_reply', true ) ) { 
  3317.  
  3318. $unsubscribe_args = array( 
  3319. 'user_id' => $original_activity->user_id,  
  3320. 'notification_type' => 'activity-comment',  
  3321. ); 
  3322.  
  3323. $args = array( 
  3324. 'tokens' => array( 
  3325. 'comment.id' => $comment_id,  
  3326. 'commenter.id' => $commenter_id,  
  3327. 'usermessage' => wp_strip_all_tags( $content ),  
  3328. 'original_activity.user_id' => $original_activity->user_id,  
  3329. 'poster.name' => $poster_name,  
  3330. 'thread.url' => esc_url( $thread_link ),  
  3331. 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),  
  3332. ),  
  3333. ); 
  3334.  
  3335. bp_send_email( 'activity-comment', $original_activity->user_id, $args ); 
  3336.  
  3337. /** 
  3338. * Fires at the point that notifications should be sent for activity comments. 
  3339. * 
  3340. * @since 2.6.0 
  3341. * 
  3342. * @param BP_Activity_Activity $original_activity The original activity. 
  3343. * @param int $comment_id ID for the newly received comment. 
  3344. * @param int $commenter_id ID of the user who made the comment. 
  3345. * @param array $params Arguments used with the original activity comment. 
  3346. */ 
  3347. do_action( 'bp_activity_sent_reply_to_update_notification', $original_activity, $comment_id, $commenter_id, $params ); 
  3348.  
  3349.  
  3350. /** 
  3351. * If this is a reply to another comment, send an email notification to the 
  3352. * author of the immediate parent comment. 
  3353. */ 
  3354. if ( empty( $params['parent_id'] ) || ( $params['activity_id'] == $params['parent_id'] ) ) { 
  3355. return; 
  3356.  
  3357. $parent_comment = new BP_Activity_Activity( $params['parent_id'] ); 
  3358.  
  3359. if ( $parent_comment->user_id != $commenter_id && $original_activity->user_id != $parent_comment->user_id ) { 
  3360.  
  3361. // Send an email if the user hasn't opted-out. 
  3362. if ( 'no' != bp_get_user_meta( $parent_comment->user_id, 'notification_activity_new_reply', true ) ) { 
  3363.  
  3364. $unsubscribe_args = array( 
  3365. 'user_id' => $parent_comment->user_id,  
  3366. 'notification_type' => 'activity-comment-author',  
  3367. ); 
  3368.  
  3369. $args = array( 
  3370. 'tokens' => array( 
  3371. 'comment.id' => $comment_id,  
  3372. 'commenter.id' => $commenter_id,  
  3373. 'usermessage' => wp_strip_all_tags( $content ),  
  3374. 'parent-comment-user.id' => $parent_comment->user_id,  
  3375. 'poster.name' => $poster_name,  
  3376. 'thread.url' => esc_url( $thread_link ),  
  3377. 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),  
  3378. ),  
  3379. ); 
  3380.  
  3381. bp_send_email( 'activity-comment-author', $parent_comment->user_id, $args ); 
  3382.  
  3383. /** 
  3384. * Fires at the point that notifications should be sent for comments on activity replies. 
  3385. * 
  3386. * @since 2.6.0 
  3387. * 
  3388. * @param BP_Activity_Activity $parent_comment The parent activity. 
  3389. * @param int $comment_id ID for the newly received comment. 
  3390. * @param int $commenter_id ID of the user who made the comment. 
  3391. * @param array $params Arguments used with the original activity comment. 
  3392. */ 
  3393. do_action( 'bp_activity_sent_reply_to_reply_notification', $parent_comment, $comment_id, $commenter_id, $params ); 
  3394.  
  3395. /** 
  3396. * Helper method to map action arguments to function parameters. 
  3397. * 
  3398. * @since 1.9.0 
  3399. * 
  3400. * @param int $comment_id ID of the comment being notified about. 
  3401. * @param array $params Parameters to use with notification. 
  3402. */ 
  3403. function bp_activity_new_comment_notification_helper( $comment_id, $params ) { 
  3404. bp_activity_new_comment_notification( $comment_id, $params['user_id'], $params ); 
  3405. add_action( 'bp_activity_comment_posted', 'bp_activity_new_comment_notification_helper', 10, 2 ); 
  3406.  
  3407. /** Embeds *******************************************************************/ 
  3408.  
  3409. /** 
  3410. * Set up activity oEmbed cache during the activity loop. 
  3411. * 
  3412. * During an activity loop, this function sets up the hooks necessary to grab 
  3413. * each item's embeds from the cache, or put them in the cache if they are 
  3414. * not there yet. 
  3415. * 
  3416. * This does not cover recursive activity comments, as they do not use a real loop. 
  3417. * For that, see {@link bp_activity_comment_embed()}. 
  3418. * 
  3419. * @since 1.5.0 
  3420. * 
  3421. * @see BP_Embed 
  3422. * @see bp_embed_activity_cache() 
  3423. * @see bp_embed_activity_save_cache() 
  3424. * 
  3425. */ 
  3426. function bp_activity_embed() { 
  3427. add_filter( 'embed_post_id', 'bp_get_activity_id' ); 
  3428. add_filter( 'oembed_dataparse', 'bp_activity_oembed_dataparse', 10, 2 ); 
  3429. add_filter( 'bp_embed_get_cache', 'bp_embed_activity_cache', 10, 3 ); 
  3430. add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 ); 
  3431. add_action( 'activity_loop_start', 'bp_activity_embed' ); 
  3432.  
  3433. /** 
  3434. * Cache full oEmbed response from oEmbed. 
  3435. * 
  3436. * @since 2.6.0 
  3437. * 
  3438. * @param string $retval Current oEmbed result. 
  3439. * @param object $data Full oEmbed response. 
  3440. * @param string $url URL used for the oEmbed request. 
  3441. * @return string 
  3442. */ 
  3443. function bp_activity_oembed_dataparse( $retval, $data ) { 
  3444. buddypress()->activity->oembed_response = $data; 
  3445.  
  3446. return $retval; 
  3447.  
  3448. /** 
  3449. * Set up activity oEmbed cache while recursing through activity comments. 
  3450. * 
  3451. * While crawling through an activity comment tree 
  3452. * ({@link bp_activity_recurse_comments}), this function sets up the hooks 
  3453. * necessary to grab each comment's embeds from the cache, or put them in 
  3454. * the cache if they are not there yet. 
  3455. * 
  3456. * @since 1.5.0 
  3457. * 
  3458. * @see BP_Embed 
  3459. * @see bp_embed_activity_cache() 
  3460. * @see bp_embed_activity_save_cache() 
  3461. * 
  3462. */ 
  3463. function bp_activity_comment_embed() { 
  3464. add_filter( 'embed_post_id', 'bp_get_activity_comment_id' ); 
  3465. add_filter( 'bp_embed_get_cache', 'bp_embed_activity_cache', 10, 3 ); 
  3466. add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 ); 
  3467. add_action( 'bp_before_activity_comment', 'bp_activity_comment_embed' ); 
  3468.  
  3469. /** 
  3470. * When a user clicks on a "Read More" item, make sure embeds are correctly parsed and shown for the expanded content. 
  3471. * 
  3472. * @since 1.5.0 
  3473. * 
  3474. * @see BP_Embed 
  3475. * 
  3476. * @param object $activity The activity that is being expanded. 
  3477. */ 
  3478. function bp_dtheme_embed_read_more( $activity ) { 
  3479. buddypress()->activity->read_more_id = $activity->id; 
  3480.  
  3481. add_filter( 'embed_post_id', function() { return buddypress()->activity->read_more_id; } ); 
  3482. add_filter( 'bp_embed_get_cache', 'bp_embed_activity_cache', 10, 3 ); 
  3483. add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 ); 
  3484. add_action( 'bp_dtheme_get_single_activity_content', 'bp_dtheme_embed_read_more' ); 
  3485. add_action( 'bp_legacy_theme_get_single_activity_content', 'bp_dtheme_embed_read_more' ); 
  3486.  
  3487. /** 
  3488. * Clean up 'embed_post_id' filter after comment recursion. 
  3489. * 
  3490. * This filter must be removed so that the non-comment filters take over again 
  3491. * once the comments are done being processed. 
  3492. * 
  3493. * @since 1.5.0 
  3494. * 
  3495. * @see bp_activity_comment_embed() 
  3496. */ 
  3497. function bp_activity_comment_embed_after_recurse() { 
  3498. remove_filter( 'embed_post_id', 'bp_get_activity_comment_id' ); 
  3499. add_action( 'bp_after_activity_comment', 'bp_activity_comment_embed_after_recurse' ); 
  3500.  
  3501. /** 
  3502. * Fetch an activity item's cached embeds. 
  3503. * 
  3504. * Used during {@link BP_Embed::parse_oembed()} via {@link bp_activity_embed()}. 
  3505. * 
  3506. * @since 1.5.0 
  3507. * 
  3508. * @see BP_Embed::parse_oembed() 
  3509. * 
  3510. * @param string $cache An empty string passed by BP_Embed::parse_oembed() for 
  3511. * functions like this one to filter. 
  3512. * @param int $id The ID of the activity item. 
  3513. * @param string $cachekey The cache key generated in BP_Embed::parse_oembed(). 
  3514. * @return mixed The cached embeds for this activity item. 
  3515. */ 
  3516. function bp_embed_activity_cache( $cache, $id, $cachekey ) { 
  3517. return bp_activity_get_meta( $id, $cachekey ); 
  3518.  
  3519. /** 
  3520. * Set an activity item's embed cache. 
  3521. * 
  3522. * Used during {@link BP_Embed::parse_oembed()} via {@link bp_activity_embed()}. 
  3523. * 
  3524. * @since 1.5.0 
  3525. * 
  3526. * @see BP_Embed::parse_oembed() 
  3527. * 
  3528. * @param string $cache An empty string passed by BP_Embed::parse_oembed() for 
  3529. * functions like this one to filter. 
  3530. * @param string $cachekey The cache key generated in BP_Embed::parse_oembed(). 
  3531. * @param int $id The ID of the activity item. 
  3532. */ 
  3533. function bp_embed_activity_save_cache( $cache, $cachekey, $id ) { 
  3534. bp_activity_update_meta( $id, $cachekey, $cache ); 
  3535.  
  3536. // Cache full oEmbed response. 
  3537. if ( true === isset( buddypress()->activity->oembed_response ) ) { 
  3538. $cachekey = str_replace( '_oembed', '_oembed_response', $cachekey ); 
  3539. bp_activity_update_meta( $id, $cachekey, buddypress()->activity->oembed_response ); 
  3540.  
  3541. /** 
  3542. * Should we use Heartbeat to refresh activities? 
  3543. * 
  3544. * @since 2.0.0 
  3545. * 
  3546. * @return bool True if activity heartbeat is enabled, otherwise false. 
  3547. */ 
  3548. function bp_activity_do_heartbeat() { 
  3549. $retval = false; 
  3550.  
  3551. if ( bp_is_activity_heartbeat_active() && ( bp_is_activity_directory() || bp_is_group_activity() ) ) { 
  3552. $retval = true; 
  3553.  
  3554. /** 
  3555. * Filters whether the heartbeat feature in the activity stream should be active. 
  3556. * 
  3557. * @since 2.8.0 
  3558. * 
  3559. * @param bool $retval Whether or not activity heartbeat is active. 
  3560. */ 
  3561. return (bool) apply_filters( 'bp_activity_do_heartbeat', $retval ); 
.