Skip to:
Content

BuddyPress.org

Ticket #3497: bp-activity-classes-adjusted.php

File bp-activity-classes-adjusted.php, 50.4 KB (added by finzend, 13 years ago)

New classes file, based on 1.9.1

Line 
1<?php
2/**
3 * BuddyPress Activity Classes
4 *
5 * @package BuddyPress
6 * @subpackage Activity
7 */
8
9// Exit if accessed directly
10if ( !defined( 'ABSPATH' ) ) exit;
11
12/**
13 * Database interaction class for the BuddyPress activity component.
14 *
15 * Instance methods are available for creating/editing an activity,
16 * static methods for querying activities.
17 *
18 * @since BuddyPress (1.0)
19 */
20class BP_Activity_Activity {
21
22 /** Properties ************************************************************/
23
24 /**
25 * ID of the activity item.
26 *
27 * @var int
28 */
29 var $id;
30
31 /**
32 * ID of the associated item.
33 *
34 * @var int
35 */
36 var $item_id;
37
38 /**
39 * ID of the associated secondary item.
40 *
41 * @var int
42 */
43 var $secondary_item_id;
44
45 /**
46 * ID of user associated with the activity item.
47 *
48 * @var int
49 */
50 var $user_id;
51
52 /**
53 * The primary URL for the activity in RSS feeds.
54 *
55 * @var string
56 */
57 var $primary_link;
58
59 /**
60 * BuddyPress component the activity item relates to.
61 *
62 * @var string
63 */
64 var $component;
65
66 /**
67 * Activity type, eg 'new_blog_post'.
68 *
69 * @var string
70 */
71 var $type;
72
73 /**
74 * Description of the activity, eg 'Alex updated his profile.'
75 *
76 * @var string
77 */
78 var $action;
79
80 /**
81 * The content of the activity item.
82 *
83 * @var string
84 */
85 var $content;
86
87 /**
88 * The date the activity item was recorded, in 'Y-m-d h:i:s' format.
89 *
90 * @var string
91 */
92 var $date_recorded;
93
94 /**
95 * Whether the item should be hidden in sitewide streams.
96 *
97 * @var int
98 */
99 var $hide_sitewide = false;
100
101 /**
102 * Node boundary start for activity or activity comment.
103 *
104 * @var int
105 */
106 var $mptt_left;
107
108 /**
109 * Node boundary end for activity or activity comment.
110 *
111 * @var int
112 */
113 var $mptt_right;
114
115 /**
116 * Whether this item is marked as spam.
117 *
118 * @var int
119 */
120 var $is_spam;
121
122 /**
123 * Constructor method.
124 *
125 * @param int $id Optional. The ID of a specific activity item.
126 */
127 public function __construct( $id = false ) {
128 if ( !empty( $id ) ) {
129 $this->id = $id;
130 $this->populate();
131 }
132 }
133
134 /**
135 * Populate the object with data about the specific activity item.
136 */
137 public function populate() {
138 global $wpdb, $bp;
139
140 if ( $row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->activity->table_name} WHERE id = %d", $this->id ) ) ) {
141 $this->id = $row->id;
142 $this->item_id = $row->item_id;
143 $this->secondary_item_id = $row->secondary_item_id;
144 $this->user_id = $row->user_id;
145 $this->primary_link = $row->primary_link;
146 $this->component = $row->component;
147 $this->type = $row->type;
148 $this->action = $row->action;
149 $this->content = $row->content;
150 $this->date_recorded = $row->date_recorded;
151 $this->hide_sitewide = $row->hide_sitewide;
152 $this->mptt_left = $row->mptt_left;
153 $this->mptt_right = $row->mptt_right;
154 $this->is_spam = $row->is_spam;
155
156 bp_activity_update_meta_cache( $this->id );
157 }
158 }
159
160 /**
161 * Save the activity item to the database.
162 *
163 * @return bool True on success.
164 */
165 public function save() {
166 global $wpdb, $bp;
167
168 $this->id = apply_filters_ref_array( 'bp_activity_id_before_save', array( $this->id, &$this ) );
169 $this->item_id = apply_filters_ref_array( 'bp_activity_item_id_before_save', array( $this->item_id, &$this ) );
170 $this->secondary_item_id = apply_filters_ref_array( 'bp_activity_secondary_item_id_before_save', array( $this->secondary_item_id, &$this ) );
171 $this->user_id = apply_filters_ref_array( 'bp_activity_user_id_before_save', array( $this->user_id, &$this ) );
172 $this->primary_link = apply_filters_ref_array( 'bp_activity_primary_link_before_save', array( $this->primary_link, &$this ) );
173 $this->component = apply_filters_ref_array( 'bp_activity_component_before_save', array( $this->component, &$this ) );
174 $this->type = apply_filters_ref_array( 'bp_activity_type_before_save', array( $this->type, &$this ) );
175 $this->action = apply_filters_ref_array( 'bp_activity_action_before_save', array( $this->action, &$this ) );
176 $this->content = apply_filters_ref_array( 'bp_activity_content_before_save', array( $this->content, &$this ) );
177 $this->date_recorded = apply_filters_ref_array( 'bp_activity_date_recorded_before_save', array( $this->date_recorded, &$this ) );
178 $this->hide_sitewide = apply_filters_ref_array( 'bp_activity_hide_sitewide_before_save', array( $this->hide_sitewide, &$this ) );
179 $this->mptt_left = apply_filters_ref_array( 'bp_activity_mptt_left_before_save', array( $this->mptt_left, &$this ) );
180 $this->mptt_right = apply_filters_ref_array( 'bp_activity_mptt_right_before_save', array( $this->mptt_right, &$this ) );
181 $this->is_spam = apply_filters_ref_array( 'bp_activity_is_spam_before_save', array( $this->is_spam, &$this ) );
182
183 // Use this, not the filters above
184 do_action_ref_array( 'bp_activity_before_save', array( &$this ) );
185
186 if ( !$this->component || !$this->type )
187 return false;
188
189 if ( !$this->primary_link )
190 $this->primary_link = bp_loggedin_user_domain();
191
192 // If we have an existing ID, update the activity item, otherwise insert it.
193 if ( $this->id )
194 $q = $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET user_id = %d, component = %s, type = %s, action = %s, content = %s, primary_link = %s, date_recorded = %s, item_id = %d, secondary_item_id = %d, hide_sitewide = %d, is_spam = %d WHERE id = %d", $this->user_id, $this->component, $this->type, $this->action, $this->content, $this->primary_link, $this->date_recorded, $this->item_id, $this->secondary_item_id, $this->hide_sitewide, $this->is_spam, $this->id );
195 else
196 $q = $wpdb->prepare( "INSERT INTO {$bp->activity->table_name} ( user_id, component, type, action, content, primary_link, date_recorded, item_id, secondary_item_id, hide_sitewide, is_spam ) VALUES ( %d, %s, %s, %s, %s, %s, %s, %d, %d, %d, %d )", $this->user_id, $this->component, $this->type, $this->action, $this->content, $this->primary_link, $this->date_recorded, $this->item_id, $this->secondary_item_id, $this->hide_sitewide, $this->is_spam );
197
198 if ( false === $wpdb->query( $q ) )
199 return false;
200
201 // If this is a new activity item, set the $id property
202 if ( empty( $this->id ) )
203 $this->id = $wpdb->insert_id;
204
205 // If an existing activity item, prevent any changes to the content generating new @mention notifications.
206 else
207 add_filter( 'bp_activity_at_name_do_notifications', '__return_false' );
208
209 do_action_ref_array( 'bp_activity_after_save', array( &$this ) );
210
211 return true;
212 }
213
214 /** Static Methods ***************************************************/
215
216 /**
217 * Get activity items, as specified by parameters
218 *
219 * @see BP_Activity_Activity::get_filter_sql() for a description of the
220 * 'filter' parameter.
221 * @see WP_Meta_Query::queries for a description of the 'meta_query'
222 * parameter format.
223 *
224 * @param array $args {
225 * An array of arguments. All items are optional.
226 * @type int $page Which page of results to fetch. Using page=1
227 * without per_page will result in no pagination.
228 * Default: 1.
229 * @type int|bool $per_page Number of results per page. Default: 25.
230 * @type int|bool $max Maximum number of results to return.
231 * Default: false (unlimited).
232 * @type string $sort ASC or DESC. Default: 'DESC'.
233 * @type array $exclude Array of activity IDs to exclude.
234 * Default: false.
235 * @type array $in Array of ids to limit query by (IN).
236 * Default: false.
237 * @type array $meta_query An array of meta_query conditions.
238 * See WP_Meta_Query::queries for description.
239 * @type array $filter See BP_Activity_Activity::get_filter_sql().
240 * @type string $search_terms Limit results by a search term.
241 * Default: false.
242 * @type bool $display_comments Whether to include activity comments.
243 * Default: false.
244 * @type bool $show_hidden Whether to show items marked hide_sitewide.
245 * Default: false.
246 * @type string $spam Spam status. Default: 'ham_only'.
247 * }
248 * @return array The array returned has two keys:
249 * - 'total' is the count of located activities
250 * - 'activities' is an array of the located activities
251 */
252 public static function get( $args = array() ) {
253 global $wpdb, $bp;
254
255 // Backward compatibility with old method of passing arguments
256 if ( !is_array( $args ) || func_num_args() > 1 ) {
257 _deprecated_argument( __METHOD__, '1.6', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
258
259 $old_args_keys = array(
260 0 => 'max',
261 1 => 'page',
262 2 => 'per_page',
263 3 => 'sort',
264 4 => 'search_terms',
265 5 => 'filter',
266 6 => 'display_comments',
267 7 => 'show_hidden',
268 8 => 'exclude',
269 9 => 'in',
270 10 => 'spam'
271 );
272
273 $func_args = func_get_args();
274 $args = bp_core_parse_args_array( $old_args_keys, $func_args );
275 }
276
277 $defaults = array(
278 'page' => 1, // The current page
279 'per_page' => 25, // Activity items per page
280 'max' => false, // Max number of items to return
281 'sort' => 'DESC', // ASC or DESC
282 'exclude' => false, // Array of ids to exclude
283 'in' => false, // Array of ids to limit query by (IN)
284 'meta_query' => false, // Filter by activitymeta
285 'filter' => false, // See self::get_filter_sql()
286 'search_terms' => false, // Terms to search by
287 'display_comments' => false, // Whether to include activity comments
288 'show_hidden' => false, // Show items marked hide_sitewide
289 'spam' => 'ham_only', // Spam status
290 );
291 $r = wp_parse_args( $args, $defaults );
292 extract( $r );
293
294 // Select conditions old:
295 //$select_sql = "SELECT DISTINCT a.*, u.user_email, u.user_nicename, u.user_login, u.display_name";
296 //$from_sql = " FROM {$bp->activity->table_name} a LEFT JOIN {$wpdb->users} u ON a.user_id = u.ID";
297
298 // Select conditions new: finzend
299 $select_sql = "SELECT id";
300 $from_sql = " FROM {$bp->activity->table_name} a";
301
302 $join_sql = '';
303
304 // Where conditions
305 $where_conditions = array();
306
307 // Spam
308 if ( 'ham_only' == $spam )
309 $where_conditions['spam_sql'] = 'a.is_spam = 0';
310 elseif ( 'spam_only' == $spam )
311 $where_conditions['spam_sql'] = 'a.is_spam = 1';
312
313 // Searching
314 if ( $search_terms ) {
315 $search_terms = esc_sql( $search_terms );
316 $where_conditions['search_sql'] = "a.content LIKE '%%" . esc_sql( like_escape( $search_terms ) ) . "%%'";
317 }
318
319 // Filtering
320 if ( $filter && $filter_sql = BP_Activity_Activity::get_filter_sql( $filter ) )
321 $where_conditions['filter_sql'] = $filter_sql;
322
323 // Sorting
324 if ( $sort != 'ASC' && $sort != 'DESC' )
325 $sort = 'DESC';
326
327 // Hide Hidden Items?
328 if ( !$show_hidden )
329 $where_conditions['hidden_sql'] = "a.hide_sitewide != 1"; //finzend
330
331 // Exclude specified items
332 if ( !empty( $exclude ) ) {
333 $exclude = implode( ',', wp_parse_id_list( $exclude ) );
334 $where_conditions['exclude'] = "a.id NOT IN ({$exclude})";
335 }
336
337 // The specific ids to which you want to limit the query
338 if ( !empty( $in ) ) {
339 $in = implode( ',', wp_parse_id_list( $in ) );
340 $where_conditions['in'] = "a.id IN ({$in})";
341 }
342
343 // Process meta_query into SQL
344 $meta_query_sql = self::get_meta_query_sql( $meta_query );
345
346 if ( ! empty( $meta_query_sql['join'] ) ) {
347 $join_sql .= $meta_query_sql['join'];
348 }
349
350 if ( ! empty( $meta_query_sql['where'] ) ) {
351 $where_conditions[] = $meta_query_sql['where'];
352 }
353
354 // Alter the query based on whether we want to show activity item
355 // comments in the stream like normal comments or threaded below
356 // the activity.
357 if ( false === $display_comments || 'threaded' === $display_comments ) {
358 $where_conditions[] = "a.type != 'activity_comment'";
359 }
360
361 // Filter the where conditions
362 $where_conditions = apply_filters( 'bp_activity_get_where_conditions', $where_conditions, $r, $select_sql, $from_sql, $join_sql );
363
364 // Join the where conditions together
365 $where_sql = 'WHERE ' . join( ' AND ', $where_conditions );
366
367 // Define the preferred order for indexes
368 $indexes = apply_filters( 'bp_activity_preferred_index_order', array( 'user_id', 'item_id', 'secondary_item_id', 'date_recorded', 'component', 'type', 'hide_sitewide', 'is_spam' ) );
369
370 foreach( $indexes as $key => $index ) {
371 if ( false !== strpos( $where_sql, $index ) ) {
372 $the_index = $index;
373 break; // Take the first one we find
374 }
375 }
376
377 if ( !empty( $the_index ) ) {
378 $index_hint_sql = "USE INDEX ({$the_index})";
379 } else {
380 $index_hint_sql = '';
381 }
382
383 if ( !empty( $per_page ) && !empty( $page ) ) {
384
385 // Make sure page values are absolute integers
386 $page = absint( $page );
387 $per_page = absint( $per_page );
388
389 $pag_sql = $wpdb->prepare( "LIMIT %d, %d", absint( ( $page - 1 ) * $per_page ), $per_page );
390
391 // Added by finzend
392 $full_sql_statement = "SELECT a1.*, u.user_email, u.user_nicename, u.user_login, u.display_name ".
393 "FROM wp_bp_activity a1, wp_users u, (".
394 " {$select_sql} {$from_sql} {$where_sql} ORDER BY a.date_recorded {$sort} {$pag_sql} ".
395 ") a2 ".
396 "WHERE a1.id = a2.id AND a1.user_id = u.ID ";
397
398 //$activities = $wpdb->get_results( apply_filters( 'bp_activity_get_user_join_filter', "{$select_sql} {$from_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort} {$pag_sql}", $select_sql, $from_sql, $where_sql, $sort, $pag_sql ) );
399 //Adjusted by finzend:
400 $activities = $wpdb->get_results( $wpdb->prepare( $full_sql_statement ) );
401 } else {
402 $activities = $wpdb->get_results( apply_filters( 'bp_activity_get_user_join_filter', "{$select_sql} {$from_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort}", $select_sql, $from_sql, $where_sql, $sort ) );
403 }
404
405 $total_activities_sql = apply_filters( 'bp_activity_total_activities_sql', "SELECT count(DISTINCT a.id) FROM {$bp->activity->table_name} a {$index_hint_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort}", $where_sql, $sort );
406
407 //$total_activities = $wpdb->get_var( $total_activities_sql );
408 //Adjusted by finzend:
409 $total_activities = $wpdb->get_var( $wpdb->prepare( "SELECT count(a.id) FROM {$bp->activity->table_name} a {$where_sql}" ) );
410
411 // Get the fullnames of users so we don't have to query in the loop
412 if ( bp_is_active( 'xprofile' ) && !empty( $activities ) ) {
413 $activity_user_ids = wp_list_pluck( $activities, 'user_id' );
414 $activity_user_ids = implode( ',', wp_parse_id_list( $activity_user_ids ) );
415
416 if ( !empty( $activity_user_ids ) ) {
417 if ( $names = $wpdb->get_results( "SELECT user_id, value AS user_fullname FROM {$bp->profile->table_name_data} WHERE field_id = 1 AND user_id IN ({$activity_user_ids})" ) ) {
418 foreach ( (array) $names as $name )
419 $tmp_names[$name->user_id] = $name->user_fullname;
420
421 foreach ( (array) $activities as $i => $activity ) {
422 if ( !empty( $tmp_names[$activity->user_id] ) )
423 $activities[$i]->user_fullname = $tmp_names[$activity->user_id];
424 }
425
426 unset( $names );
427 unset( $tmp_names );
428 }
429 }
430 }
431
432 // Get activity meta
433 $activity_ids = array();
434 foreach ( (array) $activities as $activity ) {
435 $activity_ids[] = $activity->id;
436 }
437
438 if ( !empty( $activity_ids ) ) {
439 bp_activity_update_meta_cache( $activity_ids );
440 }
441
442 if ( $activities && $display_comments )
443 $activities = BP_Activity_Activity::append_comments( $activities, $spam );
444
445 // If $max is set, only return up to the max results
446 if ( !empty( $max ) ) {
447 if ( (int) $total_activities > (int) $max )
448 $total_activities = $max;
449 }
450
451 return array( 'activities' => $activities, 'total' => (int) $total_activities );
452 }
453
454 /**
455 * Get the SQL for the 'meta_query' param in BP_Activity_Activity::get().
456 *
457 * We use WP_Meta_Query to do the heavy lifting of parsing the
458 * meta_query array and creating the necessary SQL clauses. However,
459 * since BP_Activity_Activity::get() builds its SQL differently than
460 * WP_Query, we have to alter the return value (stripping the leading
461 * AND keyword from the 'where' clause).
462 *
463 * @since BuddyPress (1.8)
464 *
465 * @param array $meta_query An array of meta_query filters. See the
466 * documentation for WP_Meta_Query for details.
467 * @return array $sql_array 'join' and 'where' clauses.
468 */
469 public static function get_meta_query_sql( $meta_query = array() ) {
470 global $wpdb;
471
472 $sql_array = array(
473 'join' => '',
474 'where' => '',
475 );
476
477 if ( ! empty( $meta_query ) ) {
478 $activity_meta_query = new WP_Meta_Query( $meta_query );
479
480 // WP_Meta_Query expects the table name at
481 // $wpdb->activitymeta
482 $wpdb->activitymeta = buddypress()->activity->table_name_meta;
483
484 $meta_sql = $activity_meta_query->get_sql( 'activity', 'a', 'id' );
485
486 // Strip the leading AND - BP handles it in get()
487 $sql_array['where'] = preg_replace( '/^\sAND/', '', $meta_sql['where'] );
488 $sql_array['join'] = $meta_sql['join'];
489 }
490
491 return $sql_array;
492 }
493
494 /**
495 * In BuddyPress 1.2.x, this was used to retrieve specific activity stream items (for example, on an activity's permalink page).
496 *
497 * As of 1.5.x, use BP_Activity_Activity::get() with an 'in' parameter instead.
498 *
499 * @since BuddyPress (1.2)
500 *
501 * @deprecated 1.5
502 * @deprecated Use BP_Activity_Activity::get() with an 'in' parameter instead.
503 *
504 * @param mixed $activity_ids Array or comma-separated string of activity IDs to retrieve
505 * @param int $max Maximum number of results to return. (Optional; default is no maximum)
506 * @param int $page The set of results that the user is viewing. Used in pagination. (Optional; default is 1)
507 * @param int $per_page Specifies how many results per page. Used in pagination. (Optional; default is 25)
508 * @param string MySQL column sort; ASC or DESC. (Optional; default is DESC)
509 * @param bool $display_comments Retrieve an activity item's associated comments or not. (Optional; default is false)
510 * @return array
511 */
512 public static function get_specific( $activity_ids, $max = false, $page = 1, $per_page = 25, $sort = 'DESC', $display_comments = false ) {
513 _deprecated_function( __FUNCTION__, '1.5', 'Use BP_Activity_Activity::get() with the "in" parameter instead.' );
514 return BP_Activity_Activity::get( $max, $page, $per_page, $sort, false, false, $display_comments, false, false, $activity_ids );
515 }
516
517 /**
518 * Get the first activity ID that matches a set of criteria.
519 *
520 * @param int $user_id The user ID to filter by.
521 * @param string $component The component to filter by.
522 * @param string $type The activity type to filter by.
523 * @param int $item_id The associated item to filter by.
524 * @param int $secondary_item_id The secondary associated item to filter by.
525 * @param string $action The action to filter by.
526 * @param string $content The content to filter by.
527 * @param string $date_recorded The date to filter by.
528 * @return int|bool Activity ID on success, false if none is found.
529 */
530 public static function get_id( $user_id, $component, $type, $item_id, $secondary_item_id, $action, $content, $date_recorded ) {
531 global $bp, $wpdb;
532
533 $where_args = false;
534
535 if ( !empty( $user_id ) )
536 $where_args[] = $wpdb->prepare( "user_id = %d", $user_id );
537
538 if ( !empty( $component ) )
539 $where_args[] = $wpdb->prepare( "component = %s", $component );
540
541 if ( !empty( $type ) )
542 $where_args[] = $wpdb->prepare( "type = %s", $type );
543
544 if ( !empty( $item_id ) )
545 $where_args[] = $wpdb->prepare( "item_id = %d", $item_id );
546
547 if ( !empty( $secondary_item_id ) )
548 $where_args[] = $wpdb->prepare( "secondary_item_id = %d", $secondary_item_id );
549
550 if ( !empty( $action ) )
551 $where_args[] = $wpdb->prepare( "action = %s", $action );
552
553 if ( !empty( $content ) )
554 $where_args[] = $wpdb->prepare( "content = %s", $content );
555
556 if ( !empty( $date_recorded ) )
557 $where_args[] = $wpdb->prepare( "date_recorded = %s", $date_recorded );
558
559 if ( !empty( $where_args ) )
560 $where_sql = 'WHERE ' . join( ' AND ', $where_args );
561 else
562 return false;
563
564 return $wpdb->get_var( "SELECT id FROM {$bp->activity->table_name} {$where_sql}" );
565 }
566
567 /**
568 * Delete activity items from the database.
569 *
570 * To delete a specific activity item, pass an 'id' parameter.
571 * Otherwise use the filters.
572 *
573 * @since BuddyPress (1.2)
574 *
575 * @param array $args {
576 * @int $id Optional. The ID of a specific item to delete.
577 * @string $action Optional. The action to filter by.
578 * @string $content Optional. The content to filter by.
579 * @string $component Optional. The component name to filter by.
580 * @string $type Optional. The activity type to filter by.
581 * @string $primary_link Optional. The primary URL to filter by.
582 * @int $user_id Optional. The user ID to filter by.
583 * @int $item_id Optional. The associated item ID to filter by.
584 * @int $secondary_item_id Optional. The secondary associated item ID to filter by.
585 * @string $date_recorded Optional. The date to filter by.
586 * @int $hide_sitewide Optional. Default: false.
587 * }
588 * @return array|bool An array of deleted activity IDs on success, false on failure.
589 */
590 public static function delete( $args = array() ) {
591 global $wpdb, $bp;
592
593 $defaults = array(
594 'id' => false,
595 'action' => false,
596 'content' => false,
597 'component' => false,
598 'type' => false,
599 'primary_link' => false,
600 'user_id' => false,
601 'item_id' => false,
602 'secondary_item_id' => false,
603 'date_recorded' => false,
604 'hide_sitewide' => false
605 );
606 $params = wp_parse_args( $args, $defaults );
607 extract( $params );
608
609 $where_args = false;
610
611 if ( !empty( $id ) )
612 $where_args[] = $wpdb->prepare( "id = %d", $id );
613
614 if ( !empty( $user_id ) )
615 $where_args[] = $wpdb->prepare( "user_id = %d", $user_id );
616
617 if ( !empty( $action ) )
618 $where_args[] = $wpdb->prepare( "action = %s", $action );
619
620 if ( !empty( $content ) )
621 $where_args[] = $wpdb->prepare( "content = %s", $content );
622
623 if ( !empty( $component ) )
624 $where_args[] = $wpdb->prepare( "component = %s", $component );
625
626 if ( !empty( $type ) )
627 $where_args[] = $wpdb->prepare( "type = %s", $type );
628
629 if ( !empty( $primary_link ) )
630 $where_args[] = $wpdb->prepare( "primary_link = %s", $primary_link );
631
632 if ( !empty( $item_id ) )
633 $where_args[] = $wpdb->prepare( "item_id = %d", $item_id );
634
635 if ( !empty( $secondary_item_id ) )
636 $where_args[] = $wpdb->prepare( "secondary_item_id = %d", $secondary_item_id );
637
638 if ( !empty( $date_recorded ) )
639 $where_args[] = $wpdb->prepare( "date_recorded = %s", $date_recorded );
640
641 //if ( !empty( $hide_sitewide ) )
642 // $where_args[] = $wpdb->prepare( "hide_sitewide = %d", $hide_sitewide );
643 // adjusted by finzend
644 if ($hide_sitewide==0) {
645 $where_args[] = $wpdb->prepare( "hide_sitewide != 1" );
646 } elseif ( !empty( $hide_sitewide ) ) {
647 $where_args[] = $wpdb->prepare( "hide_sitewide = %d", $hide_sitewide );
648 }
649
650 if ( !empty( $where_args ) )
651 $where_sql = 'WHERE ' . join( ' AND ', $where_args );
652 else
653 return false;
654
655 // Fetch the activity IDs so we can delete any comments for this activity item
656 $activity_ids = $wpdb->get_col( "SELECT id FROM {$bp->activity->table_name} {$where_sql}" );
657
658 if ( ! $wpdb->query( "DELETE FROM {$bp->activity->table_name} {$where_sql}" ) ) {
659 return false;
660 }
661
662 // Handle accompanying activity comments and meta deletion
663 if ( $activity_ids ) {
664 $activity_ids_comma = implode( ',', wp_parse_id_list( $activity_ids ) );
665 $activity_comments_where_sql = "WHERE type = 'activity_comment' AND item_id IN ({$activity_ids_comma})";
666
667 // Fetch the activity comment IDs for our deleted activity items
668 $activity_comment_ids = $wpdb->get_col( "SELECT id FROM {$bp->activity->table_name} {$activity_comments_where_sql}" );
669
670 // We have activity comments!
671 if ( ! empty( $activity_comment_ids ) ) {
672 // Delete activity comments
673 $wpdb->query( "DELETE FROM {$bp->activity->table_name} {$activity_comments_where_sql}" );
674
675 // Merge activity IDs with activity comment IDs
676 $activity_ids = array_merge( $activity_ids, $activity_comment_ids );
677 }
678
679 // Delete all activity meta entries for activity items and activity comments
680 BP_Activity_Activity::delete_activity_meta_entries( $activity_ids );
681 }
682
683 return $activity_ids;
684 }
685
686 /**
687 * Delete the comments associated with a set of activity items.
688 *
689 * @since BuddyPress (1.2)
690 *
691 * @todo Mark as deprecated? Method is no longer used internally.
692 *
693 * @param array $activity_ids Activity IDs whose comments should be deleted.
694 * @param bool $delete_meta Should we delete the activity meta items for these comments?
695 * @return bool True on success.
696 */
697 public static function delete_activity_item_comments( $activity_ids = array(), $delete_meta = true ) {
698 global $bp, $wpdb;
699
700 $delete_meta = (bool) $delete_meta;
701
702 $activity_ids = implode( ',', wp_parse_id_list( $activity_ids ) );
703
704 if ( $delete_meta ) {
705 // Fetch the activity comment IDs for our deleted activity items
706 $activity_comment_ids = $wpdb->get_col( "SELECT id FROM {$bp->activity->table_name} WHERE type = 'activity_comment' AND item_id IN ({$activity_ids})" );
707
708 if ( ! empty( $activity_comment_ids ) ) {
709 self::delete_activity_meta_entries( $activity_comment_ids );
710 }
711 }
712
713 return $wpdb->query( "DELETE FROM {$bp->activity->table_name} WHERE type = 'activity_comment' AND item_id IN ({$activity_ids})" );
714 }
715
716 /**
717 * Delete the meta entries associated with a set of activity items.
718 *
719 * @since BuddyPress (1.2)
720 *
721 * @param array $activity_ids Activity IDs whose meta should be deleted.
722 * @return bool True on success.
723 */
724 public static function delete_activity_meta_entries( $activity_ids = array() ) {
725 global $bp, $wpdb;
726
727 $activity_ids = implode( ',', wp_parse_id_list( $activity_ids ) );
728
729 foreach ( (array) $activity_ids as $activity_id ) {
730 bp_activity_clear_meta_cache_for_activity( $activity_id );
731 }
732
733 return $wpdb->query( "DELETE FROM {$bp->activity->table_name_meta} WHERE activity_id IN ({$activity_ids})" );
734 }
735
736 /**
737 * Append activity comments to their associated activity items.
738 *
739 * @since BuddyPress (1.2)
740 *
741 * @global wpdb $wpdb WordPress database object
742 *
743 * @param array $activities Activities to fetch comments for.
744 * @param bool $spam Optional. 'ham_only' (default), 'spam_only' or 'all'.
745 * @return array The updated activities with nested comments.
746 */
747 public static function append_comments( $activities, $spam = 'ham_only' ) {
748 $activity_comments = array();
749
750 // Now fetch the activity comments and parse them into the correct position in the activities array.
751 foreach( (array) $activities as $activity ) {
752 $top_level_parent_id = 'activity_comment' == $activity->type ? $activity->item_id : 0;
753 $activity_comments[$activity->id] = BP_Activity_Activity::get_activity_comments( $activity->id, $activity->mptt_left, $activity->mptt_right, $spam, $top_level_parent_id );
754 }
755
756 // Merge the comments with the activity items
757 foreach( (array) $activities as $key => $activity )
758 if ( isset( $activity_comments[$activity->id] ) )
759 $activities[$key]->children = $activity_comments[$activity->id];
760
761 return $activities;
762 }
763
764 /**
765 * Get activity comments that are associated with a specific activity ID.
766 *
767 * @since BuddyPress (1.2)
768 *
769 * @global BuddyPress $bp The one true BuddyPress instance.
770 * @global wpdb $wpdb WordPress database object.
771 *
772 * @param int $activity_id Activity ID to fetch comments for.
773 * @param int $left Left-most node boundary.
774 * @param into $right Right-most node boundary.
775 * @param bool $spam Optional. 'ham_only' (default), 'spam_only' or 'all'.
776 * @param int $top_level_parent_id Optional. The id of the root-level parent activity item.
777 * @return array The updated activities with nested comments.
778 */
779 public static function get_activity_comments( $activity_id, $left, $right, $spam = 'ham_only', $top_level_parent_id = 0 ) {
780 global $wpdb, $bp;
781
782 if ( empty( $top_level_parent_id ) ) {
783 $top_level_parent_id = $activity_id;
784 }
785
786 if ( !$comments = wp_cache_get( 'bp_activity_comments_' . $activity_id ) ) {
787
788 // Select the user's fullname with the query
789 if ( bp_is_active( 'xprofile' ) ) {
790 $fullname_select = ", pd.value as user_fullname";
791 $fullname_from = ", {$bp->profile->table_name_data} pd ";
792 $fullname_where = "AND pd.user_id = a.user_id AND pd.field_id = 1";
793
794 // Prevent debug errors
795 } else {
796 $fullname_select = $fullname_from = $fullname_where = '';
797 }
798
799 // Don't retrieve activity comments marked as spam
800 if ( 'ham_only' == $spam ) {
801 $spam_sql = 'AND a.is_spam = 0';
802 } elseif ( 'spam_only' == $spam ) {
803 $spam_sql = 'AND a.is_spam = 1';
804 } else {
805 $spam_sql = '';
806 }
807
808 // The mptt BETWEEN clause allows us to limit returned descendants to the right part of the tree
809 $sql = apply_filters( 'bp_activity_comments_user_join_filter', $wpdb->prepare( "SELECT a.*, u.user_email, u.user_nicename, u.user_login, u.display_name{$fullname_select} FROM {$bp->activity->table_name} a, {$wpdb->users} u{$fullname_from} WHERE u.ID = a.user_id {$fullname_where} AND a.type = 'activity_comment' {$spam_sql} AND a.item_id = %d AND a.mptt_left > %d AND a.mptt_left < %d ORDER BY a.date_recorded ASC", $top_level_parent_id, $left, $right ), $activity_id, $left, $right, $spam_sql );
810
811 // Retrieve all descendants of the $root node
812 $descendants = $wpdb->get_results( $sql );
813 $ref = array();
814
815 // Loop descendants and build an assoc array
816 foreach ( (array) $descendants as $d ) {
817 $d->children = array();
818
819 // If we have a reference on the parent
820 if ( isset( $ref[ $d->secondary_item_id ] ) ) {
821 $ref[ $d->secondary_item_id ]->children[ $d->id ] = $d;
822 $ref[ $d->id ] =& $ref[ $d->secondary_item_id ]->children[ $d->id ];
823
824 // If we don't have a reference on the parent, put in the root level
825 } else {
826 $comments[ $d->id ] = $d;
827 $ref[ $d->id ] =& $comments[ $d->id ];
828 }
829 }
830 wp_cache_set( 'bp_activity_comments_' . $activity_id, $comments, 'bp' );
831 }
832
833 return $comments;
834 }
835
836 /**
837 * Rebuild nested comment tree under an activity or activity comment.
838 *
839 * @since BuddyPress (1.2)
840 *
841 * @global BuddyPress $bp The one true BuddyPress instance.
842 * @global wpdb $wpdb WordPress database object.
843 *
844 * @param int $parent_id ID of an activty or activity comment.
845 * @param int $left Node boundary start for activity or activity comment.
846 * @return int Right node boundary of activity or activity comment.
847 */
848 public static function rebuild_activity_comment_tree( $parent_id, $left = 1 ) {
849 global $wpdb, $bp;
850
851 // The right value of this node is the left value + 1
852 $right = $left + 1;
853
854 // Get all descendants of this node
855 $descendants = BP_Activity_Activity::get_child_comments( $parent_id );
856
857 // Loop the descendants and recalculate the left and right values
858 foreach ( (array) $descendants as $descendant )
859 $right = BP_Activity_Activity::rebuild_activity_comment_tree( $descendant->id, $right );
860
861 // We've got the left value, and now that we've processed the children
862 // of this node we also know the right value
863 if ( 1 == $left )
864 $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET mptt_left = %d, mptt_right = %d WHERE id = %d", $left, $right, $parent_id ) );
865 else
866 $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET mptt_left = %d, mptt_right = %d WHERE type = 'activity_comment' AND id = %d", $left, $right, $parent_id ) );
867
868 // Return the right value of this node + 1
869 return $right + 1;
870 }
871
872 /**
873 * Get child comments of an activity or activity comment.
874 *
875 * @since BuddyPress (1.2)
876 *
877 * @global BuddyPress $bp The one true BuddyPress instance.
878 * @global wpdb $wpdb WordPress database object.
879 *
880 * @param int $parent_id ID of an activty or activity comment.
881 * @return object Numerically indexed array of child comments.
882 */
883 public static function get_child_comments( $parent_id ) {
884 global $bp, $wpdb;
885
886 return $wpdb->get_results( $wpdb->prepare( "SELECT id FROM {$bp->activity->table_name} WHERE type = 'activity_comment' AND secondary_item_id = %d", $parent_id ) );
887 }
888
889 /**
890 * Get a list of components that have recorded activity associated with them
891 *
892 * @return array List of component names.
893 */
894 public static function get_recorded_components() {
895 global $wpdb, $bp;
896 return $wpdb->get_col( "SELECT DISTINCT component FROM {$bp->activity->table_name} ORDER BY component ASC" );
897 }
898
899 /**
900 * Get sitewide activity items for use in an RSS feed.
901 *
902 * @param int $limit Optional. Number of items to fetch. Default: 35.
903 * @return array $activity_feed List of activity items, with RSS data added.
904 */
905 public static function get_sitewide_items_for_feed( $limit = 35 ) {
906 $activities = bp_activity_get_sitewide( array( 'max' => $limit ) );
907 $activity_feed = array();
908
909 for ( $i = 0, $count = count( $activities ); $i < $count; ++$i ) {
910 $title = explode( '<span', $activities[$i]['content'] );
911 $activity_feed[$i]['title'] = trim( strip_tags( $title[0] ) );
912 $activity_feed[$i]['link'] = $activities[$i]['primary_link'];
913 $activity_feed[$i]['description'] = @sprintf( $activities[$i]['content'], '' );
914 $activity_feed[$i]['pubdate'] = $activities[$i]['date_recorded'];
915 }
916
917 return $activity_feed;
918 }
919
920 /**
921 * Create SQL IN clause for filter queries.
922 *
923 * @since BuddyPress (1.5)
924 *
925 * @see BP_Activity_Activity::get_filter_sql()
926 *
927 * @param string $field The database field.
928 * @param array|bool $items The values for the IN clause, or false when none are found.
929 */
930 public static function get_in_operator_sql( $field, $items ) {
931 global $wpdb;
932
933 // split items at the comma
934 $items_dirty = explode( ',', $items );
935
936 // array of prepared integers or quoted strings
937 $items_prepared = array();
938
939 // clean up and format each item
940 foreach ( $items_dirty as $item ) {
941 // clean up the string
942 $item = trim( $item );
943 // pass everything through prepare for security and to safely quote strings
944 $items_prepared[] = ( is_numeric( $item ) ) ? $wpdb->prepare( '%d', $item ) : $wpdb->prepare( '%s', $item );
945 }
946
947 // build IN operator sql syntax
948 if ( count( $items_prepared ) )
949 return sprintf( '%s IN ( %s )', trim( $field ), implode( ',', $items_prepared ) );
950 else
951 return false;
952 }
953
954 /**
955 * Create filter SQL clauses.
956 *
957 * @since BuddyPress (1.5)
958 *
959 * @param array $filter_array Fields and values to filter by. Should be
960 * in the format:
961 * $filter_array = array(
962 * 'filter1' => $value,
963 * 'filter2' => $value,
964 * )
965 * Possible filters are as follows. Each can be either a single
966 * string, a comma-separated list, or an array of values.
967 * - 'user_id' User ID(s)
968 * - 'object' Corresponds to the 'component' column in the database.
969 * - 'action' Corresponds to the 'type' column in the database.
970 * - 'primary_id' Corresponds to the 'item_id' column in the database.
971 * - 'secondary_id' Corresponds to the 'secondary_item_id' column in the database.
972 * @return string The filter clause, for use in a SQL query.
973 */
974 public static function get_filter_sql( $filter_array ) {
975
976 $filter_sql = array();
977
978 if ( !empty( $filter_array['user_id'] ) ) {
979 $user_sql = BP_Activity_Activity::get_in_operator_sql( 'a.user_id', $filter_array['user_id'] );
980 if ( !empty( $user_sql ) )
981 $filter_sql[] = $user_sql;
982 }
983
984 if ( !empty( $filter_array['object'] ) ) {
985 $object_sql = BP_Activity_Activity::get_in_operator_sql( 'a.component', $filter_array['object'] );
986 if ( !empty( $object_sql ) )
987 $filter_sql[] = $object_sql;
988 }
989
990 if ( !empty( $filter_array['action'] ) ) {
991 $action_sql = BP_Activity_Activity::get_in_operator_sql( 'a.type', $filter_array['action'] );
992 if ( !empty( $action_sql ) )
993 $filter_sql[] = $action_sql;
994 }
995
996 if ( !empty( $filter_array['primary_id'] ) ) {
997 $pid_sql = BP_Activity_Activity::get_in_operator_sql( 'a.item_id', $filter_array['primary_id'] );
998 if ( !empty( $pid_sql ) )
999 $filter_sql[] = $pid_sql;
1000 }
1001
1002 if ( !empty( $filter_array['secondary_id'] ) ) {
1003 $sid_sql = BP_Activity_Activity::get_in_operator_sql( 'a.secondary_item_id', $filter_array['secondary_id'] );
1004 if ( !empty( $sid_sql ) )
1005 $filter_sql[] = $sid_sql;
1006 }
1007
1008 if ( empty( $filter_sql ) )
1009 return false;
1010
1011 return join( ' AND ', $filter_sql );
1012 }
1013
1014 /**
1015 * Get the date/time of last recorded activity.
1016 *
1017 * @since BuddyPress (1.2)
1018 *
1019 * @return string ISO timestamp.
1020 */
1021 public static function get_last_updated() {
1022 global $bp, $wpdb;
1023
1024 return $wpdb->get_var( "SELECT date_recorded FROM {$bp->activity->table_name} ORDER BY date_recorded DESC LIMIT 1" );
1025 }
1026
1027 /**
1028 * Get favorite count for a given user.
1029 *
1030 * @since BuddyPress (1.2)
1031 *
1032 * @param int The ID of the user whose favorites you're counting.
1033 * @return int A count of the user's favorites.
1034 */
1035 public static function total_favorite_count( $user_id ) {
1036 if ( !$favorite_activity_entries = bp_get_user_meta( $user_id, 'bp_favorite_activities', true ) )
1037 return 0;
1038
1039 return count( maybe_unserialize( $favorite_activity_entries ) );
1040 }
1041
1042 /**
1043 * Check whether an activity item exists with a given string content.
1044 *
1045 * @param string $content The content to filter by.
1046 * @return int|bool The ID of the first matching item if found, otherwise false.
1047 */
1048 public static function check_exists_by_content( $content ) {
1049 global $wpdb, $bp;
1050
1051 return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->activity->table_name} WHERE content = %s", $content ) );
1052 }
1053
1054 /**
1055 * Hide all activity for a given user.
1056 *
1057 * @param int $user_id The ID of the user whose activity you want to mark hidden.
1058 * @param int
1059 */
1060 public static function hide_all_for_user( $user_id ) {
1061 global $wpdb, $bp;
1062
1063 return $wpdb->get_var( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET hide_sitewide = 1 WHERE user_id = %d", $user_id ) );
1064 }
1065}
1066
1067/**
1068 * Create a RSS feed using the activity component.
1069 *
1070 * You should only construct a new feed when you've validated that you're on
1071 * the appropriate screen.
1072 *
1073 * See {@link bp_activity_action_sitewide_feed()} as an example.
1074 *
1075 * Accepted parameters:
1076 * id - internal id for the feed; should be alphanumeric only
1077 * (required)
1078 * title - RSS feed title
1079 * link - Relevant link for the RSS feed
1080 * description - RSS feed description
1081 * ttl - Time-to-live (see inline doc in constructor)
1082 * update_period - Part of the syndication module (see inline doc in
1083 * constructor for more info)
1084 * update_frequency - Part of the syndication module (see inline doc in
1085 * constructor for more info)
1086 * max - Number of feed items to display
1087 * activity_args - Arguments passed to {@link bp_has_activities()}
1088 *
1089 * @since BuddyPress (1.8)
1090 */
1091class BP_Activity_Feed {
1092 /**
1093 * Holds our custom class properties.
1094 *
1095 * These variables are stored in a protected array that is magically
1096 * updated using PHP 5.2+ methods.
1097 *
1098 * @see BP_Feed::__construct() This is where $data is added
1099 * @var array
1100 */
1101 protected $data;
1102
1103 /**
1104 * Magic method for checking the existence of a certain data variable.
1105 *
1106 * @param string $key
1107 */
1108 public function __isset( $key ) { return isset( $this->data[$key] ); }
1109
1110 /**
1111 * Magic method for getting a certain data variable.
1112 *
1113 * @param string $key
1114 */
1115 public function __get( $key ) { return isset( $this->data[$key] ) ? $this->data[$key] : null; }
1116
1117 /**
1118 * Constructor.
1119 *
1120 * @param array $args Optional
1121 */
1122 public function __construct( $args = array() ) {
1123 // If feeds are disabled, stop now!
1124 if ( false === (bool) apply_filters( 'bp_activity_enable_feeds', true ) ) {
1125 global $wp_query;
1126
1127 // set feed flag to false
1128 $wp_query->is_feed = false;
1129
1130 return false;
1131 }
1132
1133 // Setup data
1134 $this->data = wp_parse_args( $args, array(
1135 // Internal identifier for the RSS feed - should be alphanumeric only
1136 'id' => '',
1137
1138 // RSS title - should be plain-text
1139 'title' => '',
1140
1141 // relevant link for the RSS feed
1142 'link' => '',
1143
1144 // RSS description - should be plain-text
1145 'description' => '',
1146
1147 // Time-to-live - number of minutes to cache the data before an aggregator
1148 // requests it again. This is only acknowledged if the RSS client supports it
1149 //
1150 // See: http://www.rssboard.org/rss-profile#element-channel-ttl
1151 // http://www.kbcafe.com/rss/rssfeedstate.html#ttl
1152 'ttl' => '30',
1153
1154 // Syndication module - similar to ttl, but not really supported by RSS
1155 // clients
1156 //
1157 // See: http://web.resource.org/rss/1.0/modules/syndication/#description
1158 // http://www.kbcafe.com/rss/rssfeedstate.html#syndicationmodule
1159 'update_period' => 'hourly',
1160 'update_frequency' => 2,
1161
1162 // Number of items to display
1163 'max' => 50,
1164
1165 // Activity arguments passed to bp_has_activities()
1166 'activity_args' => array()
1167 ) );
1168
1169 // Plugins can use this filter to modify the feed before it is setup
1170 do_action_ref_array( 'bp_activity_feed_prefetch', array( &$this ) );
1171
1172 // Setup class properties
1173 $this->setup_properties();
1174
1175 // Check if id is valid
1176 if ( empty( $this->id ) ) {
1177 _doing_it_wrong( 'BP_Activity_Feed', __( "RSS feed 'id' must be defined", 'buddypress' ), 'BP 1.8' );
1178 return false;
1179 }
1180
1181 // Plugins can use this filter to modify the feed after it's setup
1182 do_action_ref_array( 'bp_activity_feed_postfetch', array( &$this ) );
1183
1184 // Setup feed hooks
1185 $this->setup_hooks();
1186
1187 // Output the feed
1188 $this->output();
1189
1190 // Kill the rest of the output
1191 die();
1192 }
1193
1194 /** SETUP ****************************************************************/
1195
1196 /**
1197 * Setup and validate the class properties.
1198 *
1199 * @access protected
1200 */
1201 protected function setup_properties() {
1202 $this->id = sanitize_title( $this->id );
1203 $this->title = strip_tags( $this->title );
1204 $this->link = esc_url_raw( $this->link );
1205 $this->description = strip_tags( $this->description );
1206 $this->ttl = (int) $this->ttl;
1207 $this->update_period = strip_tags( $this->update_period );
1208 $this->update_frequency = (int) $this->update_frequency;
1209
1210 $this->activity_args = wp_parse_args( $this->activity_args, array(
1211 'max' => $this->max,
1212 'per_page' => $this->max,
1213 'display_comments' => 'stream'
1214 ) );
1215
1216 }
1217
1218 /**
1219 * Setup some hooks that are used in the feed.
1220 *
1221 * Currently, these hooks are used to maintain backwards compatibility with
1222 * the RSS feeds previous to BP 1.8.
1223 *
1224 * @access protected
1225 */
1226 protected function setup_hooks() {
1227 add_action( 'bp_activity_feed_rss_attributes', array( $this, 'backpat_rss_attributes' ) );
1228 add_action( 'bp_activity_feed_channel_elements', array( $this, 'backpat_channel_elements' ) );
1229 add_action( 'bp_activity_feed_item_elements', array( $this, 'backpat_item_elements' ) );
1230 }
1231
1232 /** BACKPAT HOOKS ********************************************************/
1233
1234 /**
1235 * Fire a hook to ensure backward compatibility for RSS attributes.
1236 */
1237 public function backpat_rss_attributes() {
1238 do_action( 'bp_activity_' . $this->id . '_feed' );
1239 }
1240
1241 /**
1242 * Fire a hook to ensure backward compatibility for channel elements.
1243 */
1244 public function backpat_channel_elements() {
1245 do_action( 'bp_activity_' . $this->id . '_feed_head' );
1246 }
1247
1248 /**
1249 * Fire a hook to ensure backward compatibility for item elements.
1250 */
1251 public function backpat_item_elements() {
1252 switch ( $this->id ) {
1253
1254 // sitewide and friends feeds use the 'personal' hook
1255 case 'sitewide' :
1256 case 'friends' :
1257 $id = 'personal';
1258
1259 break;
1260
1261 default :
1262 $id = $this->id;
1263
1264 break;
1265 }
1266
1267 do_action( 'bp_activity_' . $id . '_feed_item' );
1268 }
1269
1270 /** HELPERS **************************************************************/
1271
1272 /**
1273 * Output the feed's item content.
1274 *
1275 * @access protected
1276 */
1277 protected function feed_content() {
1278 bp_activity_content_body();
1279
1280 switch ( $this->id ) {
1281
1282 // also output parent activity item if we're on a specific feed
1283 case 'favorites' :
1284 case 'friends' :
1285 case 'mentions' :
1286 case 'personal' :
1287
1288 if ( 'activity_comment' == bp_get_activity_action_name() ) :
1289 ?>
1290 <strong><?php _e( 'In reply to', 'buddypress' ) ?></strong> -
1291 <?php bp_activity_parent_content() ?>
1292 <?php
1293 endif;
1294
1295 break;
1296 }
1297 }
1298
1299 /**
1300 * Sets various HTTP headers related to Content-Type and browser caching.
1301 *
1302 * Most of this class method is derived from {@link WP::send_headers()}.
1303 *
1304 * @since BuddyPress (1.9.0)
1305 *
1306 * @access protected
1307 */
1308 protected function http_headers() {
1309 // set up some additional headers if not on a directory page
1310 // this is done b/c BP uses pseudo-pages
1311 if ( ! bp_is_directory() ) {
1312 global $wp_query;
1313
1314 $wp_query->is_404 = false;
1315 status_header( 200 );
1316 }
1317
1318 // Set content-type
1319 @header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true );
1320
1321 // Cache-related variables
1322 $last_modified = mysql2date( 'D, d M Y H:i:s O', bp_activity_get_last_updated(), false );
1323 $modified_timestamp = strtotime( $last_modified );
1324 $etag = md5( $last_modified );
1325
1326 // Set cache-related headers
1327 @header( 'Last-Modified: ' . $last_modified );
1328 @header( 'Pragma: no-cache' );
1329 @header( 'ETag: ' . '"' . $etag . '"' );
1330
1331 // First commit of BuddyPress! (Easter egg)
1332 @header( 'Expires: Tue, 25 Mar 2008 17:13:55 GMT');
1333
1334 // Get ETag from supported user agents
1335 if ( isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ) {
1336 $client_etag = wp_unslash( $_SERVER['HTTP_IF_NONE_MATCH'] );
1337
1338 // Remove quotes from ETag
1339 $client_etag = trim( $client_etag, '"' );
1340
1341 // Strip suffixes from ETag if they exist (eg. "-gzip")
1342 if ( $etag_suffix_pos = strpos( $client_etag, '-' ) ) {
1343 $client_etag = substr( $client_etag, 0, $etag_suffix_pos );
1344 }
1345
1346 // No ETag found
1347 } else {
1348 $client_etag = false;
1349 }
1350
1351 // Get client last modified timestamp from supported user agents
1352 $client_last_modified = empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ? '' : trim( $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
1353 $client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0;
1354
1355 // Set 304 status if feed hasn't been updated since last fetch
1356 if ( ( $client_last_modified && $client_etag ) ?
1357 ( ( $client_modified_timestamp >= $modified_timestamp ) && ( $client_etag == $etag ) ) :
1358 ( ( $client_modified_timestamp >= $modified_timestamp ) || ( $client_etag == $etag ) ) ) {
1359 $status = 304;
1360 } else {
1361 $status = false;
1362 }
1363
1364 // If feed hasn't changed as reported by the user agent, set 304 status header
1365 if ( ! empty( $status ) ) {
1366 status_header( $status );
1367
1368 // cached response, so stop now!
1369 if ( $status == 304 ) {
1370 exit();
1371 }
1372 }
1373 }
1374
1375 /** OUTPUT ***************************************************************/
1376
1377 /**
1378 * Output the RSS feed.
1379 *
1380 * @access protected
1381 */
1382 protected function output() {
1383 $this->http_headers();
1384 echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?'.'>';
1385 ?>
1386
1387<rss version="2.0"
1388 xmlns:content="http://purl.org/rss/1.0/modules/content/"
1389 xmlns:atom="http://www.w3.org/2005/Atom"
1390 xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
1391 xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
1392 <?php do_action( 'bp_activity_feed_rss_attributes' ); ?>
1393>
1394
1395<channel>
1396 <title><?php echo $this->title; ?></title>
1397 <link><?php echo $this->link; ?></link>
1398 <atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
1399 <description><?php echo $this->description ?></description>
1400 <lastBuildDate><?php echo mysql2date( 'D, d M Y H:i:s O', bp_activity_get_last_updated(), false ); ?></lastBuildDate>
1401 <generator>http://buddypress.org/?v=<?php bp_version(); ?></generator>
1402 <language><?php bloginfo_rss( 'language' ); ?></language>
1403 <ttl><?php echo $this->ttl; ?></ttl>
1404 <sy:updatePeriod><?php echo $this->update_period; ?></sy:updatePeriod>
1405 <sy:updateFrequency><?php echo $this->update_frequency; ?></sy:updateFrequency>
1406 <?php do_action( 'bp_activity_feed_channel_elements' ); ?>
1407
1408 <?php if ( bp_has_activities( $this->activity_args ) ) : ?>
1409 <?php while ( bp_activities() ) : bp_the_activity(); ?>
1410 <item>
1411 <guid isPermaLink="false"><?php bp_activity_feed_item_guid(); ?></guid>
1412 <title><?php echo stripslashes( bp_get_activity_feed_item_title() ); ?></title>
1413 <link><?php bp_activity_thread_permalink() ?></link>
1414 <pubDate><?php echo mysql2date( 'D, d M Y H:i:s O', bp_get_activity_feed_item_date(), false ); ?></pubDate>
1415
1416 <?php if ( bp_get_activity_feed_item_description() ) : ?>
1417 <content:encoded><![CDATA[<?php $this->feed_content(); ?>]]></content:encoded>
1418 <?php endif; ?>
1419
1420 <?php if ( bp_activity_can_comment() ) : ?>
1421 <slash:comments><?php bp_activity_comment_count(); ?></slash:comments>
1422 <?php endif; ?>
1423
1424 <?php do_action( 'bp_activity_feed_item_elements' ); ?>
1425 </item>
1426 <?php endwhile; ?>
1427
1428 <?php endif; ?>
1429</channel>
1430</rss><?php
1431 }
1432}