bp-activity-filters.php 27.5 KB
Newer Older
root's avatar
root committed
1
<?php
root's avatar
root committed
2
/**
lechuck's avatar
lechuck committed
3
 * Filters related to the Activity component.
root's avatar
root committed
4
5
6
 *
 * @package BuddyPress
 * @subpackage ActivityFilters
lechuck's avatar
lechuck committed
7
 * @since 1.0.0
root's avatar
root committed
8
9
 */

lechuck's avatar
lechuck committed
10
// Exit if accessed directly.
ale's avatar
ale committed
11
defined( 'ABSPATH' ) || exit;
root's avatar
root committed
12

lechuck's avatar
lechuck committed
13
/* Filters *******************************************************************/
lechuck's avatar
lechuck committed
14

lechuck's avatar
lechuck committed
15
// Apply WordPress defined filters.
root's avatar
root committed
16
17
18
19
20
21
22
23
24
add_filter( 'bp_get_activity_action',                'bp_activity_filter_kses', 1 );
add_filter( 'bp_get_activity_content_body',          'bp_activity_filter_kses', 1 );
add_filter( 'bp_get_activity_content',               'bp_activity_filter_kses', 1 );
add_filter( 'bp_get_activity_parent_content',        'bp_activity_filter_kses', 1 );
add_filter( 'bp_get_activity_latest_update',         'bp_activity_filter_kses', 1 );
add_filter( 'bp_get_activity_latest_update_excerpt', 'bp_activity_filter_kses', 1 );
add_filter( 'bp_get_activity_feed_item_description', 'bp_activity_filter_kses', 1 );
add_filter( 'bp_activity_content_before_save',       'bp_activity_filter_kses', 1 );
add_filter( 'bp_activity_action_before_save',        'bp_activity_filter_kses', 1 );
lucha's avatar
lucha committed
25
add_filter( 'bp_activity_latest_update_content',     'bp_activity_filter_kses', 1 );
root's avatar
root committed
26
27
28
29
30
31
32
33
34
35

add_filter( 'bp_get_activity_action',                'force_balance_tags' );
add_filter( 'bp_get_activity_content_body',          'force_balance_tags' );
add_filter( 'bp_get_activity_content',               'force_balance_tags' );
add_filter( 'bp_get_activity_latest_update',         'force_balance_tags' );
add_filter( 'bp_get_activity_latest_update_excerpt', 'force_balance_tags' );
add_filter( 'bp_get_activity_feed_item_description', 'force_balance_tags' );
add_filter( 'bp_activity_content_before_save',       'force_balance_tags' );
add_filter( 'bp_activity_action_before_save',        'force_balance_tags' );

lechuck's avatar
lechuck committed
36
37
38
39
if ( function_exists( 'wp_encode_emoji' ) ) {
	add_filter( 'bp_activity_content_before_save', 'wp_encode_emoji' );
}

root's avatar
root committed
40
41
42
43
44
45
add_filter( 'bp_get_activity_action',                'wptexturize' );
add_filter( 'bp_get_activity_content_body',          'wptexturize' );
add_filter( 'bp_get_activity_content',               'wptexturize' );
add_filter( 'bp_get_activity_parent_content',        'wptexturize' );
add_filter( 'bp_get_activity_latest_update',         'wptexturize' );
add_filter( 'bp_get_activity_latest_update_excerpt', 'wptexturize' );
lucha's avatar
lucha committed
46
add_filter( 'bp_activity_get_embed_excerpt',         'wptexturize' );
root's avatar
root committed
47
48
49
50
51
52
53

add_filter( 'bp_get_activity_action',                'convert_smilies' );
add_filter( 'bp_get_activity_content_body',          'convert_smilies' );
add_filter( 'bp_get_activity_content',               'convert_smilies' );
add_filter( 'bp_get_activity_parent_content',        'convert_smilies' );
add_filter( 'bp_get_activity_latest_update',         'convert_smilies' );
add_filter( 'bp_get_activity_latest_update_excerpt', 'convert_smilies' );
lucha's avatar
lucha committed
54
add_filter( 'bp_activity_get_embed_excerpt',         'convert_smilies' );
root's avatar
root committed
55
56
57
58
59
60
61

add_filter( 'bp_get_activity_action',                'convert_chars' );
add_filter( 'bp_get_activity_content_body',          'convert_chars' );
add_filter( 'bp_get_activity_content',               'convert_chars' );
add_filter( 'bp_get_activity_parent_content',        'convert_chars' );
add_filter( 'bp_get_activity_latest_update',         'convert_chars' );
add_filter( 'bp_get_activity_latest_update_excerpt', 'convert_chars' );
lucha's avatar
lucha committed
62
add_filter( 'bp_activity_get_embed_excerpt',         'convert_chars' );
root's avatar
root committed
63
64
65
66
67

add_filter( 'bp_get_activity_action',                'wpautop' );
add_filter( 'bp_get_activity_content_body',          'wpautop' );
add_filter( 'bp_get_activity_content',               'wpautop' );
add_filter( 'bp_get_activity_feed_item_description', 'wpautop' );
lucha's avatar
lucha committed
68
add_filter( 'bp_activity_get_embed_excerpt',         'wpautop' );
root's avatar
root committed
69

