Skip to:
Content

BuddyPress.org

Ticket #5875: bp-activity-functions-throttle.php

File bp-activity-functions-throttle.php, 70.1 KB (added by SGr33n, 10 years ago)
Line 
1<?php
2
3/**
4 * BuddyPress Activity Functions.
5 *
6 * Functions for the Activity Streams component.
7 *
8 * @package BuddyPress
9 * @subpackage ActivityFunctions
10 */
11
12// Exit if accessed directly
13if ( !defined( 'ABSPATH' ) ) exit;
14
15/**
16 * Check whether the $bp global lists an activity directory page.
17 *
18 * @since BuddyPress (1.5.0)
19 *
20 * @return bool True if activity directory page is found, otherwise false.
21 */
22function bp_activity_has_directory() {
23        return (bool) !empty( buddypress()->pages->activity->id );
24}
25
26/**
27 * Are mentions enabled or disabled?
28 *
29 * The Mentions feature does a number of things, all of which will be turned
30 * off if you disable mentions:
31 *   - Detecting and auto-linking @username in all BP/WP content
32 *   - Sending BP notifications and emails to users when they are mentioned
33 *     using the @username syntax
34 *   - The Public Message button on user profiles
35 *
36 * Mentions are enabled by default. To disable, put the following line in
37 * bp-custom.php or your theme's functions.php file:
38 *
39 *   add_filter( 'bp_activity_do_mentions', '__return_false' );
40 *
41 * @since BuddyPress (1.8.0)
42 *
43 * @uses apply_filters() To call 'bp_activity_do_mentions' hook.
44 *
45 * @return bool $retval True to enable mentions, false to disable.
46 */
47function bp_activity_do_mentions() {
48        return (bool) apply_filters( 'bp_activity_do_mentions', true );
49}
50
51/**
52 * Should BuddyPress load the mentions scripts and related assets, including results to prime the
53 * mentions suggestions?
54 *
55 * @return bool True if mentions scripts should be loaded.
56 * @since BuddyPress (2.1.0)
57 */
58function bp_activity_maybe_load_mentions_scripts() {
59        $retval =
60                bp_activity_do_mentions() &&
61                bp_is_user_active() &&
62                ( bp_is_activity_component() || bp_is_blog_page() && is_singular() && comments_open() || is_admin() );
63
64        return (bool) apply_filters( 'bp_activity_maybe_load_mentions_scripts', $retval );
65}
66
67/**
68 * Locate usernames in an activity content string, as designated by an @ sign.
69 *
70 * @since BuddyPress (1.5.0)
71 *
72 * @param string $content The content of the activity, usually found in
73 *        $activity->content.
74 * @return array|bool Associative array with user ID as key and username as
75 *         value. Boolean false if no mentions found.
76 */
77function bp_activity_find_mentions( $content ) {
78
79        $pattern = '/[@]+([A-Za-z0-9-_\.@]+)\b/';
80        preg_match_all( $pattern, $content, $usernames );
81
82        // Make sure there's only one instance of each username
83        $usernames = array_unique( $usernames[1] );
84
85        // Bail if no usernames
86        if ( empty( $usernames ) ) {
87                return false;
88        }
89
90        $mentioned_users = array();
91
92        // We've found some mentions! Check to see if users exist
93        foreach( (array) array_values( $usernames ) as $username ) {
94                $user_id = bp_activity_get_userid_from_mentionname( $username );
95
96                // user ID exists, so let's add it to our array
97                if ( ! empty( $user_id ) ) {
98                        $mentioned_users[ $user_id ] = $username;
99                }
100        }
101
102        if ( empty( $mentioned_users ) ) {
103                return false;
104        }
105
106        return $mentioned_users;
107}
108
109/**
110 * Reset a user's unread mentions list and count.
111 *
112 * @since BuddyPress (1.5.0)
113 *
114 * @uses bp_delete_user_meta()
115 *
116 * @param int $user_id The id of the user whose unread mentions are being reset.
117 */
118function bp_activity_clear_new_mentions( $user_id ) {
119        bp_delete_user_meta( $user_id, 'bp_new_mention_count' );
120        bp_delete_user_meta( $user_id, 'bp_new_mentions'      );
121}
122
123/**
124 * Adjusts mention count for mentioned users in activity items.
125 *
126 * This function is useful if you only have the activity ID handy and you
127 * haven't parsed an activity item for @mentions yet.
128 *
129 * Currently, only used in {@link bp_activity_delete()}.
130 *
131 * @since BuddyPress (1.5.0)
132 *
133 * @uses bp_activity_find_mentions()
134 * @uses bp_activity_update_mention_count_for_user()
135 *
136 * @param int $activity_id The unique id for the activity item.
137 * @param string $action Can be 'delete' or 'add'. Defaults to 'add'.
138 */
139function bp_activity_adjust_mention_count( $activity_id = 0, $action = 'add' ) {
140
141        // Bail if no activity ID passed
142        if ( empty( $activity_id ) ) {
143                return false;
144        }
145
146        // Get activity object
147        $activity  = new BP_Activity_Activity( (int) $activity_id );
148
149        // Try to find mentions
150        $usernames = bp_activity_find_mentions( strip_tags( $activity->content ) );
151
152        // Still empty? Stop now
153        if ( empty( $usernames ) ) {
154                return false;
155        }
156
157        // Increment mention count foreach mentioned user
158        foreach( (array) array_keys( $usernames ) as $user_id ) {
159                bp_activity_update_mention_count_for_user( $user_id, $activity_id, $action );
160        }
161}
162
163/**
164 * Update the mention count for a given user.
165 *
166 * This function should be used when you've already parsed your activity item
167 * for @mentions.
168 *
169 * @since BuddyPress (1.7.0)
170 *
171 * @uses bp_get_user_meta()
172 * @uses bp_update_user_meta()
173 *
174 * @param int $user_id The user ID.
175 * @param int $activity_id The unique ID for the activity item.
176 * @param string $action 'delete' or 'add'. Default: 'add'.
177 * @return bool
178 */
179function bp_activity_update_mention_count_for_user( $user_id, $activity_id, $action = 'add' ) {
180
181        if ( empty( $user_id ) || empty( $activity_id ) ) {
182                return false;
183        }
184
185        // Adjust the mention list and count for the member
186        $new_mention_count = (int) bp_get_user_meta( $user_id, 'bp_new_mention_count', true );
187        $new_mentions      =       bp_get_user_meta( $user_id, 'bp_new_mentions',      true );
188
189        // Make sure new mentions is an array
190        if ( empty( $new_mentions ) ) {
191                $new_mentions = array();
192        }
193
194        switch ( $action ) {
195                case 'delete' :
196                        $key = array_search( $activity_id, $new_mentions );
197
198                        if ( $key !== false ) {
199                                unset( $new_mentions[$key] );
200                        }
201
202                        break;
203
204                case 'add' :
205                default :
206                        if ( !in_array( $activity_id, $new_mentions ) ) {
207                                $new_mentions[] = (int) $activity_id;
208                        }
209
210                        break;
211        }
212
213        // Get an updated mention count
214        $new_mention_count = count( $new_mentions );
215
216        // Resave the user_meta
217        bp_update_user_meta( $user_id, 'bp_new_mention_count', $new_mention_count );
218        bp_update_user_meta( $user_id, 'bp_new_mentions',      $new_mentions );
219
220        return true;
221}
222
223/**
224 * Determine a user's "mentionname", the name used for that user in @-mentions.
225 *
226 * @since BuddyPress (1.9.0)
227 *
228 * @return string User name appropriate for @-mentions.
229 */
230function bp_activity_get_user_mentionname( $user_id ) {
231        $mentionname = '';
232
233        $userdata = bp_core_get_core_userdata( $user_id );
234
235        if ( $userdata ) {
236                if ( bp_is_username_compatibility_mode() ) {
237                        $mentionname = str_replace( ' ', '-', $userdata->user_login );
238                } else {
239                        $mentionname = $userdata->user_nicename;
240                }
241        }
242
243        return $mentionname;
244}
245
246/**
247 * Get a user ID from a "mentionname", the name used for a user in @-mentions.
248 *
249 * @since BuddyPress (1.9.0)
250 *
251 * @return int|bool ID of the user, if one is found. Otherwise false.
252 */
253function bp_activity_get_userid_from_mentionname( $mentionname ) {
254        $user_id = false;
255
256        // In username compatibility mode, hyphens are ambiguous between
257        // actual hyphens and converted spaces.
258        //
259        // @todo There is the potential for username clashes between 'foo bar'
260        // and 'foo-bar' in compatibility mode. Come up with a system for
261        // unique mentionnames.
262        if ( bp_is_username_compatibility_mode() ) {
263                // First, try the raw username
264                $userdata = get_user_by( 'login', $mentionname );
265
266                // Doing a direct query to use proper regex. Necessary to
267                // account for hyphens + spaces in the same user_login.
268                if ( empty( $userdata ) || ! is_a( $userdata, 'WP_User' ) ) {
269                        global $wpdb;
270                        $regex   = esc_sql( str_replace( '-', '[ \-]', $mentionname ) );
271                        $user_id = $wpdb->get_var( "SELECT ID FROM {$wpdb->users} WHERE user_login REGEXP '{$regex}'" );
272                } else {
273                        $user_id = $userdata->ID;
274                }
275
276        // When username compatibility mode is disabled, the mentionname is
277        // the same as the nicename
278        } else {
279                $user_id = bp_core_get_userid_from_nicename( $mentionname );
280        }
281
282
283        return $user_id;
284}
285
286/** Actions ******************************************************************/
287
288/**
289 * Register an activity 'type' and its action description/callback.
290 *
291 * Activity actions are strings used to describe items in the activity stream,
292 * such as 'Joe became a registered member' or 'Bill and Susie are now
293 * friends'. Each activity type (such as 'new_member' or 'friendship_created')
294 * used by a component should be registered using this function.
295 *
296 * While it's possible to post items to the activity stream whose types are
297 * not registered using bp_activity_set_action(), it is not recommended;
298 * unregistered types will not be displayed properly in the activity admin
299 * panel, and dynamic action generation (which is essential for multilingual
300 * sites, etc) will not work.
301 *
302 * @since BuddyPress (1.1.0)
303 *
304 * @param string $component_id The unique string ID of the component.
305 * @param string $type The action type.
306 * @param string $description The action description.
307 * @param callable $format_callback Callback for formatting the action string.
308 * @param string $label String to describe this action in the activity stream
309 *        filter dropdown.
310 * @param array $context Activity stream contexts where the filter should appear.
311 *        'activity', 'member', 'member_groups', 'group'
312 * @return bool False if any param is empty, otherwise true.
313 */
314function bp_activity_set_action( $component_id, $type, $description, $format_callback = false, $label = false, $context = array() ) {
315        $bp = buddypress();
316
317        // Return false if any of the above values are not set
318        if ( empty( $component_id ) || empty( $type ) || empty( $description ) ) {
319                return false;
320        }
321
322        // Set activity action
323        if ( ! isset( $bp->activity->actions ) || ! is_object( $bp->activity->actions ) ) {
324                $bp->activity->actions = new stdClass;
325        }
326
327        // Verify callback
328        if ( ! is_callable( $format_callback ) ) {
329                $format_callback = '';
330        }
331
332        if ( ! isset( $bp->activity->actions->{$component_id} ) || ! is_object( $bp->activity->actions->{$component_id} ) ) {
333                $bp->activity->actions->{$component_id} = new stdClass;
334        }
335
336        $bp->activity->actions->{$component_id}->{$type} = apply_filters( 'bp_activity_set_action', array(
337                'key'             => $type,
338                'value'           => $description,
339                'format_callback' => $format_callback,
340                'label'           => $label,
341                'context'         => $context,
342        ), $component_id, $type, $description, $format_callback, $label, $context );
343
344        return true;
345}
346
347/**
348 * Retreive the current action from a component and key.
349 *
350 * @since BuddyPress (1.1.0)
351 *
352 * @uses apply_filters() To call the 'bp_activity_get_action' hook.
353 *
354 * @param string $component_id The unique string ID of the component.
355 * @param string $key The action key.
356 * @return string|bool Action value if found, otherwise false.
357 */
358function bp_activity_get_action( $component_id, $key ) {
359
360        // Return false if any of the above values are not set
361        if ( empty( $component_id ) || empty( $key ) ) {
362                return false;
363        }
364
365        $bp     = buddypress();
366        $retval = isset( $bp->activity->actions->{$component_id}->{$key} )
367                ? $bp->activity->actions->{$component_id}->{$key}
368                : false;
369
370        return apply_filters( 'bp_activity_get_action', $retval, $component_id, $key );
371}
372
373/**
374 * Fetch details of all registered activity types.
375 *
376 * @since BuddyPress (1.7.0)
377 *
378 * @return array array( type => description ), ...
379 */
380function bp_activity_get_types() {
381        $actions  = array();
382
383        // Walk through the registered actions, and build an array of actions/values.
384        foreach ( buddypress()->activity->actions as $action ) {
385                $action = array_values( (array) $action );
386
387                for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ ) {
388                        $actions[ $action[$i]['key'] ] = $action[$i]['value'];
389                }
390        }
391
392        // This was a mis-named activity type from before BP 1.6
393        unset( $actions['friends_register_activity_action'] );
394
395        return apply_filters( 'bp_activity_get_types', $actions );
396}
397
398/** Favorites ****************************************************************/
399
400/**
401 * Get a users favorite activity stream items.
402 *
403 * @since BuddyPress (1.2.0)
404 *
405 * @uses bp_get_user_meta()
406 * @uses apply_filters() To call the 'bp_activity_get_user_favorites' hook.
407 *
408 * @param int $user_id ID of the user whose favorites are being queried.
409 * @return array IDs of the user's favorite activity items.
410 */
411function bp_activity_get_user_favorites( $user_id = 0 ) {
412
413        // Fallback to logged in user if no user_id is passed
414        if ( empty( $user_id ) ) {
415                $user_id = bp_displayed_user_id();
416        }
417
418        // Get favorites for user
419        $favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true );
420
421        return apply_filters( 'bp_activity_get_user_favorites', $favs );
422}
423
424/**
425 * Add an activity stream item as a favorite for a user.
426 *
427 * @since BuddyPress (1.2.0)
428 *
429 * @uses is_user_logged_in()
430 * @uses bp_get_user_meta()
431 * @uses bp_activity_get_meta()
432 * @uses bp_update_user_meta()
433 * @uses bp_activity_update_meta()
434 * @uses do_action() To call the 'bp_activity_add_user_favorite' hook.
435 * @uses do_action() To call the 'bp_activity_add_user_favorite_fail' hook.
436 *
437 * @param int $activity_id ID of the activity item being favorited.
438 * @param int $user_id ID of the user favoriting the activity item.
439 * @return bool True on success, false on failure.
440 */
441function bp_activity_add_user_favorite( $activity_id, $user_id = 0 ) {
442
443        // Favorite activity stream items are for logged in users only
444        if ( ! is_user_logged_in() ) {
445                return false;
446        }
447
448        // Fallback to logged in user if no user_id is passed
449        if ( empty( $user_id ) ) {
450                $user_id = bp_loggedin_user_id();
451        }
452
453        $my_favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true );
454        if ( empty( $my_favs ) || ! is_array( $my_favs ) ) {
455                $my_favs = array();
456        }
457
458        // Bail if the user has already favorited this activity item
459        if ( in_array( $activity_id, $my_favs ) ) {
460                return false;
461        }
462
463        // Add to user's favorites
464        $my_favs[] = $activity_id;
465
466        // Update the total number of users who have favorited this activity
467        $fav_count = bp_activity_get_meta( $activity_id, 'favorite_count' );
468        $fav_count = !empty( $fav_count ) ? (int) $fav_count + 1 : 1;
469
470        // Update user meta
471        bp_update_user_meta( $user_id, 'bp_favorite_activities', $my_favs );
472
473        // Update activity meta counts
474        if ( bp_activity_update_meta( $activity_id, 'favorite_count', $fav_count ) ) {
475
476                // Execute additional code
477                do_action( 'bp_activity_add_user_favorite', $activity_id, $user_id );
478
479                // Success
480                return true;
481
482        // Saving meta was unsuccessful for an unknown reason
483        } else {
484                // Execute additional code
485                do_action( 'bp_activity_add_user_favorite_fail', $activity_id, $user_id );
486
487                return false;
488        }
489}
490
491/**
492 * Remove an activity stream item as a favorite for a user.
493 *
494 * @since BuddyPress (1.2.0)
495 *
496 * @uses is_user_logged_in()
497 * @uses bp_get_user_meta()
498 * @uses bp_activity_get_meta()
499 * @uses bp_activity_update_meta()
500 * @uses bp_update_user_meta()
501 * @uses do_action() To call the 'bp_activity_remove_user_favorite' hook.
502 *
503 * @param int $activity_id ID of the activity item being unfavorited.
504 * @param int $user_id ID of the user unfavoriting the activity item.
505 * @return bool True on success, false on failure.
506 */
507function bp_activity_remove_user_favorite( $activity_id, $user_id = 0 ) {
508
509        // Favorite activity stream items are for logged in users only
510        if ( ! is_user_logged_in() ) {
511                return false;
512        }
513
514        // Fallback to logged in user if no user_id is passed
515        if ( empty( $user_id ) ) {
516                $user_id = bp_loggedin_user_id();
517        }
518
519        $my_favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true );
520        $my_favs = array_flip( (array) $my_favs );
521
522        // Bail if the user has not previously favorited the item
523        if ( ! isset( $my_favs[ $activity_id ] ) ) {
524                return false;
525        }
526
527        // Remove the fav from the user's favs
528        unset( $my_favs[$activity_id] );
529        $my_favs = array_unique( array_flip( $my_favs ) );
530
531        // Update the total number of users who have favorited this activity
532        $fav_count = bp_activity_get_meta( $activity_id, 'favorite_count' );
533        if ( ! empty( $fav_count ) ) {
534
535                // Deduct from total favorites
536                if ( bp_activity_update_meta( $activity_id, 'favorite_count', (int) $fav_count - 1 ) ) {
537
538                        // Update users favorites
539                        if ( bp_update_user_meta( $user_id, 'bp_favorite_activities', $my_favs ) ) {
540
541                                // Execute additional code
542                                do_action( 'bp_activity_remove_user_favorite', $activity_id, $user_id );
543
544                                // Success
545                                return true;
546
547                        // Error updating
548                        } else {
549                                return false;
550                        }
551
552                // Error updating favorite count
553                } else {
554                        return false;
555                }
556
557        // Error getting favorite count
558        } else {
559                return false;
560        }
561}
562
563/**
564 * Check whether an activity item exists with a given content string.
565 *
566 * @since BuddyPress (1.1.0)
567 *
568 * @uses BP_Activity_Activity::check_exists_by_content() {@link BP_Activity_Activity}
569 * @uses apply_filters() To call the 'bp_activity_check_exists_by_content' hook.
570 *
571 * @param string $content The content to filter by.
572 * @return int|null The ID of the located activity item. Null if none is found.
573 */
574function bp_activity_check_exists_by_content( $content ) {
575        return apply_filters( 'bp_activity_check_exists_by_content', BP_Activity_Activity::check_exists_by_content( $content ) );
576}
577
578/**
579 * Retrieve the last time activity was updated.
580 *
581 * @since BuddyPress (1.0.0)
582 *
583 * @uses BP_Activity_Activity::get_last_updated() {@link BP_Activity_Activity}
584 * @uses apply_filters() To call the 'bp_activity_get_last_updated' hook.
585 *
586 * @return string Date last updated.
587 */
588function bp_activity_get_last_updated() {
589        return apply_filters( 'bp_activity_get_last_updated', BP_Activity_Activity::get_last_updated() );
590}
591
592/**
593 * Retrieve the number of favorite activity stream items a user has.
594 *
595 * @since BuddyPress (1.2.0)
596 *
597 * @uses BP_Activity_Activity::total_favorite_count() {@link BP_Activity_Activity}
598 *
599 * @param int $user_id ID of the user whose favorite count is being requested.
600 * @return int Total favorite count for the user.
601 */
602function bp_activity_total_favorites_for_user( $user_id = 0 ) {
603
604        // Fallback on displayed user, and then logged in user
605        if ( empty( $user_id ) ) {
606                $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
607        }
608
609        return BP_Activity_Activity::total_favorite_count( $user_id );
610}
611
612/** Meta *********************************************************************/
613
614/**
615 * Delete a meta entry from the DB for an activity stream item.
616 *
617 * @since BuddyPress (1.2.0)
618 *
619 * @global object $wpdb WordPress database access object.
620 * @global object $bp BuddyPress global settings.
621 *
622 * @param int $activity_id ID of the activity item whose metadata is being deleted.
623 * @param string $meta_key Optional. The key of the metadata being deleted. If
624 *        omitted, all metadata associated with the activity
625 *        item will be deleted.
626 * @param string $meta_value Optional. If present, the metadata will only be
627 *        deleted if the meta_value matches this parameter.
628 * @param bool $delete_all Optional. If true, delete matching metadata entries
629 *        for all objects, ignoring the specified object_id. Otherwise,
630 *        only delete matching metadata entries for the specified
631 *        activity item. Default: false.
632 * @return bool True on success, false on failure.
633 */
634function bp_activity_delete_meta( $activity_id, $meta_key = '', $meta_value = '', $delete_all = false ) {
635
636        // Legacy - if no meta_key is passed, delete all for the item
637        if ( empty( $meta_key ) ) {
638                $all_meta = bp_activity_get_meta( $activity_id );
639                $keys     = ! empty( $all_meta ) ? array_keys( $all_meta ) : array();
640
641                // With no meta_key, ignore $delete_all
642                $delete_all = false;
643        } else {
644                $keys = array( $meta_key );
645        }
646
647        $retval = true;
648
649        add_filter( 'query', 'bp_filter_metaid_column_name' );
650        foreach ( $keys as $key ) {
651                $retval = delete_metadata( 'activity', $activity_id, $key, $meta_value, $delete_all );
652        }
653        remove_filter( 'query', 'bp_filter_metaid_column_name' );
654
655        return $retval;
656}
657
658/**
659 * Get metadata for a given activity item.
660 *
661 * @since BuddyPress (1.2.0)
662 *
663 * @uses apply_filters() To call the 'bp_activity_get_meta' hook.
664 *
665 * @param int $activity_id ID of the activity item whose metadata is being requested.
666 * @param string $meta_key Optional. If present, only the metadata matching
667 *        that meta key will be returned. Otherwise, all metadata for the
668 *        activity item will be fetched.
669 * @param bool $single Optional. If true, return only the first value of the
670 *        specified meta_key. This parameter has no effect if meta_key is not
671 *        specified. Default: true.
672 * @return mixed The meta value(s) being requested.
673 */
674function bp_activity_get_meta( $activity_id = 0, $meta_key = '', $single = true ) {
675        add_filter( 'query', 'bp_filter_metaid_column_name' );
676        $retval = get_metadata( 'activity', $activity_id, $meta_key, $single );
677        remove_filter( 'query', 'bp_filter_metaid_column_name' );
678
679        // Filter result before returning
680        return apply_filters( 'bp_activity_get_meta', $retval, $activity_id, $meta_key, $single );
681}
682
683/**
684 * Update a piece of activity meta.
685 *
686 * @since BuddyPress (1.2.0)
687 *
688 * @param int $activity_id ID of the activity item whose metadata is being
689 *        updated.
690 * @param string $meta_key Key of the metadata being updated.
691 * @param mixed $meta_value Value to be set.
692 * @param mixed $prev_value Optional. If specified, only update existing
693 *        metadata entries with the specified value. Otherwise, update all
694 *        entries.
695 * @return bool|int Returns false on failure. On successful update of existing
696 *         metadata, returns true. On successful creation of new metadata,
697 *         returns the integer ID of the new metadata row.
698 */
699function bp_activity_update_meta( $activity_id, $meta_key, $meta_value, $prev_value = '' ) {
700        add_filter( 'query', 'bp_filter_metaid_column_name' );
701        $retval = update_metadata( 'activity', $activity_id, $meta_key, $meta_value, $prev_value );
702        remove_filter( 'query', 'bp_filter_metaid_column_name' );
703
704        return $retval;
705}
706
707/**
708 * Add a piece of activity metadata.
709 *
710 * @since BuddyPress (2.0.0)
711 *
712 * @param int $activity_id ID of the activity item.
713 * @param string $meta_key Metadata key.
714 * @param mixed $meta_value Metadata value.
715 * @param bool $unique Optional. Whether to enforce a single metadata value
716 *        for the given key. If true, and the object already has a value for
717 *        the key, no change will be made. Default: false.
718 * @return int|bool The meta ID on successful update, false on failure.
719 */
720function bp_activity_add_meta( $activity_id, $meta_key, $meta_value, $unique = false ) {
721        add_filter( 'query', 'bp_filter_metaid_column_name' );
722        $retval = add_metadata( 'activity', $activity_id, $meta_key, $meta_value, $unique );
723        remove_filter( 'query', 'bp_filter_metaid_column_name' );
724
725        return $retval;
726}
727
728/** Clean up *****************************************************************/
729
730/**
731 * Completely remove a user's activity data.
732 *
733 * @since BuddyPress (1.5.0)
734 *
735 * @uses is_user_logged_in()
736 * @uses bp_activity_delete()
737 * @uses bp_delete_user_meta()
738 * @uses do_action() To call the 'bp_activity_remove_data' hook.
739 * @uses do_action() To call the 'bp_activity_remove_all_user_data' hook.
740 *
741 * @param int $user_id ID of the user whose activity is being deleted.
742 */
743function bp_activity_remove_all_user_data( $user_id = 0 ) {
744
745        // Do not delete user data unless a logged in user says so
746        if ( empty( $user_id ) || ! is_user_logged_in() ) {
747                return false;
748        }
749
750        // Clear the user's activity from the sitewide stream and clear their activity tables
751        bp_activity_delete( array( 'user_id' => $user_id ) );
752
753        // Remove any usermeta
754        bp_delete_user_meta( $user_id, 'bp_latest_update'       );
755        bp_delete_user_meta( $user_id, 'bp_favorite_activities' );
756
757        // Execute additional code
758        do_action( 'bp_activity_remove_data', $user_id ); // Deprecated! Do not use!
759
760        // Use this going forward
761        do_action( 'bp_activity_remove_all_user_data', $user_id );
762}
763add_action( 'wpmu_delete_user',  'bp_activity_remove_all_user_data' );
764add_action( 'delete_user',       'bp_activity_remove_all_user_data' );
765
766/**
767 * Mark all of the user's activity as spam.
768 *
769 * @since BuddyPress (1.6.0)
770 *
771 * @global object $wpdb WordPress database access object.
772 * @global object $bp BuddyPress global settings.
773 *
774 * @param int $user_id ID of the user whose activity is being spammed.
775 */
776function bp_activity_spam_all_user_data( $user_id = 0 ) {
777        global $wpdb;
778
779        // Do not delete user data unless a logged in user says so
780        if ( empty( $user_id ) || ! is_user_logged_in() ) {
781                return false;
782        }
783
784        // Get all the user's activities.
785        $activities = bp_activity_get( array(
786                'display_comments' => 'stream',
787                'filter'           => array( 'user_id' => $user_id ),
788                'show_hidden'      => true
789        ) );
790
791        $bp = buddypress();
792
793        // Mark each as spam
794        foreach ( (array) $activities['activities'] as $activity ) {
795
796                // Create an activity object
797                $activity_obj = new BP_Activity_Activity;
798                foreach ( $activity as $k => $v ) {
799                        $activity_obj->$k = $v;
800                }
801
802                // Mark as spam
803                bp_activity_mark_as_spam( $activity_obj );
804
805                /*
806                 * If Akismet is present, update the activity history meta.
807                 *
808                 * This is usually taken care of when BP_Activity_Activity::save() happens, but
809                 * as we're going to be updating all the activity statuses directly, for efficency,
810                 * we need to update manually.
811                 */
812                if ( ! empty( $bp->activity->akismet ) ) {
813                        $bp->activity->akismet->update_activity_spam_meta( $activity_obj );
814                }
815
816                // Tidy up
817                unset( $activity_obj );
818        }
819
820        // Mark all of this user's activities as spam
821        $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET is_spam = 1 WHERE user_id = %d", $user_id ) );
822
823        // Call an action for plugins to use
824        do_action( 'bp_activity_spam_all_user_data', $user_id, $activities['activities'] );
825}
826add_action( 'bp_make_spam_user', 'bp_activity_spam_all_user_data' );
827
828/**
829 * Mark all of the user's activity as ham (not spam).
830 *
831 * @since BuddyPress (1.6.0)
832 *
833 * @global object $wpdb WordPress database access object.
834 * @global object $bp BuddyPress global settings.
835 *
836 * @param int $user_id ID of the user whose activity is being hammed.
837 */
838function bp_activity_ham_all_user_data( $user_id = 0 ) {
839        global $wpdb;
840
841        // Do not delete user data unless a logged in user says so
842        if ( empty( $user_id ) || ! is_user_logged_in() ) {
843                return false;
844        }
845
846        // Get all the user's activities.
847        $activities = bp_activity_get( array(
848                'display_comments' => 'stream',
849                'filter'           => array( 'user_id' => $user_id ),
850                'show_hidden'      => true,
851                'spam'             => 'all'
852        ) );
853
854        $bp = buddypress();
855
856        // Mark each as not spam
857        foreach ( (array) $activities['activities'] as $activity ) {
858
859                // Create an activity object
860                $activity_obj = new BP_Activity_Activity;
861                foreach ( $activity as $k => $v ) {
862                        $activity_obj->$k = $v;
863                }
864
865                // Mark as not spam
866                bp_activity_mark_as_ham( $activity_obj );
867
868                /*
869                 * If Akismet is present, update the activity history meta.
870                 *
871                 * This is usually taken care of when BP_Activity_Activity::save() happens, but
872                 * as we're going to be updating all the activity statuses directly, for efficency,
873                 * we need to update manually.
874                 */
875                if ( ! empty( $bp->activity->akismet ) ) {
876                        $bp->activity->akismet->update_activity_ham_meta( $activity_obj );
877                }
878
879                // Tidy up
880                unset( $activity_obj );
881        }
882
883        // Mark all of this user's activities as spam
884        $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET is_spam = 0 WHERE user_id = %d", $user_id ) );
885
886        // Call an action for plugins to use
887        do_action( 'bp_activity_ham_all_user_data', $user_id, $activities['activities'] );
888}
889add_action( 'bp_make_ham_user', 'bp_activity_ham_all_user_data' );
890
891/**
892 * Register the activity stream actions for updates
893 *
894 * @since BuddyPress (1.6.0)
895 */
896function bp_activity_register_activity_actions() {
897        $bp = buddypress();
898
899        bp_activity_set_action(
900                $bp->activity->id,
901                'activity_update',
902                __( 'Posted a status update', 'buddypress' ),
903                'bp_activity_format_activity_action_activity_update',
904                __( 'Updates', 'buddypress' ),
905                array( 'activity', 'group', 'member', 'member_groups' )
906        );
907
908        bp_activity_set_action(
909                $bp->activity->id,
910                'activity_comment',
911                __( 'Replied to a status update', 'buddypress' ),
912                'bp_activity_format_activity_action_activity_comment',
913                __( 'Activity Comments', 'buddypress' )
914        );
915
916        do_action( 'bp_activity_register_activity_actions' );
917
918        // Backpat. Don't use this.
919        do_action( 'updates_register_activity_actions' );
920}
921add_action( 'bp_register_activity_actions', 'bp_activity_register_activity_actions' );
922
923/**
924 * Generate an activity action string for an activity item.
925 *
926 * @param object $activity Activity data object.
927 * @return string|bool Returns false if no callback is found, otherwise returns
928 *         the formatted action string.
929 */
930function bp_activity_generate_action_string( $activity ) {
931
932        // Check for valid input
933        if ( empty( $activity->component ) || empty( $activity->type ) ) {
934                return false;
935        }
936
937        // Check for registered format callback
938        if ( empty( buddypress()->activity->actions->{$activity->component}->{$activity->type}['format_callback'] ) ) {
939                return false;
940        }
941
942        // We apply the format_callback as a filter
943        add_filter( 'bp_activity_generate_action_string', buddypress()->activity->actions->{$activity->component}->{$activity->type}['format_callback'], 10, 2 );
944
945        // Generate the action string (run through the filter defined above)
946        $action = apply_filters( 'bp_activity_generate_action_string', $activity->action, $activity );
947
948        // Remove the filter for future activity items
949        remove_filter( 'bp_activity_generate_action_string', buddypress()->activity->actions->{$activity->component}->{$activity->type}['format_callback'], 10, 2 );
950
951        return $action;
952}
953
954/**
955 * Format 'activity_update' activity actions.
956 *
957 * @since BuddyPress (2.0.0)
958 *
959 * @param string $action Static activity action.
960 * @param object $activity Activity data object.
961 * @return string
962 */
963function bp_activity_format_activity_action_activity_update( $action, $activity ) {
964        $action = sprintf( __( '%s posted an update', 'buddypress' ), bp_core_get_userlink( $activity->user_id ) );
965        return apply_filters( 'bp_activity_new_update_action', $action, $activity );
966}
967
968/**
969 * Format 'activity_comment' activity actions.
970 *
971 * @since BuddyPress (2.0.0)
972 *
973 * @param string $action Static activity action.
974 * @param object $activity Activity data object.
975 * @return string
976 */
977function bp_activity_format_activity_action_activity_comment( $action, $activity ) {
978        $action = sprintf( __( '%s posted a new activity comment', 'buddypress' ), bp_core_get_userlink( $activity->user_id ) );
979        return apply_filters( 'bp_activity_comment_action', $action, $activity );
980}
981
982/******************************************************************************
983 * Business functions are where all the magic happens in BuddyPress. They will
984 * handle the actual saving or manipulation of information. Usually they will
985 * hand off to a database class for data access, then return
986 * true or false on success or failure.
987 */
988
989/**
990 * Retrieve an activity or activities.
991 *
992 * bp_activity_get() shares all arguments with BP_Activity_Activity::get(). The
993 * following is a list of bp_activity_get() parameters that have different
994 * default values from BP_Activity_Activity::get() (value in parentheses is
995 * the default for the bp_activity_get()).
996 *   - 'per_page' (false)
997 *
998 * @since BuddyPress (1.2.0)
999 *
1000 * @see BP_Activity_Activity::get() For more information on accepted arguments
1001 *      and the format of the returned value.
1002 * @uses wp_parse_args()
1003 * @uses wp_cache_get()
1004 * @uses wp_cache_set()
1005 * @uses BP_Activity_Activity::get() {@link BP_Activity_Activity}
1006 * @uses apply_filters_ref_array() To call the 'bp_activity_get' hook.
1007 *
1008 * @param array $args See BP_Activity_Activity::get() for description.
1009 * @return array $activity See BP_Activity_Activity::get() for description.
1010 */
1011function bp_activity_get( $args = '' ) {
1012
1013        $r = bp_parse_args( $args, array(
1014                'max'               => false,        // Maximum number of results to return
1015                'page'              => 1,            // page 1 without a per_page will result in no pagination.
1016                'per_page'          => false,        // results per page
1017                'sort'              => 'DESC',       // sort ASC or DESC
1018                'display_comments'  => false,        // false for no comments. 'stream' for within stream display, 'threaded' for below each activity item
1019
1020                'search_terms'      => false,        // Pass search terms as a string
1021                'meta_query'        => false,        // Filter by activity meta. See WP_Meta_Query for format
1022                'date_query'        => false,        // Filter by date. See first parameter of WP_Date_Query for format
1023                'show_hidden'       => false,        // Show activity items that are hidden site-wide?
1024                'exclude'           => false,        // Comma-separated list of activity IDs to exclude
1025                'in'                => false,        // Comma-separated list or array of activity IDs to which you want to limit the query
1026                'spam'              => 'ham_only',   // 'ham_only' (default), 'spam_only' or 'all'.
1027                'update_meta_cache' => true,
1028                'count_total'       => false,
1029
1030                /**
1031                 * Pass filters as an array -- all filter items can be multiple values comma separated:
1032                 * array(
1033                 *      'user_id'      => false, // user_id to filter on
1034                 *      'object'       => false, // object to filter on e.g. groups, profile, status, friends
1035                 *      'action'       => false, // action to filter on e.g. activity_update, profile_updated
1036                 *      'primary_id'   => false, // object ID to filter on e.g. a group_id or forum_id or blog_id etc.
1037                 *      'secondary_id' => false, // secondary object ID to filter on e.g. a post_id
1038                 * );
1039                 */
1040                'filter' => array()
1041        ) );
1042
1043        // Attempt to return a cached copy of the first page of sitewide activity.
1044        if ( ( 1 === (int) $r['page'] ) && empty( $r['max'] ) && empty( $r['search_terms'] ) && empty( $r['meta_query'] ) && empty( $r['date_query'] ) && empty( $r['filter'] ) && empty( $r['exclude'] ) && empty( $r['in'] ) && ( 'DESC' === $r['sort'] ) && empty( $r['exclude'] ) && ( 'ham_only' === $r['spam'] ) ) {
1045
1046                $activity = wp_cache_get( 'bp_activity_sitewide_front', 'bp' );
1047                if ( false === $activity ) {
1048
1049                        $activity = BP_Activity_Activity::get( array(
1050                                'page'              => $r['page'],
1051                                'per_page'          => $r['per_page'],
1052                                'max'               => $r['max'],
1053                                'sort'              => $r['sort'],
1054                                'search_terms'      => $r['search_terms'],
1055                                'meta_query'        => $r['meta_query'],
1056                                'date_query'        => $r['date_query'],
1057                                'filter'            => $r['filter'],
1058                                'display_comments'  => $r['display_comments'],
1059                                'show_hidden'       => $r['show_hidden'],
1060                                'spam'              => $r['spam'],
1061                                'update_meta_cache' => $r['update_meta_cache'],
1062                                'count_total'       => $r['count_total'],
1063                        ) );
1064
1065                        wp_cache_set( 'bp_activity_sitewide_front', $activity, 'bp' );
1066                }
1067
1068        } else {
1069                $activity = BP_Activity_Activity::get( array(
1070                        'page'             => $r['page'],
1071                        'per_page'         => $r['per_page'],
1072                        'max'              => $r['max'],
1073                        'sort'             => $r['sort'],
1074                        'search_terms'     => $r['search_terms'],
1075                        'meta_query'       => $r['meta_query'],
1076                        'date_query'       => $r['date_query'],
1077                        'filter'           => $r['filter'],
1078                        'display_comments' => $r['display_comments'],
1079                        'show_hidden'      => $r['show_hidden'],
1080                        'exclude'          => $r['exclude'],
1081                        'in'               => $r['in'],
1082                        'spam'             => $r['spam'],
1083                        'count_total'      => $r['count_total'],
1084                ) );
1085        }
1086
1087        return apply_filters_ref_array( 'bp_activity_get', array( &$activity, &$r ) );
1088}
1089
1090/**
1091 * Fetch specific activity items.
1092 *
1093 * @since BuddyPress (1.2.0)
1094 *
1095 * @see BP_Activity_Activity::get() For more information on accepted arguments
1096 * @uses wp_parse_args()
1097 * @uses apply_filters() To call the 'bp_activity_get_specific' hook
1098 * @uses BP_Activity_Activity::get() {@link BP_Activity_Activity}
1099 *
1100 * @param array $args {
1101 *     All arguments and defaults are shared with BP_Activity_Activity::get(),
1102 *     except for the following:
1103 *     @type string|int|array Single activity ID, comma-separated list of IDs,
1104 *           or array of IDs.
1105 * }
1106 * @return array $activity See BP_Activity_Activity::get() for description.
1107 */
1108function bp_activity_get_specific( $args = '' ) {
1109
1110        $r = bp_parse_args( $args, array(
1111                'activity_ids'      => false,      // A single activity_id or array of IDs.
1112                'display_comments'  => false,      // true or false to display threaded comments for these specific activity items
1113                'max'               => false,      // Maximum number of results to return
1114                'page'              => 1,          // page 1 without a per_page will result in no pagination.
1115                'per_page'          => false,      // results per page
1116                'show_hidden'       => true,       // When fetching specific items, show all
1117                'sort'              => 'DESC',     // sort ASC or DESC
1118                'spam'              => 'ham_only', // Retrieve items marked as spam
1119                'update_meta_cache' => true,
1120        ) );
1121
1122        $get_args = array(
1123                'display_comments'  => $r['display_comments'],
1124                'in'                => $r['activity_ids'],
1125                'max'               => $r['max'],
1126                'page'              => $r['page'],
1127                'per_page'          => $r['per_page'],
1128                'show_hidden'       => $r['show_hidden'],
1129                'sort'              => $r['sort'],
1130                'spam'              => $r['spam'],
1131                'update_meta_cache' => $r['update_meta_cache'],
1132        );
1133
1134        return apply_filters( 'bp_activity_get_specific', BP_Activity_Activity::get( $get_args ), $args, $get_args );
1135}
1136
1137/**
1138 * Add an activity item.
1139 *
1140 * @since BuddyPress (1.1.0)
1141 *
1142 * @uses wp_parse_args()
1143 * @uses BP_Activity_Activity::save() {@link BP_Activity_Activity}
1144 * @uses BP_Activity_Activity::rebuild_activity_comment_tree() {@link BP_Activity_Activity}
1145 * @uses wp_cache_delete()
1146 * @uses do_action() To call the 'bp_activity_add' hook
1147 *
1148 * @param array $args {
1149 *     An array of arguments.
1150 *     @type int|bool $id Pass an activity ID to update an existing item, or
1151 *           false to create a new item. Default: false.
1152 *     @type string $action Optional. The activity action/description, typically
1153 *           something like "Joe posted an update". Values passed to this param
1154 *           will be stored in the database and used as a fallback for when the
1155 *           activity item's format_callback cannot be found (eg, when the
1156 *           component is disabled). As long as you have registered a
1157 *           format_callback for your $type, it is unnecessary to include this
1158 *           argument - BP will generate it automatically.
1159 *           See {@link bp_activity_set_action()}.
1160 *     @type string $content Optional. The content of the activity item.
1161 *     @type string $component The unique name of the component associated with
1162 *           the activity item - 'groups', 'profile', etc.
1163 *     @type string $type The specific activity type, used for directory
1164 *           filtering. 'new_blog_post', 'activity_update', etc.
1165 *     @type string $primary_link Optional. The URL for this item, as used in
1166 *           RSS feeds. Defaults to the URL for this activity item's permalink page.
1167 *     @type int|bool $user_id Optional. The ID of the user associated with the
1168 *           activity item. May be set to false or 0 if the item is not related
1169 *           to any user. Default: the ID of the currently logged-in user.
1170 *     @type int $item_id Optional. The ID of the associated item.
1171 *     @type int $secondary_item_id Optional. The ID of a secondary associated
1172 *           item.
1173 *     @type string $date_recorded Optional. The GMT time, in Y-m-d h:i:s format,
1174 *           when the item was recorded. Defaults to the current time.
1175 *     @type bool $hide_sitewide Should the item be hidden on sitewide streams?
1176 *           Default: false.
1177 *     @type bool $is_spam Should the item be marked as spam? Default: false.
1178 * }
1179 * @return int|bool The ID of the activity on success. False on error.
1180 */
1181function bp_activity_add( $args = '' ) {
1182
1183        $r = bp_parse_args( $args, array(
1184                'id'                => false,                  // Pass an existing activity ID to update an existing entry.
1185                'action'            => '',                     // The activity action - e.g. "Jon Doe posted an update"
1186                'content'           => '',                     // Optional: The content of the activity item e.g. "BuddyPress is awesome guys!"
1187                'component'         => false,                  // The name/ID of the component e.g. groups, profile, mycomponent
1188                'type'              => false,                  // The activity type e.g. activity_update, profile_updated
1189                'primary_link'      => '',                     // Optional: The primary URL for this item in RSS feeds (defaults to activity permalink)
1190                '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.
1191                'item_id'           => false,                  // Optional: The ID of the specific item being recorded, e.g. a blog_id
1192                'secondary_item_id' => false,                  // Optional: A second ID used to further filter e.g. a comment_id
1193                'recorded_time'     => bp_core_current_time(), // The GMT time that this activity was recorded
1194                'hide_sitewide'     => false,                  // Should this be hidden on the sitewide activity stream?
1195                'is_spam'           => false,                  // Is this activity item to be marked as spam?
1196                'throttle'                      => 0
1197        ) );
1198
1199        // Make sure we are backwards compatible
1200        if ( empty( $r['component'] ) && !empty( $r['component_name'] ) ) {
1201                $r['component'] = $r['component_name'];
1202        }
1203
1204        if ( empty( $r['type'] ) && !empty( $r['component_action'] ) ) {
1205                $r['type'] = $r['component_action'];
1206        }
1207       
1208        // Check if a throttle time is required.
1209        if ( $r['throttle'] > 0 ) {
1210       
1211                // Throttle to one activity of this type per 2 hours
1212                $existing = bp_activity_get( array(
1213                        'max'    => 1,
1214                        'filter' => array(
1215                                'user_id' => $r['user_id']
1216                                'object'  => $r['component'],
1217                                'action'  => $r['action'],
1218                        ),
1219                ) );
1220
1221                // Default throttle time is 2 hours. Filter to change (in seconds)
1222                if ( ! empty( $existing['activities'] ) ) {
1223                        $throttle_period = apply_filters( 'bp_' . $r['component'] . '_' . $r['action'] . '_activity_throttle_time', HOUR_IN_SECONDS * 2 );
1224                        $then            = strtotime( $existing['activities'][0]->date_recorded );
1225                        $now             = strtotime( bp_core_current_time() );
1226
1227                        // Bail if throttled
1228                        if ( ( $now - $then ) < $throttle_period ) {
1229                                return false;
1230                        }
1231                }
1232        }
1233
1234        // Setup activity to be added
1235        $activity                    = new BP_Activity_Activity( $r['id'] );
1236        $activity->user_id           = $r['user_id'];
1237        $activity->component         = $r['component'];
1238        $activity->type              = $r['type'];
1239        $activity->content           = $r['content'];
1240        $activity->primary_link      = $r['primary_link'];
1241        $activity->item_id           = $r['item_id'];
1242        $activity->secondary_item_id = $r['secondary_item_id'];
1243        $activity->date_recorded     = $r['recorded_time'];
1244        $activity->hide_sitewide     = $r['hide_sitewide'];
1245        $activity->is_spam           = $r['is_spam'];
1246        $activity->action            = ! empty( $r['action'] )
1247                                                                                ? $r['action']
1248                                                                                : bp_activity_generate_action_string( $activity );
1249
1250        if ( ! $activity->save() ) {
1251                return false;
1252        }
1253
1254        // If this is an activity comment, rebuild the tree
1255        if ( 'activity_comment' === $activity->type ) {
1256                // Also clear the comment cache for the parent activity ID
1257                wp_cache_delete( $activity->item_id, 'bp_activity_comments' );
1258
1259                BP_Activity_Activity::rebuild_activity_comment_tree( $activity->item_id );
1260        }
1261
1262        wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
1263        do_action( 'bp_activity_add', $r );
1264
1265        return $activity->id;
1266}
1267
1268/**
1269 * Post an activity update.
1270 *
1271 * @since BuddyPress (1.2.0)
1272 *
1273 * @uses wp_parse_args()
1274 * @uses bp_is_user_inactive()
1275 * @uses bp_core_get_userlink()
1276 * @uses bp_activity_add()
1277 * @uses apply_filters() To call the 'bp_activity_new_update_action' hook.
1278 * @uses apply_filters() To call the 'bp_activity_new_update_content' hook.
1279 * @uses apply_filters() To call the 'bp_activity_new_update_primary_link' hook.
1280 * @uses bp_update_user_meta()
1281 * @uses wp_filter_kses()
1282 * @uses do_action() To call the 'bp_activity_posted_update' hook.
1283 *
1284 * @param array $args {
1285 *     @type string $content The content of the activity update.
1286 *     @type int $user_id Optional. Defaults to the logged-in user.
1287 * }
1288 * @return int $activity_id The activity id
1289 */
1290function bp_activity_post_update( $args = '' ) {
1291
1292        $r = wp_parse_args( $args, array(
1293                'content' => false,
1294                'user_id' => bp_loggedin_user_id()
1295        ) );
1296
1297        if ( empty( $r['content'] ) || !strlen( trim( $r['content'] ) ) ) {
1298                return false;
1299        }
1300
1301        if ( bp_is_user_inactive( $r['user_id'] ) ) {
1302                return false;
1303        }
1304
1305        // Record this on the user's profile
1306        $activity_content = $r['content'];
1307        $primary_link     = bp_core_get_userlink( $r['user_id'], false, true );
1308
1309        // Now write the values
1310        $activity_id = bp_activity_add( array(
1311                'user_id'      => $r['user_id'],
1312                'content'      => apply_filters( 'bp_activity_new_update_content', $activity_content ),
1313                'primary_link' => apply_filters( 'bp_activity_new_update_primary_link', $primary_link ),
1314                'component'    => buddypress()->activity->id,
1315                'type'         => 'activity_update',
1316        ) );
1317
1318        $activity_content = apply_filters( 'bp_activity_latest_update_content', $r['content'], $activity_content );
1319
1320        // Add this update to the "latest update" usermeta so it can be fetched anywhere.
1321        bp_update_user_meta( bp_loggedin_user_id(), 'bp_latest_update', array(
1322                'id'      => $activity_id,
1323                'content' => $activity_content
1324        ) );
1325
1326        do_action( 'bp_activity_posted_update', $r['content'], $r['user_id'], $activity_id );
1327
1328        return $activity_id;
1329}
1330
1331/**
1332 * Add an activity comment.
1333 *
1334 * @since BuddyPress (1.2.0)
1335 *
1336 * @global object $bp BuddyPress global settings.
1337 * @uses wp_parse_args()
1338 * @uses bp_activity_add()
1339 * @uses apply_filters() To call the 'bp_activity_comment_action' hook.
1340 * @uses apply_filters() To call the 'bp_activity_comment_content' hook.
1341 * @uses bp_activity_new_comment_notification()
1342 * @uses wp_cache_delete()
1343 * @uses do_action() To call the 'bp_activity_comment_posted' hook.
1344 *
1345 * @param array $args {
1346 *     @type int $id Optional. Pass an ID to update an existing comment.
1347 *     @type string $content The content of the comment.
1348 *     @type int $user_id Optional. The ID of the user making the comment.
1349 *           Defaults to the ID of the logged-in user.
1350 *     @type int $activity_id The ID of the "root" activity item, ie the oldest
1351 *           ancestor of the comment.
1352 *     @type int $parent_id Optional. The ID of the parent activity item, ie the
1353 *           item to which the comment is an immediate reply. If not provided,
1354 *           this value defaults to the $activity_id.
1355 * }
1356 * @return int|bool The ID of the comment on success, otherwise false.
1357 */
1358function bp_activity_new_comment( $args = '' ) {
1359
1360        $r = wp_parse_args( $args, array(
1361                'id'          => false,
1362                'content'     => false,
1363                'user_id'     => bp_loggedin_user_id(),
1364                'activity_id' => false, // ID of the root activity item
1365                'parent_id'   => false  // ID of a parent comment (optional)
1366        ) );
1367
1368        // Bail if missing necessary data
1369        if ( empty( $r['content'] ) || empty( $r['user_id'] ) || empty( $r['activity_id'] ) ) {
1370                return false;
1371        }
1372
1373        // Maybe set current activity ID as the parent
1374        if ( empty( $r['parent_id'] ) ) {
1375                $r['parent_id'] = $r['activity_id'];
1376        }
1377
1378        $activity_id = $r['activity_id'];
1379
1380        // Check to see if the parent activity is hidden, and if so, hide this comment publically.
1381        $activity  = new BP_Activity_Activity( $activity_id );
1382        $is_hidden = ( (int) $activity->hide_sitewide ) ? 1 : 0;
1383
1384        // Insert the activity comment
1385        $comment_id = bp_activity_add( array(
1386                'id'                => $r['id'],
1387                'content'           => apply_filters( 'bp_activity_comment_content', $r['content'] ),
1388                'component'         => buddypress()->activity->id,
1389                'type'              => 'activity_comment',
1390                'user_id'           => $r['user_id'],
1391                'item_id'           => $activity_id,
1392                'secondary_item_id' => $r['parent_id'],
1393                'hide_sitewide'     => $is_hidden
1394        ) );
1395
1396        // Comment caches are stored only with the top-level item
1397        wp_cache_delete( $activity_id, 'bp_activity_comments' );
1398
1399        // Walk the tree to clear caches for all parent items
1400        $clear_id = $r['parent_id'];
1401        while ( $clear_id != $activity_id ) {
1402                $clear_object = new BP_Activity_Activity( $clear_id );
1403                wp_cache_delete( $clear_id, 'bp_activity' );
1404                $clear_id = intval( $clear_object->secondary_item_id );
1405        }
1406        wp_cache_delete( $activity_id, 'bp_activity' );
1407
1408        do_action( 'bp_activity_comment_posted', $comment_id, $r, $activity );
1409
1410        return $comment_id;
1411}
1412
1413/**
1414 * Fetch the activity_id for an existing activity entry in the DB.
1415 *
1416 * @since BuddyPress (1.2.0)
1417 *
1418 * @see BP_Activity_Activity::get() For more information on accepted arguments.
1419 * @uses wp_parse_args()
1420 * @uses apply_filters() To call the 'bp_activity_get_activity_id' hook.
1421 * @uses BP_Activity_Activity::save() {@link BP_Activity_Activity}
1422 *
1423 * @param array $args See BP_Activity_Activity::get() for description.
1424 * @return int $activity_id The ID of the activity item found.
1425 */
1426function bp_activity_get_activity_id( $args = '' ) {
1427
1428        $r = bp_parse_args( $args, array(
1429                'user_id'           => false,
1430                'component'         => false,
1431                'type'              => false,
1432                'item_id'           => false,
1433                'secondary_item_id' => false,
1434                'action'            => false,
1435                'content'           => false,
1436                'date_recorded'     => false,
1437        ) );
1438
1439        return apply_filters( 'bp_activity_get_activity_id', BP_Activity_Activity::get_id(
1440                $r['user_id'],
1441                $r['component'],
1442                $r['type'],
1443                $r['item_id'],
1444                $r['secondary_item_id'],
1445                $r['action'],
1446                $r['content'],
1447                $r['date_recorded']
1448        ) );
1449}
1450
1451/**
1452 * Delete activity item(s).
1453 *
1454 * If you're looking to hook into one action that provides the ID(s) of
1455 * the activity/activities deleted, then use:
1456 *
1457 * add_action( 'bp_activity_deleted_activities', 'my_function' );
1458 *
1459 * The action passes one parameter that is a single activity ID or an
1460 * array of activity IDs depending on the number deleted.
1461 *
1462 * If you are deleting an activity comment please use bp_activity_delete_comment();
1463 *
1464 * @since BuddyPress (1.0.0)
1465 *
1466 * @see BP_Activity_Activity::get() For more information on accepted arguments.
1467 * @uses wp_parse_args()
1468 * @uses bp_activity_adjust_mention_count()
1469 * @uses BP_Activity_Activity::delete() {@link BP_Activity_Activity}
1470 * @uses do_action() To call the 'bp_before_activity_delete' hook.
1471 * @uses bp_get_user_meta()
1472 * @uses bp_delete_user_meta()
1473 * @uses do_action() To call the 'bp_activity_delete' hook.
1474 * @uses do_action() To call the 'bp_activity_deleted_activities' hook.
1475 * @uses wp_cache_delete()
1476 *
1477 * @param array $args To delete specific activity items, use
1478 *            $args = array( 'id' => $ids );
1479 *        Otherwise, to use filters for item deletion, the argument format is
1480 *        the same as BP_Activity_Activity::get(). See that method for a description.
1481 * @return bool True on success, false on failure.
1482 */
1483function bp_activity_delete( $args = '' ) {
1484
1485        // Pass one or more the of following variables to delete by those variables
1486        $args = bp_parse_args( $args, array(
1487                'id'                => false,
1488                'action'            => false,
1489                'content'           => false,
1490                'component'         => false,
1491                'type'              => false,
1492                'primary_link'      => false,
1493                'user_id'           => false,
1494                'item_id'           => false,
1495                'secondary_item_id' => false,
1496                'date_recorded'     => false,
1497                'hide_sitewide'     => false
1498        ) );
1499
1500        do_action( 'bp_before_activity_delete', $args );
1501
1502        // Adjust the new mention count of any mentioned member
1503        bp_activity_adjust_mention_count( $args['id'], 'delete' );
1504
1505        $activity_ids_deleted = BP_Activity_Activity::delete( $args );
1506        if ( empty( $activity_ids_deleted ) ) {
1507                return false;
1508        }
1509
1510        // Check if the user's latest update has been deleted
1511        $user_id = empty( $args['user_id'] )
1512                ? bp_loggedin_user_id()
1513                : $args['user_id'];
1514
1515        $latest_update = bp_get_user_meta( $user_id, 'bp_latest_update', true );
1516        if ( !empty( $latest_update ) ) {
1517                if ( in_array( (int) $latest_update['id'], (array) $activity_ids_deleted ) ) {
1518                        bp_delete_user_meta( $user_id, 'bp_latest_update' );
1519                }
1520        }
1521
1522        do_action( 'bp_activity_delete', $args );
1523        do_action( 'bp_activity_deleted_activities', $activity_ids_deleted );
1524
1525        wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
1526
1527        return true;
1528}
1529
1530        /**
1531         * Delete an activity item by activity id.
1532         *
1533         * You should use bp_activity_delete() instead.
1534         *
1535         * @since BuddyPress (1.1.0)
1536         * @deprecated BuddyPress (1.2)
1537         *
1538         * @uses wp_parse_args()
1539         * @uses bp_activity_delete()
1540         *
1541         * @param array $args See BP_Activity_Activity::get for a description
1542         *                    of accepted arguments.
1543         *
1544         * @return bool True on success, false on failure.
1545         */
1546        function bp_activity_delete_by_item_id( $args = '' ) {
1547
1548                $r = bp_parse_args( $args, array(
1549                        'item_id'           => false,
1550                        'component'         => false,
1551                        'type'              => false,
1552                        'user_id'           => false,
1553                        'secondary_item_id' => false
1554                ) );
1555
1556                return bp_activity_delete( $r );
1557        }
1558
1559        /**
1560         * Delete an activity item by activity id.
1561         *
1562         * @since BuddyPress (1.1.0)
1563         *
1564         * @uses bp_activity_delete()
1565         *
1566         * @param int ID of the activity item to be deleted.
1567         * @return bool True on success, false on failure.
1568         */
1569        function bp_activity_delete_by_activity_id( $activity_id ) {
1570                return bp_activity_delete( array( 'id' => $activity_id ) );
1571        }
1572
1573        /**
1574         * Delete an activity item by its content.
1575         *
1576         * You should use bp_activity_delete() instead.
1577         *
1578         * @since BuddyPress (1.1.0)
1579         * @deprecated BuddyPress (1.2)
1580         *
1581         * @uses bp_activity_delete()
1582         *
1583         * @param int $user_id The user id.
1584         * @param string $content The activity id.
1585         * @param string $component The activity component.
1586         * @param string $type The activity type.
1587         * @return bool True on success, false on failure.
1588         */
1589        function bp_activity_delete_by_content( $user_id, $content, $component, $type ) {
1590                return bp_activity_delete( array(
1591                        'user_id'   => $user_id,
1592                        'content'   => $content,
1593                        'component' => $component,
1594                        'type'      => $type
1595                ) );
1596        }
1597
1598        /**
1599         * Delete a user's activity for a component.
1600         *
1601         * You should use bp_activity_delete() instead.
1602         *
1603         * @since BuddyPress (1.1.0)
1604         * @deprecated BuddyPress (1.2)
1605         *
1606         * @uses bp_activity_delete()
1607         *
1608         * @param int $user_id The user id.
1609         * @param string $component The activity component.
1610         * @return bool True on success, false on failure.
1611         */
1612        function bp_activity_delete_for_user_by_component( $user_id, $component ) {
1613                return bp_activity_delete( array(
1614                        'user_id'   => $user_id,
1615                        'component' => $component
1616                ) );
1617        }
1618
1619/**
1620 * Delete an activity comment.
1621 *
1622 * @since BuddyPress (1.2.0)
1623 *
1624 * @uses apply_filters() To call the 'bp_activity_delete_comment_pre' hook.
1625 * @uses bp_activity_delete_children()
1626 * @uses bp_activity_delete()
1627 * @uses BP_Activity_Activity::rebuild_activity_comment_tree() {@link BP_Activity_Activity}
1628 * @uses do_action() To call the 'bp_activity_delete_comment' hook.
1629 * @todo Why is an activity id required? We could look this up.
1630 * @todo Why do we encourage users to call this function directly? We could just
1631 *       as easily examine the activity type in bp_activity_delete() and then
1632 *       call this function with the proper arguments if necessary.
1633 *
1634 * @param int $activity_id The ID of the "root" activity, ie the comment's
1635 *                         oldest ancestor.
1636 * @param int $comment_id The ID of the comment to be deleted.
1637 * @return bool True on success, false on failure
1638 */
1639function bp_activity_delete_comment( $activity_id, $comment_id ) {
1640        /***
1641         * You may want to hook into this filter if you want to override this function and
1642         * handle the deletion of child comments differently. Make sure you return false.
1643         */
1644        if ( ! apply_filters( 'bp_activity_delete_comment_pre', true, $activity_id, $comment_id ) ) {
1645                return false;
1646        }
1647
1648        // Delete any children of this comment.
1649        bp_activity_delete_children( $activity_id, $comment_id );
1650
1651        // Delete the actual comment
1652        if ( ! bp_activity_delete( array( 'id' => $comment_id, 'type' => 'activity_comment' ) ) ) {
1653                return false;
1654        }
1655
1656        // Purge comment cache for the root activity update
1657        wp_cache_delete( $activity_id, 'bp_activity_comments' );
1658
1659        // Recalculate the comment tree
1660        BP_Activity_Activity::rebuild_activity_comment_tree( $activity_id );
1661
1662        do_action( 'bp_activity_delete_comment', $activity_id, $comment_id );
1663
1664        return true;
1665}
1666
1667        /**
1668         * Delete an activity comment's children.
1669         *
1670         * @since BuddyPress (1.2.0)
1671         *
1672         * @uses BP_Activity_Activity::get_child_comments() {@link BP_Activity_Activity}
1673         * @uses bp_activity_delete_children()
1674         * @uses bp_activity_delete()
1675         *
1676         * @param int $activity_id The ID of the "root" activity, ie the
1677         *        comment's oldest ancestor.
1678         * @param int $comment_id The ID of the comment to be deleted.
1679         */
1680        function bp_activity_delete_children( $activity_id, $comment_id ) {
1681
1682                // Get activity children to delete
1683                $children = BP_Activity_Activity::get_child_comments( $comment_id );
1684
1685                // Recursively delete all children of this comment.
1686                if ( ! empty( $children ) ) {
1687                        foreach( (array) $children as $child ) {
1688                                bp_activity_delete_children( $activity_id, $child->id );
1689                        }
1690                }
1691               
1692                // Delete the comment itself
1693                bp_activity_delete( array(
1694                        'secondary_item_id' => $comment_id,
1695                        'type'              => 'activity_comment',
1696                        'item_id'           => $activity_id
1697                ) );
1698        }
1699
1700/**
1701 * Get the permalink for a single activity item.
1702 *
1703 * When only the $activity_id param is passed, BP has to instantiate a new
1704 * BP_Activity_Activity object. To save yourself some processing overhead,
1705 * be sure to pass the full $activity_obj parameter as well, if you already
1706 * have it available.
1707 *
1708 * @since BuddyPress (1.2.0)
1709 *
1710 * @uses bp_get_root_domain()
1711 * @uses bp_get_activity_root_slug()
1712 * @uses apply_filters_ref_array() To call the 'bp_activity_get_permalink' hook.
1713 *
1714 * @param int $activity_id The unique id of the activity object.
1715 * @param object $activity_obj Optional. The activity object.
1716 * @return string $link Permalink for the activity item.
1717 */
1718function bp_activity_get_permalink( $activity_id, $activity_obj = false ) {
1719
1720        if ( empty( $activity_obj ) ) {
1721                $activity_obj = new BP_Activity_Activity( $activity_id );
1722        }
1723
1724        if ( isset( $activity_obj->current_comment ) ) {
1725                $activity_obj = $activity_obj->current_comment;
1726        }
1727
1728        if ( 'new_blog_post' == $activity_obj->type || 'new_blog_comment' == $activity_obj->type || 'new_forum_topic' == $activity_obj->type || 'new_forum_post' == $activity_obj->type ) {
1729                $link = $activity_obj->primary_link;
1730        } else {
1731                if ( 'activity_comment' == $activity_obj->type ) {
1732                        $link = bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/p/' . $activity_obj->item_id . '/';
1733                } else {
1734                        $link = bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/p/' . $activity_obj->id . '/';
1735                }
1736        }
1737
1738        return apply_filters_ref_array( 'bp_activity_get_permalink', array( $link, &$activity_obj ) );
1739}
1740
1741/**
1742 * Hide a user's activity.
1743 *
1744 * @since BuddyPress (1.2.0)
1745 *
1746 * @uses BP_Activity_Activity::hide_all_for_user() {@link BP_Activity_Activity}
1747 *
1748 * @param int $user_id The ID of the user whose activity is being hidden.
1749 * @return bool True on success, false on failure.
1750 */
1751function bp_activity_hide_user_activity( $user_id ) {
1752        return BP_Activity_Activity::hide_all_for_user( $user_id );
1753}
1754
1755/**
1756 * Take content, remove images, and replace them with a single thumbnail image.
1757 *
1758 * The format of items in the activity stream is such that we do not want to
1759 * allow an arbitrary number of arbitrarily large images to be rendered.
1760 * However, the activity stream is built to elegantly display a single
1761 * thumbnail corresponding to the activity comment. This function looks
1762 * through the content, grabs the first image and converts it to a thumbnail,
1763 * and removes the rest of the images from the string.
1764 *
1765 * @since BuddyPress (1.2.0)
1766 *
1767 * @uses esc_attr()
1768 * @uses apply_filters() To call the 'bp_activity_thumbnail_content_images' hook
1769 *
1770 * @param string $content The content of the activity item.
1771 * @param string $link Optional. The unescaped URL that the image should link
1772 *        to. If absent, the image will not be a link.
1773 * @param array $args Optional. The args passed to the activity
1774 *        creation function (eg bp_blogs_record_activity()).
1775 * @return string $content The content with images stripped and replaced with a
1776 *         single thumb.
1777 */
1778function bp_activity_thumbnail_content_images( $content, $link = false, $args = false ) {
1779
1780        preg_match_all( '/<img[^>]*>/Ui', $content, $matches );
1781
1782        // Remove <img> tags. Also remove caption shortcodes and caption text if present
1783        $content = preg_replace('|(\[caption(.*?)\])?<img[^>]*>([^\[\[]*\[\/caption\])?|', '', $content );
1784
1785        if ( !empty( $matches ) && !empty( $matches[0] ) ) {
1786
1787                // Get the SRC value
1788                preg_match( '/<img.*?(src\=[\'|"]{0,1}.*?[\'|"]{0,1})[\s|>]{1}/i',    $matches[0][0], $src    );
1789
1790                // Get the width and height
1791                preg_match( '/<img.*?(height\=[\'|"]{0,1}.*?[\'|"]{0,1})[\s|>]{1}/i', $matches[0][0], $height );
1792                preg_match( '/<img.*?(width\=[\'|"]{0,1}.*?[\'|"]{0,1})[\s|>]{1}/i',  $matches[0][0], $width  );
1793
1794                if ( !empty( $src ) ) {
1795                        $src    = substr( substr( str_replace( 'src=',    '', $src[1]    ), 0, -1 ), 1 );
1796                        $height = substr( substr( str_replace( 'height=', '', $height[1] ), 0, -1 ), 1 );
1797                        $width  = substr( substr( str_replace( 'width=',  '', $width[1]  ), 0, -1 ), 1 );
1798
1799                        if ( empty( $width ) || empty( $height ) ) {
1800                                $width  = 100;
1801                                $height = 100;
1802                        }
1803
1804                        $ratio      = (int) $width / (int) $height;
1805                        $new_height = (int) $height >= 100 ? 100 : $height;
1806                        $new_width  = $new_height * $ratio;
1807                        $image      = '<img src="' . esc_url( $src ) . '" width="' . absint( $new_width ) . '" height="' . absint( $new_height ) . '" alt="' . __( 'Thumbnail', 'buddypress' ) . '" class="align-left thumbnail" />';
1808
1809                        if ( !empty( $link ) ) {
1810                                $image = '<a href="' . esc_url( $link ) . '">' . $image . '</a>';
1811                        }
1812
1813                        $content = $image . $content;
1814                }
1815        }
1816
1817        return apply_filters( 'bp_activity_thumbnail_content_images', $content, $matches, $args );
1818}
1819
1820/**
1821 * Fetch whether the current user is allowed to mark items as spam.
1822 *
1823 * @since BuddyPress (1.6.0)
1824 *
1825 * @return bool True if user is allowed to mark activity items as spam.
1826 */
1827function bp_activity_user_can_mark_spam() {
1828        return apply_filters( 'bp_activity_user_can_mark_spam', bp_current_user_can( 'bp_moderate' ) );
1829}
1830
1831/**
1832 * Mark an activity item as spam.
1833 *
1834 * @since BuddyPress (1.6.0)
1835 *
1836 * @param BP_Activity_Activity $activity The activity item to be spammed.
1837 * @param string $source Optional. Default is "by_a_person" (ie, a person has
1838 *        manually marked the activity as spam). BP core also accepts
1839 *        'by_akismet'.
1840 */
1841function bp_activity_mark_as_spam( &$activity, $source = 'by_a_person' ) {
1842        $bp = buddypress();
1843
1844        $activity->is_spam = 1;
1845
1846        // Clear the activity stream first page cache
1847        wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
1848
1849        // Clear the activity comment cache for this activity item
1850        wp_cache_delete( $activity->id, 'bp_activity_comments' );
1851
1852        // If Akismet is active, and this was a manual spam/ham request, stop Akismet checking the activity
1853        if ( 'by_a_person' == $source && !empty( $bp->activity->akismet ) ) {
1854                remove_action( 'bp_activity_before_save', array( $bp->activity->akismet, 'check_activity' ), 4, 1 );
1855
1856                // Build data package for Akismet
1857                $activity_data = BP_Akismet::build_akismet_data_package( $activity );
1858
1859                // Tell Akismet this is spam
1860                $activity_data = $bp->activity->akismet->send_akismet_request( $activity_data, 'submit', 'spam' );
1861
1862                // Update meta
1863                add_action( 'bp_activity_after_save', array( $bp->activity->akismet, 'update_activity_spam_meta' ), 1, 1 );
1864        }
1865
1866        do_action( 'bp_activity_mark_as_spam', $activity, $source );
1867}
1868
1869/**
1870 * Mark an activity item as ham.
1871 *
1872 * @since BuddyPress (1.6.0)
1873 *
1874 * @param BP_Activity_Activity $activity The activity item to be hammed.
1875 * @param string $source Optional. Default is "by_a_person" (ie, a person has
1876 *        manually marked the activity as spam). BP core also accepts
1877 *        'by_akismet'.
1878 */
1879function bp_activity_mark_as_ham( &$activity, $source = 'by_a_person' ) {
1880        $bp = buddypress();
1881
1882        $activity->is_spam = 0;
1883
1884        // Clear the activity stream first page cache
1885        wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
1886
1887        // Clear the activity comment cache for this activity item
1888        wp_cache_delete( $activity->id, 'bp_activity_comments' );
1889
1890        // If Akismet is active, and this was a manual spam/ham request, stop Akismet checking the activity
1891        if ( 'by_a_person' == $source && !empty( $bp->activity->akismet ) ) {
1892                remove_action( 'bp_activity_before_save', array( $bp->activity->akismet, 'check_activity' ), 4, 1 );
1893
1894                // Build data package for Akismet
1895                $activity_data = BP_Akismet::build_akismet_data_package( $activity );
1896
1897                // Tell Akismet this is spam
1898                $activity_data = $bp->activity->akismet->send_akismet_request( $activity_data, 'submit', 'ham' );
1899
1900                // Update meta
1901                add_action( 'bp_activity_after_save', array( $bp->activity->akismet, 'update_activity_ham_meta' ), 1, 1 );
1902        }
1903
1904        do_action( 'bp_activity_mark_as_ham', $activity, $source );
1905}
1906
1907
1908/** Embeds *******************************************************************/
1909
1910/**
1911 * Set up activity oEmbed cache during the activity loop.
1912 *
1913 * During an activity loop, this function sets up the hooks necessary to grab
1914 * each item's embeds from the cache, or put them in the cache if they are
1915 * not there yet.
1916 *
1917 * This does not cover recursive activity comments, as they do not use a real loop.
1918 * For that, see {@link bp_activity_comment_embed()}.
1919 *
1920 * @since BuddyPress (1.5.0)
1921 *
1922 * @see BP_Embed
1923 * @see bp_embed_activity_cache()
1924 * @see bp_embed_activity_save_cache()
1925 * @uses add_filter() To attach 'bp_get_activity_id' to 'embed_post_id'.
1926 * @uses add_filter() To attach 'bp_embed_activity_cache' to 'bp_embed_get_cache'.
1927 * @uses add_action() To attach 'bp_embed_activity_save_cache' to 'bp_embed_update_cache'.
1928 */
1929function bp_activity_embed() {
1930        add_filter( 'embed_post_id',         'bp_get_activity_id'                  );
1931        add_filter( 'bp_embed_get_cache',    'bp_embed_activity_cache',      10, 3 );
1932        add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 );
1933}
1934add_action( 'activity_loop_start', 'bp_activity_embed' );
1935
1936/**
1937 * Set up activity oEmbed cache while recursing through activity comments.
1938 *
1939 * While crawling through an activity comment tree
1940 * ({@link bp_activity_recurse_comments}), this function sets up the hooks
1941 * necessary to grab each comment's embeds from the cache, or put them in
1942 * the cache if they are not there yet.
1943 *
1944 * @since BuddyPress (1.5.0)
1945 *
1946 * @see BP_Embed
1947 * @see bp_embed_activity_cache()
1948 * @see bp_embed_activity_save_cache()
1949 * @uses add_filter() To attach 'bp_get_activity_comment_id' to 'embed_post_id'.
1950 * @uses add_filter() To attach 'bp_embed_activity_cache' to 'bp_embed_get_cache'.
1951 * @uses add_action() To attach 'bp_embed_activity_save_cache' to 'bp_embed_update_cache'.
1952 */
1953function bp_activity_comment_embed() {
1954        add_filter( 'embed_post_id',         'bp_get_activity_comment_id'          );
1955        add_filter( 'bp_embed_get_cache',    'bp_embed_activity_cache',      10, 3 );
1956        add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 );
1957}
1958add_action( 'bp_before_activity_comment', 'bp_activity_comment_embed' );
1959
1960/**
1961 * When a user clicks on a "Read More" item, make sure embeds are correctly parsed and shown for the expanded content.
1962 *
1963 * @since BuddyPress (1.5.0)
1964 *
1965 * @see BP_Embed
1966 * @uses add_filter() To attach create_function() to 'embed_post_id'.
1967 * @uses add_filter() To attach 'bp_embed_activity_cache' to 'bp_embed_get_cache'.
1968 * @uses add_action() To attach 'bp_embed_activity_save_cache' to 'bp_embed_update_cache'.
1969 *
1970 * @param object $activity The activity that is being expanded.
1971 */
1972function bp_dtheme_embed_read_more( $activity ) {
1973        buddypress()->activity->read_more_id = $activity->id;
1974
1975        add_filter( 'embed_post_id',         create_function( '', 'return buddypress()->activity->read_more_id;' ) );
1976        add_filter( 'bp_embed_get_cache',    'bp_embed_activity_cache',      10, 3 );
1977        add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 );
1978}
1979add_action( 'bp_dtheme_get_single_activity_content',       'bp_dtheme_embed_read_more' );
1980add_action( 'bp_legacy_theme_get_single_activity_content', 'bp_dtheme_embed_read_more' );
1981
1982/**
1983 * Clean up 'embed_post_id' filter after comment recursion.
1984 *
1985 * This filter must be removed so that the non-comment filters take over again
1986 * once the comments are done being processed.
1987 *
1988 * @since BuddyPress (1.5.0)
1989 *
1990 * @see bp_activity_comment_embed()
1991 * @uses remove_filter() To remove 'bp_get_activity_comment_id' from 'embed_post_id'.
1992 */
1993function bp_activity_comment_embed_after_recurse() {
1994        remove_filter( 'embed_post_id', 'bp_get_activity_comment_id' );
1995}
1996add_action( 'bp_after_activity_comment', 'bp_activity_comment_embed_after_recurse' );
1997
1998/**
1999 * Fetch an activity item's cached embeds.
2000 *
2001 * Used during {@link BP_Embed::parse_oembed()} via {@link bp_activity_embed()}.
2002 *
2003 * @since BuddyPress (1.5.0)
2004 *
2005 * @see BP_Embed::parse_oembed()
2006 * @uses bp_activity_get_meta()
2007 *
2008 * @param string $cache An empty string passed by BP_Embed::parse_oembed() for
2009 *        functions like this one to filter.
2010 * @param int $id The ID of the activity item.
2011 * @param string $cachekey The cache key generated in BP_Embed::parse_oembed().
2012 * @return mixed The cached embeds for this activity item.
2013 */
2014function bp_embed_activity_cache( $cache, $id, $cachekey ) {
2015        return bp_activity_get_meta( $id, $cachekey );
2016}
2017
2018/**
2019 * Set an activity item's embed cache.
2020 *
2021 * Used during {@link BP_Embed::parse_oembed()} via {@link bp_activity_embed()}.
2022 *
2023 * @since BuddyPress (1.5.0)
2024 *
2025 * @see BP_Embed::parse_oembed()
2026 * @uses bp_activity_update_meta()
2027 *
2028 * @param string $cache An empty string passed by BP_Embed::parse_oembed() for
2029 *        functions like this one to filter.
2030 * @param string $cachekey The cache key generated in BP_Embed::parse_oembed().
2031 * @param int $id The ID of the activity item.
2032 * @return bool True on success, false on failure.
2033 */
2034function bp_embed_activity_save_cache( $cache, $cachekey, $id ) {
2035        bp_activity_update_meta( $id, $cachekey, $cache );
2036}
2037
2038/**
2039 * Should we use Heartbeat to refresh activities?
2040 *
2041 * @since BuddyPress (2.0.0)
2042 *
2043 * @uses bp_is_activity_heartbeat_active() to check if heatbeat setting is on.
2044 * @uses bp_is_activity_directory() to check if the current page is the activity
2045 *       directory.
2046 * @uses bp_is_active() to check if the group component is active.
2047 * @uses bp_is_group_activity() to check if on a single group, the current page
2048 *       is the group activities.
2049 * @uses bp_is_group_home() to check if the current page is a single group home
2050 *       page.
2051 *
2052 * @return bool True if activity heartbeat is enabled, otherwise false.
2053 */
2054function bp_activity_do_heartbeat() {
2055        $retval = false;
2056
2057        if ( ! bp_is_activity_heartbeat_active() ) {
2058                return $retval;
2059        }
2060
2061        if ( bp_is_activity_directory() ) {
2062                $retval = true;
2063        }
2064
2065        if ( bp_is_active( 'groups') ) {
2066                // If no custom front, then activities are loaded in group's home
2067                $has_custom_front = bp_locate_template( array( 'groups/single/front.php' ), false, true );
2068
2069                if ( bp_is_group_activity() || ( ! $has_custom_front && bp_is_group_home() ) ) {
2070                        $retval = true;
2071                }
2072        }
2073
2074        return $retval;
2075}