' );
$has_audio = ! empty( $media['has']['audio'] ) && $media['has']['audio'];
$has_videos = ! empty( $media['has']['videos'] ) && $media['has']['videos'];
$has_feat_image = ! empty( $media['has']['featured_images'] ) && $media['has']['featured_images'];
$has_galleries = ! empty( $media['has']['galleries'] ) && $media['has']['galleries'];
$has_images = ! empty( $media['has']['images'] ) && $media['has']['images'];
$has_embeds = false;
// Embeds must be subtracted from the paragraph count.
if ( ! empty( $media['has']['embeds'] ) ) {
$has_embeds = $media['has']['embeds'] > 0;
$para_count -= count( $media['has']['embeds'] );
}
$extracted_media = array();
$use_media_type = '';
$image_source = '';
// If it's a short article and there's an embed/audio/video, use it.
if ( $para_count <= 3 ) {
if ( $has_embeds ) {
$use_media_type = 'embeds';
} elseif ( $has_audio ) {
$use_media_type = 'audio';
} elseif ( $has_videos ) {
$use_media_type = 'videos';
}
}
// If not, or in any other situation, try to use an image.
if ( ! $use_media_type && $has_images ) {
$use_media_type = 'images';
$image_source = 'html';
// Featured Image > Galleries > inline .
if ( $has_feat_image ) {
$image_source = 'featured_images';
} elseif ( $has_galleries ) {
$image_source = 'galleries';
}
}
// Extract an item from the $media results.
if ( $use_media_type ) {
if ( $use_media_type === 'images' ) {
$extracted_media = wp_list_filter( $media[ $use_media_type ], array( 'source' => $image_source ) );
$extracted_media = array_shift( $extracted_media );
} else {
$extracted_media = array_shift( $media[ $use_media_type ] );
}
/**
* Filter the results of the media extractor when creating an Activity summary.
*
* @since 2.3.0
*
* @param array $extracted_media Extracted media item. See {@link BP_Media_Extractor::extract()} for format.
* @param string $content Content of the activity item.
* @param array $activity The data passed to bp_activity_add() or the values from an Activity obj.
* @param array $media All results from the media extraction.
* See {@link BP_Media_Extractor::extract()} for format.
* @param string $use_media_type The kind of media item that was preferentially extracted.
* @param string $image_source If $use_media_type was "images", the preferential source of the image.
* Otherwise empty.
*/
$extracted_media = apply_filters(
'bp_activity_create_summary_extractor_result',
$extracted_media,
$content,
$activity,
$media,
$use_media_type,
$image_source
);
}
// Generate a text excerpt for this activity item (and remove any oEmbeds URLs).
$summary = bp_create_excerpt( html_entity_decode( $content ), 225, array(
'html' => false,
'filter_shortcodes' => true,
'strip_tags' => true,
'remove_links' => true
) );
if ( $use_media_type === 'embeds' ) {
$summary .= PHP_EOL . PHP_EOL . $extracted_media['url'];
} elseif ( $use_media_type === 'images' ) {
$summary .= sprintf( '
', esc_url( $extracted_media['url'] ) );
} elseif ( in_array( $use_media_type, array( 'audio', 'videos' ), true ) ) {
$summary .= PHP_EOL . PHP_EOL . $extracted_media['original']; // Full shortcode.
}
/**
* Filters the newly-generated summary for the activity item.
*
* @since 2.3.0
*
* @param string $summary Activity summary HTML.
* @param string $content Content of the activity item.
* @param array $activity The data passed to bp_activity_add() or the values from an Activity obj.
* @param array $extracted_media Media item extracted. See {@link BP_Media_Extractor::extract()} for format.
*/
return apply_filters( 'bp_activity_create_summary', $summary, $content, $activity, $extracted_media );
}
/**
* Fetch whether the current user is allowed to mark items as spam.
*
* @since 1.6.0
*
* @return bool True if user is allowed to mark activity items as spam.
*/
function bp_activity_user_can_mark_spam() {
/**
* Filters whether the current user should be able to mark items as spam.
*
* @since 1.6.0
*
* @param bool $moderate Whether or not the current user has bp_moderate capability.
*/
return apply_filters( 'bp_activity_user_can_mark_spam', bp_current_user_can( 'bp_moderate' ) );
}
/**
* Mark an activity item as spam.
*
* @since 1.6.0
*
* @todo We should probably save $source to activity meta.
*
* @param BP_Activity_Activity $activity The activity item to be spammed.
* @param string $source Optional. Default is "by_a_person" (ie, a person has
* manually marked the activity as spam). BP core also
* accepts 'by_akismet'.
*/
function bp_activity_mark_as_spam( &$activity, $source = 'by_a_person' ) {
$bp = buddypress();
$activity->is_spam = 1;
// Clear the activity stream first page cache.
wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
// Clear the activity comment cache for this activity item.
wp_cache_delete( $activity->id, 'bp_activity_comments' );
// If Akismet is active, and this was a manual spam/ham request, stop Akismet checking the activity.
if ( 'by_a_person' == $source && !empty( $bp->activity->akismet ) ) {
remove_action( 'bp_activity_before_save', array( $bp->activity->akismet, 'check_activity' ), 4 );
// Build data package for Akismet.
$activity_data = BP_Akismet::build_akismet_data_package( $activity );
// Tell Akismet this is spam.
$activity_data = $bp->activity->akismet->send_akismet_request( $activity_data, 'submit', 'spam' );
// Update meta.
add_action( 'bp_activity_after_save', array( $bp->activity->akismet, 'update_activity_spam_meta' ), 1, 1 );
}
/**
* Fires at the end of the process to mark an activity item as spam.
*
* @since 1.6.0
*
* @param BP_Activity_Activity $activity Activity item being marked as spam.
* @param string $source Source of determination of spam status. For example
* "by_a_person" or "by_akismet".
*/
do_action( 'bp_activity_mark_as_spam', $activity, $source );
}
/**
* Mark an activity item as ham.
*
* @since 1.6.0
*
* @param BP_Activity_Activity $activity The activity item to be hammed. Passed by reference.
* @param string $source Optional. Default is "by_a_person" (ie, a person has
* manually marked the activity as spam). BP core also accepts
* 'by_akismet'.
*/
function bp_activity_mark_as_ham( &$activity, $source = 'by_a_person' ) {
$bp = buddypress();
$activity->is_spam = 0;
// Clear the activity stream first page cache.
wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
// Clear the activity comment cache for this activity item.
wp_cache_delete( $activity->id, 'bp_activity_comments' );
// If Akismet is active, and this was a manual spam/ham request, stop Akismet checking the activity.
if ( 'by_a_person' == $source && !empty( $bp->activity->akismet ) ) {
remove_action( 'bp_activity_before_save', array( $bp->activity->akismet, 'check_activity' ), 4 );
// Build data package for Akismet.
$activity_data = BP_Akismet::build_akismet_data_package( $activity );
// Tell Akismet this is spam.
$activity_data = $bp->activity->akismet->send_akismet_request( $activity_data, 'submit', 'ham' );
// Update meta.
add_action( 'bp_activity_after_save', array( $bp->activity->akismet, 'update_activity_ham_meta' ), 1, 1 );
}
/**
* Fires at the end of the process to mark an activity item as ham.
*
* @since 1.6.0
*
* @param BP_Activity_Activity $activity Activity item being marked as ham.
* @param string $source Source of determination of ham status. For example
* "by_a_person" or "by_akismet".
*/
do_action( 'bp_activity_mark_as_ham', $activity, $source );
}
/* Emails *********************************************************************/
/**
* Send email and BP notifications when a user is mentioned in an update.
*
* @since 1.2.0
*
* @param int $activity_id The ID of the activity update.
* @param int $receiver_user_id The ID of the user who is receiving the update.
*/
function bp_activity_at_message_notification( $activity_id, $receiver_user_id ) {
$notifications = BP_Core_Notification::get_all_for_user( $receiver_user_id, 'all' );
// Don't leave multiple notifications for the same activity item.
foreach( $notifications as $notification ) {
if ( $activity_id == $notification->item_id ) {
return;
}
}
$activity = new BP_Activity_Activity( $activity_id );
$email_type = 'activity-at-message';
$group_name = '';
$message_link = bp_activity_get_permalink( $activity_id );
$poster_name = bp_core_get_user_displayname( $activity->user_id );
remove_filter( 'bp_get_activity_content_body', 'convert_smilies' );
remove_filter( 'bp_get_activity_content_body', 'wpautop' );
remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
/** This filter is documented in bp-activity/bp-activity-template.php */
$content = apply_filters_ref_array( 'bp_get_activity_content_body', array( $activity->content, &$activity ) );
add_filter( 'bp_get_activity_content_body', 'convert_smilies' );
add_filter( 'bp_get_activity_content_body', 'wpautop' );
add_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
// Now email the user with the contents of the message (if they have enabled email notifications).
if ( 'no' != bp_get_user_meta( $receiver_user_id, 'notification_activity_new_mention', true ) ) {
if ( bp_is_active( 'groups' ) && bp_is_group() ) {
$email_type = 'groups-at-message';
$group_name = bp_get_current_group_name();
}
$unsubscribe_args = array(
'user_id' => $receiver_user_id,
'notification_type' => $email_type,
);
$args = array(
'tokens' => array(
'activity' => $activity,
'usermessage' => wp_strip_all_tags( $content ),
'group.name' => $group_name,
'mentioned.url' => $message_link,
'poster.name' => $poster_name,
'receiver-user.id' => $receiver_user_id,
'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
),
);
bp_send_email( $email_type, $receiver_user_id, $args );
}
/**
* Fires after the sending of an @mention email notification.
*
* @since 1.5.0
* @since 2.5.0 $subject, $message, $content arguments unset and deprecated.
*
* @param BP_Activity_Activity $activity Activity Item object.
* @param string $deprecated Removed in 2.5; now an empty string.
* @param string $deprecated Removed in 2.5; now an empty string.
* @param string $deprecated Removed in 2.5; now an empty string.
* @param int $receiver_user_id The ID of the user who is receiving the update.
*/
do_action( 'bp_activity_sent_mention_email', $activity, '', '', '', $receiver_user_id );
}
/**
* Send email and BP notifications when an activity item receives a comment.
*
* @since 1.2.0
* @since 2.5.0 Updated to use new email APIs.
*
* @param int $comment_id The comment id.
* @param int $commenter_id The ID of the user who posted the comment.
* @param array $params {@link bp_activity_new_comment()}.
*/
function bp_activity_new_comment_notification( $comment_id = 0, $commenter_id = 0, $params = array() ) {
$original_activity = new BP_Activity_Activity( $params['activity_id'] );
$poster_name = bp_core_get_user_displayname( $commenter_id );
$thread_link = bp_activity_get_permalink( $params['activity_id'] );
remove_filter( 'bp_get_activity_content_body', 'convert_smilies' );
remove_filter( 'bp_get_activity_content_body', 'wpautop' );
remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
/** This filter is documented in bp-activity/bp-activity-template.php */
$content = apply_filters_ref_array( 'bp_get_activity_content_body', array( $params['content'], &$original_activity ) );
add_filter( 'bp_get_activity_content_body', 'convert_smilies' );
add_filter( 'bp_get_activity_content_body', 'wpautop' );
add_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
if ( $original_activity->user_id != $commenter_id ) {
// Send an email if the user hasn't opted-out.
if ( 'no' != bp_get_user_meta( $original_activity->user_id, 'notification_activity_new_reply', true ) ) {
$unsubscribe_args = array(
'user_id' => $original_activity->user_id,
'notification_type' => 'activity-comment',
);
$args = array(
'tokens' => array(
'comment.id' => $comment_id,
'commenter.id' => $commenter_id,
'usermessage' => wp_strip_all_tags( $content ),
'original_activity.user_id' => $original_activity->user_id,
'poster.name' => $poster_name,
'thread.url' => esc_url( $thread_link ),
'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
),
);
bp_send_email( 'activity-comment', $original_activity->user_id, $args );
}
/**
* Fires at the point that notifications should be sent for activity comments.
*
* @since 2.6.0
*
* @param BP_Activity_Activity $original_activity The original activity.
* @param int $comment_id ID for the newly received comment.
* @param int $commenter_id ID of the user who made the comment.
* @param array $params Arguments used with the original activity comment.
*/
do_action( 'bp_activity_sent_reply_to_update_notification', $original_activity, $comment_id, $commenter_id, $params );
}
/*
* If this is a reply to another comment, send an email notification to the
* author of the immediate parent comment.
*/
if ( empty( $params['parent_id'] ) || ( $params['activity_id'] == $params['parent_id'] ) ) {
return;
}
$parent_comment = new BP_Activity_Activity( $params['parent_id'] );
if ( $parent_comment->user_id != $commenter_id && $original_activity->user_id != $parent_comment->user_id ) {
// Send an email if the user hasn't opted-out.
if ( 'no' != bp_get_user_meta( $parent_comment->user_id, 'notification_activity_new_reply', true ) ) {
$unsubscribe_args = array(
'user_id' => $parent_comment->user_id,
'notification_type' => 'activity-comment-author',
);
$args = array(
'tokens' => array(
'comment.id' => $comment_id,
'commenter.id' => $commenter_id,
'usermessage' => wp_strip_all_tags( $content ),
'parent-comment-user.id' => $parent_comment->user_id,
'poster.name' => $poster_name,
'thread.url' => esc_url( $thread_link ),
'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
),
);
bp_send_email( 'activity-comment-author', $parent_comment->user_id, $args );
}
/**
* Fires at the point that notifications should be sent for comments on activity replies.
*
* @since 2.6.0
*
* @param BP_Activity_Activity $parent_comment The parent activity.
* @param int $comment_id ID for the newly received comment.
* @param int $commenter_id ID of the user who made the comment.
* @param array $params Arguments used with the original activity comment.
*/
do_action( 'bp_activity_sent_reply_to_reply_notification', $parent_comment, $comment_id, $commenter_id, $params );
}
}
/**
* Helper method to map action arguments to function parameters.
*
* @since 1.9.0
*
* @param int $comment_id ID of the comment being notified about.
* @param array $params Parameters to use with notification.
*/
function bp_activity_new_comment_notification_helper( $comment_id, $params ) {
bp_activity_new_comment_notification( $comment_id, $params['user_id'], $params );
}
add_action( 'bp_activity_comment_posted', 'bp_activity_new_comment_notification_helper', 10, 2 );
/** Embeds *******************************************************************/
/**
* Set up activity oEmbed cache during the activity loop.
*
* During an activity loop, this function sets up the hooks necessary to grab
* each item's embeds from the cache, or put them in the cache if they are
* not there yet.
*
* This does not cover recursive activity comments, as they do not use a real loop.
* For that, see {@link bp_activity_comment_embed()}.
*
* @since 1.5.0
*
* @see BP_Embed
* @see bp_embed_activity_cache()
* @see bp_embed_activity_save_cache()
*
*/
function bp_activity_embed() {
add_filter( 'embed_post_id', 'bp_get_activity_id' );
add_filter( 'oembed_dataparse', 'bp_activity_oembed_dataparse', 10, 2 );
add_filter( 'bp_embed_get_cache', 'bp_embed_activity_cache', 10, 3 );
add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 );
}
add_action( 'activity_loop_start', 'bp_activity_embed' );
/**
* Cache full oEmbed response from oEmbed.
*
* @since 2.6.0
*
* @param string $retval Current oEmbed result.
* @param object $data Full oEmbed response.
* @param string $url URL used for the oEmbed request.
* @return string
*/
function bp_activity_oembed_dataparse( $retval, $data ) {
buddypress()->activity->oembed_response = $data;
return $retval;
}
/**
* Set up activity oEmbed cache while recursing through activity comments.
*
* While crawling through an activity comment tree
* ({@link bp_activity_recurse_comments}), this function sets up the hooks
* necessary to grab each comment's embeds from the cache, or put them in
* the cache if they are not there yet.
*
* @since 1.5.0
*
* @see BP_Embed
* @see bp_embed_activity_cache()
* @see bp_embed_activity_save_cache()
*
*/
function bp_activity_comment_embed() {
add_filter( 'embed_post_id', 'bp_get_activity_comment_id' );
add_filter( 'bp_embed_get_cache', 'bp_embed_activity_cache', 10, 3 );
add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 );
}
add_action( 'bp_before_activity_comment', 'bp_activity_comment_embed' );
/**
* When a user clicks on a "Read More" item, make sure embeds are correctly parsed and shown for the expanded content.
*
* @since 1.5.0
*
* @see BP_Embed
*
* @param object $activity The activity that is being expanded.
*/
function bp_dtheme_embed_read_more( $activity ) {
buddypress()->activity->read_more_id = $activity->id;
add_filter( 'embed_post_id', function() { return buddypress()->activity->read_more_id; } );
add_filter( 'bp_embed_get_cache', 'bp_embed_activity_cache', 10, 3 );
add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 );
}
add_action( 'bp_dtheme_get_single_activity_content', 'bp_dtheme_embed_read_more' );
add_action( 'bp_legacy_theme_get_single_activity_content', 'bp_dtheme_embed_read_more' );
/**
* Clean up 'embed_post_id' filter after comment recursion.
*
* This filter must be removed so that the non-comment filters take over again
* once the comments are done being processed.
*
* @since 1.5.0
*
* @see bp_activity_comment_embed()
*/
function bp_activity_comment_embed_after_recurse() {
remove_filter( 'embed_post_id', 'bp_get_activity_comment_id' );
}
add_action( 'bp_after_activity_comment', 'bp_activity_comment_embed_after_recurse' );
/**
* Fetch an activity item's cached embeds.
*
* Used during {@link BP_Embed::parse_oembed()} via {@link bp_activity_embed()}.
*
* @since 1.5.0
*
* @see BP_Embed::parse_oembed()
*
* @param string $cache An empty string passed by BP_Embed::parse_oembed() for
* functions like this one to filter.
* @param int $id The ID of the activity item.
* @param string $cachekey The cache key generated in BP_Embed::parse_oembed().
* @return mixed The cached embeds for this activity item.
*/
function bp_embed_activity_cache( $cache, $id, $cachekey ) {
return bp_activity_get_meta( $id, $cachekey );
}
/**
* Set an activity item's embed cache.
*
* Used during {@link BP_Embed::parse_oembed()} via {@link bp_activity_embed()}.
*
* @since 1.5.0
*
* @see BP_Embed::parse_oembed()
*
* @param string $cache An empty string passed by BP_Embed::parse_oembed() for
* functions like this one to filter.
* @param string $cachekey The cache key generated in BP_Embed::parse_oembed().
* @param int $id The ID of the activity item.
*/
function bp_embed_activity_save_cache( $cache, $cachekey, $id ) {
bp_activity_update_meta( $id, $cachekey, $cache );
// Cache full oEmbed response.
if ( true === isset( buddypress()->activity->oembed_response ) ) {
$cachekey = str_replace( '_oembed', '_oembed_response', $cachekey );
bp_activity_update_meta( $id, $cachekey, buddypress()->activity->oembed_response );
}
}
/**
* Should we use Heartbeat to refresh activities?
*
* @since 2.0.0
*
* @return bool True if activity heartbeat is enabled, otherwise false.
*/
function bp_activity_do_heartbeat() {
$retval = false;
if ( bp_is_activity_heartbeat_active() && ( bp_is_activity_directory() || bp_is_group_activity() ) ) {
$retval = true;
}
/**
* Filters whether the heartbeat feature in the activity stream should be active.
*
* @since 2.8.0
*
* @param bool $retval Whether or not activity heartbeat is active.
*/
return (bool) apply_filters( 'bp_activity_do_heartbeat', $retval );
}