root's avatar
root committed
70
71
72
73
74
75
76
add_filter( 'bp_get_activity_action',                'make_clickable', 9 );
add_filter( 'bp_get_activity_content_body',          'make_clickable', 9 );
add_filter( 'bp_get_activity_content',               'make_clickable', 9 );
add_filter( 'bp_get_activity_parent_content',        'make_clickable', 9 );
add_filter( 'bp_get_activity_latest_update',         'make_clickable', 9 );
add_filter( 'bp_get_activity_latest_update_excerpt', 'make_clickable', 9 );
add_filter( 'bp_get_activity_feed_item_description', 'make_clickable', 9 );
lucha's avatar
lucha committed
77
add_filter( 'bp_activity_get_embed_excerpt',         'make_clickable', 9 );
root's avatar
root committed
78

lechuck's avatar
lechuck committed
79
80
81
82
83
84
85
86
add_filter( 'bp_acomment_name',                      'stripslashes_deep', 5 );
add_filter( 'bp_get_activity_action',                'stripslashes_deep', 5 );
add_filter( 'bp_get_activity_content',               'stripslashes_deep', 5 );
add_filter( 'bp_get_activity_content_body',          'stripslashes_deep', 5 );
add_filter( 'bp_get_activity_parent_content',        'stripslashes_deep', 5 );
add_filter( 'bp_get_activity_latest_update',         'stripslashes_deep', 5 );
add_filter( 'bp_get_activity_latest_update_excerpt', 'stripslashes_deep', 5 );
add_filter( 'bp_get_activity_feed_item_description', 'stripslashes_deep', 5 );
root's avatar
root committed
87

lechuck's avatar
lechuck committed
88
89
add_filter( 'bp_activity_primary_link_before_save',  'esc_url_raw' );

lechuck's avatar
lechuck committed
90
// Apply BuddyPress-defined filters.
root's avatar
root committed
91
92
93
94
95
96
97
add_filter( 'bp_get_activity_content',               'bp_activity_make_nofollow_filter' );
add_filter( 'bp_get_activity_content_body',          'bp_activity_make_nofollow_filter' );
add_filter( 'bp_get_activity_parent_content',        'bp_activity_make_nofollow_filter' );
add_filter( 'bp_get_activity_latest_update',         'bp_activity_make_nofollow_filter' );
add_filter( 'bp_get_activity_latest_update_excerpt', 'bp_activity_make_nofollow_filter' );
add_filter( 'bp_get_activity_feed_item_description', 'bp_activity_make_nofollow_filter' );

root's avatar
root committed
98
99
100
add_filter( 'pre_comment_content',                   'bp_activity_at_name_filter' );
add_filter( 'group_forum_topic_text_before_save',    'bp_activity_at_name_filter' );
add_filter( 'group_forum_post_text_before_save',     'bp_activity_at_name_filter' );
lechuck's avatar
lechuck committed
101
add_filter( 'the_content',                           'bp_activity_at_name_filter' );
lucha's avatar
lucha committed
102
add_filter( 'bp_activity_get_embed_excerpt',         'bp_activity_at_name_filter' );
root's avatar
root committed
103

root's avatar
root committed
104
add_filter( 'bp_get_activity_parent_content',        'bp_create_excerpt' );
root's avatar
root committed
105

lechuck's avatar
lechuck committed
106
107
108
add_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
add_filter( 'bp_get_activity_content',      'bp_activity_truncate_entry', 5 );

lucha's avatar
lucha committed
109
110
111
add_filter( 'bp_get_total_favorite_count_for_user', 'bp_core_number_format' );
add_filter( 'bp_get_total_mention_count_for_user',  'bp_core_number_format' );

lucha's avatar
lucha committed
112
113
add_filter( 'bp_activity_get_embed_excerpt', 'bp_activity_embed_excerpt_onclick_location_filter', 9 );

lechuck's avatar
lechuck committed
114
/* Actions *******************************************************************/
lechuck's avatar
lechuck committed
115

lechuck's avatar
lechuck committed
116
// At-name filter.
lechuck's avatar
lechuck committed
117
add_action( 'bp_activity_before_save', 'bp_activity_at_name_filter_updates' );
lechuck's avatar
lechuck committed
118

lechuck's avatar
lechuck committed
119
// Activity stream moderation.
lechuck's avatar
lechuck committed
120
121
122
123
124
125
add_action( 'bp_activity_before_save', 'bp_activity_check_moderation_keys', 2, 1 );
add_action( 'bp_activity_before_save', 'bp_activity_check_blacklist_keys',  2, 1 );

/** Functions *****************************************************************/

/**
lechuck's avatar
lechuck committed
126
 * Types of activity stream items to moderate.
lechuck's avatar
lechuck committed
127
 *
lechuck's avatar
lechuck committed
128
 * @since 1.6.0
lechuck's avatar
lechuck committed
129
130
 *
 * @return array $types List of the activity types to moderate.
lechuck's avatar
lechuck committed
131
132
133
134
135
136
 */
function bp_activity_get_moderated_activity_types() {
	$types = array(
		'activity_comment',
		'activity_update'
	);
ale's avatar
ale committed
137
138
139
140

	/**
	 * Filters the default activity types that BuddyPress should moderate.
	 *
lechuck's avatar
lechuck committed
141
	 * @since 1.6.0
ale's avatar
ale committed
142
143
144
	 *
	 * @param array $types Default activity types to moderate.
	 */
lechuck's avatar
lechuck committed
145
146
147
148
	return apply_filters( 'bp_activity_check_activity_types', $types );
}

/**
lechuck's avatar
lechuck committed
149
 * Moderate the posted activity item, if it contains moderate keywords.
lechuck's avatar
lechuck committed
150
 *
lechuck's avatar
lechuck committed
151
 * @since 1.6.0
lechuck's avatar
lechuck committed
152
153
 *
 * @param BP_Activity_Activity $activity The activity object to check.
lechuck's avatar
lechuck committed
154
155
156
 */
