[ Index ] |
PHP Cross Reference of BuddyPress |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Nov 21 01:00:57 2024 | Cross-referenced by PHPXref 0.7.1 |