[ Index ]

PHP Cross Reference of BuddyPress

title

Body

[close]

/src/bp-activity/classes/ -> class-bp-activity-activity.php (source)

   1  <?php
   2  /**
   3   * BuddyPress Activity Classes
   4   *
   5   * @package BuddyPress
   6   * @subpackage Activity
   7   * @since 1.0.0
   8   */
   9  
  10  // Exit if accessed directly.
  11  defined( 'ABSPATH' ) || exit;
  12  
  13  /**
  14   * Database interaction class for the BuddyPress activity component.
  15   * Instance methods are available for creating/editing an activity,
  16   * static methods for querying activities.
  17   *
  18   * @since 1.0.0
  19   */
  20  class BP_Activity_Activity {
  21  
  22      /** Properties ************************************************************/
  23  
  24      /**
  25       * ID of the activity item.
  26       *
  27       * @since 1.0.0
  28       * @var int
  29       */
  30      var $id;
  31  
  32      /**
  33       * ID of the associated item.
  34       *
  35       * @since 1.0.0
  36       * @var int
  37       */
  38      var $item_id;
  39  
  40      /**
  41       * ID of the associated secondary item.
  42       *
  43       * @since 1.0.0
  44       * @var int
  45       */
  46      var $secondary_item_id;
  47  
  48      /**
  49       * ID of user associated with the activity item.
  50       *
  51       * @since 1.0.0
  52       * @var int
  53       */
  54      var $user_id;
  55  
  56      /**
  57       * The primary URL for the activity in RSS feeds.
  58       *
  59       * @since 1.0.0
  60       * @var string
  61       */
  62      var $primary_link;
  63  
  64      /**
  65       * BuddyPress component the activity item relates to.
  66       *
  67       * @since 1.2.0
  68       * @var string
  69       */
  70      var $component;
  71  
  72      /**
  73       * Activity type, eg 'new_blog_post'.
  74       *
  75       * @since 1.2.0
  76       * @var string
  77       */
  78      var $type;
  79  
  80      /**
  81       * Description of the activity, eg 'Alex updated his profile.'.
  82       *
  83       * @since 1.2.0
  84       * @var string
  85       */
  86      var $action;
  87  
  88      /**
  89       * The content of the activity item.
  90       *
  91       * @since 1.2.0
  92       * @var string
  93       */
  94      var $content;
  95  
  96      /**
  97       * The date the activity item was recorded, in 'Y-m-d h:i:s' format.
  98       *
  99       * @since 1.0.0
 100       * @var string
 101       */
 102      var $date_recorded;
 103  
 104      /**
 105       * Whether the item should be hidden in sitewide streams.
 106       *
 107       * @since 1.1.0
 108       * @var int
 109       */
 110      var $hide_sitewide = 0;
 111  
 112      /**
 113       * Node boundary start for activity or activity comment.
 114       *
 115       * @since 1.5.0
 116       * @var int
 117       */
 118      var $mptt_left;
 119  
 120      /**
 121       * Node boundary end for activity or activity comment.
 122       *
 123       * @since 1.5.0
 124       * @var int
 125       */
 126      var $mptt_right;
 127  
 128      /**
 129       * Whether this item is marked as spam.
 130       *
 131       * @since 1.6.0
 132       * @var int
 133       */
 134      var $is_spam;
 135  
 136      /**
 137       * Error holder.
 138       *
 139       * @since 2.6.0
 140       *
 141       * @var WP_Error
 142       */
 143      public $errors;
 144  
 145      /**
 146       * Error type to return. Either 'bool' or 'wp_error'.
 147       *
 148       * @since 2.6.0
 149       *
 150       * @var string
 151       */
 152      public $error_type = 'bool';
 153  
 154      /**
 155       * Constructor method.
 156       *
 157       * @since 1.5.0
 158       *
 159       * @param int|bool $id Optional. The ID of a specific activity item.
 160       */
 161  	public function __construct( $id = false ) {
 162          // Instantiate errors object.
 163          $this->errors = new WP_Error;
 164  
 165          if ( !empty( $id ) ) {
 166              $this->id = (int) $id;
 167              $this->populate();
 168          }
 169      }
 170  
 171      /**
 172       * Populate the object with data about the specific activity item.
 173       *
 174       * @since 1.0.0
 175       */
 176  	public function populate() {
 177          global $wpdb;
 178  
 179          $row = wp_cache_get( $this->id, 'bp_activity' );
 180  
 181          if ( false === $row ) {
 182              $bp  = buddypress();
 183              $row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->activity->table_name} WHERE id = %d", $this->id ) );
 184  
 185              wp_cache_set( $this->id, $row, 'bp_activity' );
 186          }
 187  
 188          if ( empty( $row ) ) {
 189              $this->id = 0;
 190              return;
 191          }
 192  
 193          $this->id                = (int) $row->id;
 194          $this->item_id           = (int) $row->item_id;
 195          $this->secondary_item_id = (int) $row->secondary_item_id;
 196          $this->user_id           = (int) $row->user_id;
 197          $this->primary_link      = $row->primary_link;
 198          $this->component         = $row->component;
 199          $this->type              = $row->type;
 200          $this->action            = $row->action;
 201          $this->content           = $row->content;
 202          $this->date_recorded     = $row->date_recorded;
 203          $this->hide_sitewide     = (int) $row->hide_sitewide;
 204          $this->mptt_left         = (int) $row->mptt_left;
 205          $this->mptt_right        = (int) $row->mptt_right;
 206          $this->is_spam           = (int) $row->is_spam;
 207  
 208          // Generate dynamic 'action' when possible.
 209          $action = bp_activity_generate_action_string( $this );
 210          if ( false !== $action ) {
 211              $this->action = $action;
 212  
 213              // If no callback is available, use the literal string from
 214              // the database row.
 215          } elseif ( ! empty( $row->action ) ) {
 216              $this->action = $row->action;
 217  
 218              // Provide a fallback to avoid PHP notices.
 219          } else {
 220              $this->action = '';
 221          }
 222      }
 223  
 224      /**
 225       * Save the activity item to the database.
 226       *
 227       * @since 1.0.0
 228       *
 229       * @return WP_Error|bool True on success.
 230       */
 231  	public function save() {
 232          global $wpdb;
 233  
 234          $bp = buddypress();
 235  
 236          $this->id                = apply_filters_ref_array( 'bp_activity_id_before_save',                array( $this->id,                &$this ) );
 237          $this->item_id           = apply_filters_ref_array( 'bp_activity_item_id_before_save',           array( $this->item_id,           &$this ) );
 238          $this->secondary_item_id = apply_filters_ref_array( 'bp_activity_secondary_item_id_before_save', array( $this->secondary_item_id, &$this ) );
 239          $this->user_id           = apply_filters_ref_array( 'bp_activity_user_id_before_save',           array( $this->user_id,           &$this ) );
 240          $this->primary_link      = apply_filters_ref_array( 'bp_activity_primary_link_before_save',      array( $this->primary_link,      &$this ) );
 241          $this->component         = apply_filters_ref_array( 'bp_activity_component_before_save',         array( $this->component,         &$this ) );
 242          $this->type              = apply_filters_ref_array( 'bp_activity_type_before_save',              array( $this->type,              &$this ) );
 243          $this->action            = apply_filters_ref_array( 'bp_activity_action_before_save',            array( $this->action,            &$this ) );
 244          $this->content           = apply_filters_ref_array( 'bp_activity_content_before_save',           array( $this->content,           &$this ) );
 245          $this->date_recorded     = apply_filters_ref_array( 'bp_activity_date_recorded_before_save',     array( $this->date_recorded,     &$this ) );
 246          $this->hide_sitewide     = apply_filters_ref_array( 'bp_activity_hide_sitewide_before_save',     array( $this->hide_sitewide,     &$this ) );
 247          $this->mptt_left         = apply_filters_ref_array( 'bp_activity_mptt_left_before_save',         array( $this->mptt_left,         &$this ) );
 248          $this->mptt_right        = apply_filters_ref_array( 'bp_activity_mptt_right_before_save',        array( $this->mptt_right,        &$this ) );
 249          $this->is_spam           = apply_filters_ref_array( 'bp_activity_is_spam_before_save',           array( $this->is_spam,           &$this ) );
 250  
 251          /**
 252           * Fires before the current activity item gets saved.
 253           *
 254           * Please use this hook to filter the properties above. Each part will be passed in.
 255           *
 256           * @since 1.0.0
 257           *
 258           * @param BP_Activity_Activity $this Current instance of the activity item being saved. Passed by reference.
 259           */
 260          do_action_ref_array( 'bp_activity_before_save', array( &$this ) );
 261  
 262          if ( 'wp_error' === $this->error_type && $this->errors->get_error_code() ) {
 263              return $this->errors;
 264          }
 265  
 266          if ( empty( $this->component ) || empty( $this->type ) ) {
 267              if ( 'bool' === $this->error_type ) {
 268                  return false;
 269              } else {
 270                  if ( empty( $this->component ) ) {
 271                      $this->errors->add( 'bp_activity_missing_component' );
 272                  } else {
 273                      $this->errors->add( 'bp_activity_missing_type' );
 274                  }
 275  
 276                  return $this->errors;
 277              }
 278          }
 279  
 280          if ( empty( $this->primary_link ) ) {
 281              $this->primary_link = bp_loggedin_user_domain();
 282          }
 283  
 284          // If we have an existing ID, update the activity item, otherwise insert it.
 285          if ( ! empty( $this->id ) ) {
 286              $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 );
 287          } else {
 288              $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 );
 289          }
 290  
 291          if ( false === $wpdb->query( $q ) ) {
 292              return false;
 293          }
 294  
 295          // If this is a new activity item, set the $id property.
 296          if ( empty( $this->id ) ) {
 297              $this->id = $wpdb->insert_id;
 298  
 299              // If an existing activity item, prevent any changes to the content generating new @mention notifications.
 300          } else {
 301              add_filter( 'bp_activity_at_name_do_notifications', '__return_false' );
 302          }
 303  
 304          /**
 305           * Fires after an activity item has been saved to the database.
 306           *
 307           * @since 1.0.0
 308           *
 309           * @param BP_Activity_Activity $this Current instance of activity item being saved. Passed by reference.
 310           */
 311          do_action_ref_array( 'bp_activity_after_save', array( &$this ) );
 312  
 313          return true;
 314      }
 315  
 316      /** Static Methods ***************************************************/
 317  
 318      /**
 319       * Get activity items, as specified by parameters.
 320       *
 321       * @since 1.2.0
 322       * @since 2.4.0 Introduced the `$fields` parameter.
 323       * @since 2.9.0 Introduced the `$order_by` parameter.
 324       *
 325       * @see BP_Activity_Activity::get_filter_sql() for a description of the
 326       *      'filter' parameter.
 327       * @see WP_Meta_Query::queries for a description of the 'meta_query'
 328       *      parameter format.
 329       *
 330       * @param array $args {
 331       *     An array of arguments. All items are optional.
 332       *     @type int          $page              Which page of results to fetch. Using page=1 without per_page will result
 333       *                                           in no pagination. Default: 1.
 334       *     @type int|bool     $per_page          Number of results per page. Default: 25.
 335       *     @type int|bool     $max               Maximum number of results to return. Default: false (unlimited).
 336       *     @type string       $fields            Activity fields to return. Pass 'ids' to get only the activity IDs.
 337       *                                           'all' returns full activity objects.
 338       *     @type string       $sort              ASC or DESC. Default: 'DESC'.
 339       *     @type string       $order_by          Column to order results by.
 340       *     @type array        $exclude           Array of activity IDs to exclude. Default: false.
 341       *     @type array        $in                Array of ids to limit query by (IN). Default: false.
 342       *     @type array        $meta_query        Array of meta_query conditions. See WP_Meta_Query::queries.
 343       *     @type array        $date_query        Array of date_query conditions. See first parameter of
 344       *                                           WP_Date_Query::__construct().
 345       *     @type array        $filter_query      Array of advanced query conditions. See BP_Activity_Query::__construct().
 346       *     @type string|array $scope             Pre-determined set of activity arguments.
 347       *     @type array        $filter            See BP_Activity_Activity::get_filter_sql().
 348       *     @type string       $search_terms      Limit results by a search term. Default: false.
 349       *     @type bool         $display_comments  Whether to include activity comments. Default: false.
 350       *     @type bool         $show_hidden       Whether to show items marked hide_sitewide. Default: false.
 351       *     @type string       $spam              Spam status. Default: 'ham_only'.
 352       *     @type bool         $update_meta_cache Whether to pre-fetch metadata for queried activity items. Default: true.
 353       *     @type string|bool  $count_total       If true, an additional DB query is run to count the total activity items
 354       *                                           for the query. Default: false.
 355       * }
 356       * @return array The array returned has two keys:
 357       *               - 'total' is the count of located activities
 358       *               - 'activities' is an array of the located activities
 359       */
 360  	public static function get( $args = array() ) {
 361          global $wpdb;
 362  
 363          // Backward compatibility with old method of passing arguments.
 364          if ( !is_array( $args ) || func_num_args() > 1 ) {
 365              _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__ ) );
 366  
 367              $old_args_keys = array(
 368                  0 => 'max',
 369                  1 => 'page',
 370                  2 => 'per_page',
 371                  3 => 'sort',
 372                  4 => 'search_terms',
 373                  5 => 'filter',
 374                  6 => 'display_comments',
 375                  7 => 'show_hidden',
 376                  8 => 'exclude',
 377                  9 => 'in',
 378                  10 => 'spam'
 379              );
 380  
 381              $args = bp_core_parse_args_array( $old_args_keys, func_get_args() );
 382          }
 383  
 384          $bp = buddypress();
 385          $r  = wp_parse_args( $args, array(
 386              'page'              => 1,               // The current page.
 387              'per_page'          => 25,              // Activity items per page.
 388              'max'               => false,           // Max number of items to return.
 389              'fields'            => 'all',           // Fields to include.
 390              'sort'              => 'DESC',          // ASC or DESC.
 391              'order_by'          => 'date_recorded', // Column to order by.
 392              'exclude'           => false,           // Array of ids to exclude.
 393              'in'                => false,           // Array of ids to limit query by (IN).
 394              'meta_query'        => false,           // Filter by activitymeta.
 395              'date_query'        => false,           // Filter by date.
 396              'filter_query'      => false,           // Advanced filtering - see BP_Activity_Query.
 397              'filter'            => false,           // See self::get_filter_sql().
 398              'scope'             => false,           // Preset activity arguments.
 399              'search_terms'      => false,           // Terms to search by.
 400              'display_comments'  => false,           // Whether to include activity comments.
 401              'show_hidden'       => false,           // Show items marked hide_sitewide.
 402              'spam'              => 'ham_only',      // Spam status.
 403              'update_meta_cache' => true,            // Whether or not to update meta cache.
 404              'count_total'       => false,           // Whether or not to use count_total.
 405          ) );
 406  
 407          // Select conditions.
 408          $select_sql = "SELECT DISTINCT a.id";
 409  
 410          $from_sql   = " FROM {$bp->activity->table_name} a";
 411  
 412          $join_sql   = '';
 413  
 414          // Where conditions.
 415          $where_conditions = array();
 416  
 417          // Excluded types.
 418          $excluded_types = array();
 419  
 420          // Scope takes precedence.
 421          if ( ! empty( $r['scope'] ) ) {
 422              $scope_query = self::get_scope_query_sql( $r['scope'], $r );
 423  
 424              // Add our SQL conditions if matches were found.
 425              if ( ! empty( $scope_query['sql'] ) ) {
 426                  $where_conditions['scope_query_sql'] = $scope_query['sql'];
 427              }
 428  
 429              // Override some arguments if needed.
 430              if ( ! empty( $scope_query['override'] ) ) {
 431                  $r = array_replace_recursive( $r, $scope_query['override'] );
 432              }
 433  
 434              // Advanced filtering.
 435          } elseif ( ! empty( $r['filter_query'] ) ) {
 436              $filter_query = new BP_Activity_Query( $r['filter_query'] );
 437              $sql          = $filter_query->get_sql();
 438              if ( ! empty( $sql ) ) {
 439                  $where_conditions['filter_query_sql'] = $sql;
 440              }
 441          }
 442  
 443          // Regular filtering.
 444          if ( $r['filter'] && $filter_sql = BP_Activity_Activity::get_filter_sql( $r['filter'] ) ) {
 445              $where_conditions['filter_sql'] = $filter_sql;
 446          }
 447  
 448          // Spam.
 449          if ( 'ham_only' == $r['spam'] ) {
 450              $where_conditions['spam_sql'] = 'a.is_spam = 0';
 451          } elseif ( 'spam_only' == $r['spam'] ) {
 452              $where_conditions['spam_sql'] = 'a.is_spam = 1';
 453          }
 454  
 455          // Searching.
 456          if ( $r['search_terms'] ) {
 457              $search_terms_like = '%' . bp_esc_like( $r['search_terms'] ) . '%';
 458              $where_conditions['search_sql'] = $wpdb->prepare( 'a.content LIKE %s', $search_terms_like );
 459  
 460              /**
 461               * Filters whether or not to include users for search parameters.
 462               *
 463               * @since 3.0.0
 464               *
 465               * @param bool $value Whether or not to include user search. Default false.
 466               */
 467              if ( apply_filters( 'bp_activity_get_include_user_search', false ) ) {
 468                  $user_search = get_user_by( 'slug', $r['search_terms'] );
 469                  if ( false !== $user_search ) {
 470                      $user_id                         = $user_search->ID;
 471                      $where_conditions['search_sql'] .= $wpdb->prepare( ' OR a.user_id = %d', $user_id );
 472                  }
 473              }
 474          }
 475  
 476          // Sorting.
 477          $sort = $r['sort'];
 478          if ( $sort != 'ASC' && $sort != 'DESC' ) {
 479              $sort = 'DESC';
 480          }
 481  
 482          switch( $r['order_by'] ) {
 483              case 'id' :
 484              case 'user_id' :
 485              case 'component' :
 486              case 'type' :
 487              case 'action' :
 488              case 'content' :
 489              case 'primary_link' :
 490              case 'item_id' :
 491              case 'secondary_item_id' :
 492              case 'date_recorded' :
 493              case 'hide_sitewide' :
 494              case 'mptt_left' :
 495              case 'mptt_right' :
 496              case 'is_spam' :
 497                  break;
 498  
 499              default :
 500                  $r['order_by'] = 'date_recorded';
 501                  break;
 502          }
 503          $order_by = 'a.' . $r['order_by'];
 504  
 505          // Hide Hidden Items?
 506          if ( ! $r['show_hidden'] ) {
 507              $where_conditions['hidden_sql'] = "a.hide_sitewide = 0";
 508          }
 509  
 510          // Exclude specified items.
 511          if ( ! empty( $r['exclude'] ) ) {
 512              $exclude = implode( ',', wp_parse_id_list( $r['exclude'] ) );
 513              $where_conditions['exclude'] = "a.id NOT IN ({$exclude})";
 514          }
 515  
 516          // The specific ids to which you want to limit the query.
 517          if ( ! empty( $r['in'] ) ) {
 518              $in = implode( ',', wp_parse_id_list( $r['in'] ) );
 519              $where_conditions['in'] = "a.id IN ({$in})";
 520          }
 521  
 522          // Process meta_query into SQL.
 523          $meta_query_sql = self::get_meta_query_sql( $r['meta_query'] );
 524  
 525          if ( ! empty( $meta_query_sql['join'] ) ) {
 526              $join_sql .= $meta_query_sql['join'];
 527          }
 528  
 529          if ( ! empty( $meta_query_sql['where'] ) ) {
 530              $where_conditions[] = $meta_query_sql['where'];
 531          }
 532  
 533          // Process date_query into SQL.
 534          $date_query_sql = self::get_date_query_sql( $r['date_query'] );
 535  
 536          if ( ! empty( $date_query_sql ) ) {
 537              $where_conditions['date'] = $date_query_sql;
 538          }
 539  
 540          // Alter the query based on whether we want to show activity item
 541          // comments in the stream like normal comments or threaded below
 542          // the activity.
 543          if ( false === $r['display_comments'] || 'threaded' === $r['display_comments'] ) {
 544              $excluded_types[] = 'activity_comment';
 545          }
 546  
 547          // Exclude 'last_activity' items unless the 'action' filter has
 548          // been explicitly set.
 549          if ( empty( $r['filter']['object'] ) ) {
 550              $excluded_types[] = 'last_activity';
 551          }
 552  
 553          // Build the excluded type sql part.
 554          if ( ! empty( $excluded_types ) ) {
 555              $not_in = "'" . implode( "', '", esc_sql( $excluded_types ) ) . "'";
 556              $where_conditions['excluded_types'] = "a.type NOT IN ({$not_in})";
 557          }
 558  
 559          /**
 560           * Filters the MySQL WHERE conditions for the Activity items get method.
 561           *
 562           * @since 1.9.0
 563           *
 564           * @param array  $where_conditions Current conditions for MySQL WHERE statement.
 565           * @param array  $r                Parsed arguments passed into method.
 566           * @param string $select_sql       Current SELECT MySQL statement at point of execution.
 567           * @param string $from_sql         Current FROM MySQL statement at point of execution.
 568           * @param string $join_sql         Current INNER JOIN MySQL statement at point of execution.
 569           */
 570          $where_conditions = apply_filters( 'bp_activity_get_where_conditions', $where_conditions, $r, $select_sql, $from_sql, $join_sql );
 571  
 572          // Join the where conditions together.
 573          $where_sql = 'WHERE ' . join( ' AND ', $where_conditions );
 574  
 575          /**
 576           * Filter the MySQL JOIN clause for the main activity query.
 577           *
 578           * @since 2.5.0
 579           *
 580           * @param string $join_sql   JOIN clause.
 581           * @param array  $r          Method parameters.
 582           * @param string $select_sql Current SELECT MySQL statement.
 583           * @param string $from_sql   Current FROM MySQL statement.
 584           * @param string $where_sql  Current WHERE MySQL statement.
 585           */
 586          $join_sql = apply_filters( 'bp_activity_get_join_sql', $join_sql, $r, $select_sql, $from_sql, $where_sql );
 587  
 588          // Sanitize page and per_page parameters.
 589          $page     = absint( $r['page']     );
 590          $per_page = absint( $r['per_page'] );
 591  
 592          $retval = array(
 593              'activities'     => null,
 594              'total'          => null,
 595              'has_more_items' => null,
 596          );
 597  
 598          /**
 599           * Filters if BuddyPress should use legacy query structure over current structure for version 2.0+.
 600           *
 601           * It is not recommended to use the legacy structure, but allowed to if needed.
 602           *
 603           * @since 2.0.0
 604           *
 605           * @param bool                 $value Whether to use legacy structure or not.
 606           * @param BP_Activity_Activity $value Current method being called.
 607           * @param array                $r     Parsed arguments passed into method.
 608           */
 609          if ( apply_filters( 'bp_use_legacy_activity_query', false, __METHOD__, $r ) ) {
 610  
 611              // Legacy queries joined against the user table.
 612              $select_sql = "SELECT DISTINCT a.*, u.user_email, u.user_nicename, u.user_login, u.display_name";
 613              $from_sql   = " FROM {$bp->activity->table_name} a LEFT JOIN {$wpdb->users} u ON a.user_id = u.ID";
 614  
 615              if ( ! empty( $page ) && ! empty( $per_page ) ) {
 616                  $pag_sql = $wpdb->prepare( "LIMIT %d, %d", absint( ( $page - 1 ) * $per_page ), $per_page );
 617  
 618                  /** This filter is documented in bp-activity/bp-activity-classes.php */
 619                  $activity_sql = apply_filters( 'bp_activity_get_user_join_filter', "{$select_sql} {$from_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort}, a.id {$sort} {$pag_sql}", $select_sql, $from_sql, $where_sql, $sort, $pag_sql );
 620              } else {
 621                  $pag_sql = '';
 622  
 623                  /**
 624                   * Filters the legacy MySQL query statement so plugins can alter before results are fetched.
 625                   *
 626                   * @since 1.5.0
 627                   *
 628                   * @param string $value      Concatenated MySQL statement pieces to be query results with for legacy query.
 629                   * @param string $select_sql Final SELECT MySQL statement portion for legacy query.
 630                   * @param string $from_sql   Final FROM MySQL statement portion for legacy query.
 631                   * @param string $where_sql  Final WHERE MySQL statement portion for legacy query.
 632                   * @param string $sort       Final sort direction for legacy query.
 633                   */
 634                  $activity_sql = apply_filters( 'bp_activity_get_user_join_filter', "{$select_sql} {$from_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort}, a.id {$sort}", $select_sql, $from_sql, $where_sql, $sort, $pag_sql );
 635              }
 636  
 637              /*
 638               * Queries that include 'last_activity' are cached separately,
 639               * since they are generally much less long-lived.
 640               */
 641              if ( preg_match( '/a\.type NOT IN \([^\)]*\'last_activity\'[^\)]*\)/', $activity_sql ) ) {
 642                  $cache_group = 'bp_activity';
 643              } else {
 644                  $cache_group = 'bp_activity_with_last_activity';
 645              }
 646  
 647              $activities = $wpdb->get_results( $activity_sql );
 648  
 649              // Integer casting for legacy activity query.
 650              foreach ( (array) $activities as $i => $ac ) {
 651                  $activities[ $i ]->id                = (int) $ac->id;
 652                  $activities[ $i ]->item_id           = (int) $ac->item_id;
 653                  $activities[ $i ]->secondary_item_id = (int) $ac->secondary_item_id;
 654                  $activities[ $i ]->user_id           = (int) $ac->user_id;
 655                  $activities[ $i ]->hide_sitewide     = (int) $ac->hide_sitewide;
 656                  $activities[ $i ]->mptt_left         = (int) $ac->mptt_left;
 657                  $activities[ $i ]->mptt_right        = (int) $ac->mptt_right;
 658                  $activities[ $i ]->is_spam           = (int) $ac->is_spam;
 659              }
 660  
 661          } else {
 662              // Query first for activity IDs.
 663              $activity_ids_sql = "{$select_sql} {$from_sql} {$join_sql} {$where_sql} ORDER BY {$order_by} {$sort}, a.id {$sort}";
 664  
 665              if ( ! empty( $per_page ) && ! empty( $page ) ) {
 666                  // We query for $per_page + 1 items in order to
 667                  // populate the has_more_items flag.
 668                  $activity_ids_sql .= $wpdb->prepare( " LIMIT %d, %d", absint( ( $page - 1 ) * $per_page ), $per_page + 1 );
 669              }
 670  
 671              /**
 672               * Filters the paged activities MySQL statement.
 673               *
 674               * @since 2.0.0
 675               *
 676               * @param string $activity_ids_sql MySQL statement used to query for Activity IDs.
 677               * @param array  $r                Array of arguments passed into method.
 678               */
 679              $activity_ids_sql = apply_filters( 'bp_activity_paged_activities_sql', $activity_ids_sql, $r );
 680  
 681              /*
 682               * Queries that include 'last_activity' are cached separately,
 683               * since they are generally much less long-lived.
 684               */
 685              if ( preg_match( '/a\.type NOT IN \([^\)]*\'last_activity\'[^\)]*\)/', $activity_ids_sql ) ) {
 686                  $cache_group = 'bp_activity';
 687              } else {
 688                  $cache_group = 'bp_activity_with_last_activity';
 689              }
 690  
 691              $cached = bp_core_get_incremented_cache( $activity_ids_sql, $cache_group );
 692              if ( false === $cached ) {
 693                  $activity_ids = $wpdb->get_col( $activity_ids_sql );
 694                  bp_core_set_incremented_cache( $activity_ids_sql, $cache_group, $activity_ids );
 695              } else {
 696                  $activity_ids = $cached;
 697              }
 698  
 699              $retval['has_more_items'] = ! empty( $per_page ) && count( $activity_ids ) > $per_page;
 700  
 701              // If we've fetched more than the $per_page value, we
 702              // can discard the extra now.
 703              if ( ! empty( $per_page ) && count( $activity_ids ) === $per_page + 1 ) {
 704                  array_pop( $activity_ids );
 705              }
 706  
 707              if ( 'ids' === $r['fields'] ) {
 708                  $activities = array_map( 'intval', $activity_ids );
 709              } else {
 710                  $activities = self::get_activity_data( $activity_ids );
 711              }
 712          }
 713  
 714          if ( 'ids' !== $r['fields'] ) {
 715              // Get the fullnames of users so we don't have to query in the loop.
 716              $activities = self::append_user_fullnames( $activities );
 717  
 718              // Get activity meta.
 719              $activity_ids = array();
 720              foreach ( (array) $activities as $activity ) {
 721                  $activity_ids[] = $activity->id;
 722              }
 723  
 724              if ( ! empty( $activity_ids ) && $r['update_meta_cache'] ) {
 725                  bp_activity_update_meta_cache( $activity_ids );
 726              }
 727  
 728              if ( $activities && $r['display_comments'] ) {
 729                  $activities = BP_Activity_Activity::append_comments( $activities, $r['spam'] );
 730              }
 731  
 732              // Pre-fetch data associated with activity users and other objects.
 733              BP_Activity_Activity::prefetch_object_data( $activities );
 734  
 735              // Generate action strings.
 736              $activities = BP_Activity_Activity::generate_action_strings( $activities );
 737          }
 738  
 739          $retval['activities'] = $activities;
 740  
 741          // If $max is set, only return up to the max results.
 742          if ( ! empty( $r['count_total'] ) ) {
 743  
 744              /**
 745               * Filters the total activities MySQL statement.
 746               *
 747               * @since 1.5.0
 748               *
 749               * @param string $value     MySQL statement used to query for total activities.
 750               * @param string $where_sql MySQL WHERE statement portion.
 751               * @param string $sort      Sort direction for query.
 752               */
 753              $total_activities_sql = apply_filters( 'bp_activity_total_activities_sql', "SELECT count(DISTINCT a.id) FROM {$bp->activity->table_name} a {$join_sql} {$where_sql}", $where_sql, $sort );
 754              $cached = bp_core_get_incremented_cache( $total_activities_sql, $cache_group );
 755              if ( false === $cached ) {
 756                  $total_activities = $wpdb->get_var( $total_activities_sql );
 757                  bp_core_set_incremented_cache( $total_activities_sql, $cache_group, $total_activities );
 758              } else {
 759                  $total_activities = $cached;
 760              }
 761  
 762              if ( !empty( $r['max'] ) ) {
 763                  if ( (int) $total_activities > (int) $r['max'] ) {
 764                      $total_activities = $r['max'];
 765                  }
 766              }
 767  
 768              $retval['total'] = $total_activities;
 769          }
 770  
 771          return $retval;
 772      }
 773  
 774      /**
 775       * Convert activity IDs to activity objects, as expected in template loop.
 776       *
 777       * @since 2.0.0
 778       *
 779       * @param array $activity_ids Array of activity IDs.
 780       * @return array
 781       */
 782  	protected static function get_activity_data( $activity_ids = array() ) {
 783          global $wpdb;
 784  
 785          // Bail if no activity ID's passed.
 786          if ( empty( $activity_ids ) ) {
 787              return array();
 788          }
 789  
 790          // Get BuddyPress.
 791          $bp = buddypress();
 792  
 793          $activities   = array();
 794          $uncached_ids = bp_get_non_cached_ids( $activity_ids, 'bp_activity' );
 795  
 796          // Prime caches as necessary.
 797          if ( ! empty( $uncached_ids ) ) {
 798              // Format the activity ID's for use in the query below.
 799              $uncached_ids_sql = implode( ',', wp_parse_id_list( $uncached_ids ) );
 800  
 801              // Fetch data from activity table, preserving order.
 802              $queried_adata = $wpdb->get_results( "SELECT * FROM {$bp->activity->table_name} WHERE id IN ({$uncached_ids_sql})");
 803  
 804              // Put that data into the placeholders created earlier,
 805              // and add it to the cache.
 806              foreach ( (array) $queried_adata as $adata ) {
 807                  wp_cache_set( $adata->id, $adata, 'bp_activity' );
 808              }
 809          }
 810  
 811          // Now fetch data from the cache.
 812          foreach ( $activity_ids as $activity_id ) {
 813              // Integer casting.
 814              $activity = wp_cache_get( $activity_id, 'bp_activity' );
 815              if ( ! empty( $activity ) ) {
 816                  $activity->id                = (int) $activity->id;
 817                  $activity->user_id           = (int) $activity->user_id;
 818                  $activity->item_id           = (int) $activity->item_id;
 819                  $activity->secondary_item_id = (int) $activity->secondary_item_id;
 820                  $activity->hide_sitewide     = (int) $activity->hide_sitewide;
 821                  $activity->mptt_left         = (int) $activity->mptt_left;
 822                  $activity->mptt_right        = (int) $activity->mptt_right;
 823                  $activity->is_spam           = (int) $activity->is_spam;
 824              }
 825  
 826              $activities[] = $activity;
 827          }
 828  
 829          // Then fetch user data.
 830          $user_query = new BP_User_Query( array(
 831              'user_ids'        => wp_list_pluck( $activities, 'user_id' ),
 832              'populate_extras' => false,
 833          ) );
 834  
 835          // Associated located user data with activity items.
 836          foreach ( $activities as $a_index => $a_item ) {
 837              $a_user_id = intval( $a_item->user_id );
 838              $a_user    = isset( $user_query->results[ $a_user_id ] ) ? $user_query->results[ $a_user_id ] : '';
 839  
 840              if ( !empty( $a_user ) ) {
 841                  $activities[ $a_index ]->user_email    = $a_user->user_email;
 842                  $activities[ $a_index ]->user_nicename = $a_user->user_nicename;
 843                  $activities[ $a_index ]->user_login    = $a_user->user_login;
 844                  $activities[ $a_index ]->display_name  = $a_user->display_name;
 845              }
 846          }
 847  
 848          return $activities;
 849      }
 850  
 851      /**
 852       * Append xProfile fullnames to an activity array.
 853       *
 854       * @since 2.0.0
 855       *
 856       * @param array $activities Activities array.
 857       * @return array
 858       */
 859  	protected static function append_user_fullnames( $activities ) {
 860  
 861          if ( bp_is_active( 'xprofile' ) && ! empty( $activities ) ) {
 862              $activity_user_ids = wp_list_pluck( $activities, 'user_id' );
 863  
 864              if ( ! empty( $activity_user_ids ) ) {
 865                  $fullnames = bp_core_get_user_displaynames( $activity_user_ids );
 866                  if ( ! empty( $fullnames ) ) {
 867                      foreach ( (array) $activities as $i => $activity ) {
 868                          if ( ! empty( $fullnames[ $activity->user_id ] ) ) {
 869                              $activities[ $i ]->user_fullname = $fullnames[ $activity->user_id ];
 870                          }
 871                      }
 872                  }
 873              }
 874          }
 875  
 876          return $activities;
 877      }
 878  
 879      /**
 880       * Pre-fetch data for objects associated with activity items.
 881       *
 882       * Activity items are associated with users, and often with other
 883       * BuddyPress data objects. Here, we pre-fetch data about these
 884       * associated objects, so that inline lookups - done primarily when
 885       * building action strings - do not result in excess database queries.
 886       *
 887       * The only object data required for activity component activity types
 888       * (activity_update and activity_comment) is related to users, and that
 889       * info is fetched separately in BP_Activity_Activity::get_activity_data().
 890       * So this method contains nothing but a filter that allows other
 891       * components, such as bp-friends and bp-groups, to hook in and prime
 892       * their own caches at the beginning of an activity loop.
 893       *
 894       * @since 2.0.0
 895       *
 896       * @param array $activities Array of activities.
 897       * @return array $activities Array of activities.
 898       */
 899  	protected static function prefetch_object_data( $activities ) {
 900  
 901          /**
 902           * Filters inside prefetch_object_data method to aid in pre-fetching object data associated with activity item.
 903           *
 904           * @since 2.0.0
 905           *
 906           * @param array $activities Array of activities.
 907           */
 908          return apply_filters( 'bp_activity_prefetch_object_data', $activities );
 909      }
 910  
 911      /**
 912       * Generate action strings for the activities located in BP_Activity_Activity::get().
 913       *
 914       * If no string can be dynamically generated for a given item
 915       * (typically because the activity type has not been properly
 916       * registered), the static 'action' value pulled from the database will
 917       * be left in place.
 918       *
 919       * @since 2.0.0
 920       *
 921       * @param array $activities Array of activities.
 922       * @return array
 923       */
 924  	protected static function generate_action_strings( $activities ) {
 925          foreach ( $activities as $key => $activity ) {
 926              $generated_action = bp_activity_generate_action_string( $activity );
 927              if ( false !== $generated_action ) {
 928                  $activity->action = $generated_action;
 929              }
 930  
 931              $activities[ $key ] = $activity;
 932          }
 933  
 934          return $activities;
 935      }
 936  
 937      /**
 938       * Get the SQL for the 'meta_query' param in BP_Activity_Activity::get().
 939       *
 940       * We use WP_Meta_Query to do the heavy lifting of parsing the
 941       * meta_query array and creating the necessary SQL clauses. However,
 942       * since BP_Activity_Activity::get() builds its SQL differently than
 943       * WP_Query, we have to alter the return value (stripping the leading
 944       * AND keyword from the 'where' clause).
 945       *
 946       * @since 1.8.0
 947       *
 948       * @param array $meta_query An array of meta_query filters. See the
 949       *                          documentation for WP_Meta_Query for details.
 950       * @return array $sql_array 'join' and 'where' clauses.
 951       */
 952  	public static function get_meta_query_sql( $meta_query = array() ) {
 953          global $wpdb;
 954  
 955          $sql_array = array(
 956              'join'  => '',
 957              'where' => '',
 958          );
 959  
 960          if ( ! empty( $meta_query ) ) {
 961              $activity_meta_query = new WP_Meta_Query( $meta_query );
 962  
 963              // WP_Meta_Query expects the table name at
 964              // $wpdb->activitymeta.
 965              $wpdb->activitymeta = buddypress()->activity->table_name_meta;
 966  
 967              $meta_sql = $activity_meta_query->get_sql( 'activity', 'a', 'id' );
 968  
 969              // Strip the leading AND - BP handles it in get().
 970              $sql_array['where'] = preg_replace( '/^\sAND/', '', $meta_sql['where'] );
 971              $sql_array['join']  = $meta_sql['join'];
 972          }
 973  
 974          return $sql_array;
 975      }
 976  
 977      /**
 978       * Get the SQL for the 'date_query' param in BP_Activity_Activity::get().
 979       *
 980       * We use BP_Date_Query, which extends WP_Date_Query, to do the heavy lifting
 981       * of parsing the date_query array and creating the necessary SQL clauses.
 982       * However, since BP_Activity_Activity::get() builds its SQL differently than
 983       * WP_Query, we have to alter the return value (stripping the leading AND
 984       * keyword from the query).
 985       *
 986       * @since 2.1.0
 987       *
 988       * @param array $date_query An array of date_query parameters. See the
 989       *                          documentation for the first parameter of WP_Date_Query.
 990       * @return string
 991       */
 992  	public static function get_date_query_sql( $date_query = array() ) {
 993          $sql = '';
 994  
 995          // Date query.
 996          if ( ! empty( $date_query ) && is_array( $date_query ) ) {
 997              $date_query = new BP_Date_Query( $date_query, 'date_recorded' );
 998              $sql = preg_replace( '/^\sAND/', '', $date_query->get_sql() );
 999          }
1000  
1001          return $sql;
1002      }
1003  
1004      /**
1005       * Get the SQL for the 'scope' param in BP_Activity_Activity::get().
1006       *
1007       * A scope is a predetermined set of activity arguments.  This method is used
1008       * to grab these activity arguments and override any existing args if needed.
1009       *
1010       * Can handle multiple scopes.
1011       *
1012       * @since 2.2.0
1013       *
1014       * @param  mixed $scope  The activity scope. Accepts string or array of scopes.
1015       * @param  array $r      Current activity arguments. Same as those of BP_Activity_Activity::get(),
1016       *                       but merged with defaults.
1017       * @return false|array 'sql' WHERE SQL string and 'override' activity args.
1018       */
1019  	public static function get_scope_query_sql( $scope = false, $r = array() ) {
1020  
1021          // Define arrays for future use.
1022          $query_args = array();
1023          $override   = array();
1024          $retval     = array();
1025  
1026          // Check for array of scopes.
1027          if ( is_array( $scope ) ) {
1028              $scopes = $scope;
1029  
1030              // Explode a comma separated string of scopes.
1031          } elseif ( is_string( $scope ) ) {
1032              $scopes = explode( ',', $scope );
1033          }
1034  
1035          // Bail if no scope passed.
1036          if ( empty( $scopes ) ) {
1037              return false;
1038          }
1039  
1040          // Helper to easily grab the 'user_id'.
1041          if ( ! empty( $r['filter']['user_id'] ) ) {
1042              $r['user_id'] = $r['filter']['user_id'];
1043          }
1044  
1045          // Parse each scope; yes! we handle multiples!
1046          foreach ( $scopes as $scope ) {
1047              $scope_args = array();
1048  
1049              /**
1050               * Plugins can hook here to set their activity arguments for custom scopes.
1051               *
1052               * This is a dynamic filter based on the activity scope. eg:
1053               *   - 'bp_activity_set_groups_scope_args'
1054               *   - 'bp_activity_set_friends_scope_args'
1055               *
1056               * To see how this filter is used, plugin devs should check out:
1057               *   - bp_groups_filter_activity_scope() - used for 'groups' scope
1058               *   - bp_friends_filter_activity_scope() - used for 'friends' scope
1059               *
1060               * @since 2.2.0
1061               *
1062               * @param array {
1063               *     Activity query clauses.
1064               *     @type array {
1065               *         Activity arguments for your custom scope.
1066               *         See {@link BP_Activity_Query::_construct()} for more details.
1067               *     }
1068               *     @type array  $override Optional. Override existing activity arguments passed by $r.
1069               *     }
1070               * }
1071               * @param array $r Current activity arguments passed in BP_Activity_Activity::get().
1072               */
1073              $scope_args = apply_filters( "bp_activity_set_{$scope}_scope_args", array(), $r );
1074  
1075              if ( ! empty( $scope_args ) ) {
1076                  // Merge override properties from other scopes
1077                  // this might be a problem...
1078                  if ( ! empty( $scope_args['override'] ) ) {
1079                      $override = array_merge( $override, $scope_args['override'] );
1080                      unset( $scope_args['override'] );
1081                  }
1082  
1083                  // Save scope args.
1084                  if ( ! empty( $scope_args ) ) {
1085                      $query_args[] = $scope_args;
1086                  }
1087              }
1088          }
1089  
1090          if ( ! empty( $query_args ) ) {
1091              // Set relation to OR.
1092              $query_args['relation'] = 'OR';
1093  
1094              $query = new BP_Activity_Query( $query_args );
1095              $sql   = $query->get_sql();
1096              if ( ! empty( $sql ) ) {
1097                  $retval['sql'] = $sql;
1098              }
1099          }
1100  
1101          if ( ! empty( $override ) ) {
1102              $retval['override'] = $override;
1103          }
1104  
1105          return $retval;
1106      }
1107  
1108      /**
1109       * In BuddyPress 1.2.x, this was used to retrieve specific activity stream items (for example, on an activity's permalink page).
1110       *
1111       * As of 1.5.x, use BP_Activity_Activity::get() with an 'in' parameter instead.
1112       *
1113       * @since 1.2.0
1114       *
1115       * @deprecated 1.5
1116       * @deprecated Use BP_Activity_Activity::get() with an 'in' parameter instead.
1117       *
1118       * @param mixed    $activity_ids     Array or comma-separated string of activity IDs to retrieve.
1119       * @param int|bool $max              Maximum number of results to return. (Optional; default is no maximum).
1120       * @param int      $page             The set of results that the user is viewing. Used in pagination. (Optional; default is 1).
1121       * @param int      $per_page         Specifies how many results per page. Used in pagination. (Optional; default is 25).
1122       * @param string   $sort             MySQL column sort; ASC or DESC. (Optional; default is DESC).
1123       * @param bool     $display_comments Retrieve an activity item's associated comments or not. (Optional; default is false).
1124       * @return array
1125       */
1126  	public static function get_specific( $activity_ids, $max = false, $page = 1, $per_page = 25, $sort = 'DESC', $display_comments = false ) {
1127          _deprecated_function( __FUNCTION__, '1.5', 'Use BP_Activity_Activity::get() with the "in" parameter instead.' );
1128          return BP_Activity_Activity::get( $max, $page, $per_page, $sort, false, false, $display_comments, false, false, $activity_ids );
1129      }
1130  
1131      /**
1132       * Get the first activity ID that matches a set of criteria.
1133       *
1134       * @since 1.2.0
1135       *
1136       * @todo Should parameters be optional?
1137       *
1138       * @param int    $user_id           User ID to filter by.
1139       * @param string $component         Component to filter by.
1140       * @param string $type              Activity type to filter by.
1141       * @param int    $item_id           Associated item to filter by.
1142       * @param int    $secondary_item_id Secondary associated item to filter by.
1143       * @param string $action            Action to filter by.
1144       * @param string $content           Content to filter by.
1145       * @param string $date_recorded     Date to filter by.
1146       * @return int|false Activity ID on success, false if none is found.
1147       */
1148  	public static function get_id( $user_id, $component, $type, $item_id, $secondary_item_id, $action, $content, $date_recorded ) {
1149          global $wpdb;
1150  
1151          $bp = buddypress();
1152  
1153          $where_args = false;
1154  
1155          if ( ! empty( $user_id ) ) {
1156              $where_args[] = $wpdb->prepare( "user_id = %d", $user_id );
1157          }
1158  
1159          if ( ! empty( $component ) ) {
1160              $where_args[] = $wpdb->prepare( "component = %s", $component );
1161          }
1162  
1163          if ( ! empty( $type ) ) {
1164              $where_args[] = $wpdb->prepare( "type = %s", $type );
1165          }
1166  
1167          if ( ! empty( $item_id ) ) {
1168              $where_args[] = $wpdb->prepare( "item_id = %d", $item_id );
1169          }
1170  
1171          if ( ! empty( $secondary_item_id ) ) {
1172              $where_args[] = $wpdb->prepare( "secondary_item_id = %d", $secondary_item_id );
1173          }
1174  
1175          if ( ! empty( $action ) ) {
1176              $where_args[] = $wpdb->prepare( "action = %s", $action );
1177          }
1178  
1179          if ( ! empty( $content ) ) {
1180              $where_args[] = $wpdb->prepare( "content = %s", $content );
1181          }
1182  
1183          if ( ! empty( $date_recorded ) ) {
1184              $where_args[] = $wpdb->prepare( "date_recorded = %s", $date_recorded );
1185          }
1186  
1187          if ( ! empty( $where_args ) ) {
1188              $where_sql = 'WHERE ' . join( ' AND ', $where_args );
1189              $result = $wpdb->get_var( "SELECT id FROM {$bp->activity->table_name} {$where_sql}" );
1190  
1191              return is_numeric( $result ) ? (int) $result : false;
1192          }
1193  
1194          return false;
1195      }
1196  
1197      /**
1198       * Delete activity items from the database.
1199       *
1200       * To delete a specific activity item, pass an 'id' parameter.
1201       * Otherwise use the filters.
1202       *
1203       * @since 1.2.0
1204       *
1205       * @param array $args {
1206       *     @int    $id                Optional. The ID of a specific item to delete.
1207       *     @string $action            Optional. The action to filter by.
1208       *     @string $content           Optional. The content to filter by.
1209       *     @string $component         Optional. The component name to filter by.
1210       *     @string $type              Optional. The activity type to filter by.
1211       *     @string $primary_link      Optional. The primary URL to filter by.
1212       *     @int    $user_id           Optional. The user ID to filter by.
1213       *     @int    $item_id           Optional. The associated item ID to filter by.
1214       *     @int    $secondary_item_id Optional. The secondary associated item ID to filter by.
1215       *     @string $date_recorded     Optional. The date to filter by.
1216       *     @int    $hide_sitewide     Optional. Default: false.
1217       * }
1218       * @return array|bool An array of deleted activity IDs on success, false on failure.
1219       */
1220  	public static function delete( $args = array() ) {
1221          global $wpdb;
1222  
1223          $bp = buddypress();
1224          $r  = wp_parse_args( $args, array(
1225              'id'                => false,
1226              'action'            => false,
1227              'content'           => false,
1228              'component'         => false,
1229              'type'              => false,
1230              'primary_link'      => false,
1231              'user_id'           => false,
1232              'item_id'           => false,
1233              'secondary_item_id' => false,
1234              'date_recorded'     => false,
1235              'hide_sitewide'     => false
1236          ) );
1237  
1238          // Setup empty array from where query arguments.
1239          $where_args = array();
1240  
1241          // ID.
1242          if ( ! empty( $r['id'] ) ) {
1243              $where_args[] = $wpdb->prepare( "id = %d", $r['id'] );
1244          }
1245  
1246          // User ID.
1247          if ( ! empty( $r['user_id'] ) ) {
1248              $where_args[] = $wpdb->prepare( "user_id = %d", $r['user_id'] );
1249          }
1250  
1251          // Action.
1252          if ( ! empty( $r['action'] ) ) {
1253              $where_args[] = $wpdb->prepare( "action = %s", $r['action'] );
1254          }
1255  
1256          // Content.
1257          if ( ! empty( $r['content'] ) ) {
1258              $where_args[] = $wpdb->prepare( "content = %s", $r['content'] );
1259          }
1260  
1261          // Component.
1262          if ( ! empty( $r['component'] ) ) {
1263              $where_args[] = $wpdb->prepare( "component = %s", $r['component'] );
1264          }
1265  
1266          // Type.
1267          if ( ! empty( $r['type'] ) ) {
1268              $where_args[] = $wpdb->prepare( "type = %s", $r['type'] );
1269          }
1270  
1271          // Primary Link.
1272          if ( ! empty( $r['primary_link'] ) ) {
1273              $where_args[] = $wpdb->prepare( "primary_link = %s", $r['primary_link'] );
1274          }
1275  
1276          // Item ID.
1277          if ( ! empty( $r['item_id'] ) ) {
1278              $where_args[] = $wpdb->prepare( "item_id = %d", $r['item_id'] );
1279          }
1280  
1281          // Secondary item ID.
1282          if ( ! empty( $r['secondary_item_id'] ) ) {
1283              $where_args[] = $wpdb->prepare( "secondary_item_id = %d", $r['secondary_item_id'] );
1284          }
1285  
1286          // Date Recorded.
1287          if ( ! empty( $r['date_recorded'] ) ) {
1288              $where_args[] = $wpdb->prepare( "date_recorded = %s", $r['date_recorded'] );
1289          }
1290  
1291          // Hidden sitewide.
1292          if ( ! empty( $r['hide_sitewide'] ) ) {
1293              $where_args[] = $wpdb->prepare( "hide_sitewide = %d", $r['hide_sitewide'] );
1294          }
1295  
1296          // Bail if no where arguments.
1297          if ( empty( $where_args ) ) {
1298              return false;
1299          }
1300  
1301          // Join the where arguments for querying.
1302          $where_sql = 'WHERE ' . join( ' AND ', $where_args );
1303  
1304          // Fetch all activities being deleted so we can perform more actions.
1305          $activities = $wpdb->get_results( "SELECT * FROM {$bp->activity->table_name} {$where_sql}" );
1306  
1307          /**
1308           * Action to allow intercepting activity items to be deleted.
1309           *
1310           * @since 2.3.0
1311           *
1312           * @param array $activities Array of activities.
1313           * @param array $r          Array of parsed arguments.
1314           */
1315          do_action_ref_array( 'bp_activity_before_delete', array( $activities, $r ) );
1316  
1317          // Attempt to delete activities from the database.
1318          $deleted = $wpdb->query( "DELETE FROM {$bp->activity->table_name} {$where_sql}" );
1319  
1320          // Bail if nothing was deleted.
1321          if ( empty( $deleted ) ) {
1322              return false;
1323          }
1324  
1325          /**
1326           * Action to allow intercepting activity items just deleted.
1327           *
1328           * @since 2.3.0
1329           *
1330           * @param array $activities Array of activities.
1331           * @param array $r          Array of parsed arguments.
1332           */
1333          do_action_ref_array( 'bp_activity_after_delete', array( $activities, $r ) );
1334  
1335          // Pluck the activity IDs out of the $activities array.
1336          $activity_ids = wp_parse_id_list( wp_list_pluck( $activities, 'id' ) );
1337  
1338          // Handle accompanying activity comments and meta deletion.
1339          if ( ! empty( $activity_ids ) ) {
1340  
1341              // Delete all activity meta entries for activity items.
1342              BP_Activity_Activity::delete_activity_meta_entries( $activity_ids );
1343  
1344              // Setup empty array for comments.
1345              $comment_ids = array();
1346  
1347              // Loop through activity ids and attempt to delete comments.
1348              foreach ( $activity_ids as $activity_id ) {
1349  
1350                  // Attempt to delete comments.
1351                  $comments = BP_Activity_Activity::delete( array(
1352                      'type'    => 'activity_comment',
1353                      'item_id' => $activity_id
1354                  ) );
1355  
1356                  // Merge IDs together.
1357                  if ( ! empty( $comments ) ) {
1358                      $comment_ids = array_merge( $comment_ids, $comments );
1359                  }
1360              }
1361  
1362              // Merge activity IDs with any deleted comment IDs.
1363              if ( ! empty( $comment_ids ) ) {
1364                  $activity_ids = array_unique( array_merge( $activity_ids, $comment_ids ) );
1365              }
1366          }
1367  
1368          return $activity_ids;
1369      }
1370  
1371      /**
1372       * Delete the comments associated with a set of activity items.
1373       *
1374       * This method is no longer used by BuddyPress, and it is recommended not to
1375       * use it going forward, and use BP_Activity_Activity::delete() instead.
1376       *
1377       * @since 1.2.0
1378       *
1379       * @deprecated 2.3.0
1380       *
1381       * @param array $activity_ids Activity IDs whose comments should be deleted.
1382       * @param bool  $delete_meta  Should we delete the activity meta items for these comments.
1383       * @return bool True on success.
1384       */
1385  	public static function delete_activity_item_comments( $activity_ids = array(), $delete_meta = true ) {
1386          global $wpdb;
1387  
1388          $bp = buddypress();
1389  
1390          $delete_meta  = (bool) $delete_meta;
1391          $activity_ids = implode( ',', wp_parse_id_list( $activity_ids ) );
1392  
1393          if ( $delete_meta ) {
1394              // Fetch the activity comment IDs for our deleted activity items.
1395              $activity_comment_ids = $wpdb->get_col( "SELECT id FROM {$bp->activity->table_name} WHERE type = 'activity_comment' AND item_id IN ({$activity_ids})" );
1396  
1397              if ( ! empty( $activity_comment_ids ) ) {
1398                  self::delete_activity_meta_entries( $activity_comment_ids );
1399              }
1400          }
1401  
1402          return $wpdb->query( "DELETE FROM {$bp->activity->table_name} WHERE type = 'activity_comment' AND item_id IN ({$activity_ids})" );
1403      }
1404  
1405      /**
1406       * Delete the meta entries associated with a set of activity items.
1407       *
1408       * @since 1.2.0
1409       *
1410       * @param array $activity_ids Activity IDs whose meta should be deleted.
1411       * @return bool True on success.
1412       */
1413  	public static function delete_activity_meta_entries( $activity_ids = array() ) {
1414          $activity_ids = wp_parse_id_list( $activity_ids );
1415  
1416          foreach ( $activity_ids as $activity_id ) {
1417              bp_activity_delete_meta( $activity_id );
1418          }
1419  
1420          return true;
1421      }
1422  
1423      /**
1424       * Append activity comments to their associated activity items.
1425       *
1426       * @since 1.2.0
1427       *
1428       * @global wpdb $wpdb WordPress database object.
1429       *
1430       * @param array  $activities Activities to fetch comments for.
1431       * @param string $spam       Optional. 'ham_only' (default), 'spam_only' or 'all'.
1432       * @return array The updated activities with nested comments.
1433       */
1434  	public static function append_comments( $activities, $spam = 'ham_only' ) {
1435          $activity_comments = array();
1436  
1437          // Now fetch the activity comments and parse them into the correct position in the activities array.
1438          foreach ( (array) $activities as $activity ) {
1439              $top_level_parent_id = 'activity_comment' == $activity->type ? $activity->item_id : 0;
1440              $activity_comments[$activity->id] = BP_Activity_Activity::get_activity_comments( $activity->id, $activity->mptt_left, $activity->mptt_right, $spam, $top_level_parent_id );
1441          }
1442  
1443          // Merge the comments with the activity items.
1444          foreach ( (array) $activities as $key => $activity ) {
1445              if ( isset( $activity_comments[$activity->id] ) ) {
1446                  $activities[$key]->children = $activity_comments[$activity->id];
1447              }
1448          }
1449  
1450          return $activities;
1451      }
1452  
1453      /**
1454       * Get activity comments that are associated with a specific activity ID.
1455       *
1456       * @since 1.2.0
1457       *
1458       * @global wpdb $wpdb WordPress database object.
1459       *
1460       * @param int    $activity_id         Activity ID to fetch comments for.
1461       * @param int    $left                Left-most node boundary.
1462       * @param int    $right               Right-most node boundary.
1463       * @param string $spam                Optional. 'ham_only' (default), 'spam_only' or 'all'.
1464       * @param int    $top_level_parent_id Optional. The id of the root-level parent activity item.
1465       * @return array The updated activities with nested comments.
1466       */
1467  	public static function get_activity_comments( $activity_id, $left, $right, $spam = 'ham_only', $top_level_parent_id = 0 ) {
1468          global $wpdb;
1469  
1470          if ( empty( $top_level_parent_id ) ) {
1471              $top_level_parent_id = $activity_id;
1472          }
1473  
1474          $comments = wp_cache_get( $activity_id, 'bp_activity_comments' );
1475  
1476          // We store the string 'none' to cache the fact that the
1477          // activity item has no comments.
1478          if ( 'none' === $comments ) {
1479              $comments = false;
1480  
1481              // A true cache miss.
1482          } elseif ( empty( $comments ) ) {
1483  
1484              $bp = buddypress();
1485  
1486              // Select the user's fullname with the query.
1487              if ( bp_is_active( 'xprofile' ) ) {
1488                  $fullname_select = ", pd.value as user_fullname";
1489                  $fullname_from = ", {$bp->profile->table_name_data} pd ";
1490                  $fullname_where = "AND pd.user_id = a.user_id AND pd.field_id = 1";
1491  
1492                  // Prevent debug errors.
1493              } else {
1494                  $fullname_select = $fullname_from = $fullname_where = '';
1495              }
1496  
1497              // Don't retrieve activity comments marked as spam.
1498              if ( 'ham_only' == $spam ) {
1499                  $spam_sql = 'AND a.is_spam = 0';
1500              } elseif ( 'spam_only' == $spam ) {
1501                  $spam_sql = 'AND a.is_spam = 1';
1502              } else {
1503                  $spam_sql = '';
1504              }
1505  
1506              // Legacy query - not recommended.
1507  
1508              /**
1509               * Filters if BuddyPress should use the legacy activity query.
1510               *
1511               * @since 2.0.0
1512               *
1513               * @param bool                 $value     Whether or not to use the legacy query.
1514               * @param BP_Activity_Activity $value     Magic method referring to currently called method.
1515               * @param array                $func_args Array of the method's argument list.
1516               */
1517              if ( apply_filters( 'bp_use_legacy_activity_query', false, __METHOD__, func_get_args() ) ) {
1518  
1519                  /**
1520                   * Filters the MySQL prepared statement for the legacy activity query.
1521                   *
1522                   * @since 1.5.0
1523                   *
1524                   * @param string $value       Prepared statement for the activity query.
1525                   * @param int    $activity_id Activity ID to fetch comments for.
1526                   * @param int    $left        Left-most node boundary.
1527                   * @param int    $right       Right-most node boundary.
1528                   * @param string $spam_sql    SQL Statement portion to differentiate between ham or spam.
1529                   */
1530                  $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 );
1531  
1532                  $descendants = $wpdb->get_results( $sql );
1533  
1534                  // We use the mptt BETWEEN clause to limit returned
1535                  // descendants to the correct part of the tree.
1536              } else {
1537                  $sql = $wpdb->prepare( "SELECT id FROM {$bp->activity->table_name} a WHERE 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 );
1538  
1539                  $descendant_ids = $wpdb->get_col( $sql );
1540                  $descendants    = self::get_activity_data( $descendant_ids );
1541                  $descendants    = self::append_user_fullnames( $descendants );
1542              }
1543  
1544              $ref = array();
1545  
1546              // Loop descendants and build an assoc array.
1547              foreach ( (array) $descendants as $d ) {
1548                  $d->children = array();
1549  
1550                  // If we have a reference on the parent.
1551                  if ( isset( $ref[ $d->secondary_item_id ] ) ) {
1552                      $ref[ $d->secondary_item_id ]->children[ $d->id ] = $d;
1553                      $ref[ $d->id ] =& $ref[ $d->secondary_item_id ]->children[ $d->id ];
1554  
1555                      // If we don't have a reference on the parent, put in the root level.
1556                  } else {
1557                      $comments[ $d->id ] = $d;
1558                      $ref[ $d->id ] =& $comments[ $d->id ];
1559                  }
1560              }
1561  
1562              // Calculate depth for each item.
1563              foreach ( $ref as &$r ) {
1564                  $depth = 1;
1565                  $parent_id = $r->secondary_item_id;
1566  
1567                  while ( $parent_id !== $r->item_id ) {
1568                      $depth++;
1569  
1570                      // When display_comments=stream, the parent comment may not be part of the
1571                      // returned results, so we manually fetch it.
1572                      if ( empty( $ref[ $parent_id ] ) ) {
1573                          $direct_parent = new BP_Activity_Activity( $parent_id );
1574                          if ( isset( $direct_parent->secondary_item_id ) ) {
1575                              // If the direct parent is not an activity update, that means we've reached
1576                              // the parent activity item (eg. new_blog_post).
1577                              if ( 'activity_update' !== $direct_parent->type ) {
1578                                  $parent_id = $r->item_id;
1579  
1580                              } else {
1581                                  $parent_id = $direct_parent->secondary_item_id;
1582                              }
1583  
1584                          } else {
1585                              // Something went wrong.  Short-circuit the depth calculation.
1586                              $parent_id = $r->item_id;
1587                          }
1588                      } else {
1589                          $parent_id = $ref[ $parent_id ]->secondary_item_id;
1590                      }
1591                  }
1592                  $r->depth = $depth;
1593              }
1594  
1595              // If we cache a value of false, it'll count as a cache
1596              // miss the next time the activity comments are fetched.
1597              // Storing the string 'none' is a hack workaround to
1598              // avoid unnecessary queries.
1599              if ( false === $comments ) {
1600                  $cache_value = 'none';
1601              } else {
1602                  $cache_value = $comments;
1603              }
1604  
1605              wp_cache_set( $activity_id, $cache_value, 'bp_activity_comments' );
1606          }
1607  
1608          return $comments;
1609      }
1610  
1611      /**
1612       * Rebuild nested comment tree under an activity or activity comment.
1613       *
1614       * @since 1.2.0
1615       *
1616       * @global wpdb $wpdb WordPress database object.
1617       *
1618       * @param int $parent_id ID of an activity or activity comment.
1619       * @param int $left      Node boundary start for activity or activity comment.
1620       * @return int Right Node boundary of activity or activity comment.
1621       */
1622  	public static function rebuild_activity_comment_tree( $parent_id, $left = 1 ) {
1623          global $wpdb;
1624  
1625          $bp = buddypress();
1626  
1627          // The right value of this node is the left value + 1.
1628          $right = intval( $left + 1 );
1629  
1630          // Get all descendants of this node.
1631          $comments    = BP_Activity_Activity::get_child_comments( $parent_id );
1632          $descendants = wp_list_pluck( $comments, 'id' );
1633  
1634          // Loop the descendants and recalculate the left and right values.
1635          foreach ( (array) $descendants as $descendant_id ) {
1636              $right = BP_Activity_Activity::rebuild_activity_comment_tree( $descendant_id, $right );
1637          }
1638  
1639          // We've got the left value, and now that we've processed the children
1640          // of this node we also know the right value.
1641          if ( 1 === $left ) {
1642              $wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET mptt_left = %d, mptt_right = %d WHERE id = %d", $left, $right, $parent_id ) );
1643          } else {
1644              $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 ) );
1645          }
1646  
1647          // Return the right value of this node + 1.
1648          return intval( $right + 1 );
1649      }
1650  
1651      /**
1652       * Get child comments of an activity or activity comment.
1653       *
1654       * @since 1.2.0
1655       *
1656       * @global wpdb $wpdb WordPress database object.
1657       *
1658       * @param int $parent_id ID of an activity or activity comment.
1659       * @return object Numerically indexed array of child comments.
1660       */
1661  	public static function get_child_comments( $parent_id ) {
1662          global $wpdb;
1663  
1664          $bp = buddypress();
1665  
1666          return $wpdb->get_results( $wpdb->prepare( "SELECT id FROM {$bp->activity->table_name} WHERE type = 'activity_comment' AND secondary_item_id = %d", $parent_id ) );
1667      }
1668  
1669      /**
1670       * Get a list of components that have recorded activity associated with them.
1671       *
1672       * @since 1.2.0
1673       *
1674       * @param bool $skip_last_activity If true, components will not be
1675       *                                 included if the only activity type associated with them is
1676       *                                 'last_activity'. (Since 2.0.0, 'last_activity' is stored in
1677       *                                 the activity table, but these items are not full-fledged
1678       *                                 activity items.) Default: true.
1679       * @return array List of component names.
1680       */
1681  	public static function get_recorded_components( $skip_last_activity = true ) {
1682          global $wpdb;
1683  
1684          $bp = buddypress();
1685  
1686          if ( true === $skip_last_activity ) {
1687              $components = $wpdb->get_col( "SELECT DISTINCT component FROM {$bp->activity->table_name} WHERE action != '' AND action != 'last_activity' ORDER BY component ASC" );
1688          } else {
1689              $components = $wpdb->get_col( "SELECT DISTINCT component FROM {$bp->activity->table_name} ORDER BY component ASC" );
1690          }
1691  
1692          return $components;
1693      }
1694  
1695      /**
1696       * Get sitewide activity items for use in an RSS feed.
1697       *
1698       * @since 1.0.0
1699       *
1700       * @param int $limit Optional. Number of items to fetch. Default: 35.
1701       * @return array $activity_feed List of activity items, with RSS data added.
1702       */
1703  	public static function get_sitewide_items_for_feed( $limit = 35 ) {
1704          $activities    = bp_activity_get_sitewide( array( 'max' => $limit ) );
1705          $activity_feed = array();
1706  
1707          for ( $i = 0, $count = count( $activities ); $i < $count; ++$i ) {
1708              $title                            = explode( '<span', $activities[$i]['content'] );
1709              $activity_feed[$i]['title']       = trim( strip_tags( $title[0] ) );
1710              $activity_feed[$i]['link']        = $activities[$i]['primary_link'];
1711              $activity_feed[$i]['description'] = @sprintf( $activities[$i]['content'], '' );
1712              $activity_feed[$i]['pubdate']     = $activities[$i]['date_recorded'];
1713          }
1714  
1715          return $activity_feed;
1716      }
1717  
1718      /**
1719       * Create SQL IN clause for filter queries.
1720       *
1721       * @since 1.5.0
1722       *
1723       * @see BP_Activity_Activity::get_filter_sql()
1724       *
1725       * @param string     $field The database field.
1726       * @param array|bool $items The values for the IN clause, or false when none are found.
1727       * @return string|false
1728       */
1729  	public static function get_in_operator_sql( $field, $items ) {
1730          global $wpdb;
1731  
1732          // Split items at the comma.
1733          if ( ! is_array( $items ) ) {
1734              $items = explode( ',', $items );
1735          }
1736  
1737          // Array of prepared integers or quoted strings.
1738          $items_prepared = array();
1739  
1740          // Clean up and format each item.
1741          foreach ( $items as $item ) {
1742              // Clean up the string.
1743              $item = trim( $item );
1744              // Pass everything through prepare for security and to safely quote strings.
1745              $items_prepared[] = ( is_numeric( $item ) ) ? $wpdb->prepare( '%d', $item ) : $wpdb->prepare( '%s', $item );
1746          }
1747  
1748          // Build IN operator sql syntax.
1749          if ( count( $items_prepared ) )
1750              return sprintf( '%s IN ( %s )', trim( $field ), implode( ',', $items_prepared ) );
1751          else
1752              return false;
1753      }
1754  
1755      /**
1756       * Create filter SQL clauses.
1757       *
1758       * @since 1.5.0
1759       *
1760       * @param array $filter_array {
1761       *     Fields and values to filter by.
1762       *
1763       *     @type array|string|int $user_id      User ID(s).
1764       *     @type array|string     $object       Corresponds to the 'component'
1765       *                                          column in the database.
1766       *     @type array|string     $action       Corresponds to the 'type' column
1767       *                                          in the database.
1768       *     @type array|string|int $primary_id   Corresponds to the 'item_id'
1769       *                                          column in the database.
1770       *     @type array|string|int $secondary_id Corresponds to the
1771       *                                          'secondary_item_id' column in the database.
1772       *     @type int              $offset       Return only those items with an ID greater
1773       *                                          than the offset value.
1774       *     @type string           $since        Return only those items that have a
1775       *                                          date_recorded value greater than a
1776       *                                          given MySQL-formatted date.
1777       * }
1778       * @return string The filter clause, for use in a SQL query.
1779       */
1780  	public static function get_filter_sql( $filter_array ) {
1781  
1782          $filter_sql = array();
1783  
1784          if ( !empty( $filter_array['user_id'] ) ) {
1785              $user_sql = BP_Activity_Activity::get_in_operator_sql( 'a.user_id', $filter_array['user_id'] );
1786              if ( !empty( $user_sql ) )
1787                  $filter_sql[] = $user_sql;
1788          }
1789  
1790          if ( !empty( $filter_array['object'] ) ) {
1791              $object_sql = BP_Activity_Activity::get_in_operator_sql( 'a.component', $filter_array['object'] );
1792              if ( !empty( $object_sql ) )
1793                  $filter_sql[] = $object_sql;
1794          }
1795  
1796          if ( !empty( $filter_array['action'] ) ) {
1797              $action_sql = BP_Activity_Activity::get_in_operator_sql( 'a.type', $filter_array['action'] );
1798              if ( ! empty( $action_sql ) )
1799                  $filter_sql[] = $action_sql;
1800          }
1801  
1802          if ( !empty( $filter_array['primary_id'] ) ) {
1803              $pid_sql = BP_Activity_Activity::get_in_operator_sql( 'a.item_id', $filter_array['primary_id'] );
1804              if ( !empty( $pid_sql ) )
1805                  $filter_sql[] = $pid_sql;
1806          }
1807  
1808          if ( !empty( $filter_array['secondary_id'] ) ) {
1809              $sid_sql = BP_Activity_Activity::get_in_operator_sql( 'a.secondary_item_id', $filter_array['secondary_id'] );
1810              if ( !empty( $sid_sql ) )
1811                  $filter_sql[] = $sid_sql;
1812          }
1813  
1814          if ( ! empty( $filter_array['offset'] ) ) {
1815              $sid_sql = absint( $filter_array['offset'] );
1816              $filter_sql[] = "a.id >= {$sid_sql}";
1817          }
1818  
1819          if ( ! empty( $filter_array['since'] ) ) {
1820              // Validate that this is a proper Y-m-d H:i:s date.
1821              // Trick: parse to UNIX date then translate back.
1822              $translated_date = date( 'Y-m-d H:i:s', strtotime( $filter_array['since'] ) );
1823              if ( $translated_date === $filter_array['since'] ) {
1824                  $filter_sql[] = "a.date_recorded > '{$translated_date}'";
1825              }
1826          }
1827  
1828          if ( empty( $filter_sql ) )
1829              return false;
1830  
1831          return join( ' AND ', $filter_sql );
1832      }
1833  
1834      /**
1835       * Get the date/time of last recorded activity.
1836       *
1837       * @since 1.2.0
1838       *
1839       * @return string ISO timestamp.
1840       */
1841  	public static function get_last_updated() {
1842          global $wpdb;
1843  
1844          $bp = buddypress();
1845  
1846          return $wpdb->get_var( "SELECT date_recorded FROM {$bp->activity->table_name} ORDER BY date_recorded DESC LIMIT 1" );
1847      }
1848  
1849      /**
1850       * Get favorite count for a given user.
1851       *
1852       * @since 1.2.0
1853       *
1854       * @param int $user_id The ID of the user whose favorites you're counting.
1855       * @return int $value A count of the user's favorites.
1856       */
1857  	public static function total_favorite_count( $user_id ) {
1858  
1859          // Get activities from user meta.
1860          $favorite_activity_entries = bp_get_user_meta( $user_id, 'bp_favorite_activities', true );
1861          if ( ! empty( $favorite_activity_entries ) ) {
1862              return count( $favorite_activity_entries );
1863          }
1864  
1865          // No favorites.
1866          return 0;
1867      }
1868  
1869      /**
1870       * Check whether an activity item exists with a given string content.
1871       *
1872       * @since 1.1.0
1873       *
1874       * @param string $content The content to filter by.
1875       * @return int|false The ID of the first matching item if found, otherwise false.
1876       */
1877  	public static function check_exists_by_content( $content ) {
1878          global $wpdb;
1879  
1880          $bp = buddypress();
1881  
1882          $result = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->activity->table_name} WHERE content = %s", $content ) );
1883  
1884          return is_numeric( $result ) ? (int) $result : false;
1885      }
1886  
1887      /**
1888       * Hide all activity for a given user.
1889       *
1890       * @since 1.2.0
1891       *
1892       * @param int $user_id The ID of the user whose activity you want to mark hidden.
1893       * @return mixed
1894       */
1895  	public static function hide_all_for_user( $user_id ) {
1896          global $wpdb;
1897  
1898          $bp = buddypress();
1899  
1900          return $wpdb->get_var( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET hide_sitewide = 1 WHERE user_id = %d", $user_id ) );
1901      }
1902  }


Generated: Tue Jul 16 01:01:43 2019 Cross-referenced by PHPXref 0.7.1