function bp_activity_check_moderation_keys( $activity ) {

lechuck's avatar
lechuck committed
157
	// Only check specific types of activity updates.
lucha's avatar
lucha committed
158
	if ( ! in_array( $activity->type, bp_activity_get_moderated_activity_types() ) ) {
lechuck's avatar
lechuck committed
159
		return;
lucha's avatar
lucha committed
160
	}
lechuck's avatar
lechuck committed
161

lucha's avatar
lucha committed
162
	// Send back the error so activity update fails.
lechuck's avatar
lechuck committed
163
	// @todo This is temporary until some kind of moderation is built.
lucha's avatar
lucha committed
164
165
166
167
168
	$moderate = bp_core_check_for_moderation( $activity->user_id, '', $activity->content, 'wp_error' );
	if ( is_wp_error( $moderate ) ) {
		$activity->errors = $moderate;

		// Backpat.
lechuck's avatar
lechuck committed
169
		$activity->component = false;
lucha's avatar
lucha committed
170
	}
lechuck's avatar
lechuck committed
171
172
173
}

/**
lechuck's avatar
lechuck committed
174
 * Mark the posted activity as spam, if it contains blacklist keywords.
lechuck's avatar
lechuck committed
175
 *
lechuck's avatar
lechuck committed
176
 * @since 1.6.0
lechuck's avatar
lechuck committed
177
178
 *
 * @param BP_Activity_Activity $activity The activity object to check.
lechuck's avatar
lechuck committed
179
180
181
 */
function bp_activity_check_blacklist_keys( $activity ) {

lechuck's avatar
lechuck committed
182
	// Only check specific types of activity updates.
lucha's avatar
lucha committed
183
	if ( ! in_array( $activity->type, bp_activity_get_moderated_activity_types() ) ) {
lechuck's avatar
lechuck committed
184
		return;
lucha's avatar
lucha committed
185
186
187
188
189
190
191
	}

	// Send back the error so activity update fails.
	// @todo This is temporary until some kind of trash status is built.
	$blacklist = bp_core_check_for_blacklist( $activity->user_id, '', $activity->content, 'wp_error' );
	if ( is_wp_error( $blacklist ) ) {
		$activity->errors = $blacklist;
lechuck's avatar
lechuck committed
192

lucha's avatar
lucha committed
193
194
195
		// Backpat.
		$activity->component = false;
	}
lechuck's avatar
lechuck committed
196
197
}

root's avatar
root committed
198
/**
lechuck's avatar
lechuck committed
199
 * Custom kses filtering for activity content.
root's avatar
root committed
200
 *
lechuck's avatar
lechuck committed
201
 * @since 1.1.0
root's avatar
root committed
202
 *
lechuck's avatar
lechuck committed
203
204
 * @param string $content The activity content.
 * @return string $content Filtered activity content.
root's avatar
root committed
205
 */
root's avatar
root committed
206
207
208
209
function bp_activity_filter_kses( $content ) {
	global $allowedtags;

	$activity_allowedtags = $allowedtags;
lucha's avatar
lucha committed
210
211
212
213
214
215
216
217
218
	$activity_allowedtags['a']['class'] = array();
	$activity_allowedtags['a']['id']    = array();
	$activity_allowedtags['a']['rel']   = array();
	$activity_allowedtags['a']['title'] = array();

	$activity_allowedtags['b']    = array();
	$activity_allowedtags['code'] = array();
	$activity_allowedtags['i']    = array();

root's avatar
root committed
219
220
221
222
223
224
225
226
	$activity_allowedtags['img']           = array();
	$activity_allowedtags['img']['src']    = array();
	$activity_allowedtags['img']['alt']    = array();
	$activity_allowedtags['img']['width']  = array();
	$activity_allowedtags['img']['height'] = array();
	$activity_allowedtags['img']['class']  = array();
	$activity_allowedtags['img']['id']     = array();
	$activity_allowedtags['img']['title']  = array();
lucha's avatar
lucha committed
227
228
229
230

	$activity_allowedtags['span']                   = array();
	$activity_allowedtags['span']['class']          = array();
	$activity_allowedtags['span']['data-livestamp'] = array();
root's avatar
root committed
231

ale's avatar
ale committed
232
233
234
235

	/**
	 * Filters the allowed HTML tags for BuddyPress Activity content.
	 *
lechuck's avatar
lechuck committed
236
	 * @since 1.2.0
ale's avatar
ale committed
237
238
239
	 *
	 * @param array $value Array of allowed HTML tags and attributes.
	 */
root's avatar
root committed
240
241
242
243
	$activity_allowedtags = apply_filters( 'bp_activity_allowed_tags', $activity_allowedtags );
	return wp_kses( $content, $activity_allowedtags );
}

root's avatar
root committed
244
/**
lechuck's avatar
lechuck committed
245
 * Find and link @-mentioned users in the contents of a given item.
root's avatar
root committed
246
 *
lechuck's avatar
lechuck committed
247
 * @since 1.2.0
root's avatar
root committed
248
 *
ale's avatar
ale committed
249
250
 * @param string $content     The contents of a given item.
 * @param int    $activity_id The activity id. Deprecated.
lechuck's avatar
lechuck committed
251
 * @return string $content Content filtered for mentions.
root's avatar
root committed
252
253
 */
