[ Index ]

PHP Cross Reference of BuddyPress

title

Body

[close]

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

   1  <?php
   2  /**
   3   * BuddyPress Notifications Classes.
   4   *
   5   * Classes used for the Notifications component.
   6   *
   7   * @package BuddyPress
   8   * @subpackage NotificationsClasses
   9   * @since 1.9.0
  10   */
  11  
  12  // Exit if accessed directly.
  13  defined( 'ABSPATH' ) || exit;
  14  
  15  /**
  16   * BuddyPress Notification items.
  17   *
  18   * Use this class to create, access, edit, or delete BuddyPress Notifications.
  19   *
  20   * @since 1.9.0
  21   */
  22  class BP_Notifications_Notification {
  23  
  24      /**
  25       * The notification ID.
  26       *
  27       * @since 1.9.0
  28       * @var int
  29       */
  30      public $id;
  31  
  32      /**
  33       * The ID of the item associated with the notification.
  34       *
  35       * @since 1.9.0
  36       * @var int
  37       */
  38      public $item_id;
  39  
  40      /**
  41       * The ID of the secondary item associated with the notification.
  42       *
  43       * @since 1.9.0
  44       * @var int|null
  45       */
  46      public $secondary_item_id = null;
  47  
  48      /**
  49       * The ID of the user the notification is associated with.
  50       *
  51       * @since 1.9.0
  52       * @var int
  53       */
  54      public $user_id;
  55  
  56      /**
  57       * The name of the component that the notification is for.
  58       *
  59       * @since 1.9.0
  60       * @var string
  61       */
  62      public $component_name;
  63  
  64      /**
  65       * The component action which the notification is related to.
  66       *
  67       * @since 1.9.0
  68       * @var string
  69       */
  70      public $component_action;
  71  
  72      /**
  73       * The date the notification was created.
  74       *
  75       * @since 1.9.0
  76       * @var string
  77       */
  78      public $date_notified;
  79  
  80      /**
  81       * Is the notification new, or has it already been read.
  82       *
  83       * @since 1.9.0
  84       * @var bool
  85       */
  86      public $is_new;
  87  
  88      /**
  89       * Columns in the notifications table.
  90       *
  91       * @since 9.1.0
  92       * @var array
  93       */
  94      public static $columns = array(
  95          'id',
  96          'user_id',
  97          'item_id',
  98          'secondary_item_id',
  99          'component_name',
 100          'component_action',
 101          'date_notified',
 102          'is_new',
 103      );
 104  
 105      /** Public Methods ********************************************************/
 106  
 107      /**
 108       * Constructor method.
 109       *
 110       * @since 1.9.0
 111       *
 112       * @param int $id Optional. Provide an ID to access an existing
 113       *                notification item.
 114       */
 115  	public function __construct( $id = 0 ) {
 116          if ( ! empty( $id ) ) {
 117              $this->id = (int) $id;
 118              $this->populate();
 119          }
 120      }
 121  
 122      /**
 123       * Update or insert notification details into the database.
 124       *
 125       * @since 1.9.0
 126       *
 127       * @global wpdb $wpdb WordPress database object.
 128       *
 129       * @return bool True on success, false on failure.
 130       */
 131  	public function save() {
 132          $retval = false;
 133  
 134          /**
 135           * Fires before the current notification item gets saved.
 136           *
 137           * Please use this hook to filter the properties above. Each part will be passed in.
 138           *
 139           * @since 2.0.0
 140           *
 141           * @param BP_Notifications_Notification $value Current instance of the notification item being saved. Passed by reference.
 142           */
 143          do_action_ref_array( 'bp_notification_before_save', array( &$this ) );
 144  
 145          $data = array(
 146              'user_id'           => $this->user_id,
 147              'item_id'           => $this->item_id,
 148              'secondary_item_id' => $this->secondary_item_id,
 149              'component_name'    => $this->component_name,
 150              'component_action'  => $this->component_action,
 151              'date_notified'     => $this->date_notified,
 152              'is_new'            => $this->is_new,
 153          );
 154          $data_format = array( '%d', '%d', '%d', '%s', '%s', '%s', '%d' );
 155  
 156          // Update.
 157          if ( ! empty( $this->id ) ) {
 158              $result = self::_update( $data, array( 'ID' => $this->id ), $data_format, array( '%d' ) );
 159  
 160          // Insert.
 161          } else {
 162              $result = self::_insert( $data, $data_format );
 163          }
 164  
 165          // Set the notification ID if successful.
 166          if ( ! empty( $result ) && ! is_wp_error( $result ) ) {
 167              global $wpdb;
 168  
 169              $this->id = $wpdb->insert_id;
 170              $retval   = $wpdb->insert_id;
 171          }
 172  
 173          /**
 174           * Fires after the current notification item gets saved.
 175           *
 176           * @since 2.0.0
 177           *
 178           * @param BP_Notifications_Notification $value Current instance of the notification item being saved.
 179           *                                             Passed by reference.
 180           */
 181          do_action_ref_array( 'bp_notification_after_save', array( &$this ) );
 182  
 183          // Return the result.
 184          return $retval;
 185      }
 186  
 187      /**
 188       * Fetch data for an existing notification from the database.
 189       *
 190       * @since 1.9.0
 191       *
 192       * @global BuddyPress $bp The one true BuddyPress instance.
 193       * @global wpdb $wpdb WordPress database object.
 194       */
 195  	public function populate() {
 196          global $wpdb;
 197  
 198          $bp = buddypress();
 199  
 200          // Look for a notification.
 201          $notification = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->notifications->table_name} WHERE id = %d", $this->id ) );
 202  
 203          // Setup the notification data.
 204          if ( ! empty( $notification ) && ! is_wp_error( $notification ) ) {
 205              $this->item_id           = (int) $notification->item_id;
 206              $this->secondary_item_id = (int) $notification->secondary_item_id;
 207              $this->user_id           = (int) $notification->user_id;
 208              $this->component_name    = $notification->component_name;
 209              $this->component_action  = $notification->component_action;
 210              $this->date_notified     = $notification->date_notified;
 211              $this->is_new            = (int) $notification->is_new;
 212          }
 213      }
 214  
 215      /** Protected Static Methods **********************************************/
 216  
 217      /**
 218       * Create a notification entry.
 219       *
 220       * @since 1.9.0
 221       *
 222       * @global wpdb $wpdb WordPress database object.
 223       *
 224       * @see wpdb::insert() for further description of paramater formats.
 225       *
 226       * @param array $data {
 227       *     Array of notification data, passed to {@link wpdb::insert()}.
 228       *     @type int    $user_id           ID of the associated user.
 229       *     @type int    $item_id           ID of the associated item.
 230       *     @type int    $secondary_item_id ID of the secondary associated item.
 231       *     @type string $component_name    Name of the associated component.
 232       *     @type string $component_action  Name of the associated component
 233       *                                     action.
 234       *     @type string $date_notified     Timestamp of the notification.
 235       *     @type bool   $is_new            True if the notification is unread, otherwise false.
 236       * }
 237       * @param array $data_format See {@link wpdb::insert()}.
 238       * @return int|false The number of rows inserted, or false on error.
 239       */
 240  	protected static function _insert( $data = array(), $data_format = array() ) {
 241          global $wpdb;
 242          return $wpdb->insert( buddypress()->notifications->table_name, $data, $data_format );
 243      }
 244  
 245      /**
 246       * Update notifications.
 247       *
 248       * @since 1.9.0
 249       *
 250       * @global wpdb $wpdb WordPress database object.
 251       *
 252       * @see wpdb::update() for further description of paramater formats.
 253       *
 254       * @param array $data         Array of notification data to update, passed to
 255       *                            {@link wpdb::update()}. Accepts any property of a
 256       *                            BP_Notification_Notification object.
 257       * @param array $where        The WHERE params as passed to wpdb::update().
 258       *                            Typically consists of array( 'ID' => $id ) to specify the ID
 259       *                            of the item being updated. See {@link wpdb::update()}.
 260       * @param array $data_format  See {@link wpdb::insert()}.
 261       * @param array $where_format See {@link wpdb::insert()}.
 262       * @return int|false The number of rows updated, or false on error.
 263       */
 264  	protected static function _update( $data = array(), $where = array(), $data_format = array(), $where_format = array() ) {
 265          global $wpdb;
 266          return $wpdb->update( buddypress()->notifications->table_name, $data, $where, $data_format, $where_format );
 267      }
 268  
 269      /**
 270       * Delete notifications.
 271       *
 272       * @since 1.9.0
 273       *
 274       * @global wpdb $wpdb WordPress database object.
 275       *
 276       * @see wpdb::delete() for further description of paramater formats.
 277       *
 278       * @param array $where        Array of WHERE clauses to filter by, passed to
 279       *                            {@link wpdb::delete()}. Accepts any property of a
 280       *                            BP_Notification_Notification object.
 281       * @param array $where_format See {@link wpdb::insert()}.
 282       * @return int|false The number of rows updated, or false on error.
 283       */
 284  	protected static function _delete( $where = array(), $where_format = array() ) {
 285          global $wpdb;
 286          return $wpdb->delete( buddypress()->notifications->table_name, $where, $where_format );
 287      }
 288  
 289      /**
 290       * Assemble the WHERE clause of a get() SQL statement.
 291       *
 292       * Used by BP_Notifications_Notification::get() to create its WHERE
 293       * clause.
 294       *
 295       * @since 1.9.0
 296       *
 297       * @global wpdb $wpdb WordPress database object.
 298       *
 299       * @param array  $args           See {@link BP_Notifications_Notification::get()}
 300       *                               for more details.
 301       * @param string $select_sql     SQL SELECT fragment.
 302       * @param string $from_sql       SQL FROM fragment.
 303       * @param string $join_sql       SQL JOIN fragment.
 304       * @param string $meta_query_sql SQL meta query fragment.
 305       * @return string WHERE clause.
 306       */
 307  	protected static function get_where_sql( $args = array(), $select_sql = '', $from_sql = '', $join_sql = '', $meta_query_sql = '' ) {
 308          global $wpdb;
 309  
 310          $where_conditions = array();
 311          $where            = '';
 312  
 313          // The id.
 314          if ( ! empty( $args['id'] ) ) {
 315              $id_in = implode( ',', wp_parse_id_list( $args['id'] ) );
 316              $where_conditions['id'] = "id IN ({$id_in})";
 317          }
 318  
 319          // The user_id.
 320          if ( ! empty( $args['user_id'] ) ) {
 321              $user_id_in = implode( ',', wp_parse_id_list( $args['user_id'] ) );
 322              $where_conditions['user_id'] = "user_id IN ({$user_id_in})";
 323          }
 324  
 325          // The item_id.
 326          if ( ! empty( $args['item_id'] ) ) {
 327              $item_id_in = implode( ',', wp_parse_id_list( $args['item_id'] ) );
 328              $where_conditions['item_id'] = "item_id IN ({$item_id_in})";
 329          }
 330  
 331          // The secondary_item_id.
 332          if ( ! empty( $args['secondary_item_id'] ) ) {
 333              $secondary_item_id_in = implode( ',', wp_parse_id_list( $args['secondary_item_id'] ) );
 334              $where_conditions['secondary_item_id'] = "secondary_item_id IN ({$secondary_item_id_in})";
 335          }
 336  
 337          // The component_name.
 338          if ( ! empty( $args['component_name'] ) ) {
 339              if ( ! is_array( $args['component_name'] ) ) {
 340                  $component_names = explode( ',', $args['component_name'] );
 341              } else {
 342                  $component_names = $args['component_name'];
 343              }
 344  
 345              $cn_clean = array();
 346              foreach ( $component_names as $cn ) {
 347                  $cn_clean[] = $wpdb->prepare( '%s', $cn );
 348              }
 349  
 350              $cn_in = implode( ',', $cn_clean );
 351              $where_conditions['component_name'] = "component_name IN ({$cn_in})";
 352          }
 353  
 354          // The component_action.
 355          if ( ! empty( $args['component_action'] ) ) {
 356              if ( ! is_array( $args['component_action'] ) ) {
 357                  $component_actions = explode( ',', $args['component_action'] );
 358              } else {
 359                  $component_actions = $args['component_action'];
 360              }
 361  
 362              $ca_clean = array();
 363              foreach ( $component_actions as $ca ) {
 364                  $ca_clean[] = $wpdb->prepare( '%s', $ca );
 365              }
 366  
 367              $ca_in = implode( ',', $ca_clean );
 368              $where_conditions['component_action'] = "component_action IN ({$ca_in})";
 369          }
 370  
 371          // If is_new.
 372          if ( ! empty( $args['is_new'] ) && 'both' !== $args['is_new'] ) {
 373              $where_conditions['is_new'] = "is_new = 1";
 374          } elseif ( isset( $args['is_new'] ) && ( 0 === $args['is_new'] || false === $args['is_new'] ) ) {
 375              $where_conditions['is_new'] = "is_new = 0";
 376          }
 377  
 378          // The search_terms.
 379          if ( ! empty( $args['search_terms'] ) ) {
 380              $search_terms_like = '%' . bp_esc_like( $args['search_terms'] ) . '%';
 381              $where_conditions['search_terms'] = $wpdb->prepare( "( component_name LIKE %s OR component_action LIKE %s )", $search_terms_like, $search_terms_like );
 382          }
 383  
 384          // The date query.
 385          if ( ! empty( $args['date_query'] ) ) {
 386              $where_conditions['date_query'] = self::get_date_query_sql( $args['date_query'] );
 387          }
 388  
 389          // The meta query.
 390          if ( ! empty( $meta_query_sql['where'] ) ) {
 391              $where_conditions['meta_query'] = $meta_query_sql['where'];
 392          }
 393  
 394          /**
 395           * Filters the MySQL WHERE conditions for the Notifications items get method.
 396           *
 397           * @since 2.3.0
 398           *
 399           * @param array  $where_conditions Current conditions for MySQL WHERE statement.
 400           * @param array  $args             Parsed arguments passed into method.
 401           * @param string $select_sql       Current SELECT MySQL statement at point of execution.
 402           * @param string $from_sql         Current FROM MySQL statement at point of execution.
 403           * @param string $join_sql         Current INNER JOIN MySQL statement at point of execution.
 404           * @param string $meta_query_sql   Current meta query WHERE statement at point of execution.
 405           */
 406          $where_conditions = apply_filters( 'bp_notifications_get_where_conditions', $where_conditions, $args, $select_sql, $from_sql, $join_sql, $meta_query_sql );
 407  
 408          // Custom WHERE.
 409          if ( ! empty( $where_conditions ) ) {
 410              $where = 'WHERE ' . implode( ' AND ', $where_conditions );
 411          }
 412  
 413          return $where;
 414      }
 415  
 416      /**
 417       * Assemble the ORDER BY clause of a get() SQL statement.
 418       *
 419       * Used by BP_Notifications_Notification::get() to create its ORDER BY
 420       * clause.
 421       *
 422       * @since 1.9.0
 423       *
 424       * @param array $args See {@link BP_Notifications_Notification::get()}
 425       *                    for more details.
 426       * @return string ORDER BY clause.
 427       */
 428  	protected static function get_order_by_sql( $args = array() ) {
 429  
 430          // Setup local variable.
 431          $conditions = array();
 432          $retval     = '';
 433  
 434          // Order by.
 435          if ( ! empty( $args['order_by'] ) ) {
 436              $order_by_clean = array();
 437              foreach ( (array) $args['order_by'] as $key => $value ) {
 438                  if ( in_array( $value, self::$columns, true ) ) {
 439                      $order_by_clean[] = $value;
 440                  }
 441              }
 442              if ( ! empty( $order_by_clean ) ) {
 443                  $order_by               = implode( ', ', $order_by_clean );
 444                  $conditions['order_by'] = "{$order_by}";
 445              }
 446          }
 447  
 448          // Sort order direction.
 449          if ( ! empty( $args['sort_order'] ) ) {
 450              $sort_order               = bp_esc_sql_order( $args['sort_order'] );
 451              $conditions['sort_order'] = "{$sort_order}";
 452          }
 453  
 454          // Custom ORDER BY.
 455          if ( ! empty( $conditions ) ) {
 456              $retval = 'ORDER BY ' . implode( ' ', $conditions );
 457          }
 458  
 459          return $retval;
 460      }
 461  
 462      /**
 463       * Assemble the LIMIT clause of a get() SQL statement.
 464       *
 465       * Used by BP_Notifications_Notification::get() to create its LIMIT clause.
 466       *
 467       * @since 1.9.0
 468       *
 469       * @global wpdb $wpdb WordPress database object.
 470       *
 471       * @param array $args See {@link BP_Notifications_Notification::get()}
 472       *                    for more details.
 473       * @return string $retval LIMIT clause.
 474       */
 475  	protected static function get_paged_sql( $args = array() ) {
 476          global $wpdb;
 477  
 478          // Setup local variable.
 479          $retval = '';
 480  
 481          // Custom LIMIT.
 482          if ( ! empty( $args['page'] ) && ! empty( $args['per_page'] ) ) {
 483              $page     = absint( $args['page']     );
 484              $per_page = absint( $args['per_page'] );
 485              $offset   = $per_page * ( $page - 1 );
 486              $retval   = $wpdb->prepare( "LIMIT %d, %d", $offset, $per_page );
 487          }
 488  
 489          return $retval;
 490      }
 491  
 492      /**
 493       * Assemble query clauses, based on arguments, to pass to $wpdb methods.
 494       *
 495       * The insert(), update(), and delete() methods of {@link wpdb} expect
 496       * arguments of the following forms:
 497       *
 498       * - associative arrays whose key/value pairs are column => value, to
 499       *   be used in WHERE, SET, or VALUES clauses.
 500       * - arrays of "formats", which tell $wpdb->prepare() which type of
 501       *   value to expect when sanitizing (eg, array( '%s', '%d' ))
 502       *
 503       * This utility method can be used to assemble both kinds of params,
 504       * out of a single set of associative array arguments, such as:
 505       *
 506       *     $args = array(
 507       *         'user_id' => 4,
 508       *         'component_name' => 'groups',
 509       *     );
 510       *
 511       * This will be converted to:
 512       *
 513       *     array(
 514       *         'data' => array(
 515       *             'user_id' => 4,
 516       *             'component_name' => 'groups',
 517       *         ),
 518       *         'format' => array(
 519       *             '%d',
 520       *             '%s',
 521       *         ),
 522       *     )
 523       *
 524       * which can easily be passed as arguments to the $wpdb methods.
 525       *
 526       * @since 1.9.0
 527       *
 528       * @param array $args Associative array of filter arguments.
 529       *                    See {@BP_Notifications_Notification::get()}
 530       *                    for a breakdown.
 531       * @return array Associative array of 'data' and 'format' args.
 532       */
 533  	protected static function get_query_clauses( $args = array() ) {
 534          $where_clauses = array(
 535              'data'   => array(),
 536              'format' => array(),
 537          );
 538  
 539          // The id.
 540          if ( ! empty( $args['id'] ) ) {
 541              $where_clauses['data']['id'] = absint( $args['id'] );
 542              $where_clauses['format'][] = '%d';
 543          }
 544  
 545          // The user_id.
 546          if ( ! empty( $args['user_id'] ) ) {
 547              $where_clauses['data']['user_id'] = absint( $args['user_id'] );
 548              $where_clauses['format'][] = '%d';
 549          }
 550  
 551          // The item_id.
 552          if ( ! empty( $args['item_id'] ) ) {
 553              $where_clauses['data']['item_id'] = absint( $args['item_id'] );
 554              $where_clauses['format'][] = '%d';
 555          }
 556  
 557          // The secondary_item_id.
 558          if ( ! empty( $args['secondary_item_id'] ) ) {
 559              $where_clauses['data']['secondary_item_id'] = absint( $args['secondary_item_id'] );
 560              $where_clauses['format'][] = '%d';
 561          }
 562  
 563          // The component_name.
 564          if ( ! empty( $args['component_name'] ) ) {
 565              $where_clauses['data']['component_name'] = $args['component_name'];
 566              $where_clauses['format'][] = '%s';
 567          }
 568  
 569          // The component_action.
 570          if ( ! empty( $args['component_action'] ) ) {
 571              $where_clauses['data']['component_action'] = $args['component_action'];
 572              $where_clauses['format'][] = '%s';
 573          }
 574  
 575          // If is_new.
 576          if ( isset( $args['is_new'] ) ) {
 577              $where_clauses['data']['is_new'] = ! empty( $args['is_new'] ) ? 1 : 0;
 578              $where_clauses['format'][] = '%d';
 579          }
 580  
 581          return $where_clauses;
 582      }
 583  
 584      /** Public Static Methods *************************************************/
 585  
 586      /**
 587       * Check that a specific notification is for a specific user.
 588       *
 589       * @since 1.9.0
 590       *
 591       * @global BuddyPress $bp The one true BuddyPress instance.
 592       * @global wpdb $wpdb WordPress database object.
 593       *
 594       * @param int $user_id         ID of the user being checked.
 595       * @param int $notification_id ID of the notification being checked.
 596       * @return bool True if the notification belongs to the user, otherwise false.
 597       */
 598  	public static function check_access( $user_id = 0, $notification_id = 0 ) {
 599          global $wpdb;
 600  
 601          $bp = buddypress();
 602  
 603          $query   = "SELECT COUNT(id) FROM {$bp->notifications->table_name} WHERE id = %d AND user_id = %d";
 604          $prepare = $wpdb->prepare( $query, $notification_id, $user_id );
 605          $result  = $wpdb->get_var( $prepare );
 606  
 607          return $result;
 608      }
 609  
 610      /**
 611       * Parse notifications query arguments.
 612       *
 613       * @since 2.3.0
 614       *
 615       * @param array|string $args Args to parse.
 616       * @return array
 617       */
 618  	public static function parse_args( $args = '' ) {
 619          return bp_parse_args(
 620              $args,
 621              array(
 622                  'id'                => false,
 623                  'user_id'           => false,
 624                  'item_id'           => false,
 625                  'secondary_item_id' => false,
 626                  'component_name'    => bp_notifications_get_registered_components(),
 627                  'component_action'  => false,
 628                  'is_new'            => true,
 629                  'search_terms'      => '',
 630                  'order_by'          => false,
 631                  'sort_order'        => false,
 632                  'page'              => false,
 633                  'per_page'          => false,
 634                  'meta_query'        => false,
 635                  'date_query'        => false,
 636                  'update_meta_cache' => true,
 637              )
 638          );
 639      }
 640  
 641      /**
 642       * Get notifications, based on provided filter parameters.
 643       *
 644       * @since 1.9.0
 645       *
 646       * @global BuddyPress $bp The one true BuddyPress instance.
 647       * @global wpdb $wpdb WordPress database object.
 648       *
 649       * @param array $args {
 650       *     Associative array of arguments. All arguments but $page and
 651       *     $per_page can be treated as filter values for get_where_sql()
 652       *     and get_query_clauses(). All items are optional.
 653       *     @type int|array    $id                ID of notification being updated. Can be an
 654       *                                           array of IDs.
 655       *     @type int|array    $user_id           ID of user being queried. Can be an
 656       *                                           array of user IDs.
 657       *     @type int|array    $item_id           ID of associated item. Can be an array
 658       *                                           of multiple item IDs.
 659       *     @type int|array    $secondary_item_id ID of secondary associated
 660       *                                           item. Can be an array of multiple IDs.
 661       *     @type string|array $component_name    Name of the component to
 662       *                                           filter by. Can be an array of component names.
 663       *     @type string|array $component_action  Name of the action to
 664       *                                           filter by. Can be an array of actions.
 665       *     @type bool         $is_new            Whether to limit to new notifications. True
 666       *                                           returns only new notifications, false returns only non-new
 667       *                                           notifications. 'both' returns all. Default: true.
 668       *     @type string       $search_terms      Term to match against component_name
 669       *                                           or component_action fields.
 670       *     @type string       $order_by          Database column to order notifications by.
 671       *     @type string       $sort_order        Either 'ASC' or 'DESC'.
 672       *     @type string       $order_by          Field to order results by.
 673       *     @type string       $sort_order        ASC or DESC.
 674       *     @type int          $page              Number of the current page of results. Default:
 675       *                                           false (no pagination - all items).
 676       *     @type int          $per_page          Number of items to show per page. Default:
 677       *                                           false (no pagination - all items).
 678       *     @type array        $meta_query        Array of meta_query conditions. See WP_Meta_Query::queries.
 679       *     @type array        $date_query        Array of date_query conditions. See first parameter of
 680       *                                           WP_Date_Query::__construct().
 681       *     @type bool         $update_meta_cache Whether to update meta cache. Default: true.
 682       * }
 683       * @return array Located notifications.
 684       */
 685  	public static function get( $args = array() ) {
 686          global $wpdb;
 687  
 688          // Parse the arguments.
 689          $r = self::parse_args( $args );
 690  
 691          // Get BuddyPress.
 692          $bp = buddypress();
 693  
 694          // METADATA.
 695          $meta_query_sql = self::get_meta_query_sql( $r['meta_query'] );
 696  
 697          // SELECT.
 698          $select_sql = "SELECT *";
 699  
 700          // FROM.
 701          $from_sql   = "FROM {$bp->notifications->table_name} n ";
 702  
 703          // JOIN.
 704          $join_sql   = $meta_query_sql['join'];
 705  
 706          // WHERE.
 707          $where_sql  = self::get_where_sql( array(
 708              'id'                => $r['id'],
 709              'user_id'           => $r['user_id'],
 710              'item_id'           => $r['item_id'],
 711              'secondary_item_id' => $r['secondary_item_id'],
 712              'component_name'    => $r['component_name'],
 713              'component_action'  => $r['component_action'],
 714              'is_new'            => $r['is_new'],
 715              'search_terms'      => $r['search_terms'],
 716              'date_query'        => $r['date_query']
 717          ), $select_sql, $from_sql, $join_sql, $meta_query_sql );
 718  
 719          // ORDER BY.
 720          $order_sql  = self::get_order_by_sql( array(
 721              'order_by'   => $r['order_by'],
 722              'sort_order' => $r['sort_order']
 723          ) );
 724  
 725          // LIMIT %d, %d.
 726          $pag_sql    = self::get_paged_sql( array(
 727              'page'     => $r['page'],
 728              'per_page' => $r['per_page']
 729          ) );
 730  
 731          // Concatenate query parts.
 732          $sql = "{$select_sql} {$from_sql} {$join_sql} {$where_sql} {$order_sql} {$pag_sql}";
 733  
 734          $results = $wpdb->get_results( $sql );
 735  
 736          // Integer casting.
 737          foreach ( $results as $key => $result ) {
 738              $results[$key]->id                = (int) $results[$key]->id;
 739              $results[$key]->user_id           = (int) $results[$key]->user_id;
 740              $results[$key]->item_id           = (int) $results[$key]->item_id;
 741              $results[$key]->secondary_item_id = (int) $results[$key]->secondary_item_id;
 742              $results[$key]->is_new            = (int) $results[$key]->is_new;
 743          }
 744  
 745          // Update meta cache.
 746          if ( true === $r['update_meta_cache'] ) {
 747              bp_notifications_update_meta_cache( wp_list_pluck( $results, 'id' ) );
 748          }
 749  
 750          return $results;
 751      }
 752  
 753      /**
 754       * Get a count of total notifications matching a set of arguments.
 755       *
 756       * @since 1.9.0
 757       *
 758       * @global BuddyPress $bp The one true BuddyPress instance.
 759       * @global wpdb $wpdb WordPress database object.
 760       *
 761       * @param array|string $args See {@link BP_Notifications_Notification::get()}.
 762       * @return int Count of located items.
 763       */
 764  	public static function get_total_count( $args ) {
 765          global $wpdb;
 766  
 767          // Parse the arguments.
 768          $r = self::parse_args( $args );
 769  
 770          // Load BuddyPress.
 771          $bp = buddypress();
 772  
 773          // METADATA.
 774          $meta_query_sql = self::get_meta_query_sql( $r['meta_query'] );
 775  
 776          // SELECT.
 777          $select_sql = "SELECT COUNT(*)";
 778  
 779          // FROM.
 780          $from_sql   = "FROM {$bp->notifications->table_name} n ";
 781  
 782          // JOIN.
 783          $join_sql   = $meta_query_sql['join'];
 784  
 785          // WHERE.
 786          $where_sql  = self::get_where_sql( array(
 787              'id'                => $r['id'],
 788              'user_id'           => $r['user_id'],
 789              'item_id'           => $r['item_id'],
 790              'secondary_item_id' => $r['secondary_item_id'],
 791              'component_name'    => $r['component_name'],
 792              'component_action'  => $r['component_action'],
 793              'is_new'            => $r['is_new'],
 794              'search_terms'      => $r['search_terms'],
 795              'date_query'        => $r['date_query']
 796          ), $select_sql, $from_sql, $join_sql, $meta_query_sql );
 797  
 798          // Concatenate query parts.
 799          $sql = "{$select_sql} {$from_sql} {$join_sql} {$where_sql}";
 800  
 801          // Return the queried results.
 802          return (int) $wpdb->get_var( $sql );
 803      }
 804  
 805      /**
 806       * Get the SQL for the 'meta_query' param in BP_Notifications_Notification::get().
 807       *
 808       * We use WP_Meta_Query to do the heavy lifting of parsing the
 809       * meta_query array and creating the necessary SQL clauses. However,
 810       * since BP_Notifications_Notification::get() builds its SQL differently than
 811       * WP_Query, we have to alter the return value (stripping the leading
 812       * AND keyword from the 'where' clause).
 813       *
 814       * @since 2.3.0
 815       *
 816       * @param  array $meta_query An array of meta_query filters. See the
 817       *                           documentation for WP_Meta_Query for details.
 818       * @return array $sql_array 'join' and 'where' clauses.
 819       */
 820  	public static function get_meta_query_sql( $meta_query = array() ) {
 821  
 822          // Default array keys & empty values.
 823          $sql_array = array(
 824              'join'  => '',
 825              'where' => '',
 826          );
 827  
 828          // Bail if no meta query.
 829          if ( empty( $meta_query ) ) {
 830              return $sql_array;
 831          }
 832  
 833          // WP_Meta_Query expects the table name at $wpdb->notificationmeta.
 834          $GLOBALS['wpdb']->notificationmeta = buddypress()->notifications->table_name_meta;
 835  
 836          $n_meta_query = new WP_Meta_Query( $meta_query );
 837          $meta_sql     = $n_meta_query->get_sql( 'notification', 'n', 'id' );
 838  
 839          // Strip the leading AND - it's handled in get().
 840          $sql_array['where'] = preg_replace( '/^\sAND/', '', $meta_sql['where'] );
 841          $sql_array['join']  = $meta_sql['join'];
 842  
 843          return $sql_array;
 844      }
 845  
 846      /**
 847       * Get the SQL for the 'date_query' param in BP_Notifications_Notification::get().
 848       *
 849       * We use BP_Date_Query, which extends WP_Date_Query, to do the heavy lifting
 850       * of parsing the date_query array and creating the necessary SQL clauses.
 851       *
 852       * @since 2.3.0
 853       *
 854       * @param array $date_query An array of date_query parameters. See the
 855       *                          documentation for the first parameter of WP_Date_Query.
 856       * @return string
 857       */
 858  	public static function get_date_query_sql( $date_query = array() ) {
 859          return BP_Date_Query::get_where_sql( $date_query, 'n.date_notified' );
 860      }
 861  
 862      /**
 863       * Update notifications.
 864       *
 865       * @since 1.9.0
 866       *
 867       * @see BP_Notifications_Notification::get() for a description of
 868       *      accepted update/where arguments.
 869       *
 870       * @param array $update_args Associative array of fields to update,
 871       *                           and the values to update them to. Of the format
 872       *                           array( 'user_id' => 4, 'component_name' => 'groups', ).
 873       * @param array $where_args  Associative array of columns/values, to
 874       *                           determine which rows should be updated. Of the format
 875       *                           array( 'item_id' => 7, 'component_action' => 'members', ).
 876       * @return int|false Number of rows updated on success, false on failure.
 877       */
 878  	public static function update( $update_args = array(), $where_args = array() ) {
 879          $update = self::get_query_clauses( $update_args );
 880          $where  = self::get_query_clauses( $where_args );
 881  
 882          /**
 883           * Fires before the update of a notification item.
 884           *
 885           * @since 2.3.0
 886           *
 887           * @param array $update_args See BP_Notifications_Notification::update().
 888           * @param array $where_args  See BP_Notifications_Notification::update().
 889           */
 890          do_action( 'bp_notification_before_update', $update_args, $where_args );
 891  
 892          return self::_update(
 893              $update['data'],
 894              $where['data'],
 895              $update['format'],
 896              $where['format']
 897          );
 898      }
 899  
 900      /**
 901       * Update notifications using a list of ids/items_ids.
 902       *
 903       * @since 10.0.0
 904       *
 905       * @param string $field The name of the db field of the items to update.
 906       *                      Possible values are `id` or `item_id`.
 907       * @param int[]  $items The list of items to update.
 908       * @param array  $data  Array of notification data to update.
 909       * @param array  $where The WHERE params to use to specify the item IDs to update.
 910       * @return int|false    The number of updated rows. False on error.
 911       */
 912  	public static function update_id_list( $field, $items = array(), $data = array(), $where = array() ) {
 913          global $wpdb;
 914          $bp = buddypress();
 915  
 916          $supported_fields = array( 'id', 'item_id' );
 917  
 918          if ( false === in_array( $field, $supported_fields, true ) ) {
 919              return false;
 920          }
 921  
 922          if ( ! is_array( $items ) || ! is_array( $data ) || ! is_array( $where ) ) {
 923              return false;
 924          }
 925  
 926          $update_args = self::get_query_clauses( $data );
 927          $where_args  = self::get_query_clauses( $where );
 928  
 929          $fields     = array();
 930          $conditions = array();
 931          $values     = array();
 932  
 933          $_items       = implode( ',', wp_parse_id_list( $items ) );
 934          $conditions[] = "{$field} IN ({$_items})";
 935  
 936          foreach ( $update_args['data'] as $update_field => $value ) {
 937              $index  = array_search( $update_field, array_keys( $update_args['data'] ) );
 938              $format = $update_args['format'][ $index ];
 939  
 940              $fields[] = "{$update_field} = {$format}";
 941              $values[] = $value;
 942          }
 943  
 944          foreach ( $where_args['data'] as $where_field => $value ) {
 945              $index  = array_search( $where_field, array_keys( $where_args['data'] ) );
 946              $format = $where_args['format'][ $index ];
 947  
 948              $conditions[] = "{$where_field} = {$format}";
 949              $values[]     = $value;
 950          }
 951  
 952          $fields     = implode( ', ', $fields );
 953          $conditions = implode( ' AND ', $conditions );
 954  
 955          if ( 'item_id' === $field && isset( $where_args['data']['user_id'] ) ) {
 956              $where_args['item_ids'] = $items;
 957              $where_args['user_id']  = $where_args['data']['user_id'];
 958          } elseif ( 'id' === $field ) {
 959              $where_args['ids'] = $items;
 960          }
 961  
 962          /** This action is documented in bp-notifications/classes/class-bp-notifications-notification.php */
 963          do_action( 'bp_notification_before_update', $update_args, $where_args );
 964  
 965          return $wpdb->query( $wpdb->prepare( "UPDATE {$bp->notifications->table_name} SET {$fields} WHERE {$conditions}", $values ) );
 966      }
 967  
 968      /**
 969       * Delete notifications.
 970       *
 971       * @since 1.9.0
 972       *
 973       * @see BP_Notifications_Notification::get() for a description of
 974       *      accepted where arguments.
 975       *
 976       * @param array $args Associative array of columns/values, to determine
 977       *                    which rows should be deleted.  Of the format
 978       *                    array( 'item_id' => 7, 'component_action' => 'members', ).
 979       * @return int|false Number of rows deleted on success, false on failure.
 980       */
 981  	public static function delete( $args = array() ) {
 982          $where = self::get_query_clauses( $args );
 983  
 984          /**
 985           * Fires before the deletion of a notification item.
 986           *
 987           * @since 2.0.0
 988           *
 989           * @param array $args Associative array of columns/values, to determine
 990           *                    which rows should be deleted. Of the format
 991           *                    array( 'item_id' => 7, 'component_action' => 'members' ).
 992           */
 993          do_action( 'bp_notification_before_delete', $args );
 994  
 995          return self::_delete( $where['data'], $where['format'] );
 996      }
 997  
 998      /**
 999       * Delete notifications using a list of ids/items_ids.
1000       *
1001       * @since 10.0.0
1002       *
1003       * @param string $field The name of the db field of the items to delete.
1004       *                      Possible values are `id` or `item_id`.
1005       * @param int[]  $items The list of items to delete.
1006       * @param array  $args  The WHERE arguments to use to specify the item IDs to delete.
1007       * @return int|false    The number of deleted rows. False on error.
1008       */
1009  	public static function delete_by_id_list( $field, $items = array(), $args = array() ) {
1010          global $wpdb;
1011          $bp = buddypress();
1012  
1013          $supported_fields = array( 'id', 'item_id' );
1014  
1015          if ( false === in_array( $field, $supported_fields, true ) ) {
1016              return false;
1017          }
1018  
1019          if ( ! is_array( $items ) || ! is_array( $args ) ) {
1020              return false;
1021          }
1022  
1023          $where = self::get_query_clauses( $args );
1024  
1025          $conditions = array();
1026          $values     = array();
1027  
1028          $_items       = implode( ',', wp_parse_id_list( $items ) );
1029          $conditions[] = "{$field} IN ({$_items})";
1030  
1031          foreach ( $where['data'] as $where_field => $value ) {
1032              $index  = array_search( $where_field, array_keys( $where['data'] ) );
1033              $format = $where['format'][ $index ];
1034  
1035              $conditions[] = "{$where_field} = {$format}";
1036              $values[]     = $value;
1037          }
1038  
1039          $conditions = implode( ' AND ', $conditions );
1040  
1041          if ( 'id' === $field ) {
1042              $args['id'] = $items;
1043          }
1044  
1045          /** This action is documented in bp-notifications/classes/class-bp-notifications-notification.php */
1046          do_action( 'bp_notification_before_delete', $args );
1047  
1048          if ( ! $values ) {
1049              return $wpdb->query( "DELETE FROM {$bp->notifications->table_name} WHERE {$conditions}" );
1050          }
1051  
1052          return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->notifications->table_name} WHERE {$conditions}", $values ) );
1053      }
1054  
1055      /** Convenience methods ***************************************************/
1056  
1057      /**
1058       * Delete a single notification by ID.
1059       *
1060       * @since 1.9.0
1061       *
1062       * @see BP_Notifications_Notification::delete() for explanation of
1063       *      return value.
1064       *
1065       * @param int $id ID of the notification item to be deleted.
1066       * @return int|false True on success, false on failure.
1067       */
1068  	public static function delete_by_id( $id ) {
1069          return self::delete( array(
1070              'id' => $id,
1071          ) );
1072      }
1073  
1074      /**
1075       * Fetch all the notifications in the database for a specific user.
1076       *
1077       * @since 1.9.0
1078       *
1079       * @param int    $user_id ID of the user whose notifications are being
1080       *                        fetched.
1081       * @param string $status  Optional. Status of notifications to fetch.
1082       *                        'is_new' to get only unread items, 'all' to get all.
1083       * @return array Associative array of notification items.
1084       */
1085  	public static function get_all_for_user( $user_id, $status = 'is_new' ) {
1086          return self::get( array(
1087              'user_id' => $user_id,
1088              'is_new'  => 'is_new' === $status,
1089          ) );
1090      }
1091  
1092      /**
1093       * Fetch all the unread notifications in the database for a specific user.
1094       *
1095       * @since 1.9.0
1096       *
1097       * @param int $user_id ID of the user whose notifications are being
1098       *                     fetched.
1099       * @return array Associative array of unread notification items.
1100       */
1101  	public static function get_unread_for_user( $user_id = 0 ) {
1102          return self::get( array(
1103              'user_id' => $user_id,
1104              'is_new'  => true,
1105          ) );
1106      }
1107  
1108      /**
1109       * Fetch all the read notifications in the database for a specific user.
1110       *
1111       * @since 1.9.0
1112       *
1113       * @param int $user_id ID of the user whose notifications are being
1114       *                     fetched.
1115       * @return array Associative array of unread notification items.
1116       */
1117  	public static function get_read_for_user( $user_id = 0 ) {
1118          return self::get( array(
1119              'user_id' => $user_id,
1120              'is_new'  => false,
1121          ) );
1122      }
1123  
1124      /**
1125       * Get unread notifications for a user, in a pagination-friendly format.
1126       *
1127       * @since 1.9.0
1128       *
1129       * @param array $args {
1130       *     Array of arguments.
1131       *     @type int    $user_id      ID of the user for whom the notifications are
1132       *                                being fetched. Default: logged-in user ID.
1133       *     @type bool   $is_new       Whether to limit the query to unread
1134       *                                notifications. Default: true.
1135       *     @type int    $page         Number of the page to return. Default: 1.
1136       *     @type int    $per_page     Number of results to display per page.
1137       *                                Default: 10.
1138       *     @type string $search_terms Optional. A term to search against in
1139       *                                the 'component_name' and 'component_action' columns.
1140       * }
1141       * @return array {
1142       *     @type array $notifications Array of notification results.
1143       *     @type int   $total         Count of all located notifications matching
1144       *                                the query params.
1145       * }
1146       */
1147  	public static function get_current_notifications_for_user( $args = array() ) {
1148          $r = bp_parse_args(
1149              $args,
1150              array(
1151                  'user_id'      => bp_loggedin_user_id(),
1152                  'is_new'       => true,
1153                  'page'         => 1,
1154                  'per_page'     => 25,
1155                  'search_terms' => '',
1156              )
1157          );
1158  
1159          $notifications = self::get( $r );
1160  
1161          // Bail if no notifications.
1162          if ( empty( $notifications ) ) {
1163              return false;
1164          }
1165  
1166          $total_count = self::get_total_count( $r );
1167  
1168          return array( 'notifications' => &$notifications, 'total' => $total_count );
1169      }
1170  
1171      /** Mark ******************************************************************/
1172  
1173      /**
1174       * Mark all user notifications as read.
1175       *
1176       * @since 1.9.0
1177       *
1178       * @param int    $user_id           The ID of the user who the notifications are for.
1179       * @param int    $is_new            Mark as read (1) or unread (0).
1180       * @param int    $item_id           Item ID being acted on.
1181       * @param string $component_name    Name of component the notifications are for.
1182       * @param string $component_action  Name of the component action.
1183       * @param int    $secondary_item_id The ID of the secondary item.
1184       * @return int|false False on failure to update. ID on success.
1185       */
1186  	public static function mark_all_for_user( $user_id, $is_new = 0, $item_id = 0, $component_name = '', $component_action = '', $secondary_item_id = 0 ) {
1187  
1188          // Values to be updated.
1189          $update_args = array(
1190              'is_new' => $is_new,
1191          );
1192  
1193          // WHERE clauses.
1194          $where_args = array(
1195              'user_id' => $user_id,
1196          );
1197  
1198          if ( ! empty( $item_id ) ) {
1199              $where_args['item_id'] = $item_id;
1200          }
1201  
1202          if ( ! empty( $component_name ) ) {
1203              $where_args['component_name'] = $component_name;
1204          }
1205  
1206          if ( ! empty( $component_action ) ) {
1207              $where_args['component_action'] = $component_action;
1208          }
1209  
1210          if ( ! empty( $secondary_item_id ) ) {
1211              $where_args['secondary_item_id'] = $secondary_item_id;
1212          }
1213  
1214          return self::update( $update_args, $where_args );
1215      }
1216  
1217      /**
1218       * Mark all notifications from a user as read.
1219       *
1220       * @since 1.9.0
1221       *
1222       * @param int    $user_id           The ID of the user who the notifications are from.
1223       * @param int    $is_new            Mark as read (1) or unread (0).
1224       * @param string $component_name    Name of component the notifications are for.
1225       * @param string $component_action  Name of the component action.
1226       * @param int    $secondary_item_id The ID of the secondary item.
1227       * @return int|false
1228       */
1229  	public static function mark_all_from_user( $user_id, $is_new = 0, $component_name = '', $component_action = '', $secondary_item_id = 0 ) {
1230  
1231          // Values to be updated.
1232          $update_args = array(
1233              'is_new' => $is_new,
1234          );
1235  
1236          // WHERE clauses.
1237          $where_args = array(
1238              'item_id' => $user_id,
1239          );
1240  
1241          if ( ! empty( $component_name ) ) {
1242              $where_args['component_name'] = $component_name;
1243          }
1244  
1245          if ( ! empty( $component_action ) ) {
1246              $where_args['component_action'] = $component_action;
1247          }
1248  
1249          if ( ! empty( $secondary_item_id ) ) {
1250              $where_args['secondary_item_id'] = $secondary_item_id;
1251          }
1252  
1253          return self::update( $update_args, $where_args );
1254      }
1255  
1256      /**
1257       * Mark all notifications for all users as read by item id, and optional
1258       * secondary item id, and component name and action.
1259       *
1260       * @since 1.9.0
1261       *
1262       * @param int    $item_id           The ID of the item associated with the
1263       *                                  notifications.
1264       * @param int    $is_new            Mark as read (1) or unread (0).
1265       * @param string $component_name    The component that the notifications
1266       *                                  are associated with.
1267       * @param string $component_action  The action that the notifications
1268       *                                  are associated with.
1269       * @param int    $secondary_item_id Optional. ID of the secondary
1270       *                                  associated item.
1271       * @return int|false
1272       */
1273  	public static function mark_all_by_type( $item_id, $is_new = 0, $component_name = '', $component_action = '', $secondary_item_id = 0 ) {
1274  
1275          // Values to be updated.
1276          $update_args = array(
1277              'is_new' => $is_new,
1278          );
1279  
1280          // WHERE clauses.
1281          $where_args = array(
1282              'item_id' => $item_id,
1283          );
1284  
1285          if ( ! empty( $component_name ) ) {
1286              $where_args['component_name'] = $component_name;
1287          }
1288  
1289          if ( ! empty( $component_action ) ) {
1290              $where_args['component_action'] = $component_action;
1291          }
1292  
1293          if ( ! empty( $secondary_item_id ) ) {
1294              $where_args['secondary_item_id'] = $secondary_item_id;
1295          }
1296  
1297          return self::update( $update_args, $where_args );
1298      }
1299  
1300      /**
1301       * Get a user's unread notifications, grouped by component and action.
1302       *
1303       * Multiple notifications of the same type (those that share the same component_name
1304       * and component_action) are collapsed for formatting as "You have 5 pending
1305       * friendship requests", etc. See bp_notifications_get_notifications_for_user().
1306       * For a full-fidelity list of user notifications, use
1307       * bp_notifications_get_all_notifications_for_user().
1308       *
1309       * @since 3.0.0
1310       *
1311       * @global BuddyPress $bp The one true BuddyPress instance.
1312       * @global wpdb $wpdb WordPress database object.
1313       *
1314       * @param int $user_id ID of the user whose notifications are being fetched.
1315       * @return array Notifications items for formatting into a list.
1316       */
1317  	public static function get_grouped_notifications_for_user( $user_id ) {
1318          global $wpdb;
1319  
1320          // Load BuddyPress.
1321          $bp = buddypress();
1322  
1323          // SELECT.
1324          $select_sql = "SELECT id, user_id, item_id, secondary_item_id, component_name, component_action, date_notified, is_new, COUNT(id) as total_count ";
1325  
1326          // FROM.
1327          $from_sql = "FROM {$bp->notifications->table_name} n ";
1328  
1329          // WHERE.
1330          $where_sql = self::get_where_sql( array(
1331              'user_id'        => $user_id,
1332              'is_new'         => 1,
1333              'component_name' => bp_notifications_get_registered_components(),
1334          ), $select_sql, $from_sql );
1335  
1336          // GROUP
1337          $group_sql = "GROUP BY user_id, component_name, component_action";
1338  
1339          // SORT
1340          $order_sql = "ORDER BY date_notified desc";
1341  
1342          // Concatenate query parts.
1343          $sql = "{$select_sql} {$from_sql} {$where_sql} {$group_sql} {$order_sql}";
1344  
1345          // Return the queried results.
1346          return $wpdb->get_results( $sql );
1347      }
1348  }


Generated: Sat Apr 27 01:00:55 2024 Cross-referenced by PHPXref 0.7.1