function bp_activity_at_name_filter( $content, $activity_id = 0 ) {
root's avatar
root committed
254

lechuck's avatar
lechuck committed
255
256
257
258
259
	// Are mentions disabled?
	if ( ! bp_activity_do_mentions() ) {
		return $content;
	}

lechuck's avatar
lechuck committed
260
	// Try to find mentions.
lechuck's avatar
lechuck committed
261
	$usernames = bp_activity_find_mentions( $content );
root's avatar
root committed
262

lechuck's avatar
lechuck committed
263
264
265
266
	// No mentions? Stop now!
	if ( empty( $usernames ) )
		return $content;

lechuck's avatar
lechuck committed
267
	// We don't want to link @mentions that are inside of links, so we
lechuck's avatar
lechuck committed
268
	// temporarily remove them.
lechuck's avatar
lechuck committed
269
270
271
	$replace_count = 0;
	$replacements = array();
	foreach ( $usernames as $username ) {
lechuck's avatar
lechuck committed
272
		// Prevent @ name linking inside <a> tags.
lechuck's avatar
lechuck committed
273
274
275
276
277
278
279
280
281
282
		preg_match_all( '/(<a.*?(?!<\/a>)@' . $username . '.*?<\/a>)/', $content, $content_matches );
		if ( ! empty( $content_matches[1] ) ) {
			foreach ( $content_matches[1] as $replacement ) {
				$replacements[ '#BPAN' . $replace_count ] = $replacement;
				$content = str_replace( $replacement, '#BPAN' . $replace_count, $content );
				$replace_count++;
			}
		}
	}

lechuck's avatar
lechuck committed
283
	// Linkify the mentions with the username.
lechuck's avatar
lechuck committed
284
	foreach ( (array) $usernames as $user_id => $username ) {
lucha's avatar
lucha committed
285
		$content = preg_replace( '/(@' . $username . '\b)/', "<a class='bp-suggestions-mention' href='" . bp_core_get_user_domain( $user_id ) . "' rel='nofollow'>@$username</a>", $content );
root's avatar
root committed
286
287
	}

lechuck's avatar
lechuck committed
288
	// Put everything back.
lechuck's avatar
lechuck committed
289
290
291
292
293
294
	if ( ! empty( $replacements ) ) {
		foreach ( $replacements as $placeholder => $original ) {
			$content = str_replace( $placeholder, $original, $content );
		}
	}

lechuck's avatar
lechuck committed
295
	// Return the content.
root's avatar
root committed
296
297
298
	return $content;
}

root's avatar
root committed
299
/**
lechuck's avatar
lechuck committed
300
 * Catch mentions in an activity item before it is saved into the database.
lechuck's avatar
lechuck committed
301
302
 *
 * If mentions are found, replace @mention text with user links and add our
lechuck's avatar
lechuck committed
303
 * hook to send mention notifications after the activity item is saved.
root's avatar
root committed
304
 *
lechuck's avatar
lechuck committed
305
 * @since 1.5.0
root's avatar
root committed
306
 *
lechuck's avatar
lechuck committed
307
 * @param BP_Activity_Activity $activity Activity Object.
root's avatar
root committed
308
309
 */
function bp_activity_at_name_filter_updates( $activity ) {
lechuck's avatar
lechuck committed
310
311
312
313
314
	// Are mentions disabled?
	if ( ! bp_activity_do_mentions() ) {
		return;
	}

lechuck's avatar
lechuck committed
315
316
317
318
	// If activity was marked as spam, stop the rest of this function.
	if ( ! empty( $activity->is_spam ) )
		return;

lechuck's avatar
lechuck committed
319
	// Try to find mentions.
lechuck's avatar
lechuck committed
320
321
322
323
	$usernames = bp_activity_find_mentions( $activity->content );

	// We have mentions!
	if ( ! empty( $usernames ) ) {
lechuck's avatar
lechuck committed
324
		// Replace @mention text with userlinks.
lechuck's avatar
lechuck committed
325
		foreach( (array) $usernames as $user_id => $username ) {
lucha's avatar
lucha committed
326
			$activity->content = preg_replace( '/(@' . $username . '\b)/', "<a class='bp-suggestions-mention' href='" . bp_core_get_user_domain( $user_id ) . "' rel='nofollow'>@$username</a>", $activity->content );
lechuck's avatar
lechuck committed
327
		}
root's avatar
root committed
328

lechuck's avatar
lechuck committed
329
		// Add our hook to send @mention emails after the activity item is saved.
lechuck's avatar
lechuck committed
330
		add_action( 'bp_activity_after_save', 'bp_activity_at_name_send_emails' );
root's avatar
root committed
331

lechuck's avatar
lechuck committed
332
		// Temporary variable to avoid having to run bp_activity_find_mentions() again.
lechuck's avatar
lechuck committed
333
334
335
336
337
		buddypress()->activity->mentioned_users = $usernames;
	}
}

/**
lechuck's avatar
lechuck committed
338
 * Sends emails and BP notifications for users @-mentioned in an activity item.
lechuck's avatar
lechuck committed
339
 *
lechuck's avatar
lechuck committed
340
 * @since 1.7.0
lechuck's avatar
lechuck committed
341
 *
ale's avatar
ale committed
342
 * @param BP_Activity_Activity $activity The BP_Activity_Activity object.
lechuck's avatar
lechuck committed
343
344
 */
function bp_activity_at_name_send_emails( $activity ) {
lechuck's avatar
lechuck committed
345
346
347
348
349
	// Are mentions disabled?
	if ( ! bp_activity_do_mentions() ) {
		return;
	}

lechuck's avatar
lechuck committed
350
351
352
353
	// If our temporary variable doesn't exist, stop now.
	if ( empty( buddypress()->activity->mentioned_users ) )
		return;

lechuck's avatar
lechuck committed
354
	// Grab our temporary variable from bp_activity_at_name_filter_updates().
lechuck's avatar
lechuck committed
355
356
	$usernames = buddypress()->activity->mentioned_users;

lechuck's avatar
lechuck committed
357
	// Get rid of temporary variable.
lechuck's avatar
lechuck committed
358
359
	unset( buddypress()->activity->mentioned_users );

lechuck's avatar
lechuck committed
360
	// Send @mentions and setup BP notifications.
lechuck's avatar
lechuck committed
361
	foreach( (array) $usernames as $user_id => $username ) {
ale's avatar
ale committed
362
363
364
365

		/**
		 * Filters BuddyPress' ability to send email notifications for @mentions.
		 *
lechuck's avatar
lechuck committed
366
367
		 * @since 1.6.0
		 * @since 2.5.0 Introduced `$user_id` and `$activity` parameters.
ale's avatar
ale committed
368
		 *
lechuck's avatar
lechuck committed
369
370
371
372
		 * @param bool                 $value     Whether or not BuddyPress should send a notification to the mentioned users.
		 * @param array                $usernames Array of users potentially notified.
		 * @param int                  $user_id   ID of the current user being notified.
		 * @param BP_Activity_Activity $activity  Activity object.
ale's avatar
ale committed
373
		 */
lechuck's avatar
lechuck committed
374
		if ( apply_filters( 'bp_activity_at_name_do_notifications', true, $usernames, $user_id, $activity ) ) {
lechuck's avatar
lechuck committed
375
376
377
			bp_activity_at_message_notification( $activity->id, $user_id );
		}

lechuck's avatar
lechuck committed
378
		// Updates mention count for the user.
lechuck's avatar
lechuck committed
379
380
		bp_activity_update_mention_count_for_user( $user_id, $activity->id );
	}
root's avatar
root committed
381
382
383
}

/**
lechuck's avatar
lechuck committed
384
 * Catch links in activity text so rel=nofollow can be added.
root's avatar
root committed
385
 *
lechuck's avatar
lechuck committed
386
 * @since 1.2.0
root's avatar
root committed
387
 *
lechuck's avatar
lechuck committed
388
389
 * @param string $text Activity text.
 * @return string $text Text with rel=nofollow added to any links.
root's avatar
root committed
390
 */
root's avatar
root committed
391
392
393
function bp_activity_make_nofollow_filter( $text ) {
	return preg_replace_callback( '|<a (.+?)>|i', 'bp_activity_make_nofollow_filter_callback', $text );
}
root's avatar
root committed
394
395

	/**
lechuck's avatar
lechuck committed
396
	 * Add rel=nofollow to a link.
root's avatar
root committed
397
	 *
lechuck's avatar
lechuck committed
398
	 * @since 1.2.0
root's avatar
root committed
399
	 *
lechuck's avatar
lechuck committed
400
	 * @param array $matches Items matched by preg_replace_callback() in bp_activity_make_nofollow_filter().
ale's avatar
ale committed
401
	 * @return string $text Link with rel=nofollow added.
root's avatar
root committed
402
	 */
root's avatar
root committed
403
404
405
406
407
408
	function bp_activity_make_nofollow_filter_callback( $matches ) {
		$text = $matches[1];
		$text = str_replace( array( ' rel="nofollow"', " rel='nofollow'"), '', $text );
		return "<a $text rel=\"nofollow\">";
	}

root's avatar
root committed
409
/**
lechuck's avatar
lechuck committed
410
 * Truncate long activity entries when viewed in activity streams.
root's avatar
root committed
411
 *
ale's avatar
ale committed
412
413
 * This method can only be used inside the Activity loop.
 *
lechuck's avatar
lechuck committed
414
 * @since 1.5.0
lucha's avatar
lucha committed
415
 * @since 2.6.0 Added $args parameter.
root's avatar
root committed
416
 *
lechuck's avatar
lechuck committed
417
 * @param string $text The original activity entry text.
lucha's avatar
lucha committed
418
419
420
421
 * @param array  $args {
 *     Optional parameters. See $options argument of {@link bp_create_excerpt()}
 *     for all available parameters.
 * }
lechuck's avatar
lechuck committed
422
 * @return string $excerpt The truncated text.
root's avatar
root committed
423
 */
lucha's avatar
lucha committed
424
function bp_activity_truncate_entry( $text, $args = array() ) {
root's avatar
root committed
425
426
	global $activities_template;

ale's avatar
ale committed
427
428
429
	/**
	 * Provides a filter that lets you choose whether to skip this filter on a per-activity basis.
	 *
lechuck's avatar
lechuck committed
430
	 * @since 2.3.0
ale's avatar
ale committed
431
432
433
434
435
436
437
438
	 *
	 * @param bool $value If true, text should be checked to see if it needs truncating.
	 */
	$maybe_truncate_text = apply_filters(
		'bp_activity_maybe_truncate_entry',
		isset( $activities_template->activity->type ) && ! in_array( $activities_template->activity->type, array( 'new_blog_post', ), true )
	);

lechuck's avatar
lechuck committed
439
	// The full text of the activity update should always show on the single activity screen.
lucha's avatar
lucha committed
440
	if ( empty( $args['force_truncate'] ) && ( ! $maybe_truncate_text || bp_is_single_activity() ) ) {
root's avatar
root committed
441
		return $text;
ale's avatar
ale committed
442
	}
root's avatar
root committed
443

ale's avatar
ale committed
444
445
446
	/**
	 * Filters the appended text for the activity excerpt.
	 *
lechuck's avatar
lechuck committed
447
	 * @since 1.5.0
ale's avatar
ale committed
448
449
450
	 *
	 * @param string $value Internationalized "Read more" text.
	 */
root's avatar
root committed
451
	$append_text    = apply_filters( 'bp_activity_excerpt_append_text', __( '[Read more]', 'buddypress' ) );
ale's avatar
ale committed
452
453
454
455

	/**
	 * Filters the excerpt length for the activity excerpt.
	 *
lechuck's avatar
lechuck committed
456
	 * @since 1.5.0
ale's avatar
ale committed
457
458
459
	 *
	 * @param int $value Number indicating how many words to trim the excerpt down to.
	 */
root's avatar
root committed
460
461
	$excerpt_length = apply_filters( 'bp_activity_excerpt_length', 358 );

lucha's avatar
lucha committed
462
463
	$args = wp_parse_args( $args, array( 'ending' => __( '&hellip;', 'buddypress' ) ) );

lechuck's avatar
lechuck committed
464
	// Run the text through the excerpt function. If it's too short, the original text will be returned.
lucha's avatar
lucha committed
465
	$excerpt        = bp_create_excerpt( $text, $excerpt_length, $args );
root's avatar
root committed
466

lechuck's avatar
lechuck committed
467
468
469
470
471
	/*
	 * If the text returned by bp_create_excerpt() is different from the original text (ie it's
	 * been truncated), add the "Read More" link. Note that bp_create_excerpt() is stripping
	 * shortcodes, so we have strip them from the $text before the comparison.
	 */
lucha's avatar
lucha committed
472
	if ( strlen( $excerpt ) < strlen( strip_shortcodes( $text ) ) ) {
root's avatar
root committed
473
474
475
476
477
		$id = !empty( $activities_template->activity->current_comment->id ) ? 'acomment-read-more-' . $activities_template->activity->current_comment->id : 'activity-read-more-' . bp_get_activity_id();

		$excerpt = sprintf( '%1$s<span class="activity-read-more" id="%2$s"><a href="%3$s" rel="nofollow">%4$s</a></span>', $excerpt, $id, bp_get_activity_thread_permalink(), $append_text );
	}

ale's avatar
ale committed
478
479
480
	/**
	 * Filters the composite activity excerpt entry.
	 *
lechuck's avatar
lechuck committed
481
	 * @since 1.5.0
ale's avatar
ale committed
482
483
484
485
486
	 *
	 * @param string $excerpt     Excerpt text and markup to be displayed.
	 * @param string $text        The original activity entry text.
	 * @param string $append_text The final append text applied.
	 */
root's avatar
root committed
487
488
	return apply_filters( 'bp_activity_truncate_entry', $excerpt, $text, $append_text );
}
lechuck's avatar
lechuck committed
489
490

/**
ale's avatar
ale committed
491
 * Include extra JavaScript dependencies for activity component.
lechuck's avatar
lechuck committed
492
 *
lechuck's avatar
lechuck committed
493
 * @since 2.0.0
lechuck's avatar
lechuck committed
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
 *
 * @param array $js_handles The original dependencies.
 * @return array $js_handles The new dependencies.
 */
function bp_activity_get_js_dependencies( $js_handles = array() ) {
	if ( bp_activity_do_heartbeat() ) {
		$js_handles[] = 'heartbeat';
	}

	return $js_handles;
}
add_filter( 'bp_core_get_js_dependencies', 'bp_activity_get_js_dependencies', 10, 1 );

/**
 * Add a just-posted classes to the most recent activity item.
 *
 * We use these classes to avoid pagination issues when items are loaded
 * dynamically into the activity stream.
 *
lechuck's avatar
lechuck committed
513
 * @since 2.0.0
ale's avatar
ale committed
514
 *
lechuck's avatar
lechuck committed
515
 * @param string $classes Array of classes for most recent activity item.
lechuck's avatar
lechuck committed
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
 * @return string $classes
 */
function bp_activity_newest_class( $classes = '' ) {
	$bp = buddypress();

	if ( ! empty( $bp->activity->last_recorded ) && $bp->activity->last_recorded == bp_get_activity_date_recorded() ) {
		$classes .= ' new-update';
	}

	$classes .= ' just-posted';
	return $classes;
}

/**
 * Check if Activity Heartbeat feature i on to add a timestamp class.
 *
lechuck's avatar
lechuck committed
532
 * @since 2.0.0
ale's avatar
ale committed
533
 *
lechuck's avatar
lechuck committed
534
 * @param string $classes Array of classes for timestamp.
lechuck's avatar
lechuck committed
535
536
537
538
539
540
541
542
543
544
545
546
547
 * @return string $classes
 */
function bp_activity_timestamp_class( $classes = '' ) {

	if ( ! bp_activity_do_heartbeat() ) {
		return $classes;
	}

	$activity_date = bp_get_activity_date_recorded();

	if ( empty( $activity_date ) ) {
		return $classes;
	}
lucha's avatar
lucha committed
548

lechuck's avatar
lechuck committed
549
550
551
552
553
554
555
556
557
	$classes .= ' date-recorded-' . strtotime( $activity_date );

	return $classes;
}
add_filter( 'bp_get_activity_css_class', 'bp_activity_timestamp_class', 9, 1 );

/**
 * Use WordPress Heartbeat API to check for latest activity update.
 *
lechuck's avatar
lechuck committed
558
 * @since 2.0.0
lechuck's avatar
lechuck committed
559
 *
lechuck's avatar
lechuck committed
560
561
 * @param array $response Array containing Heartbeat API response.
 * @param array $data     Array containing data for Heartbeat API response.
lechuck's avatar
lechuck committed
562
563
564
565
566
567
568
569
 * @return array $response
 */
function bp_activity_heartbeat_last_recorded( $response = array(), $data = array() ) {
	if ( empty( $data['bp_activity_last_recorded'] ) ) {
		return $response;
	}

	// Use the querystring argument stored in the cookie (to preserve
lechuck's avatar
lechuck committed
570
	// filters), but force the offset to get only new items.
lechuck's avatar
lechuck committed
571
572
573
574
575
576
	$activity_latest_args = bp_parse_args(
		bp_ajax_querystring( 'activity' ),
		array( 'since' => date( 'Y-m-d H:i:s', $data['bp_activity_last_recorded'] ) ),
		'activity_latest_args'
	);

lucha's avatar
lucha committed
577
578
579
580
	if ( ! empty( $data['bp_activity_last_recorded_search_terms'] ) && empty( $activity_latest_args['search_terms'] ) ) {
		$activity_latest_args['search_terms'] = addslashes( $data['bp_activity_last_recorded_search_terms'] );
	}

lechuck's avatar
lechuck committed
581
582
583
	$newest_activities = array();
	$last_activity_recorded = 0;

lechuck's avatar
lechuck committed
584
	// Temporarily add a just-posted class for new activity items.
lechuck's avatar
lechuck committed
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
	add_filter( 'bp_get_activity_css_class', 'bp_activity_newest_class', 10, 1 );

	ob_start();
	if ( bp_has_activities( $activity_latest_args ) ) {
		while ( bp_activities() ) {
			bp_the_activity();

			$atime = strtotime( bp_get_activity_date_recorded() );
			if ( $last_activity_recorded < $atime ) {
				$last_activity_recorded = $atime;
			}

			bp_get_template_part( 'activity/entry' );
		}
	}

	$newest_activities['activities']    = ob_get_contents();
	$newest_activities['last_recorded'] = $last_activity_recorded;
	ob_end_clean();

lechuck's avatar
lechuck committed
605
	// Remove the temporary filter.
lechuck's avatar
lechuck committed
606
607
608
609
610
611
612
613
614
615
616
617
618
619
	remove_filter( 'bp_get_activity_css_class', 'bp_activity_newest_class', 10, 1 );

	if ( ! empty( $newest_activities['last_recorded'] ) ) {
		$response['bp_activity_newest_activities'] = $newest_activities;
	}

	return $response;
}
add_filter( 'heartbeat_received', 'bp_activity_heartbeat_last_recorded', 10, 2 );
add_filter( 'heartbeat_nopriv_received', 'bp_activity_heartbeat_last_recorded', 10, 2 );

/**
 * Set the strings for WP HeartBeat API where needed.
 *
lechuck's avatar
lechuck committed
620
 * @since 2.0.0
lechuck's avatar
lechuck committed
621
622
623
624
625
626
627
628
629
630
631
632
 *
 * @param array $strings Localized strings.
 * @return array $strings
 */
function bp_activity_heartbeat_strings( $strings = array() ) {

	if ( ! bp_activity_do_heartbeat() ) {
		return $strings;
	}

	$global_pulse = 0;

ale's avatar
ale committed
633
634
635
	/**
	 * Filter that checks whether the global heartbeat settings already exist.
	 *
lechuck's avatar
lechuck committed
636
	 * @since 2.0.0
ale's avatar
ale committed
637
638
639
	 *
	 * @param array $value Heartbeat settings array.
	 */
lechuck's avatar
lechuck committed
640
641
642
643
644
645
	$heartbeat_settings = apply_filters( 'heartbeat_settings', array() );
	if ( ! empty( $heartbeat_settings['interval'] ) ) {
		// 'Fast' is 5
		$global_pulse = is_numeric( $heartbeat_settings['interval'] ) ? absint( $heartbeat_settings['interval'] ) : 5;
	}

ale's avatar
ale committed
646
647
648
	/**
	 * Filters the pulse frequency to be used for the BuddyPress Activity heartbeat.
	 *
lechuck's avatar
lechuck committed
649
	 * @since 2.0.0
ale's avatar
ale committed
650
651
652
	 *
	 * @param int $value The frequency in seconds between pulses.
	 */
lechuck's avatar
lechuck committed
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
	$bp_activity_pulse = apply_filters( 'bp_activity_heartbeat_pulse', 15 );

	/**
	 * Use the global pulse value unless:
	 * a. the BP-specific value has been specifically filtered, or
	 * b. it doesn't exist (ie, BP will be the only one using the heartbeat,
	 *    so we're responsible for enabling it)
	 */
	if ( has_filter( 'bp_activity_heartbeat_pulse' ) || empty( $global_pulse ) ) {
		$pulse = $bp_activity_pulse;
	} else {
		$pulse = $global_pulse;
	}

	$strings = array_merge( $strings, array(
		'newest' => __( 'Load Newest', 'buddypress' ),
		'pulse'  => absint( $pulse ),
	) );

	return $strings;
}
add_filter( 'bp_core_get_js_strings', 'bp_activity_heartbeat_strings', 10, 1 );
ale's avatar
ale committed
675
676
677
678
679
680

/** Scopes ********************************************************************/

/**
 * Set up activity arguments for use with the 'just-me' scope.
 *
lechuck's avatar
lechuck committed
681
 * @since 2.2.0
ale's avatar
ale committed
682
683
684
 *
 * @param array $retval Empty array by default.
 * @param array $filter Current activity arguments.
lechuck's avatar
lechuck committed
685
 * @return array $retval
ale's avatar
ale committed
686
687
688
 */
function bp_activity_filter_just_me_scope( $retval = array(), $filter = array() ) {

lechuck's avatar
lechuck committed
689
	// Determine the user_id.
ale's avatar
ale committed
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
	if ( ! empty( $filter['user_id'] ) ) {
		$user_id = $filter['user_id'];
	} else {
		$user_id = bp_displayed_user_id()
			? bp_displayed_user_id()
			: bp_loggedin_user_id();
	}

	// Should we show all items regardless of sitewide visibility?
	$show_hidden = array();
	if ( ! empty( $user_id ) && $user_id !== bp_loggedin_user_id() ) {
		$show_hidden = array(
			'column' => 'hide_sitewide',
			'value'  => 0
		);
	}

	$retval = array(
		'relation' => 'AND',
		array(
			'column' => 'user_id',
			'value'  => $user_id
		),
		$show_hidden,

lechuck's avatar
lechuck committed
715
		// Overrides.
ale's avatar
ale committed
716
717
718
719
720
721
722
723
724
725
726
727
728
729
		'override' => array(
			'display_comments' => 'stream',
			'filter'           => array( 'user_id' => 0 ),
			'show_hidden'      => true
		),
	);

	return $retval;
}
add_filter( 'bp_activity_set_just-me_scope_args', 'bp_activity_filter_just_me_scope', 10, 2 );

/**
 * Set up activity arguments for use with the 'favorites' scope.
 *
lechuck's avatar
lechuck committed
730
 * @since 2.2.0
ale's avatar
ale committed
731
732
733
 *
 * @param array $retval Empty array by default.
 * @param array $filter Current activity arguments.
lechuck's avatar
lechuck committed
734
 * @return array $retval
ale's avatar
ale committed
735
736
737
 */
function bp_activity_filter_favorites_scope( $retval = array(), $filter = array() ) {

lechuck's avatar
lechuck committed
738
	// Determine the user_id.
ale's avatar
ale committed
739
740
741
742
743
744
745
746
	if ( ! empty( $filter['user_id'] ) ) {
		$user_id = $filter['user_id'];
	} else {
		$user_id = bp_displayed_user_id()
			? bp_displayed_user_id()
			: bp_loggedin_user_id();
	}

lechuck's avatar
lechuck committed
747
	// Determine the favorites.
ale's avatar
ale committed
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
	$favs = bp_activity_get_user_favorites( $user_id );
	if ( empty( $favs ) ) {
		$favs = array( 0 );
	}

	// Should we show all items regardless of sitewide visibility?
	$show_hidden = array();
	if ( ! empty( $user_id ) && ( $user_id !== bp_loggedin_user_id() ) ) {
		$show_hidden = array(
			'column' => 'hide_sitewide',
			'value'  => 0
		);
	}

	$retval = array(
		'relation' => 'AND',
		array(
			'column'  => 'id',
			'compare' => 'IN',
			'value'   => (array) $favs
		),
		$show_hidden,

lechuck's avatar
lechuck committed
771
		// Overrides.
ale's avatar
ale committed
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
		'override' => array(
			'display_comments' => true,
			'filter'           => array( 'user_id' => 0 ),
			'show_hidden'      => true
		),
	);

	return $retval;
}
add_filter( 'bp_activity_set_favorites_scope_args', 'bp_activity_filter_favorites_scope', 10, 2 );


/**
 * Set up activity arguments for use with the 'favorites' scope.
 *
lechuck's avatar
lechuck committed
787
 * @since 2.2.0
ale's avatar
ale committed
788
789
790
 *
 * @param array $retval Empty array by default.
 * @param array $filter Current activity arguments.
lechuck's avatar
lechuck committed
791
 * @return array $retval
ale's avatar
ale committed
792
793
794
795
796
797
798
799
 */
function bp_activity_filter_mentions_scope( $retval = array(), $filter = array() ) {

	// Are mentions disabled?
	if ( ! bp_activity_do_mentions() ) {
		return $retval;
	}

lechuck's avatar
lechuck committed
800
	// Determine the user_id.
ale's avatar
ale committed
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
	if ( ! empty( $filter['user_id'] ) ) {
		$user_id = $filter['user_id'];
	} else {
		$user_id = bp_displayed_user_id()
			? bp_displayed_user_id()
			: bp_loggedin_user_id();
	}

	// Should we show all items regardless of sitewide visibility?
	$show_hidden = array();
	if ( ! empty( $user_id ) && $user_id !== bp_loggedin_user_id() ) {
		$show_hidden = array(
			'column' => 'hide_sitewide',
			'value'  => 0
		);
	}

	$retval = array(
		'relation' => 'AND',
		array(
			'column'  => 'content',
			'compare' => 'LIKE',

			// Start search at @ symbol and stop search at closing tag delimiter.
			'value'   => '@' . bp_activity_get_user_mentionname( $user_id ) . '<'
		),
		$show_hidden,

lechuck's avatar
lechuck committed
829
		// Overrides.
ale's avatar
ale committed
830
831
832
833
834
835
836
837
838
839
		'override' => array(
			'display_comments' => 'stream',
			'filter'           => array( 'user_id' => 0 ),
			'show_hidden'      => true
		),
	);

	return $retval;
}
add_filter( 'bp_activity_set_mentions_scope_args', 'bp_activity_filter_mentions_scope', 10, 2 );