Ticket #6210: 6210.01.patch
File 6210.01.patch, 158.5 KB (added by , 9 years ago) |
---|
-
src/bp-core/admin/bp-core-admin-schema.php
diff --git src/bp-core/admin/bp-core-admin-schema.php src/bp-core/admin/bp-core-admin-schema.php index a603e6c..daa355d 100644
function bp_core_install( $active_components = false ) { 54 54 // Install the signups table. 55 55 bp_core_maybe_install_signups(); 56 56 57 // Notifications. 57 // Create/update the invitations table. 58 bp_core_install_invitations(); 59 60 // Notifications 58 61 if ( !empty( $active_components['notifications'] ) ) { 59 62 bp_core_install_notifications(); 60 63 } … … function bp_core_install_emails() { 564 567 */ 565 568 do_action( 'bp_core_install_emails' ); 566 569 } 570 571 /** 572 * Install database tables for the Invitations API 573 * 574 * @since 2.6.0 575 * 576 * @uses bp_core_set_charset() 577 * @uses bp_core_get_table_prefix() 578 * @uses dbDelta() 579 */ 580 function bp_core_install_invitations() { 581 $sql = array(); 582 $charset_collate = bp_core_set_charset(); 583 $bp_prefix = bp_core_get_table_prefix(); 584 $sql[] = "CREATE TABLE {$bp_prefix}bp_invitations ( 585 id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY, 586 user_id bigint(20) NOT NULL, 587 inviter_id bigint(20) NOT NULL, 588 invitee_email varchar(100) DEFAULT NULL, 589 component_name varchar(75) NOT NULL, 590 component_action varchar(75) NOT NULL, 591 item_id bigint(20) NOT NULL, 592 secondary_item_id bigint(20) DEFAULT NULL, 593 type varchar(12) NOT NULL DEFAULT 'invite', 594 content longtext DEFAULT '', 595 date_modified datetime NOT NULL, 596 invite_sent tinyint(1) NOT NULL DEFAULT '0', 597 accepted tinyint(1) NOT NULL DEFAULT '0', 598 KEY user_id (user_id), 599 KEY inviter_id (inviter_id), 600 KEY invitee_email (invitee_email), 601 KEY component_name (component_name), 602 KEY component_action (component_action), 603 KEY item_id (item_id), 604 KEY secondary_item_id (secondary_item_id), 605 KEY type (type), 606 KEY invite_sent (invite_sent), 607 KEY accepted (accepted) 608 ) {$charset_collate};"; 609 dbDelta( $sql ); 610 } -
src/bp-core/bp-core-classes.php
diff --git src/bp-core/bp-core-classes.php src/bp-core/bp-core-classes.php index bebf4ed..c6287ec 100644
require dirname( __FILE__ ) . '/classes/class-bp-email-recipient.php'; 30 30 require dirname( __FILE__ ) . '/classes/class-bp-email.php'; 31 31 require dirname( __FILE__ ) . '/classes/class-bp-email-delivery.php'; 32 32 require dirname( __FILE__ ) . '/classes/class-bp-phpmailer.php'; 33 require dirname( __FILE__ ) . '/classes/class-bp-invitations-component.php'; 34 require dirname( __FILE__ ) . '/classes/class-bp-invitations-invitation.php'; -
new file src/bp-core/bp-core-invitations.php
diff --git src/bp-core/bp-core-invitations.php src/bp-core/bp-core-invitations.php new file mode 100644 index 0000000..3270ee5
- + 1 <?php 2 /** 3 * BuddyPress invitations functions. 4 * 5 * @package BuddyPress 6 * @subpackage Invitations 7 * @since 2.7.0 8 */ 9 10 // Exit if accessed directly. 11 defined( 'ABSPATH' ) || exit; 12 13 /** Set up ********************************************************************/ 14 15 /** 16 * Start the invitations component. 17 * This is a very minimal component that has no screens/navigation items of its 18 * own, only a database. 19 * 20 * @since 2.7.0 21 */ 22 function bp_setup_invitations_component() { 23 buddypress()->invitations = new BP_Invitations_Component(); 24 } 25 add_action( 'bp_setup_components', 'bp_setup_invitations_component', 1 ); 26 27 28 /** Create ********************************************************************/ 29 30 /** 31 * Add an invitation to a specific user, from a specific user, related to a 32 * specific component. 33 * 34 * @since 2.7.0 35 * 36 * @param array $args { 37 * Array of arguments describing the invitation. All are optional. 38 * @type int $user_id ID of the invited user. 39 * @type int $inviter_id ID of the user who created the invitation. 40 * @type string $invitee_email Email address of the invited user. 41 * @type string $component_name Name of the related component. 42 * @type string $component_action Name of the related component action. 43 * @type int $item_id ID associated with the invitation and component. 44 * @type int $secondary_item_id secondary ID associated with the 45 * invitation and component. 46 * @type string $type @TODO. 47 * @type string $content Extra information provided by the requester 48 * or inviter. 49 * @type string $date_modified Date the invitation was last modified. 50 * @type int $invite_sent Has the invitation been sent, or is it a 51 * draft invite? 52 * } 53 * @return int|bool ID of the newly created invitation on success, false 54 * on failure. 55 */ 56 function bp_invitations_add_invitation( $args = array() ) { 57 58 $r = wp_parse_args( $args, array( 59 'user_id' => 0, 60 'invitee_email' => '', 61 'inviter_id' => 0, 62 'component_name' => '', 63 'component_action' => '', 64 'item_id' => 0, 65 'secondary_item_id' => 0, 66 'type' => 'invite', 67 'content' => '', 68 'date_modified' => bp_core_current_time(), 69 'invite_sent' => 0, 70 'accepted' => 0 71 ) ); 72 73 // Invitations must have an invitee and inviter. 74 if ( ! ( ( $r['user_id'] || $r['invitee_email'] ) && $r['inviter_id'] ) ) { 75 return false; 76 } 77 78 /** 79 * Is this user allowed to extend invitations from this component/item? 80 * 81 * @since 2.7.0 82 * 83 * @param array $r Describes the invitation to be added. 84 */ 85 if ( ! apply_filters( 'bp_invitations_allow_invitation', true, $r ) ) { 86 return false; 87 } 88 89 // Avoid creating duplicate invitations. 90 $existing = bp_invitations_get_invitations( array( 91 'user_id' => $r['user_id'], 92 'invitee_email' => $r['invitee_email'], 93 'inviter_id' => $r['inviter_id'], 94 'component_name' => $r['component_name'], 95 'component_action' => $r['component_action'], 96 'item_id' => $r['item_id'], 97 'secondary_item_id' => $r['secondary_item_id'], 98 ) ); 99 100 if ( $existing ) { 101 return false; 102 } 103 104 // Set up the new invitation as a draft. 105 $invitation = new BP_Invitations_Invitation; 106 $invitation->user_id = $r['user_id']; 107 $invitation->inviter_id = $r['inviter_id']; 108 $invitation->invitee_email = $r['invitee_email']; 109 $invitation->component_name = $r['component_name']; 110 $invitation->component_action = $r['component_action']; 111 $invitation->item_id = $r['item_id']; 112 $invitation->secondary_item_id = $r['secondary_item_id']; 113 $invitation->type = $r['type']; 114 $invitation->content = $r['content']; 115 $invitation->date_modified = $r['date_modified']; 116 $invitation->invite_sent = 0; 117 $invitation->accepted = 0; 118 119 $save_success = $invitation->save(); 120 121 // "Send" the invite if necessary. 122 if ( $r['invite_sent'] && $save_success ) { 123 $sent = bp_invitations_send_invitation_by_id( $save_success ); 124 if ( ! $sent ) { 125 return false; 126 } 127 } 128 129 return $save_success; 130 } 131 132 function bp_invitations_send_invitation_by_id( $invitation_id ) { 133 $updated = false; 134 135 $invitation = bp_invitations_get_invitation_by_id( $invitation_id ); 136 137 // Different uses may need different actions on sending. Plugins can hook in here to perform their own tasks. 138 do_action( 'bp_invitations_send_invitation_by_id_before_send', $invitation_id, $invitation ); 139 140 // Plugins can stop the process here. 141 $allowed = apply_filters( 'bp_invitations_send_invitation_by_id', true, $invitation_id, $invitation ); 142 143 if ( $allowed ) { 144 /* 145 * Before creating a sent invitation, check for outstanding requests to the same item. 146 * A sent invitation + a request = acceptance. 147 */ 148 $request_args = array( 149 'user_id' => $invitation->user_id, 150 'invitee_email' => $invitation->invitee_email, 151 'component_name' => $invitation->component_name, 152 'component_action' => $invitation->component_action, 153 'item_id' => $invitation->item_id, 154 'secondary_item_id' => $invitation->secondary_item_id, 155 ); 156 $request = bp_invitations_get_requests( $request_args ); 157 158 if ( ! empty( $request ) ) { 159 // Accept the request. 160 return bp_invitations_accept_request( $request_args ); 161 } 162 163 $updated = bp_invitations_mark_sent_by_id( $invitation_id ); 164 } 165 166 return $updated; 167 } 168 169 /** 170 * Add a request to an item for a specific user, related to a 171 * specific component. 172 * 173 * @since 2.7.0 174 * 175 * @param array $args { 176 * Array of arguments describing the invitation. All are optional. 177 * @type int $user_id ID of the invited user. 178 * @type int $inviter_id ID of the user who created the invitation. 179 * @type string $component_name Name of the related component. 180 * @type string $component_action Name of the related component action. 181 * @type int $item_id ID associated with the invitation and component. 182 * @type int $secondary_item_id secondary ID associated with the 183 * invitation and component. 184 * @type string $type @TODO. 185 * @type string $content Extra information provided by the requester 186 * or inviter. 187 * @type string $date_modified Date the invitation was last modified. 188 * @type int $invite_sent Has the invitation been sent, or is it a 189 * draft invite? 190 * } 191 * @return int|bool ID of the newly created invitation on success, false 192 * on failure. 193 */ 194 function bp_invitations_add_request( $args = array() ) { 195 196 $r = wp_parse_args( $args, array( 197 'user_id' => 0, 198 'inviter_id' => 0, 199 'invitee_email' => '', 200 'component_name' => '', 201 'component_action' => '', 202 'item_id' => 0, 203 'secondary_item_id' => 0, 204 'type' => 'request', 205 'content' => '', 206 'date_modified' => bp_core_current_time(), 207 'invite_sent' => 0, 208 'accepted' => 0 209 ) ); 210 211 // If there is no invitee, bail. 212 if ( ! ( $r['user_id'] ) ) { 213 return false; 214 } 215 216 /** 217 * Is the item accepting requests? 218 * 219 * @since 2.7.0 220 * 221 * @param array $r Describes the invitation to be added. 222 */ 223 if ( ! apply_filters( 'bp_invitations_allow_request', true, $r ) ) { 224 return false; 225 } 226 227 228 // Check for existing duplicate requests. 229 $existing = bp_invitations_get_requests( array( 230 'user_id' => $r['user_id'], 231 'invitee_email' => $r['invitee_email'], 232 'component_name' => $r['component_name'], 233 'component_action' => $r['component_action'], 234 'item_id' => $r['item_id'], 235 'secondary_item_id' => $r['secondary_item_id'], 236 ) ); 237 238 if ( $existing ) { 239 return false; 240 } 241 242 /* 243 * Check for outstanding invitations to the same item. 244 * A request + a sent invite = acceptance. 245 */ 246 $invite = bp_invitations_get_invitations( array( 247 'user_id' => $r['user_id'], 248 'invitee_email' => $r['invitee_email'], 249 'component_name' => $r['component_name'], 250 'component_action' => $r['component_action'], 251 'item_id' => $r['item_id'], 252 'secondary_item_id' => $r['secondary_item_id'], 253 'invite_sent' => 'sent' 254 ) ); 255 256 if ( $invite ) { 257 // Accept the invite. 258 return bp_invitations_accept_invitation( array( 259 'user_id' => $r['user_id'], 260 'invitee_email' => $r['invitee_email'], 261 'component_name' => $r['component_name'], 262 'component_action' => $r['component_action'], 263 'item_id' => $r['item_id'], 264 'secondary_item_id' => $r['secondary_item_id'], 265 ) ); 266 } else { 267 // Set up the new invitation 268 $request = new BP_Invitations_Invitation; 269 $request->user_id = $r['user_id']; 270 $request->inviter_id = $r['inviter_id']; 271 $request->invitee_email = $r['invitee_email']; 272 $request->component_name = $r['component_name']; 273 $request->component_action = $r['component_action']; 274 $request->item_id = $r['item_id']; 275 $request->secondary_item_id = $r['secondary_item_id']; 276 $request->type = $r['type']; 277 $request->content = $r['content']; 278 $request->date_modified = $r['date_modified']; 279 $request->invite_sent = $r['invite_sent']; 280 $request->accepted = $r['accepted']; 281 282 // Save the new invitation. 283 return $request->save(); 284 } 285 } 286 287 /** Retrieve ******************************************************************/ 288 289 /** 290 * Get a specific invitation by its ID. 291 * 292 * @since 2.7.0 293 * 294 * @param int $id ID of the invitation. 295 * @return BP_Invitations_Invitation object 296 */ 297 function bp_invitations_get_invitation_by_id( $id ) { 298 $invitation = wp_cache_get( 'invitation_id_' . $id, 'bp_invitations' ); 299 if ( false === $invitation ) { 300 $invitation = new BP_Invitations_Invitation( $id ); 301 wp_cache_set( 'invitation_id_' . $id, $invitation, 'bp_invitations' ); 302 } 303 return $invitation; 304 } 305 306 /** 307 * Get invitations, based on provided filter parameters. 308 * 309 * @since 2.7.0 310 * 311 * @param array $args { 312 * Associative array of arguments. All arguments but $page and 313 * $per_page can be treated as filter values for get_where_sql() 314 * and get_query_clauses(). All items are optional. 315 * @type int|array $id ID of invitation being updated. 316 * Can be an array of IDs. 317 * @type int|array $user_id ID of user being queried. Can be an 318 * Can be an array of IDs. 319 * @type int|array $inviter_id ID of user who created the 320 * invitation. Can be an array of IDs. 321 * @type string|array $invitee_email Email address of invited users 322 * being queried. Can be an array of 323 * addresses. 324 * @type string|array $component_name Name of the component to filter by. 325 * Can be an array of component names. 326 * @type string|array $component_action Name of the action to filter by. 327 * Can be an array of actions. 328 * @type int|array $item_id ID of associated item. 329 * Can be an array of multiple item IDs. 330 * @type int|array $secondary_item_id ID of secondary associated item. 331 * Can be an array of multiple IDs. 332 * @type string|array $type Type of item. An "invite" is sent 333 * from one user to another. 334 * A "request" is submitted by a 335 * user and no inviter is required. 336 * 'all' returns all. Default: 'all'. 337 * @type string $invite_sent Limit to draft, sent or all 338 * 'draft' limits to unsent invites, 339 * 'sent' returns only sent invites, 340 * 'all' returns all. Default: 'all'. 341 * @type bool $accepted Limit to accepted or 342 * not-yet-accepted invitations. 343 * 'accepted' returns accepted invites, 344 * 'pending' returns pending invites, 345 * 'all' returns all. Default: 'pending' 346 * @type string $search_terms Term to match against component_name 347 * or component_action fields. 348 * @type string $order_by Database column to order by. 349 * @type string $sort_order Either 'ASC' or 'DESC'. 350 * @type string $order_by Field to order results by. 351 * @type string $sort_order ASC or DESC. 352 * @type int $page Number of the current page of results. 353 * Default: false (no pagination, 354 * all items). 355 * @type int $per_page Number of items to show per page. 356 * Default: false (no pagination, 357 * all items). 358 * } 359 * 360 * @return array Located invitations. 361 */ 362 function bp_invitations_get_invitations( $args ) { 363 // Default to returning invitations, not requests. 364 if ( empty( $args['type'] ) ) { 365 $args['type'] = 'invite'; 366 } 367 return BP_Invitations_Invitation::get( $args ); 368 } 369 370 /** 371 * Get requests, based on provided filter parameters. This is the 372 * Swiss Army Knife function. When possible, use the filter_invitations 373 * functions that take advantage of caching. 374 * 375 * @since 2.7.0 376 * 377 * @param array $args { 378 * Associative array of arguments. All arguments but $page and 379 * $per_page can be treated as filter values for get_where_sql() 380 * and get_query_clauses(). All items are optional. 381 * @type int|array $id ID of invitation. Can be an array of IDs. 382 * @type int|array $user_id ID of user being queried. Can be an 383 * array of user IDs. 384 * @type string|array $invitee_email Email address of invited users 385 * being queried. Can be an array of addresses. 386 * @type string|array $component_name Name of the component to 387 * filter by. Can be an array of component names. 388 * @type string|array $component_action Name of the action to 389 * filter by. Can be an array of actions. 390 * @type int|array $item_id ID of associated item. Can be an array 391 * of multiple item IDs. 392 * @type int|array $secondary_item_id ID of secondary associated 393 * item. Can be an array of multiple IDs. 394 * @type string $invite_sent Limit to draft, sent or all 395 * invitations. 'draft' returns only unsent 396 * invitations, 'sent' returns only sent 397 * invitations, 'all' returns all. Default: 'all'. 398 * @type string $search_terms Term to match against 399 * component_name or component_action fields. 400 * @type string $order_by Database column to order by. 401 * @type string $sort_order Either 'ASC' or 'DESC'. 402 * @type string $order_by Field to order results by. 403 * @type string $sort_order ASC or DESC. 404 * @type int $page Number of the current page of results. 405 * Default: false (no pagination - all items). 406 * @type int $per_page Number of items to show per page. 407 * Default: false (no pagination - all items). 408 * } 409 * @return array Located invitations. 410 */ 411 function bp_invitations_get_requests( $args ) { 412 // Set request-specific parameters. 413 $args['type'] = 'request'; 414 $args['inviter_id'] = 0; 415 $args['invite_sent'] = 'all'; 416 417 return BP_Invitations_Invitation::get( $args ); 418 } 419 420 /** 421 * @param array $args { 422 * Array of optional arguments. 423 * @type string $component_name Name of the component to filter by. 424 * @type string $component_action Name of the action to filter by. 425 * @type int $item_id ID of associated item. Can be an array 426 * of multiple item IDs. 427 * @type int $secondary_item_id ID of secondary associated item. 428 * Can be an array of multiple IDs. 429 * @type string $type Type of invite: invite or request. 430 * Default: invite. 431 * @type string $invite_sent Limit to draft, sent or all invitations. 432 * 'draft' returns only unsent invitations, 433 * 'sent' returns only sent invitations, 434 * 'all' returns all. Default: 'sent'. 435 * @type bool $accepted Limit to accepted or not-yet-accepted 436 * invitations. 437 * 'accepted' returns only accepted invites, 438 * 'pending' returns only pending invites, 439 * 'all' returns all. Default: 'pending' 440 * @type string $sort_order Order of results. 'ASC' or 'DESC'. 441 * @type int $page Which page of results to return. 442 * @type string $per_page How many invites to include on each page 443 * of results. 444 * } 445 */ 446 function bp_get_user_invitations( $user_id = 0, $args = array(), $invitee_email = false ) { 447 $r = bp_parse_args( $args, array( 448 'inviter_id' => 0, 449 'component_name' => '', 450 'component_action' => '', 451 'item_id' => false, 452 'secondary_item_id' => false, 453 'type' => 'invite', 454 'invite_sent' => 'sent', 455 'accepted' => 'pending', 456 'orderby' => 'id', 457 'sort_order' => 'ASC', 458 'page' => false, 459 'per_page' => false 460 ), 'bp_get_user_invitations' ); 461 $invitations = array(); 462 463 // Two cases: we're searching by email address or user ID. 464 if ( ! empty( $invitee_email ) && is_email( $invitee_email ) ) { 465 // Get invitations out of the cache, or query for all if necessary 466 $encoded_email = rawurlencode( $invitee_email ); 467 $invitations = wp_cache_get( 'all_to_user_' . $encoded_email, 'bp_invitations' ); 468 if ( false === $invitations ) { 469 $all_args = array( 470 'invitee_email' => $invitee_email, 471 'invite_sent' => 'all', 472 'accepted' => 'all' 473 ); 474 $invitations = bp_invitations_get_invitations( $all_args ); 475 wp_cache_set( 'all_to_user_' . $encoded_email, $invitations, 'bp_invitations' ); 476 } 477 } else { 478 // Default to displayed user or logged-in user if no ID is passed 479 if ( empty( $user_id ) ) { 480 $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id(); 481 } 482 // Get invitations out of the cache, or query for all if necessary 483 $invitations = wp_cache_get( 'all_to_user_' . $user_id, 'bp_invitations' ); 484 if ( false === $invitations ) { 485 $all_args = array( 486 'user_id' => $user_id, 487 'invite_sent' => 'all', 488 'accepted' => 'all', 489 'type' => 'all' 490 ); 491 $invitations = bp_invitations_get_invitations( $all_args ); 492 wp_cache_set( 'all_to_user_' . $user_id, $invitations, 'bp_invitations' ); 493 } 494 } 495 496 // Pass the list of invitations to the filter. 497 $invitations = BP_Invitations_Invitation::filter_invitations_by_arguments( $invitations, $r ); 498 499 if ( 'request' == $r['type'] ) { 500 $filter_hook_name = 'bp_get_user_requests'; 501 } else { 502 $filter_hook_name = 'bp_get_user_invitations'; 503 } 504 505 /** 506 * Fires before finalization of group creation and cookies are set. 507 * 508 * This hook is a variable hook dependent on the current step 509 * in the creation process. 510 * 511 * @since 2.7.0 512 */ 513 return apply_filters( $filter_hook_name, $invitations, $user_id, $args ); 514 } 515 516 function bp_get_user_requests( $user_id = 0, $args = array() ){ 517 // Requests are a type of invitation, so we can use our main function. 518 $args['type'] = 'request'; 519 // Passing 'all' ensures that all statuses are returned. 520 $args['invite_sent'] = 'all'; 521 522 // Filter the results on the `bp_get_user_requests` hook. 523 return bp_get_user_invitations( $user_id, $args ); 524 } 525 526 /** 527 * Get outgoing invitations from a user. 528 * We get and cache all of the outgoing invitations from a user. We'll 529 * filter the complete result set in PHP, in order to take advantage of 530 * the cache. 531 * 532 * @since 2.7.0 533 * 534 * @param array $args { 535 * Array of optional arguments. 536 * @type int|array $user_id ID of user being queried. Can be an 537 * array of user IDs. 538 * @type string|array $invitee_email Email address of invited users 539 * being queried. Can be an array of addresses. 540 * @type string|array $component_name Name of the component to 541 * filter by. Can be an array of component names. 542 * @type string|array $component_action Name of the action to 543 * filter by. Can be an array of actions. 544 * @type int|array $item_id ID of associated item. Can be an array 545 * of multiple item IDs. 546 * @type int|array $secondary_item_id ID of secondary associated 547 * item. Can be an array of multiple IDs. 548 * @type string $invite_sent Limit to draft, sent or all 549 * invitations. 'draft' returns only unsent 550 * invitations, 'sent' returns only sent 551 * invitations, 'all' returns all. Default: 'all'. 552 * @type string $order_by Database column to order by. 553 * @type string $sort_order Either 'ASC' or 'DESC'. 554 * } 555 * @return array $invitations Array of invitation results. 556 * (Returns an empty array if none found.) 557 */ 558 function bp_get_invitations_from_user( $inviter_id = 0, $args = array() ) { 559 $r = bp_parse_args( $args, array( 560 'component_name' => '', 561 'component_action' => '', 562 'item_id' => null, 563 'secondary_item_id' => null, 564 'type' => 'invite', 565 'invite_sent' => 'all', 566 'accepted' => false, 567 'orderby' => 'id', 568 'sort_order' => 'ASC', 569 'page' => false, 570 'per_page' => false 571 ), 'bp_get_invitations_from_user' ); 572 $invitations = array(); 573 574 // Default to displayed user if no ID is passed 575 if ( empty( $inviter_id ) ) { 576 $inviter_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id(); 577 } 578 579 // Get invitations out of the cache, or query if necessary 580 $invitations = wp_cache_get( 'all_from_user_' . $inviter_id, 'bp_invitations' ); 581 if ( false === $invitations ) { 582 $args = array( 583 'inviter_id' => $inviter_id, 584 'invite_sent' => 'all' 585 ); 586 $invitations = bp_invitations_get_invitations( $args ); 587 wp_cache_set( 'all_from_user_' . $inviter_id, $invitations, 'bp_invitations' ); 588 } 589 590 // Pass the list of invitations to the filter. 591 $invitations = BP_Invitations_Invitation::filter_invitations_by_arguments( $invitations, $r ); 592 593 /** 594 * Fires before finalization of group creation and cookies are set. 595 * 596 * This hook is a variable hook dependent on the current step 597 * in the creation process. 598 * 599 * @since 2.7.0 600 */ 601 return apply_filters( 'bp_get_invitations_from_user', $invitations, $inviter_id, $args ); 602 } 603 604 /** Update ********************************************************************/ 605 606 /** 607 * Accept invitation, based on provided filter parameters. 608 * 609 * @since 2.7.0 610 * 611 * @see BP_Invitations_Invitation::get() for a description of 612 * accepted update/where arguments. 613 * 614 * @param array $update_args Associative array of fields to update, 615 * and the values to update them to. Of the format 616 * array( 'user_id' => 4, 'component_name' => 'groups', ) 617 * 618 * @return int|bool Number of rows updated on success, false on failure. 619 */ 620 function bp_invitations_accept_invitation( $args = array() ) { 621 /* 622 * Some basic info is required to accept an invitation, 623 * because we'll need to mark all similar invitations and requests. 624 * The following, except the optional 'secondary_item_id', are required. 625 */ 626 $r = bp_parse_args( $args, array( 627 'user_id' => 0, 628 'invitee_email' => '', 629 'component_name' => '', 630 'component_action' => '', 631 'item_id' => null, 632 'secondary_item_id' => null, 633 ), 'bp_get_invitations_from_user' ); 634 635 if ( ! ( ( $r['user_id'] || $r['invitee_email'] ) && $r['component_name'] && $r['component_action'] && $r['item_id'] ) ) { 636 return false; 637 } 638 639 //@TODO: access check (invitee or site admin)? 640 $success = false; 641 if ( apply_filters( 'bp_invitations_accept_invitation', true, $args ) ) { 642 // Mark invitations & requests to this item for this user. 643 $success = bp_invitations_mark_accepted( $r ); 644 } 645 return $success; 646 } 647 648 /** 649 * Accept invitation, based on provided filter parameters. 650 * 651 * @since 2.7.0 652 * 653 * @see BP_Invitations_Invitation::get() for a description of 654 * accepted update/where arguments. 655 * 656 * @param array $update_args Associative array of fields to update, 657 * and the values to update them to. Of the format 658 * array( 'user_id' => 4, 'component_name' => 'groups', ) 659 * 660 * @return bool Number of rows updated on success, false on failure. 661 */ 662 function bp_invitations_accept_request( $args = array() ) { 663 /* 664 * Some basic info is required to accept an invitation, 665 * because we'll need to accept all similar invitations and requests. 666 * The following, except the optional 'secondary_item_id', are required. 667 */ 668 $r = bp_parse_args( $args, array( 669 'user_id' => 0, 670 'component_name' => '', 671 'component_action' => '', 672 'item_id' => null, 673 'secondary_item_id' => null, 674 ), 'bp_get_invitations_from_user' ); 675 676 if ( ! ( $r['user_id'] && $r['component_name'] && $r['component_action'] && $r['item_id'] ) ) { 677 return false; 678 } 679 680 //@TODO: access check (object admin or site admin)? 681 $success = false; 682 if ( apply_filters( 'bp_invitations_accept_request', true, $args ) ) { 683 // Delete all related invitations & requests to this item for this user. 684 $success = bp_invitations_mark_accepted( $r ); 685 } 686 return $success; 687 } 688 689 /** 690 * Update invitation, based on provided filter parameters. 691 * 692 * @since 2.7.0 693 * 694 * @see BP_Invitations_Invitation::get() for a description of 695 * accepted update/where arguments. 696 * 697 * @param array $update_args Associative array of fields to update, 698 * and the values to update them to. Of the format 699 * array( 'user_id' => 4, 'component_name' => 'groups', ) 700 * @param array $where_args Associative array of columns/values, to 701 * determine which invitations should be updated. Formatted as 702 * array( 'item_id' => 7, 'component_action' => 'members', ) 703 * @return int|bool Number of rows updated on success, false on failure. 704 */ 705 function bp_invitations_update_invitation( $update_args = array(), $where_args = array() ) { 706 //@TODO: access check (invitee, inviter or site admin)? 707 return BP_Invitations_Invitation::update( $update_args, $where_args ); 708 } 709 710 /** 711 * Mark invitation as sent by invitation ID. 712 * 713 * @since 2.7.0 714 * 715 * @param int $id The ID of the invitation to mark as sent. 716 * @return bool True on success, false on failure. 717 */ 718 function bp_invitations_mark_sent_by_id( $id ) { 719 //@TODO: access check (inviter or site admin)? 720 return BP_Invitations_Invitation::mark_sent( $id ); 721 } 722 723 /** 724 * Mark invitations as sent that are found by user_id, inviter_id, 725 * invitee_email, component name and action, optional item id, 726 * optional secondary item id. 727 * 728 * @since 2.7.0 729 * 730 * @param array $args { 731 * Associative array of arguments. All arguments but $page and 732 * $per_page can be treated as filter values for get_where_sql() 733 * and get_query_clauses(). All items are optional. 734 * @type int|array $user_id ID of user being queried. Can be an 735 * array of user IDs. 736 * @type int|array $inviter_id ID of user who created the 737 * invitation. Can be an array of user IDs. 738 * Special cases 739 * @type string|array $invitee_email Email address of invited users 740 * being queried. Can be an array of addresses. 741 * @type string|array $component_name Name of the component to 742 * filter by. Can be an array of component names. 743 * @type string|array $component_action Name of the action to 744 * filter by. Can be an array of actions. 745 * @type int|array $item_id ID of associated item. Can be an array 746 * of multiple item IDs. 747 * @type int|array $secondary_item_id ID of secondary associated 748 * item. Can be an array of multiple IDs. 749 * } 750 */ 751 function bp_invitations_mark_sent( $args ) { 752 //@TODO: access check (inviter or site admin)? 753 return BP_Invitations_Invitation::mark_sent_by_data( $args ); 754 } 755 756 /** 757 * Mark invitation as accepted by invitation ID. 758 * 759 * @since 2.7.0 760 * 761 * @param int $id The ID of the invitation to mark as sent. 762 * @return bool True on success, false on failure. 763 */ 764 function bp_invitations_mark_accepted_by_id( $id ) { 765 //@TODO: access check (invitee or site admin)? 766 return BP_Invitations_Invitation::mark_accepted( $id ); 767 } 768 769 /** 770 * Mark invitations as sent that are found by user_id, inviter_id, 771 * invitee_email, component name and action, optional item id, 772 * optional secondary item id. 773 * 774 * @since 2.7.0 775 * 776 * @param array $args { 777 * Associative array of arguments. All arguments but $page and 778 * $per_page can be treated as filter values for get_where_sql() 779 * and get_query_clauses(). All items are optional. 780 * @type int|array $user_id ID of user being queried. Can be an 781 * array of user IDs. 782 * @type int|array $inviter_id ID of user who created the 783 * invitation. Can be an array of user IDs. 784 * Special cases 785 * @type string|array $invitee_email Email address of invited users 786 * being queried. Can be an array of addresses. 787 * @type string|array $component_name Name of the component to 788 * filter by. Can be an array of component names. 789 * @type string|array $component_action Name of the action to 790 * filter by. Can be an array of actions. 791 * @type int|array $item_id ID of associated item. Can be an array 792 * of multiple item IDs. 793 * @type int|array $secondary_item_id ID of secondary associated 794 * item. Can be an array of multiple IDs. 795 * } 796 */ 797 function bp_invitations_mark_accepted( $args ) { 798 //@TODO: access check (invitee or site admin)? 799 return BP_Invitations_Invitation::mark_accepted_by_data( $args ); 800 } 801 802 /** Delete ********************************************************************/ 803 804 /** 805 * Delete a specific invitation by its ID. 806 * 807 * Used when rejecting invitations or membership requests. 808 * 809 * @since 2.7.0 810 * 811 * @param int $id ID of the invitation to delete. 812 * @return int|false Number of rows deleted on success, false on failure. 813 */ 814 function bp_invitations_delete_invitation_by_id( $id ) { 815 //@TODO: access check (invitee, inviter or site admin)? 816 return BP_Invitations_Invitation::delete_by_id( $id ); 817 } 818 819 /** 820 * Delete an invitation or invitations by query data. 821 * 822 * Used when declining invitations. 823 * 824 * @since 2.7.0 825 * 826 * @see bp_invitations_get_invitations() for a description of 827 * accepted where arguments. 828 * 829 * @param array $args { 830 * Associative array of arguments. All arguments but $page and 831 * $per_page can be treated as filter values for get_where_sql() 832 * and get_query_clauses(). All items are optional. 833 * @type int|array $user_id ID of user being queried. Can be an 834 * array of user IDs. 835 * @type int|array $inviter_id ID of user who created the 836 * invitation. Can be an array of user IDs. 837 * Special cases 838 * @type string|array $invitee_email Email address of invited users 839 * being queried. Can be an array of addresses. 840 * @type string|array $component_name Name of the component to 841 * filter by. Can be an array of component names. 842 * @type string|array $component_action Name of the action to 843 * filter by. Can be an array of actions. 844 * @type int|array $item_id ID of associated item. Can be an array 845 * of multiple item IDs. 846 * @type int|array $secondary_item_id ID of secondary associated 847 * item. Can be an array of multiple IDs. 848 * @type string $type Invite or request. 849 * } 850 * @return int|false Number of rows deleted on success, false on failure. 851 */ 852 function bp_invitations_delete_invitations( $args ) { 853 //@TODO: access check (invitee, inviter or site admin)? 854 if ( empty( $args['type'] ) ) { 855 $args['type'] = 'invite'; 856 } 857 return BP_Invitations_Invitation::delete( $args ); 858 } 859 860 /** 861 * Delete a request or requests by query data. 862 * 863 * Used when rejecting membership requests. 864 * 865 * @since 2.7.0 866 * 867 * @see bp_invitations_get_invitations() for a description of 868 * accepted where arguments. 869 * 870 * @param array $args { 871 * Associative array of arguments. All arguments but $page and 872 * $per_page can be treated as filter values for get_where_sql() 873 * and get_query_clauses(). All items are optional. 874 * @type int|array $user_id ID of user being queried. Can be an 875 * array of user IDs. 876 * @type int|array $inviter_id ID of user who created the 877 * invitation. Can be an array of user IDs. 878 * Special cases 879 * @type string|array $invitee_email Email address of invited users 880 * being queried. Can be an array of addresses. 881 * @type string|array $component_name Name of the component to 882 * filter by. Can be an array of component names. 883 * @type string|array $component_action Name of the action to 884 * filter by. Can be an array of actions. 885 * @type int|array $item_id ID of associated item. Can be an array 886 * of multiple item IDs. 887 * @type int|array $secondary_item_id ID of secondary associated 888 * item. Can be an array of multiple IDs. 889 * } 890 * @return int|false Number of rows deleted on success, false on failure. 891 */ 892 function bp_invitations_delete_requests( $args ) { 893 //@TODO: access check 894 $args['type'] = 'request'; 895 return BP_Invitations_Invitation::delete( $args ); 896 } 897 898 /** 899 * Delete all invitations by component. 900 * 901 * Used when clearing out invitations for an entire component. Possibly used 902 * when deactivating a component that created invitations. 903 * 904 * @since 2.7.0 905 * 906 * @param string $component_name Name of the associated component. 907 * @param string $component_action Optional. Name of the associated action. 908 * @return int|false Number of rows deleted on success, false on failure. 909 */ 910 function bp_invitations_delete_all_invitations_by_component( $component_name, $component_action = false ) { 911 //@TODO: access check 912 return BP_Invitations_Invitation::delete( array( 913 'component_name' => $component_name, 914 'component_action' => $component_action, 915 ) ); 916 } 917 918 /** Helpers *******************************************************************/ 919 920 /** 921 * Return an array of component names that are currently active and have 922 * registered Invitations callbacks. 923 * @TODO: Useful or not? 924 * 925 * @since 2.7.0 926 * 927 * @return array 928 */ 929 function bp_invitations_get_registered_components() { 930 931 // Load BuddyPress 932 $bp = buddypress(); 933 934 // Setup return value 935 $component_names = array(); 936 937 // Get the active components 938 $active_components = array_keys( $bp->active_components ); 939 940 // Loop through components, look for callbacks, add to return value 941 foreach ( $active_components as $component ) { 942 if ( ! empty( $bp->$component->invitation_callback ) ) { 943 $component_names[] = $component; 944 } 945 } 946 947 // Return active components with registered invitations callbacks 948 return apply_filters( 'bp_invitations_get_registered_components', $component_names, $active_components ); 949 } 950 951 /* Caching ********************************************************************/ 952 953 /** 954 * Invalidate 'all_from_user_' and 'all_to_user_' caches when saving. 955 * 956 * @since 2.7.0 957 * 958 * @param BP_Invitations_Invitation $n Invitation object. 959 */ 960 function bp_invitations_clear_user_caches_after_save( BP_Invitations_Invitation $n ) { 961 // User_id could be empty if a non-member is being invited via email. 962 if ( $n->user_id ) { 963 wp_cache_delete( 'all_to_user_' . $n->user_id, 'bp_invitations' ); 964 } 965 // Inviter_id could be empty if this is a request for membership. 966 if ( $n->inviter_id ) { 967 wp_cache_delete( 'all_from_user_' . $n->inviter_id, 'bp_invitations' ); 968 } 969 } 970 add_action( 'bp_invitation_after_save', 'bp_invitations_clear_user_caches_after_save' ); 971 972 /** 973 * Invalidate 'all_from_user_' and 'all_to_user_' caches when 974 * updating or deleting. 975 * 976 * @since 2.7.0 977 * 978 * @param int $args Invitation deletion arguments. 979 */ 980 function bp_invitations_clear_user_caches_before_update( $args ) { 981 // Pull up a list of invitations matching the args (those about to be updated or deleted) 982 $invites = BP_Invitations_Invitation::get( $args ); 983 984 $user_ids = array(); 985 $inviter_ids = array(); 986 foreach ( $invites as $i ) { 987 $user_ids[] = $i->user_id; 988 $inviter_ids[] = $i->inviter_id; 989 } 990 991 foreach ( array_unique( $user_ids ) as $user_id ) { 992 wp_cache_delete( 'all_to_user_' . $user_id, 'bp_invitations' ); 993 } 994 995 foreach ( array_unique( $inviter_ids ) as $inviter_id ) { 996 wp_cache_delete( 'all_from_user_' . $inviter_id, 'bp_invitations' ); 997 } 998 } 999 add_action( 'bp_invitation_before_update', 'bp_invitations_clear_user_caches_before_update' ); 1000 add_action( 'bp_invitation_before_delete', 'bp_invitations_clear_user_caches_before_update' ); 1001 No newline at end of file -
src/bp-core/bp-core-update.php
diff --git src/bp-core/bp-core-update.php src/bp-core/bp-core-update.php index 7fbdd30..b6e1b7e 100644
function bp_version_updater() { 275 275 if ( $raw_db_version < 10440 ) { 276 276 bp_update_to_2_5(); 277 277 } 278 279 // 2.5.0 280 if ( $raw_db_version < 10800 ) { 281 bp_update_to_2_6(); 282 } 278 283 } 279 284 280 285 /* All done! *************************************************************/ … … function bp_update_to_2_5() { 514 519 } 515 520 516 521 /** 522 * 2.6.0 update routine. 523 * 524 * - Create invitations table. 525 * 526 * @since 2.6.0 527 */ 528 function bp_update_to_2_6() { 529 bp_core_install_invitations(); 530 } 531 532 /** 517 533 * Updates the component field for new_members type. 518 534 * 519 535 * @since 2.2.0 -
new file src/bp-core/classes/class-bp-invitations-component.php
diff --git src/bp-core/classes/class-bp-invitations-component.php src/bp-core/classes/class-bp-invitations-component.php new file mode 100644 index 0000000..e8ddcda
- + 1 <?php 2 /** 3 * Initializes the Invitations skeleton component. 4 * 5 * @package BuddyPress 6 * @subpackage Invitations 7 * @since 2.6.0 8 */ 9 10 // Exit if accessed directly. 11 defined( 'ABSPATH' ) || exit; 12 13 /** 14 * Extends the component class to set up the Invitations component. 15 */ 16 class BP_Invitations_Component extends BP_Component { 17 18 /** 19 * Start the invitations component creation process. 20 * 21 * @since 2.6.0 22 */ 23 public function __construct() { 24 parent::start( 25 'invitations', 26 _x( 'Invitations', 'Page <title>', 'buddypress' ), 27 buddypress()->plugin_dir, 28 array() 29 ); 30 } 31 32 /** 33 * Include invitations component files. 34 * 35 * @since 1.9.0 36 * 37 * @see BP_Component::includes() for a description of arguments. 38 * 39 * @param array $includes See BP_Component::includes() for a description. 40 */ 41 public function includes( $includes = array() ) { 42 } 43 44 /** 45 * Set up component global data. 46 * 47 * @since 2.6.0 48 * 49 * @see BP_Component::setup_globals() for a description of arguments. 50 * 51 * @param array $args See BP_Component::setup_globals() for a description. 52 */ 53 public function setup_globals( $args = array() ) { 54 $bp = buddypress(); 55 56 // Define a slug, if necessary. 57 if ( ! defined( 'BP_INVITATIONS_SLUG' ) ) { 58 define( 'BP_INVITATIONS_SLUG', $this->id ); 59 } 60 61 // Global tables for the invitations component. 62 $global_tables = array( 63 'table_name' => $bp->table_prefix . 'bp_invitations', 64 ); 65 66 // All globals for the invitations component. 67 // Note that global_tables is included in this array. 68 $args = array( 69 'slug' => BP_INVITATIONS_SLUG, 70 'has_directory' => false, 71 'search_string' => __( 'Search Invitations...', 'buddypress' ), 72 'global_tables' => $global_tables, 73 ); 74 75 parent::setup_globals( $args ); 76 } 77 78 /** 79 * Set up component navigation. 80 * 81 * @since 2.6.0 82 * 83 * @see BP_Component::setup_nav() for a description of arguments. 84 * 85 * @param array $main_nav Optional. See BP_Component::setup_nav() for 86 * description. 87 * @param array $sub_nav Optional. See BP_Component::setup_nav() for 88 * description. 89 */ 90 public function setup_nav( $main_nav = array(), $sub_nav = array() ) { 91 } 92 93 /** 94 * Set up the component entries in the WordPress Admin Bar. 95 * 96 * @since 2.6.0 97 * 98 * @see BP_Component::setup_nav() for a description of the $wp_admin_nav 99 * parameter array. 100 * 101 * @param array $wp_admin_nav See BP_Component::setup_admin_bar() for a 102 * description. 103 */ 104 public function setup_admin_bar( $wp_admin_nav = array() ) { 105 } 106 107 /** 108 * Set up the title for pages and <title>. 109 * 110 * @since 2.6.0 111 */ 112 public function setup_title() { 113 } 114 115 /** 116 * Set up cache groups. 117 * 118 * @since 2.6.0 119 */ 120 public function setup_cache_groups() { 121 122 // Global groups. 123 wp_cache_add_global_groups( array( 124 'bp_invitations' 125 ) ); 126 127 parent::setup_cache_groups(); 128 } 129 } -
new file src/bp-core/classes/class-bp-invitations-invitation.php
diff --git src/bp-core/classes/class-bp-invitations-invitation.php src/bp-core/classes/class-bp-invitations-invitation.php new file mode 100644 index 0000000..781da2e
- + 1 <?php 2 3 /** 4 * BuddyPress Invitations Class 5 * 6 * @package BuddyPress 7 * @subpackage Invitations 8 * 9 * @since 2.7.0 10 */ 11 12 // Exit if accessed directly. 13 defined( 'ABSPATH' ) || exit; 14 15 /** 16 * BuddyPress Invitations. 17 * 18 * Use this class to create, access, edit, or delete BuddyPress Invitations. 19 * 20 * @since 2.7.0 21 */ 22 class BP_Invitations_Invitation { 23 24 /** 25 * The invitation ID. 26 * 27 * @since 2.7.0 28 * @access public 29 * @var int 30 */ 31 public $id; 32 33 /** 34 * The ID of the invited user. 35 * 36 * @since 2.7.0 37 * @access public 38 * @var int 39 */ 40 public $user_id; 41 42 /** 43 * The ID of the user who created the invitation. 44 * 45 * @since 2.7.0 46 * @access public 47 * @var int 48 */ 49 public $inviter_id; 50 51 /** 52 * The email address of the invited user. 53 * Used when extending an invitation to someone who does not belong to the site. 54 * 55 * @since 2.7.0 56 * @access public 57 * @var string 58 */ 59 public $invitee_email; 60 61 /** 62 * The name of the related component. 63 * 64 * @since 2.7.0 65 * @access public 66 * @var string 67 */ 68 public $component_name; 69 70 /** 71 * The name of the related component action. 72 * 73 * @since 2.7.0 74 * @access public 75 * @var string 76 */ 77 public $component_action; 78 79 /** 80 * The ID associated with the invitation and component. 81 * Example: the group ID if a group invitation 82 * 83 * @since 2.7.0 84 * @access public 85 * @var int 86 */ 87 public $item_id; 88 89 /** 90 * The secondary ID associated with the invitation and component. 91 * Example: a taxonomy term ID if invited to a site's category-specific RSS feed 92 * 93 * @since 2.7.0 94 * @access public 95 * @var int 96 */ 97 public $secondary_item_id = null; 98 99 100 /** 101 * Invite or request. 102 * 103 * @since 2.7.0 104 * @access public 105 * @var string 106 */ 107 public $type; 108 109 /** 110 * Extra information provided by the requester or inviter. 111 * 112 * @since 2.7.0 113 * @access public 114 * @var string 115 */ 116 public $content; 117 118 /** 119 * The date the invitation was last modified. 120 * 121 * @since 2.7.0 122 * @access public 123 * @var string 124 */ 125 public $date_modified; 126 127 /** 128 * Has the invitation been sent, or is it a draft invite? 129 * 130 * @since 2.7.0 131 * @access public 132 * @var bool 133 */ 134 public $invite_sent; 135 136 /** 137 * Has the invitation been accepted by the invitee? 138 * 139 * @since 2.7.0 140 * @access public 141 * @var bool 142 */ 143 public $accepted; 144 145 /** Public Methods ****************************************************/ 146 147 /** 148 * Constructor method. 149 * 150 * @since 2.7.0 151 * 152 * @param int $id Optional. Provide an ID to access an existing 153 * invitation item. 154 */ 155 public function __construct( $id = 0 ) { 156 if ( ! empty( $id ) ) { 157 $this->id = $id; 158 $this->populate(); 159 } 160 } 161 162 /** 163 * Update or insert invitation details into the database. 164 * 165 * @since 2.7.0 166 * 167 * @global wpdb $wpdb WordPress database object. 168 * 169 * @return bool True on success, false on failure. 170 */ 171 public function save() { 172 173 // Return value 174 $retval = false; 175 176 // Default data and format 177 $data = array( 178 'user_id' => $this->user_id, 179 'inviter_id' => $this->inviter_id, 180 'invitee_email' => $this->invitee_email, 181 'component_name' => $this->component_name, 182 'component_action' => $this->component_action, 183 'item_id' => $this->item_id, 184 'secondary_item_id' => $this->secondary_item_id, 185 'type' => $this->type, 186 'content' => $this->content, 187 'date_modified' => $this->date_modified, 188 'invite_sent' => $this->invite_sent, 189 'accepted' => $this->accepted, 190 ); 191 $data_format = array( '%d', '%d', '%s', '%s', '%s', '%d', '%d', '%s', '%s', '%s', '%d', '%d' ); 192 193 do_action_ref_array( 'bp_invitation_before_save', array( &$this ) ); 194 195 // Update 196 if ( ! empty( $this->id ) ) { 197 $result = self::_update( $data, array( 'ID' => $this->id ), $data_format, array( '%d' ) ); 198 // Insert 199 } else { 200 $result = self::_insert( $data, $data_format ); 201 } 202 203 // Set the invitation ID if successful 204 if ( ! empty( $result ) && ! is_wp_error( $result ) ) { 205 global $wpdb; 206 207 $this->id = $wpdb->insert_id; 208 $retval = $wpdb->insert_id; 209 } 210 211 do_action_ref_array( 'bp_invitation_after_save', array( &$this ) ); 212 213 // Return the result 214 return $retval; 215 } 216 217 /** 218 * Fetch data for an existing invitation from the database. 219 * 220 * @since 2.7.0 221 * 222 * @global BuddyPress $bp The one true BuddyPress instance. 223 * @global wpdb $wpdb WordPress database object. 224 */ 225 public function populate() { 226 global $wpdb; 227 $bp = buddypress(); 228 229 // Fetch the invitation 230 $invitation = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->invitations->table_name} WHERE id = %d", $this->id ) ); 231 232 // Set up the invitation data 233 if ( ! empty( $invitation ) && ! is_wp_error( $invitation ) ) { 234 $this->user_id = $invitation->user_id; 235 $this->inviter_id = $invitation->inviter_id; 236 $this->invitee_email = $invitation->invitee_email; 237 $this->component_name = $invitation->component_name; 238 $this->component_action = $invitation->component_action; 239 $this->item_id = $invitation->item_id; 240 $this->secondary_item_id = $invitation->secondary_item_id; 241 $this->type = $invitation->type; 242 $this->content = $invitation->content; 243 $this->date_modified = $invitation->date_modified; 244 $this->invite_sent = $invitation->invite_sent; 245 $this->accepted = $invitation->accepted; 246 } 247 } 248 249 /** Protected Static Methods ******************************************/ 250 251 /** 252 * Create a invitation entry. 253 * 254 * @since 2.7.0 255 * 256 * @param array $data { 257 * Array of invitation data, passed to {@link wpdb::insert()}. 258 * @type int $user_id ID of the invited user. 259 * @type int $inviter_id ID of the user who created the invitation. 260 * @type string $invitee_email Email address of the invited user. 261 * @type string $component_name Name of the related component. 262 * @type string $component_action Name of the related component action. 263 * @type int item_id ID associated with the invitation and component. 264 * @type int secondary_item_id secondary ID associated with the 265 * invitation and component. 266 * @type string content Extra information provided by the requester 267 * or inviter. 268 * @type string date_modified Date the invitation was last modified. 269 * @type int invite_sent Has the invitation been sent, or is it a 270 * draft invite? 271 * } 272 * @param array $data_format See {@link wpdb::insert()}. 273 * @return int|false The number of rows inserted, or false on error. 274 */ 275 protected static function _insert( $data = array(), $data_format = array() ) { 276 global $wpdb; 277 return $wpdb->insert( buddypress()->invitations->table_name, $data, $data_format ); 278 } 279 280 /** 281 * Update invitations. 282 * 283 * @since 2.7.0 284 * 285 * @see wpdb::update() for further description of paramater formats. 286 * 287 * @param array $data Array of invitation data to update, passed to 288 * {@link wpdb::update()}. Accepts any property of a 289 * BP_Invitations_Invitation object. 290 * @param array $where The WHERE params as passed to wpdb::update(). 291 * Typically consists of array( 'ID' => $id ) to specify the ID 292 * of the item being updated. See {@link wpdb::update()}. 293 * @param array $data_format See {@link wpdb::insert()}. 294 * @param array $where_format See {@link wpdb::insert()}. 295 * @return int|false The number of rows updated, or false on error. 296 */ 297 protected static function _update( $data = array(), $where = array(), $data_format = array(), $where_format = array() ) { 298 global $wpdb; 299 return $wpdb->update( buddypress()->invitations->table_name, $data, $where, $data_format, $where_format ); 300 } 301 302 /** 303 * Delete invitations. 304 * 305 * @since 2.7.0 306 * 307 * @see wpdb::update() for further description of paramater formats. 308 * 309 * @param array $where Array of WHERE clauses to filter by, passed to 310 * {@link wpdb::delete()}. Accepts any property of a 311 * BP_Invitations_Invitation object. 312 * @param array $where_format See {@link wpdb::insert()}. 313 * @return int|false The number of rows updated, or false on error. 314 */ 315 protected static function _delete( $where = array(), $where_format = array() ) { 316 global $wpdb; 317 return $wpdb->delete( buddypress()->invitations->table_name, $where, $where_format ); 318 } 319 320 /** 321 * Assemble the WHERE clause of a get() SQL statement. 322 * 323 * Used by BP_Invitations_Invitation::get() to create its WHERE 324 * clause. 325 * 326 * @since 2.7.0 327 * 328 * @param array $args See {@link BP_Invitations_Invitation::get()} 329 * for more details. 330 * @return string WHERE clause. 331 */ 332 protected static function get_where_sql( $args = array() ) { 333 global $wpdb; 334 335 $where_conditions = array(); 336 $where = ''; 337 338 // id 339 if ( ! empty( $args['id'] ) ) { 340 $id_in = implode( ',', wp_parse_id_list( $args['id'] ) ); 341 $where_conditions['id'] = "id IN ({$id_in})"; 342 } 343 344 // user_id 345 if ( ! empty( $args['user_id'] ) ) { 346 $user_id_in = implode( ',', wp_parse_id_list( $args['user_id'] ) ); 347 $where_conditions['user_id'] = "user_id IN ({$user_id_in})"; 348 } 349 350 // inviter_id. 0 can be meaningful, in the case of requests. 351 if ( ! empty( $args['inviter_id'] ) || 0 === $args['inviter_id'] ) { 352 $inviter_id_in = implode( ',', wp_parse_id_list( $args['inviter_id'] ) ); 353 $where_conditions['inviter_id'] = "inviter_id IN ({$inviter_id_in})"; 354 } 355 356 // invitee_email 357 if ( ! empty( $args['invitee_email'] ) ) { 358 if ( ! is_array( $args['invitee_email'] ) ) { 359 $invitee_emails = explode( ',', $args['invitee_email'] ); 360 } else { 361 $invitee_emails = $args['invitee_email']; 362 } 363 364 $email_clean = array(); 365 foreach ( $invitee_emails as $email ) { 366 $email_clean[] = $wpdb->prepare( '%s', $email ); 367 } 368 369 $invitee_email_in = implode( ',', $email_clean ); 370 $where_conditions['invitee_email'] = "invitee_email IN ({$invitee_email_in})"; 371 } 372 373 // component_name 374 if ( ! empty( $args['component_name'] ) ) { 375 if ( ! is_array( $args['component_name'] ) ) { 376 $component_names = explode( ',', $args['component_name'] ); 377 } else { 378 $component_names = $args['component_name']; 379 } 380 381 $cn_clean = array(); 382 foreach ( $component_names as $cn ) { 383 $cn_clean[] = $wpdb->prepare( '%s', $cn ); 384 } 385 386 $cn_in = implode( ',', $cn_clean ); 387 $where_conditions['component_name'] = "component_name IN ({$cn_in})"; 388 } 389 390 // component_action 391 if ( ! empty( $args['component_action'] ) ) { 392 if ( ! is_array( $args['component_action'] ) ) { 393 $component_actions = explode( ',', $args['component_action'] ); 394 } else { 395 $component_actions = $args['component_action']; 396 } 397 398 $ca_clean = array(); 399 foreach ( $component_actions as $ca ) { 400 $ca_clean[] = $wpdb->prepare( '%s', $ca ); 401 } 402 403 $ca_in = implode( ',', $ca_clean ); 404 $where_conditions['component_action'] = "component_action IN ({$ca_in})"; 405 } 406 407 // item_id 408 if ( ! empty( $args['item_id'] ) ) { 409 $item_id_in = implode( ',', wp_parse_id_list( $args['item_id'] ) ); 410 $where_conditions['item_id'] = "item_id IN ({$item_id_in})"; 411 } 412 413 // secondary_item_id 414 if ( ! empty( $args['secondary_item_id'] ) ) { 415 $secondary_item_id_in = implode( ',', wp_parse_id_list( $args['secondary_item_id'] ) ); 416 $where_conditions['secondary_item_id'] = "secondary_item_id IN ({$secondary_item_id_in})"; 417 } 418 419 // type 420 if ( ! empty( $args['type'] ) && 'all' !== $args['type'] ) { 421 if ( 'invite' == $args['type'] || 'request' == $args['type'] ) { 422 $type_clean = $wpdb->prepare( '%s', $args['type'] ); 423 $where_conditions['type'] = "type = {$type_clean}"; 424 } 425 } 426 427 // invite_sent 428 // Only create a where statement if something less than "all" has been 429 // specifically requested. 430 if ( ! empty( $args['invite_sent'] ) && 'all' !== $args['invite_sent'] ) { 431 if ( $args['invite_sent'] == 'draft' ) { 432 $where_conditions['invite_sent'] = "invite_sent = 0"; 433 } else if ( $args['invite_sent'] == 'sent' ) { 434 $where_conditions['invite_sent'] = "invite_sent = 1"; 435 } 436 } 437 438 // accepted 439 if ( ! empty( $args['accepted'] ) && 'all' !== $args['accepted'] ) { 440 if ( $args['accepted'] == 'pending' ) { 441 $where_conditions['accepted'] = "accepted = 0"; 442 } else if ( $args['accepted'] == 'accepted' ) { 443 $where_conditions['accepted'] = "accepted = 1"; 444 } 445 } 446 447 // search_terms 448 if ( ! empty( $args['search_terms'] ) ) { 449 $search_terms_like = '%' . bp_esc_like( $args['search_terms'] ) . '%'; 450 $where_conditions['search_terms'] = $wpdb->prepare( "( component_name LIKE %s OR component_action LIKE %s )", $search_terms_like, $search_terms_like ); 451 } 452 453 // Custom WHERE 454 if ( ! empty( $where_conditions ) ) { 455 $where = 'WHERE ' . implode( ' AND ', $where_conditions ); 456 } 457 458 return $where; 459 } 460 461 /** 462 * Assemble the ORDER BY clause of a get() SQL statement. 463 * 464 * Used by BP_Invitations_Invitation::get() to create its ORDER BY 465 * clause. 466 * 467 * @since 2.7.0 468 * 469 * @param array $args See {@link BP_Invitations_Invitation::get()} 470 * for more details. 471 * @return string ORDER BY clause. 472 */ 473 protected static function get_order_by_sql( $args = array() ) { 474 475 // Setup local variable 476 $conditions = array(); 477 $retval = ''; 478 479 // Order by 480 if ( ! empty( $args['order_by'] ) ) { 481 $order_by = implode( ', ', (array) $args['order_by'] ); 482 $conditions['order_by'] = "{$order_by}"; 483 } 484 485 // Sort order direction 486 if ( ! empty( $args['sort_order'] ) && in_array( $args['sort_order'], array( 'ASC', 'DESC' ) ) ) { 487 $sort_order = $args['sort_order']; 488 $conditions['sort_order'] = "{$sort_order}"; 489 } 490 491 // Custom ORDER BY 492 if ( ! empty( $conditions ) ) { 493 $retval = 'ORDER BY ' . implode( ' ', $conditions ); 494 } 495 496 return $retval; 497 } 498 499 /** 500 * Assemble the LIMIT clause of a get() SQL statement. 501 * 502 * Used by BP_Invitations_Invitation::get() to create its LIMIT clause. 503 * 504 * @since 2.7.0 505 * 506 * @param array $args See {@link BP_Invitations_Invitation::get()} 507 * for more details. 508 * @return string LIMIT clause. 509 */ 510 protected static function get_paged_sql( $args = array() ) { 511 global $wpdb; 512 513 // Setup local variable 514 $retval = ''; 515 516 // Custom LIMIT 517 if ( ! empty( $args['page'] ) && ! empty( $args['per_page'] ) ) { 518 $page = absint( $args['page'] ); 519 $per_page = absint( $args['per_page'] ); 520 $offset = $per_page * ( $page - 1 ); 521 $retval = $wpdb->prepare( "LIMIT %d, %d", $offset, $per_page ); 522 } 523 524 return $retval; 525 } 526 527 /** 528 * Assemble query clauses, based on arguments, to pass to $wpdb methods. 529 * 530 * The insert(), update(), and delete() methods of {@link wpdb} expect 531 * arguments of the following forms: 532 * 533 * - associative arrays whose key/value pairs are column => value, to 534 * be used in WHERE, SET, or VALUES clauses 535 * - arrays of "formats", which tell $wpdb->prepare() which type of 536 * value to expect when sanitizing (eg, array( '%s', '%d' )) 537 * 538 * This utility method can be used to assemble both kinds of params, 539 * out of a single set of associative array arguments, such as: 540 * 541 * $args = array( 542 * 'user_id' => 4, 543 * 'component_name' => 'groups', 544 * ); 545 * 546 * This will be converted to: 547 * 548 * array( 549 * 'data' => array( 550 * 'user_id' => 4, 551 * 'component_name' => 'groups', 552 * ), 553 * 'format' => array( 554 * '%d', 555 * '%s', 556 * ), 557 * ) 558 * 559 * which can easily be passed as arguments to the $wpdb methods. 560 * 561 * @since 2.7.0 562 * 563 * @param $args Associative array of filter arguments. 564 * See {@BP_Invitations_Invitation::get()} for a breakdown. 565 * @return array Associative array of 'data' and 'format' args. 566 */ 567 protected static function get_query_clauses( $args = array() ) { 568 $where_clauses = array( 569 'data' => array(), 570 'format' => array(), 571 ); 572 573 // id 574 if ( ! empty( $args['id'] ) ) { 575 $where_clauses['data']['id'] = absint( $args['id'] ); 576 $where_clauses['format'][] = '%d'; 577 } 578 579 // user_id 580 if ( ! empty( $args['user_id'] ) ) { 581 $where_clauses['data']['user_id'] = absint( $args['user_id'] ); 582 $where_clauses['format'][] = '%d'; 583 } 584 585 // inviter_id 586 if ( ! empty( $args['inviter_id'] ) ) { 587 $where_clauses['data']['inviter_id'] = absint( $args['inviter_id'] ); 588 $where_clauses['format'][] = '%d'; 589 } 590 591 // invitee_email 592 if ( ! empty( $args['invitee_email'] ) ) { 593 $where_clauses['data']['invitee_email'] = $args['invitee_email']; 594 $where_clauses['format'][] = '%s'; 595 } 596 597 // component_name 598 if ( ! empty( $args['component_name'] ) ) { 599 $where_clauses['data']['component_name'] = $args['component_name']; 600 $where_clauses['format'][] = '%s'; 601 } 602 603 // component_action 604 if ( ! empty( $args['component_action'] ) ) { 605 $where_clauses['data']['component_action'] = $args['component_action']; 606 $where_clauses['format'][] = '%s'; 607 } 608 609 // item_id 610 if ( ! empty( $args['item_id'] ) ) { 611 $where_clauses['data']['item_id'] = absint( $args['item_id'] ); 612 $where_clauses['format'][] = '%d'; 613 } 614 615 // secondary_item_id 616 if ( ! empty( $args['secondary_item_id'] ) ) { 617 $where_clauses['data']['secondary_item_id'] = absint( $args['secondary_item_id'] ); 618 $where_clauses['format'][] = '%d'; 619 } 620 621 // type 622 if ( ! empty( $args['type'] ) && 'all' !== $args['type'] ) { 623 if ( 'invite' == $args['type'] || 'request' == $args['type'] ) { 624 $where_clauses['data']['type'] = $args['type']; 625 $where_clauses['format'][] = '%s'; 626 } 627 } 628 629 // invite_sent 630 // Only create a where statement if something less than "all" has been 631 // specifically requested. 632 if ( ! empty( $args['invite_sent'] ) && 'all' !== $args['invite_sent'] ) { 633 if ( $args['invite_sent'] == 'draft' ) { 634 $where_clauses['data']['invite_sent'] = 0; 635 $where_clauses['format'][] = '%d'; 636 } else if ( $args['invite_sent'] == 'sent' ) { 637 $where_clauses['data']['invite_sent'] = 1; 638 $where_clauses['format'][] = '%d'; 639 } 640 } 641 642 // accepted 643 if ( ! empty( $args['accepted'] ) && 'all' !== $args['accepted'] ) { 644 if ( $args['accepted'] == 'pending' ) { 645 $where_clauses['data']['accepted'] = 0; 646 $where_clauses['format'][] = '%d'; 647 } else if ( $args['accepted'] == 'accepted' ) { 648 $where_clauses['data']['accepted'] = 1; 649 $where_clauses['format'][] = '%d'; 650 } 651 } 652 653 return $where_clauses; 654 } 655 656 /** Public Static Methods *********************************************/ 657 658 /** 659 * @TODO: use? 660 * Check that a specific invitation is for a specific user. 661 * 662 * @since 2.7.0 663 * 664 * @param int $user_id ID of the user being checked. 665 * @param int $invitation_id ID of the invitation being checked. 666 * @return bool True if the invitation belongs to the user, otherwise 667 * false. 668 */ 669 public static function check_access( $user_id, $invitation_id ) { 670 global $wpdb; 671 672 $bp = buddypress(); 673 674 return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->core->table_name_invitations} WHERE id = %d AND user_id = %d", $invitation_id, $user_id ) ); 675 } 676 677 /** 678 * Get invitations, based on provided filter parameters. 679 * 680 * @since 2.7.0 681 * 682 * @param array $args { 683 * Associative array of arguments. All arguments but $page and 684 * $per_page can be treated as filter values for get_where_sql() 685 * and get_query_clauses(). All items are optional. 686 * @type int|array $id ID of invitation being updated. 687 * Can be an array of IDs. 688 * @type int|array $user_id ID of user being queried. Can be an 689 * Can be an array of IDs. 690 * @type int|array $inviter_id ID of user who created the 691 * invitation. Can be an array of IDs. 692 * @type string|array $invitee_email Email address of invited users 693 * being queried. Can be an array of 694 * addresses. 695 * @type string|array $component_name Name of the component to filter by. 696 * Can be an array of component names. 697 * @type string|array $component_action Name of the action to filter by. 698 * Can be an array of actions. 699 * @type int|array $item_id ID of associated item. 700 * Can be an array of multiple item IDs. 701 * @type int|array $secondary_item_id ID of secondary associated item. 702 * Can be an array of multiple IDs. 703 * @type string|array $type Type of item. An "invite" is sent 704 * from one user to another. 705 * A "request" is submitted by a 706 * user and no inviter is required. 707 * 'all' returns all. Default: 'all'. 708 * @type string $invite_sent Limit to draft, sent or all 709 * 'draft' limits to unsent invites, 710 * 'sent' returns only sent invites, 711 * 'all' returns all. Default: 'all'. 712 * @type bool $accepted Limit to accepted or 713 * not-yet-accepted invitations. 714 * 'accepted' returns accepted invites, 715 * 'pending' returns pending invites, 716 * 'all' returns all. Default: 'pending' 717 * @type string $search_terms Term to match against component_name 718 * or component_action fields. 719 * @type string $order_by Database column to order by. 720 * @type string $sort_order Either 'ASC' or 'DESC'. 721 * @type string $order_by Field to order results by. 722 * @type string $sort_order ASC or DESC. 723 * @type int $page Number of the current page of results. 724 * Default: false (no pagination, 725 * all items). 726 * @type int $per_page Number of items to show per page. 727 * Default: false (no pagination, 728 * all items). 729 * } 730 * 731 * @return array Located invitations. 732 */ 733 public static function get( $args = array() ) { 734 global $wpdb; 735 736 // Parse the arguments 737 $r = wp_parse_args( $args, array( 738 'id' => false, 739 'user_id' => false, 740 'inviter_id' => false, 741 'invitee_email' => false, 742 'component_name' => bp_invitations_get_registered_components(), 743 'component_action' => false, 744 'item_id' => false, 745 'secondary_item_id' => false, 746 'type' => 'all', 747 'invite_sent' => 'all', 748 'accepted' => 'pending', 749 'search_terms' => '', 750 'order_by' => false, 751 'sort_order' => false, 752 'page' => false, 753 'per_page' => false, 754 ) ); 755 756 // SELECT 757 $select_sql = "SELECT *"; 758 759 // FROM 760 $from_sql = "FROM " . buddypress()->invitations->table_name; 761 762 // WHERE 763 $where_sql = self::get_where_sql( array( 764 'id' => $r['id'], 765 'user_id' => $r['user_id'], 766 'inviter_id' => $r['inviter_id'], 767 'invitee_email' => $r['invitee_email'], 768 'component_name' => $r['component_name'], 769 'component_action' => $r['component_action'], 770 'item_id' => $r['item_id'], 771 'secondary_item_id' => $r['secondary_item_id'], 772 'type' => $r['type'], 773 'invite_sent' => $r['invite_sent'], 774 'accepted' => $r['accepted'], 775 'search_terms' => $r['search_terms'], 776 ) ); 777 778 // ORDER BY 779 $order_sql = self::get_order_by_sql( array( 780 'order_by' => $r['order_by'], 781 'sort_order' => $r['sort_order'] 782 ) ); 783 784 // LIMIT %d, %d 785 $pag_sql = self::get_paged_sql( array( 786 'page' => $r['page'], 787 'per_page' => $r['per_page'], 788 ) ); 789 790 $sql = "{$select_sql} {$from_sql} {$where_sql} {$order_sql} {$pag_sql}"; 791 792 return $wpdb->get_results( $sql ); 793 } 794 795 /** 796 * Get a count of total invitations matching a set of arguments. 797 * 798 * @since 2.7.0 799 * 800 * @see BP_Invitations_Invitation::get() for a description of 801 * arguments. 802 * 803 * @param array $args See {@link BP_Invitations_Invitation::get()}. 804 * @return int Count of located items. 805 */ 806 public static function get_total_count( $args ) { 807 global $wpdb; 808 809 /** 810 * Default component_name to active_components 811 * 812 * @see http://buddypress.trac.wordpress.org/ticket/5300 813 */ 814 // $args = wp_parse_args( $args, array( 815 // 'component_name' => bp_invitations_get_registered_components() 816 // ) ); 817 818 // Load BuddyPress 819 $bp = buddypress(); 820 821 // Build the query 822 $select_sql = "SELECT COUNT(*)"; 823 $from_sql = "FROM {$bp->invitations->table_name}"; 824 $where_sql = self::get_where_sql( $args ); 825 $sql = "{$select_sql} {$from_sql} {$where_sql}"; 826 827 // Return the queried results 828 return $wpdb->get_var( $sql ); 829 } 830 831 /** 832 * Update invitations. 833 * 834 * @since 2.7.0 835 * 836 * @see BP_Invitations_Invitation::get() for a description of 837 * accepted update/where arguments. 838 * 839 * @param array $update_args Associative array of fields to update, 840 * and the values to update them to. Of the format 841 * array( 'user_id' => 4, 'component_name' => 'groups', ) 842 * @param array $where_args Associative array of columns/values, to 843 * determine which rows should be updated. Of the format 844 * array( 'item_id' => 7, 'component_action' => 'members', ) 845 * @return int|bool Number of rows updated on success, false on failure. 846 */ 847 public static function update( $update_args = array(), $where_args = array() ) { 848 $update = self::get_query_clauses( $update_args ); 849 $where = self::get_query_clauses( $where_args ); 850 851 do_action( 'bp_invitation_before_update', $where_args, $update_args ); 852 853 $retval = self::_update( $update['data'], $where['data'], $update['format'], $where['format'] ); 854 855 return $retval; 856 } 857 858 /** 859 * Delete invitations. 860 * 861 * @since 2.7.0 862 * 863 * @see BP_Invitations_Invitation::get() for a description of 864 * accepted where arguments. 865 * 866 * @param array $args Associative array of columns/values, to determine 867 * which rows should be deleted. Of the format 868 * array( 'item_id' => 7, 'component_action' => 'members', ) 869 * @return int|bool Number of rows deleted on success, false on failure. 870 */ 871 public static function delete( $args = array() ) { 872 $where = self::get_query_clauses( $args ); 873 874 do_action( 'bp_invitation_before_delete', $args ); 875 876 return self::_delete( $where['data'], $where['format'] ); 877 } 878 879 /** Convenience methods ***********************************************/ 880 881 /** 882 * Delete a single invitation by ID. 883 * 884 * @since 2.7.0 885 * 886 * @see BP_Invitations_Invitation::delete() for explanation of 887 * return value. 888 * 889 * @param int $id ID of the invitation item to be deleted. 890 * @return bool True on success, false on failure. 891 */ 892 public static function delete_by_id( $id ) { 893 return self::delete( array( 894 'id' => $id, 895 ) ); 896 } 897 898 /** Sent status ***********************************************************/ 899 900 /** 901 * Mark specific invitations as sent by invitation ID. 902 * 903 * @since 2.7.0 904 * 905 * @param int $id The ID of the invitation to mark as sent. 906 */ 907 public static function mark_sent( $id = 0 ) { 908 909 if ( ! $id ) { 910 return false; 911 } 912 913 // Values to be updated 914 $update_args = array( 915 'invite_sent' => 1, 916 ); 917 918 // WHERE clauses 919 $where_args = array( 920 'id' => $id, 921 ); 922 923 return self::update( $update_args, $where_args ); 924 } 925 926 /** 927 * Mark invitations as sent that are found by user_id, inviter_id, item id, and optional 928 * secondary item id, and component name and action. 929 * 930 * @since 2.7.0 931 * 932 * @param int $user_id ID of user being invited. 933 * @param int $inviter_id ID of user who created the invitation. 934 * @param string $component_name The component that the invitations 935 * are associated with. 936 * @param string $component_action The action that the invitations 937 * are associated with. 938 * @param int $item_id The ID of the item associated with the 939 * invitations. 940 * @param string $secondary_item_id Optional. ID of the secondary 941 * associated item. 942 */ 943 public static function mark_sent_by_data( $args ) { 944 945 // Values to be updated 946 $update_args = array( 947 'invite_sent' => 1, 948 ); 949 950 return self::update( $update_args, $args ); 951 } 952 953 /** Accepted status ***********************************************************/ 954 955 /** 956 * Mark specific invitations as accepted by invitation ID. 957 * 958 * @since 2.7.0 959 * 960 * @param int $id The ID of the invitation to mark as sent. 961 */ 962 public static function mark_accepted( $id = 0 ) { 963 964 if ( ! $id ) { 965 return false; 966 } 967 968 // Values to be updated 969 $update_args = array( 970 'accepted' => 1, 971 ); 972 973 // WHERE clauses 974 $where_args = array( 975 'id' => $id, 976 ); 977 978 return self::update( $update_args, $where_args ); 979 } 980 981 /** 982 * Mark invitations as accepted that are found by user_id, inviter_id, 983 * item id, and optional secondary item id, and component name and action. 984 * 985 * @since 2.7.0 986 * 987 * @param int $user_id ID of user being invited. 988 * @param int $inviter_id ID of user who created the invitation. 989 * @param string $component_name The component that the invitations 990 * are associated with. 991 * @param string $component_action The action that the invitations 992 * are associated with. 993 * @param int $item_id The ID of the item associated with the 994 * invitations. 995 * @param string $secondary_item_id Optional. ID of the secondary 996 * associated item. 997 */ 998 public static function mark_accepted_by_data( $args ) { 999 1000 // Values to be updated 1001 $update_args = array( 1002 'accepted' => 1, 1003 ); 1004 1005 return self::update( $update_args, $args ); 1006 } 1007 1008 /** 1009 * Filter a list of invitations based on an array of arguments. 1010 * 1011 * @since 2.7.0 1012 * 1013 * @param array $invitations List of invitation objects to filter. 1014 * @param array $r { 1015 * Array of optional arguments. 1016 * @type int|array $user_id ID of user being queried. Can be an 1017 * array of user IDs. 1018 * @type string|array $invitee_email Email address of invited users 1019 * being queried. Can be an array of addresses. 1020 * @type string|array $component_name Name of the component to 1021 * filter by. Can be an array of component names. 1022 * @type string|array $component_action Name of the action to 1023 * filter by. Can be an array of actions. 1024 * @type int|array $item_id ID of associated item. Can be an array 1025 * of multiple item IDs. 1026 * @type int|array $secondary_item_id ID of secondary associated 1027 * item. Can be an array of multiple IDs. 1028 * @type string $invite_sent Limit to draft, sent or all 1029 * invitations. 'draft' returns only unsent 1030 * invitations, 'sent' returns only sent 1031 * invitations, 'all' returns all. Default: 'all'. 1032 * @type string $order_by Database column to order by. 1033 * @type string $sort_order Either 'ASC' or 'DESC'. 1034 * } 1035 * 1036 * @return array Filtered list of invitations 1037 */ 1038 public static function filter_invitations_by_arguments( $invitations, $args ) { 1039 // Normalize group data. 1040 foreach ( $invitations as &$invitation ) { 1041 // Integer values. 1042 foreach ( array( 'id', 'user_id', 'inviter_id', 'item_id', 'secondary_item_id' ) as $index ) { 1043 $invitation->{$index} = intval( $invitation->{$index} ); 1044 } 1045 // Boolean values. 1046 $invitation->invite_sent = (bool) $invitation->invite_sent; 1047 $invitation->accepted = (bool) $invitation->accepted; 1048 } 1049 // Normalize arguments. 1050 $r = wp_parse_args( $args, array( 1051 'user_id' => false, 1052 'inviter_id' => false, 1053 'invitee_email' => false, 1054 'component_name' => false, 1055 'component_action' => false, 1056 'item_id' => false, 1057 'secondary_item_id' => false, 1058 'type' => false, 1059 'invite_sent' => false, 1060 'accepted' => false, 1061 'order_by' => false, 1062 'sort_order' => 'ASC', 1063 'page' => false, 1064 'per_page' => false, 1065 ) ); 1066 1067 // Filter the results 1068 // Assemble filter array for use in `wp_list_filter()`. 1069 $filters = wp_array_slice_assoc( $r, array( 'user_id', 'inviter_id', 'component_name', 'component_action', 'item_id', 'secondary_item_id', 'type', 'invite_sent', 'accepted' ) ); 1070 1071 foreach ( $filters as $filter_name => $filter_value ) { 1072 if ( ! $filter_value ) { 1073 unset( $filters[ $filter_name ] ); 1074 } elseif ( 'type' == $filter_name ) { 1075 // Special case for handling type values. 1076 switch ( $filter_value ) { 1077 case 'invite': 1078 $filters[ $filter_name ] = 'invite'; 1079 break; 1080 case 'request': 1081 $filters[ $filter_name ] = 'request'; 1082 break; 1083 default: 1084 // Treat any other value as 'all'--no filtering. 1085 unset( $filters[ $filter_name ] ); 1086 break; 1087 } 1088 } elseif ( 'invite_sent' == $filter_name ) { 1089 // Special case for handling invite_sent values. 1090 switch ( $filter_value ) { 1091 case 'draft': 1092 $filters[ $filter_name ] = 0; 1093 break; 1094 case 'sent': 1095 $filters[ $filter_name ] = 1; 1096 break; 1097 default: 1098 // Treat any other value as 'all'--no filtering. 1099 unset( $filters[ $filter_name ] ); 1100 break; 1101 } 1102 } elseif ( 'accepted' == $filter_name ) { 1103 // Special case for handling invite_sent values. 1104 switch ( $filter_value ) { 1105 case 'pending': 1106 $filters[ $filter_name ] = 0; 1107 break; 1108 case 'accepted': 1109 $filters[ $filter_name ] = 1; 1110 break; 1111 default: 1112 // Treat any other value as 'pending'--no filtering. 1113 unset( $filters[ $filter_name ] ); 1114 break; 1115 } 1116 } 1117 } 1118 1119 if ( ! empty( $filters ) ) { 1120 $invitations = self::invite_list_filter( $invitations, $filters ); 1121 } 1122 1123 // Sort the results on a column name. 1124 if ( in_array( $r['order_by'], array( 'component_name', 'component_action', 'item_id', 'secondary_item_id' ) ) ) { 1125 $invitations = bp_sort_by_key( $invitations, $r['order_by'] ); 1126 } 1127 1128 // Adjust the sort direction of the results. 1129 if ( 'DESC' === strtoupper( $r['sort_order'] ) ) { 1130 // `true` to preserve keys. 1131 $invitations = array_reverse( $invitations, true ); 1132 } 1133 1134 // Paginate the results. 1135 if ( $r['per_page'] ) { 1136 $start = ( $r['page'] - 1 ) * ( $r['per_page'] ); 1137 $invitations = array_slice( $invitations, $start, $r['per_page'] ); 1138 } 1139 1140 return $invitations; 1141 } 1142 1143 /** 1144 * Filters a list of objects, based on a set of key => value arguments. 1145 * Almost an exact copy of `wp_list_filter()`, this function allows the 1146 * filters to be arrays of values for an `IN()` analog. 1147 * 1148 * @since 2.7.0 1149 * 1150 * @param array $list An array of objects to filter. 1151 * @param array $args Optional. An array of key => value arguments to match 1152 * against each object. Default empty array. 1153 * @param string $operator Optional. The logical operation to perform. 'AND' means 1154 * all elements from the array must match. 'OR' means only 1155 * one element needs to match. 'NOT' means no elements may 1156 * match. Default 'AND'. 1157 * @return array Array of found values. 1158 */ 1159 private static function invite_list_filter( $list, $args = array(), $operator = 'AND' ) { 1160 if ( ! is_array( $list ) ){ 1161 return array(); 1162 } 1163 1164 if ( empty( $args ) ) { 1165 return $list; 1166 } 1167 1168 $operator = strtoupper( $operator ); 1169 $count = count( $args ); 1170 $filtered = array(); 1171 1172 foreach ( $list as $key => $obj ) { 1173 $to_match = (array) $obj; 1174 1175 $matched = 0; 1176 foreach ( $args as $m_key => $m_value ) { 1177 if ( array_key_exists( $m_key, $to_match ) ) { 1178 if ( is_array( $m_value) && in_array( $to_match[ $m_key ], $m_value ) ) { 1179 $matched++; 1180 } elseif ( $m_value == $to_match[ $m_key ] ) { 1181 $matched++; 1182 } 1183 } 1184 } 1185 1186 if ( ( 'AND' == $operator && $matched == $count ) 1187 || ( 'OR' == $operator && $matched > 0 ) 1188 || ( 'NOT' == $operator && 0 == $matched ) ) { 1189 $filtered[$key] = $obj; 1190 } 1191 } 1192 1193 return $filtered; 1194 } 1195 } -
src/bp-groups/bp-groups-actions.php
diff --git src/bp-groups/bp-groups-actions.php src/bp-groups/bp-groups-actions.php index 2190cec..1224f55 100644
function groups_action_group_feed() { 551 551 ) ); 552 552 } 553 553 add_action( 'bp_actions', 'groups_action_group_feed' ); 554 555 /** 556 * Clean up requests/invites when a member leaves a group. 557 * 558 * @since 2.7.0 559 * 560 * @return int|false Number of rows changed on success. False on failure. 561 */ 562 function groups_action_clean_up_invites_requests( $user_id, $group_id ) { 563 $bp = buddypress(); 564 565 $args = array( 566 'user_id' => $user_id, 567 'component_name' => $bp->groups->id, 568 'component_action' => $bp->groups->id . '_invite', 569 'item_id' => $group_id, 570 'type' => 'all', 571 'invite_sent' => 'all', 572 'accepted' => 'all' 573 ); 574 bp_invitations_delete_invitations( $args ); 575 } 576 add_action( 'bp_groups_member_after_delete', 'groups_action_clean_up_invites_requests', 10, 2 ); -
src/bp-groups/bp-groups-functions.php
diff --git src/bp-groups/bp-groups-functions.php src/bp-groups/bp-groups-functions.php index c5cdc1f..2934fdf 100644
function groups_join_group( $group_id, $user_id = 0 ) { 480 480 if ( empty( $user_id ) ) 481 481 $user_id = bp_loggedin_user_id(); 482 482 483 // Check if the user has an outstanding invite. If so, delete it.484 if ( groups_check_user_has_invite( $user_id, $group_id ) ) 483 // Check if the user has any outstanding invites. If so, delete it. 484 if ( groups_check_user_has_invite( $user_id, $group_id ) ) { 485 485 groups_delete_invite( $user_id, $group_id ); 486 } 486 487 487 488 // Check if the user has an outstanding request. If so, delete it. 488 if ( groups_check_for_membership_request( $user_id, $group_id ) ) 489 groups_delete_membership_request( null, $user_id, $group_id ); 489 if ( groups_check_for_membership_request( $user_id, $group_id ) ) { 490 groups_delete_membership_request( false, $user_id, $group_id ); 491 } 490 492 491 493 // User is already a member, just return true. 492 if ( groups_is_user_member( $user_id, $group_id ) ) 494 if ( groups_is_user_member( $user_id, $group_id ) ) { 493 495 return true; 496 } 494 497 495 498 $new_member = new BP_Groups_Member; 496 499 $new_member->group_id = $group_id; … … function groups_join_group( $group_id, $user_id = 0 ) { 501 504 $new_member->date_modified = bp_core_current_time(); 502 505 $new_member->is_confirmed = 1; 503 506 504 if ( ! $new_member->save() )507 if ( ! $new_member->save() ) 505 508 return false; 506 509 507 510 $bp = buddypress(); … … function groups_post_update( $args = '' ) { 1047 1050 */ 1048 1051 function groups_get_invites_for_user( $user_id = 0, $limit = false, $page = false, $exclude = false ) { 1049 1052 1050 if ( empty( $user_id ) ) 1053 if ( empty( $user_id ) ) { 1051 1054 $user_id = bp_loggedin_user_id(); 1055 } 1052 1056 1053 1057 return BP_Groups_Member::get_invites( $user_id, $limit, $page, $exclude ); 1054 1058 } … … function groups_get_invites_for_user( $user_id = 0, $limit = false, $page = fals 1062 1066 * @return int 1063 1067 */ 1064 1068 function groups_get_invite_count_for_user( $user_id = 0 ) { 1069 1065 1070 if ( empty( $user_id ) ) { 1066 1071 $user_id = bp_loggedin_user_id(); 1067 1072 } 1068 1073 1069 return BP_Groups_Member::get_invite_count_for_user( $user_id ); 1074 $count = wp_cache_get( $user_id, 'bp_group_invite_count' ); 1075 1076 if ( false === $count ) { 1077 $count = BP_Groups_Member::get_invite_count_for_user( $user_id ); 1078 wp_cache_set( $user_id, $count, 'bp_group_invite_count' ); 1079 } 1080 1081 return $count; 1082 } 1083 1084 /** 1085 * Get an array of group IDs to which a user is invited. 1086 * 1087 * @since 2.7.0 1088 * 1089 * @param int $user_id The user ID. 1090 * 1091 * @return array Array of group IDs. 1092 */ 1093 function groups_get_invited_to_group_ids( $user_id = 0 ) { 1094 1095 if ( empty( $user_id ) ) { 1096 $user_id = bp_loggedin_user_id(); 1097 } 1098 1099 return BP_Groups_Member::get_invited_to_group_ids( $user_id ); 1070 1100 } 1071 1101 1072 1102 /** 1073 1103 * Invite a user to a group. 1074 1104 * 1075 1105 * @since 1.0.0 1106 * @since 2.7.0 Added 'content' parameter. 1076 1107 * 1077 1108 * @param array|string $args { 1078 1109 * Array of arguments. … … function groups_get_invite_count_for_user( $user_id = 0 ) { 1082 1113 * ID of the logged-in user. 1083 1114 * @type string $date_modified Optional. Modified date for the invitation. 1084 1115 * Default: current date/time. 1116 * @type string $content Optional. Message to invitee. 1085 1117 * @type bool $is_confirmed Optional. Whether the invitation should be 1086 1118 * marked confirmed. Default: false. 1087 1119 * } … … function groups_invite_user( $args = '' ) { 1094 1126 'group_id' => false, 1095 1127 'inviter_id' => bp_loggedin_user_id(), 1096 1128 'date_modified' => bp_core_current_time(), 1129 'content' => '', 1097 1130 'is_confirmed' => 0 1098 1131 ); 1099 1132 1100 1133 $args = wp_parse_args( $args, $defaults ); 1101 extract( $args, EXTR_SKIP );1102 1134 1103 if ( ! $ user_id || ! $group_id || ! $inviter_id) {1135 if ( ! $args['user_id'] || ! $args['group_id'] || ! $args['inviter_id'] ) { 1104 1136 return false; 1105 1137 } 1106 1138 1107 1139 // If the user has already requested membership, accept the request. 1108 if ( $membership_id = groups_check_for_membership_request( $user_id, $group_id) ) {1109 groups_accept_membership_request( $membership_id, $user_id, $group_id);1140 if ( groups_check_for_membership_request( $args['user_id'], $args['group_id'] ) ) { 1141 groups_accept_membership_request( null, $args['user_id'], $args['group_id'] ); 1110 1142 1111 1143 // Otherwise, create a new invitation. 1112 } elseif ( ! groups_is_user_member( $user_id, $group_id ) && ! groups_check_user_has_invite( $user_id, $group_id, 'all' ) ) { 1113 $invite = new BP_Groups_Member; 1114 $invite->group_id = $group_id; 1115 $invite->user_id = $user_id; 1116 $invite->date_modified = $date_modified; 1117 $invite->inviter_id = $inviter_id; 1118 $invite->is_confirmed = $is_confirmed; 1119 1120 if ( !$invite->save() ) 1144 } elseif ( ! groups_is_user_member( $args['user_id'], $args['group_id'] ) && ! groups_check_has_invite_from_user( $args['user_id'], $args['group_id'], $args['inviter_id'], 'all' ) ) { 1145 1146 $bp = buddypress(); 1147 1148 $args = array( 1149 'user_id' => $args['user_id'], 1150 'inviter_id' => $args['inviter_id'], 1151 'component_name' => $bp->groups->id, 1152 'component_action' => $bp->groups->id . '_invite', 1153 'item_id' => $args['group_id'], 1154 'content' => $args['content'], 1155 'date_modified' => $args['date_modified'] 1156 ); 1157 if ( ! bp_invitations_add_invitation( $args ) ) { 1121 1158 return false; 1159 } 1122 1160 1123 1161 /** 1124 1162 * Fires after the creation of a new group invite. … … function groups_invite_user( $args = '' ) { 1134 1172 } 1135 1173 1136 1174 /** 1137 * Uninvite a user from a group. 1138 * 1139 * Functionally, this is equivalent to removing a user from a group. 1175 * Unextend a group invitation. 1140 1176 * 1141 1177 * @since 1.0.0 1142 1178 * 1143 * @param int $user_id ID of the user. 1144 * @param int $group_id ID of the group. 1179 * @param int $user_id ID of the user. 1180 * @param int $group_id ID of the group. 1181 * @param int $inviter_id ID of the inviter. 1182 * 1145 1183 * @return bool True on success, false on failure. 1146 1184 */ 1147 function groups_uninvite_user( $user_id, $group_id ) {1185 function groups_uninvite_user( $user_id, $group_id, $inviter_id = false ) { 1148 1186 1149 if ( ! BP_Groups_Member::delete_invite( $user_id, $group_id ) )1187 if ( ! BP_Groups_Member::delete_invite( $user_id, $group_id, $inviter_id ) ) { 1150 1188 return false; 1189 } 1151 1190 1152 1191 /** 1153 1192 * Fires after uninviting a user from a group. 1154 1193 * 1155 1194 * @since 1.0.0 1195 * @since 2.7.0 Added $inviter_id parameter 1156 1196 * 1157 1197 * @param int $group_id ID of the group being uninvited from. 1158 1198 * @param int $user_id ID of the user being uninvited. 1159 1199 */ 1160 do_action( 'groups_uninvite_user', $group_id, $user_id );1200 do_action( 'groups_uninvite_user', $group_id, $user_id, $inviter_id ); 1161 1201 1162 1202 return true; 1163 1203 } … … function groups_uninvite_user( $user_id, $group_id ) { 1174 1214 * @return bool True when the user is a member of the group, otherwise false. 1175 1215 */ 1176 1216 function groups_accept_invite( $user_id, $group_id ) { 1217 $bp = buddypress(); 1218 $accept_args = array( 1219 'user_id' => $user_id, 1220 'component_name' => $bp->groups->id, 1221 'component_action' => $bp->groups->id . '_invite', 1222 'item_id' => $group_id, 1223 ); 1177 1224 1178 1225 // If the user is already a member (because BP at one point allowed two invitations to 1179 1226 // slip through), delete all existing invitations/requests and return true. 1180 1227 if ( groups_is_user_member( $user_id, $group_id ) ) { 1181 1228 if ( groups_check_user_has_invite( $user_id, $group_id ) ) { 1182 groups_delete_invite( $user_id, $group_id);1229 bp_invitations_mark_accepted( $accept_args ); 1183 1230 } 1184 1231 1185 1232 if ( groups_check_for_membership_request( $user_id, $group_id ) ) { … … function groups_accept_invite( $user_id, $group_id ) { 1192 1239 $member = new BP_Groups_Member( $user_id, $group_id ); 1193 1240 $member->accept_invite(); 1194 1241 1195 if ( ! $member->save() ) {1242 if ( ! $member->save() ) { 1196 1243 return false; 1197 1244 } 1198 1245 1199 1246 // Remove request to join. 1200 if ( $member->check_for_membership_request( $user_id, $group_id ) ) {1201 $member->delete_request($user_id, $group_id );1247 if ( groups_check_for_membership_request( $user_id, $group_id ) ) { 1248 groups_delete_membership_request( null, $user_id, $group_id ); 1202 1249 } 1203 1250 1251 // Mark invitation as accepted. 1252 bp_invitations_mark_accepted( $accept_args ); 1253 1204 1254 // Modify group meta. 1205 1255 groups_update_groupmeta( $group_id, 'last_activity', bp_core_current_time() ); 1206 1256 … … function groups_accept_invite( $user_id, $group_id ) { 1222 1272 * 1223 1273 * @since 1.0.0 1224 1274 * 1225 * @param int $user_id ID of the user. 1226 * @param int $group_id ID of the group. 1275 * @param int $user_id ID of the user. 1276 * @param int $group_id ID of the group. 1277 * @param int $inviter_id ID of the inviter. 1278 * 1227 1279 * @return bool True on success, false on failure. 1228 1280 */ 1229 function groups_reject_invite( $user_id, $group_id ) {1230 if ( ! BP_Groups_Member::delete_invite( $user_id, $group_id ) )1281 function groups_reject_invite( $user_id, $group_id, $inviter_id = false ) { 1282 if ( ! BP_Groups_Member::delete_invite( $user_id, $group_id, $inviter_id ) ) { 1231 1283 return false; 1284 } 1232 1285 1233 1286 /** 1234 1287 * Fires after a user rejects a group invitation. … … function groups_reject_invite( $user_id, $group_id ) { 1250 1303 * 1251 1304 * @param int $user_id ID of the invited user. 1252 1305 * @param int $group_id ID of the group. 1306 * @param int $inviter_id ID of the inviter. 1307 * 1253 1308 * @return bool True on success, false on failure. 1254 1309 */ 1255 function groups_delete_invite( $user_id, $group_id ) {1256 if ( ! BP_Groups_Member::delete_invite( $user_id, $group_id ) )1310 function groups_delete_invite( $user_id, $group_id, $inviter_id = false ) { 1311 if ( ! BP_Groups_Member::delete_invite( $user_id, $group_id, $inviter_id ) ) { 1257 1312 return false; 1313 } 1258 1314 1259 1315 /** 1260 1316 * Fires after the deletion of a group invitation. … … function groups_delete_invite( $user_id, $group_id ) { 1278 1334 * @param int $group_id ID of the group. 1279 1335 */ 1280 1336 function groups_send_invites( $user_id, $group_id ) { 1337 $bp = buddypress(); 1281 1338 1282 if ( empty( $user_id ) ) 1339 if ( empty( $user_id ) ) { 1283 1340 $user_id = bp_loggedin_user_id(); 1341 } 1284 1342 1285 1343 // Send friend invites. 1344 $success = 0; 1286 1345 $invited_users = groups_get_invites_for_group( $user_id, $group_id ); 1287 $group = groups_get_group( array( 'group_id' => $group_id ) );1288 1346 1289 for ( $i = 0, $count = count( $invited_users ); $i < $count; ++$i ) { 1290 $member = new BP_Groups_Member( $invited_users[$i], $group_id ); 1347 $invite_args = array( 1348 'inviter_id' => $user_id, 1349 'component_name' => $bp->groups->id, 1350 'component_action' => $bp->groups->id . '_invite', 1351 'item_id' => $group_id, 1352 ); 1291 1353 1292 // Send the actual invite. 1293 groups_notification_group_invites( $group, $member, $user_id ); 1354 foreach ( $invited_users as $invited_user_id ) { 1355 // Send the notification and associated email. 1356 groups_notification_single_group_invite( $group_id, $invited_user_id, $user_id, false ); 1294 1357 1295 $member->invite_sent = 1; 1296 $member->save(); 1358 $invite_args['user_id'] = $invited_user_id; 1359 if ( bp_invitations_mark_sent( $invite_args ) ) { 1360 $success++; 1361 } 1297 1362 } 1298 1363 1299 1364 /** … … function groups_send_invites( $user_id, $group_id ) { 1307 1372 * @param int $user_id ID of the inviting user. 1308 1373 */ 1309 1374 do_action( 'groups_send_invites', $group_id, $invited_users, $user_id ); 1375 1376 if ( $success == count( $invited_users ) ) { 1377 return true; 1378 } else { 1379 return false; 1380 } 1310 1381 } 1311 1382 1312 1383 /** … … function groups_get_invites_for_group( $user_id, $group_id ) { 1324 1395 } 1325 1396 1326 1397 /** 1398 * Get invitations to a given group filtered by arguments. Cached. 1399 * 1400 * @since 2.7.0 1401 * 1402 * @param int $group_id ID of the group. 1403 * @param array $args Invitation arguments. 1404 * See `bp_invitations_get_invitations()` for list. 1405 * 1406 * @return array { 1407 * array $invites Matching invitation objects. 1408 * int $total_count Total number of invites to group. 1409 * } user but have not yet accepted. 1410 */ 1411 function groups_get_invites_for_group_by_data( $group_id, $args = array() ) { 1412 return BP_Groups_Group::get_invitations_by_data( $group_id, $args ); 1413 } 1414 1415 /** 1327 1416 * Check to see whether a user has already been invited to a group. 1328 1417 * 1329 1418 * By default, the function checks for invitations that have been sent. … … function groups_check_user_has_invite( $user_id, $group_id, $type = 'sent' ) { 1343 1432 } 1344 1433 1345 1434 /** 1435 * Check to see whether a user has already been invited to a group by a particular user. 1436 * 1437 * By default, the function checks for invitations that have been sent. 1438 * Entering 'all' as the $type parameter will return unsent invitations as 1439 * well (useful to make sure AJAX requests are not duplicated). 1440 * 1441 * @since 1.0.0 1442 * 1443 * @param int $user_id ID of potential group member. 1444 * @param int $group_id ID of potential group. 1445 * @param string $type Optional. Use 'sent' to check for sent invites, 1446 * 'all' to check for all. Default: 'sent'. 1447 * @return bool True if an invitation is found, otherwise false. 1448 */ 1449 function groups_check_has_invite_from_user( $user_id, $group_id, $inviter_id = 0, $type = 'sent' ) { 1450 return BP_Groups_Member::check_has_invite_from_user( $user_id, $group_id, $inviter_id, $type = 'sent' ); 1451 } 1452 1453 /** 1454 * Get the details of a single group invitation. 1455 * 1456 * @since 1.0.0 1457 * 1458 * @param int $user_id ID of the inviting user. 1459 * @param int $group_id ID of the group. 1460 * @param int $inviter_id ID of the inviting user. 1461 * 1462 * @return array $invitation Details of group invitation. 1463 */ 1464 function groups_get_single_invite( $user_id, $group_id, $inviter_id ) { 1465 $bp = buddypress(); 1466 1467 if ( empty( $user_id ) || empty( $group_id ) || empty( $inviter_id ) ) { 1468 return false; 1469 } 1470 1471 $args = array( 1472 'inviter_id' => $inviter_id, 1473 'component_name' => $bp->groups->id, 1474 'component_action' => $bp->groups->id . '_invite', 1475 'item_id' => $group_id, 1476 'invite_sent' => 'all', 1477 'accepted' => 'all' 1478 ); 1479 $invite = bp_get_user_invitations( $user_id, $args ); 1480 if ( $invite ) { 1481 return current( $invite ); 1482 } 1483 } 1484 1485 /** 1346 1486 * Delete all invitations to a given group. 1347 1487 * 1348 1488 * @since 1.0.0 … … function groups_check_user_has_invite( $user_id, $group_id, $type = 'sent' ) { 1351 1491 * @return int|null Number of rows records deleted on success, null on failure. 1352 1492 */ 1353 1493 function groups_delete_all_group_invites( $group_id ) { 1494 // DC: updated 1354 1495 return BP_Groups_Group::delete_all_invites( $group_id ); 1355 1496 } 1356 1497 … … function groups_send_membership_request( $requesting_user_id, $group_id ) { 1535 1676 groups_accept_invite( $requesting_user_id, $group_id ); 1536 1677 return true; 1537 1678 } 1679 $bp = buddypress(); 1680 1681 $request_args = array( 1682 'user_id' => $requesting_user_id, 1683 'component_name' => $bp->groups->id, 1684 'component_action' => $bp->groups->id . '_invite', 1685 'item_id' => $group_id, 1686 'content' => isset( $_POST['group-request-membership-comments'] ) ? $_POST['group-request-membership-comments'] : '', 1687 ); 1538 1688 1539 $requesting_user = new BP_Groups_Member; 1540 $requesting_user->group_id = $group_id; 1541 $requesting_user->user_id = $requesting_user_id; 1542 $requesting_user->inviter_id = 0; 1543 $requesting_user->is_admin = 0; 1544 $requesting_user->user_title = ''; 1545 $requesting_user->date_modified = bp_core_current_time(); 1546 $requesting_user->is_confirmed = 0; 1547 $requesting_user->comments = isset( $_POST['group-request-membership-comments'] ) ? $_POST['group-request-membership-comments'] : ''; 1548 1549 if ( $requesting_user->save() ) { 1689 if ( $request_id = bp_invitations_add_request( $request_args ) ) { 1550 1690 $admins = groups_get_group_admins( $group_id ); 1551 1691 1552 1692 // Saved okay, now send the email notification. 1553 1693 for ( $i = 0, $count = count( $admins ); $i < $count; ++$i ) 1554 groups_notification_new_membership_request( $requesting_user_id, $admins[$i]->user_id, $group_id, $request ing_user->id );1694 groups_notification_new_membership_request( $requesting_user_id, $admins[$i]->user_id, $group_id, $request_id ); 1555 1695 1556 1696 /** 1557 1697 * Fires after the creation of a new membership request. … … function groups_send_membership_request( $requesting_user_id, $group_id ) { 1563 1703 * @param int $group_id ID of the group being requested to. 1564 1704 * @param int $requesting_user->id ID of the user requesting membership. 1565 1705 */ 1566 do_action( 'groups_membership_requested', $requesting_user_id, $admins, $group_id, $request ing_user->id );1706 do_action( 'groups_membership_requested', $requesting_user_id, $admins, $group_id, $request_id ); 1567 1707 1568 1708 return true; 1569 1709 } … … function groups_send_membership_request( $requesting_user_id, $group_id ) { 1575 1715 * Accept a pending group membership request. 1576 1716 * 1577 1717 * @since 1.0.0 1718 * @since 2.7.0 Deprecated $membership_id argument. 1578 1719 * 1579 * @param int $membership_id ID of the membership object.1580 * @param int $user_id Optional.ID of the user who requested membership.1720 * @param int $membership_id Deprecated 2.7.0. ID of the membership object. 1721 * @param int $user_id ID of the user who requested membership. 1581 1722 * Provide this value along with $group_id to override 1582 1723 * $membership_id. 1583 * @param int $group_id Optional.ID of the group to which membership is being1724 * @param int $group_id ID of the group to which membership is being 1584 1725 * requested. Provide this value along with $user_id to 1585 1726 * override $membership_id. 1586 1727 * @return bool True on success, false on failure. 1587 1728 */ 1588 1729 function groups_accept_membership_request( $membership_id, $user_id = 0, $group_id = 0 ) { 1589 1730 1590 if ( !empty( $user_id ) && !empty( $group_id ) ) { 1591 $membership = new BP_Groups_Member( $user_id, $group_id ); 1592 } else { 1593 $membership = new BP_Groups_Member( false, false, $membership_id ); 1731 if ( ! empty( $membership_id ) ){ 1732 _deprecated_argument( __METHOD__, '2.0.0', sprintf( __( 'Argument `membership_id` passed to %1$s is deprecated. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) ); 1594 1733 } 1595 1734 1735 if ( ! $user_id || ! $group_id ) { 1736 return false; 1737 } 1738 1739 $membership = new BP_Groups_Member( $user_id, $group_id ); 1740 1596 1741 $membership->accept_request(); 1597 1742 1598 if ( ! $membership->save() ) {1743 if ( ! $membership->save() ) { 1599 1744 return false; 1600 1745 } 1601 1746 1602 // Check if the user has an outstanding invite, if so delete it. 1603 if ( groups_check_user_has_invite( $membership->user_id, $membership->group_id ) ) { 1604 groups_delete_invite( $membership->user_id, $membership->group_id ); 1605 } 1747 // Mark the request & any invitations as accepted. 1748 $bp = buddypress(); 1749 $request_args = array( 1750 'user_id' => $user_id, 1751 'component_name' => $bp->groups->id, 1752 'component_action' => $bp->groups->id . '_invite', 1753 'item_id' => $group_id, 1754 ); 1755 bp_invitations_accept_request( $request_args ); 1606 1756 1607 1757 /** 1608 1758 * Fires after a group membership request has been accepted. … … function groups_accept_membership_request( $membership_id, $user_id = 0, $group_ 1622 1772 * Reject a pending group membership request. 1623 1773 * 1624 1774 * @since 1.0.0 1775 * @since 2.7.0 Deprecated $membership_id argument. 1625 1776 * 1626 * @param int $membership_id ID of the membership object.1777 * @param int $membership_id Deprecated 2.7.0. ID of the membership object. 1627 1778 * @param int $user_id Optional. ID of the user who requested membership. 1628 1779 * Provide this value along with $group_id to override 1629 1780 * $membership_id. … … function groups_accept_membership_request( $membership_id, $user_id = 0, $group_ 1633 1784 * @return bool True on success, false on failure. 1634 1785 */ 1635 1786 function groups_reject_membership_request( $membership_id, $user_id = 0, $group_id = 0 ) { 1636 if ( !$membership = groups_delete_membership_request( $membership_id, $user_id, $group_id ) ) { 1787 if ( ! empty( $membership_id ) ){ 1788 _deprecated_argument( __METHOD__, '2.0.0', sprintf( __( 'Argument `membership_id` passed to %1$s is deprecated. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) ); 1789 } 1790 1791 if ( ! $membership = groups_delete_membership_request( false, $user_id, $group_id ) ) { 1637 1792 return false; 1638 1793 } 1639 1794 … … function groups_reject_membership_request( $membership_id, $user_id = 0, $group_ 1646 1801 * @param int $group_id ID of the group that was rejected membership to. 1647 1802 * @param bool $value If membership was accepted. 1648 1803 */ 1649 do_action( 'groups_membership_rejected', $ membership->user_id, $membership->group_id, false );1804 do_action( 'groups_membership_rejected', $user_id, $group_id, false ); 1650 1805 1651 1806 return true; 1652 1807 } … … function groups_reject_membership_request( $membership_id, $user_id = 0, $group_ 1655 1810 * Delete a pending group membership request. 1656 1811 * 1657 1812 * @since 1.2.0 1813 * @since 2.7.0 Deprecated $membership_id argument. 1658 1814 * 1659 * @param int $membership_id ID of the membership object.1660 * @param int $user_id Optional.ID of the user who requested membership.1815 * @param int $membership_id Deprecated 2.7.0. ID of the membership object. 1816 * @param int $user_id ID of the user who requested membership. 1661 1817 * Provide this value along with $group_id to override 1662 1818 * $membership_id. 1663 * @param int $group_id Optional.ID of the group to which membership is being1819 * @param int $group_id ID of the group to which membership is being 1664 1820 * requested. Provide this value along with $user_id to 1665 1821 * override $membership_id. 1666 1822 * @return bool True on success, false on failure. 1667 1823 */ 1668 1824 function groups_delete_membership_request( $membership_id, $user_id = 0, $group_id = 0 ) { 1669 if ( !empty( $user_id ) && !empty( $group_id ) ) 1670 $membership = new BP_Groups_Member( $user_id, $group_id ); 1671 else 1672 $membership = new BP_Groups_Member( false, false, $membership_id ); 1825 if ( ! empty( $membership_id ) ){ 1826 _deprecated_argument( __METHOD__, '2.0.0', sprintf( __( 'Argument `membership_id` passed to %1$s is deprecated. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) ); 1827 } 1673 1828 1674 if ( ! BP_Groups_Member::delete_request( $ membership->user_id, $membership->group_id ) )1829 if ( ! BP_Groups_Member::delete_request( $user_id, $group_id ) ) { 1675 1830 return false; 1831 } 1676 1832 1677 return $membership;1833 return true; 1678 1834 } 1679 1835 1680 1836 /** … … function groups_check_for_membership_request( $user_id, $group_id ) { 1691 1847 } 1692 1848 1693 1849 /** 1850 * Get an array of group IDs to which a user has requested membership. 1851 * 1852 * @since 2.7.0 1853 * 1854 * @param int $user_id The user ID. 1855 * 1856 * @return array Array of group IDs. 1857 */ 1858 function groups_get_membership_requested_group_ids( $user_id = 0 ) { 1859 if ( empty( $user_id ) ) { 1860 $user_id = bp_loggedin_user_id(); 1861 } 1862 1863 return BP_Groups_Member::get_membership_requested_group_ids( $user_id ); 1864 } 1865 1866 /** 1694 1867 * Accept all pending membership requests to a group. 1695 1868 * 1696 1869 * @since 1.0.2 … … function groups_check_for_membership_request( $user_id, $group_id ) { 1701 1874 function groups_accept_all_pending_membership_requests( $group_id ) { 1702 1875 $user_ids = BP_Groups_Member::get_all_membership_request_user_ids( $group_id ); 1703 1876 1704 if ( ! $user_ids )1877 if ( ! $user_ids ) { 1705 1878 return false; 1879 } 1706 1880 1707 foreach ( (array) $user_ids as $user_id ) 1881 foreach ( (array) $user_ids as $user_id ) { 1708 1882 groups_accept_membership_request( false, $user_id, $group_id ); 1883 } 1709 1884 1710 1885 /** 1711 1886 * Fires after the acceptance of all pending membership requests to a group. -
src/bp-groups/bp-groups-notifications.php
diff --git src/bp-groups/bp-groups-notifications.php src/bp-groups/bp-groups-notifications.php index 3ee37a2..b52d66d 100644
function groups_notification_group_invites( &$group, &$member, $inviter_user_id 257 257 return; 258 258 } 259 259 260 // @todo $inviter_ud may be used for caching, test without it261 $inviter_ud = bp_core_get_core_userdata( $inviter_user_id );262 260 $invited_user_id = $member->user_id; 263 261 262 groups_notification_single_group_invite( $group->id, $invited_user_id, $inviter_user_id ); 263 } 264 265 /** 266 * Notify a member they have been invited to a group. 267 * 268 * @since 2.7.0 269 * 270 * @param BP_Groups_Group $group Group object. 271 * @param int $user_id ID of invitee. 272 * @param int $inviter_id ID of the user who sent the invite. 273 * @param bool $resend Whether to send more than one email. 274 */ 275 function groups_notification_single_group_invite( $group_id, $user_id, $inviter_id, $resend = false ) { 276 // Get invitation. 277 $invite = groups_get_single_invite( $user_id, $group_id, $inviter_id ); 278 279 // Bail if no invite, or if member has already been notified. 280 if ( ! $invite || ( $invite->invite_sent && ! $resend ) ) { 281 return false; 282 } 283 284 // Get group object. 285 $group = groups_get_group( array( 'group_id' => $group_id ) ); 286 264 287 // Trigger a BuddyPress Notification. 265 288 if ( bp_is_active( 'notifications' ) ) { 266 289 bp_notifications_add_notification( array( 267 'user_id' => $ invited_user_id,268 'item_id' => $group ->id,290 'user_id' => $user_id, 291 'item_id' => $group_id, 269 292 'component_name' => buddypress()->groups->id, 270 293 'component_action' => 'group_invite', 271 294 ) ); … … function groups_notification_group_invites( &$group, &$member, $inviter_user_id 279 302 $invited_link = bp_core_get_user_domain( $invited_user_id ) . bp_get_groups_slug(); 280 303 $args = array( 281 304 'tokens' => array( 282 'group' => $group, 283 'group.url' => bp_get_group_permalink( $group ), 284 'group.name' => $group->name, 285 'inviter.name' => bp_core_get_userlink( $inviter_user_id, true, false, true ), 286 'inviter.url' => bp_core_get_user_domain( $inviter_user_id ), 287 'inviter.id' => $inviter_user_id, 288 'invites.url' => esc_url( $invited_link . '/invites/' ), 305 'group' => $group, 306 'group.url' => bp_get_group_permalink( $group ), 307 'group.name' => $group->name, 308 'inviter.name' => bp_core_get_userlink( $inviter_user_id, true, false, true ), 309 'inviter.url' => bp_core_get_user_domain( $inviter_user_id ), 310 'inviter.id' => $inviter_user_id, 311 'invites.url' => esc_url( $invited_link . '/invites/' ), 312 'invite.content' => $invite->content, 289 313 ), 290 314 ); 315 291 316 bp_send_email( 'groups-invitation', (int) $invited_user_id, $args ); 292 317 } 293 318 -
src/bp-groups/bp-groups-screens.php
diff --git src/bp-groups/bp-groups-screens.php src/bp-groups/bp-groups-screens.php index 904368e..7246fbd 100644
function groups_screen_group_admin_requests() { 1274 1274 } 1275 1275 1276 1276 $request_action = (string) bp_action_variable( 1 ); 1277 $membership_id = (int) bp_action_variable( 2 ); 1277 $user_id = (int) bp_action_variable( 2 ); 1278 $group_id = bp_get_current_group_id(); 1278 1279 1279 if ( ! empty( $request_action ) && !empty( $membership_id ) ) {1280 if ( 'accept' == $request_action && is_numeric( $ membership_id ) ) {1280 if ( ! empty( $request_action ) && ! empty( $user_id ) ) { 1281 if ( 'accept' == $request_action && is_numeric( $user_id ) ) { 1281 1282 1282 1283 // Check the nonce first. 1283 if ( ! check_admin_referer( 'groups_accept_membership_request' ) )1284 if ( ! check_admin_referer( 'groups_accept_membership_request' ) ) { 1284 1285 return false; 1286 } 1285 1287 1286 1288 // Accept the membership request. 1287 if ( ! groups_accept_membership_request( $membership_id ) )1289 if ( ! groups_accept_membership_request( false, $user_id, $group_id ) ) { 1288 1290 bp_core_add_message( __( 'There was an error accepting the membership request. Please try again.', 'buddypress' ), 'error' ); 1289 else1291 } else { 1290 1292 bp_core_add_message( __( 'Group membership request accepted', 'buddypress' ) ); 1293 } 1291 1294 1292 } elseif ( 'reject' == $request_action && is_numeric( $ membership_id ) ) {1295 } elseif ( 'reject' == $request_action && is_numeric( $user_id ) ) { 1293 1296 /* Check the nonce first. */ 1294 if ( ! check_admin_referer( 'groups_reject_membership_request' ) )1297 if ( ! check_admin_referer( 'groups_reject_membership_request' ) ) { 1295 1298 return false; 1299 } 1296 1300 1297 1301 // Reject the membership request. 1298 if ( ! groups_reject_membership_request( $membership_id ) )1302 if ( ! groups_reject_membership_request(false, $user_id, $group_id ) ) { 1299 1303 bp_core_add_message( __( 'There was an error rejecting the membership request. Please try again.', 'buddypress' ), 'error' ); 1300 else1304 } else { 1301 1305 bp_core_add_message( __( 'Group membership request rejected', 'buddypress' ) ); 1306 } 1302 1307 } 1303 1308 1309 // Was the member added to the group? 1310 $membership_id = groups_is_user_member( $user_id, $group_id ); 1311 1304 1312 /** 1305 1313 * Fires before the redirect if a group membership request has been handled. 1306 1314 * 1307 1315 * @since 1.0.0 1316 * @since 2.7.0 Added user ID and group ID parameters. 1308 1317 * 1309 1318 * @param int $id ID of the group that was edited. 1310 1319 * @param string $request_action Membership request action being performed. 1311 * @param int $membership_id The key of the action_variables array that you want. 1320 * @param int $membership_id The membership ID of the new user; false if rejected. 1321 * @param int $user_id The ID of the requesting user. 1322 * @param int $group_id The ID of the requested group. 1312 1323 */ 1313 do_action( 'groups_group_request_managed', $bp->groups->current_group->id, $request_action, $membership_id );1324 do_action( 'groups_group_request_managed', $bp->groups->current_group->id, $request_action, $membership_id, $user_id, $group_id ); 1314 1325 bp_core_redirect( bp_get_group_permalink( groups_get_current_group() ) . 'admin/membership-requests/' ); 1315 1326 } 1316 1327 -
src/bp-groups/bp-groups-template.php
diff --git src/bp-groups/bp-groups-template.php src/bp-groups/bp-groups-template.php index 10feea0..4874fc0 100644
function bp_group_request_reject_link() { 5317 5317 * 5318 5318 * @param string $value URL to use to reject a membership request. 5319 5319 */ 5320 return apply_filters( 'bp_get_group_request_reject_link', wp_nonce_url( bp_get_group_permalink( groups_get_current_group() ) . 'admin/membership-requests/reject/' . $requests_template->request-> membership_id, 'groups_reject_membership_request' ) );5320 return apply_filters( 'bp_get_group_request_reject_link', wp_nonce_url( bp_get_group_permalink( groups_get_current_group() ) . 'admin/membership-requests/reject/' . $requests_template->request->user_id, 'groups_reject_membership_request' ) ); 5321 5321 } 5322 5322 5323 5323 /** … … function bp_group_request_accept_link() { 5341 5341 * 5342 5342 * @param string $value URL to use to accept a membership request. 5343 5343 */ 5344 return apply_filters( 'bp_get_group_request_accept_link', wp_nonce_url( bp_get_group_permalink( groups_get_current_group() ) . 'admin/membership-requests/accept/' . $requests_template->request-> membership_id, 'groups_accept_membership_request' ) );5344 return apply_filters( 'bp_get_group_request_accept_link', wp_nonce_url( bp_get_group_permalink( groups_get_current_group() ) . 'admin/membership-requests/accept/' . $requests_template->request->user_id, 'groups_accept_membership_request' ) ); 5345 5345 } 5346 5346 5347 5347 /** -
src/bp-groups/classes/class-bp-group-member-query.php
diff --git src/bp-groups/classes/class-bp-group-member-query.php src/bp-groups/classes/class-bp-group-member-query.php index e6a55db..4205c8c 100644
class BP_Group_Member_Query extends BP_User_Query { 127 127 } 128 128 129 129 $bp = buddypress(); 130 $sql = array(131 'select' => "SELECT user_id FROM {$bp->groups->table_name_members}",132 'where' => array(),133 'orderby' => '',134 'order' => '',135 );136 137 /* WHERE clauses *****************************************************/138 139 // Group id.140 $sql['where'][] = $wpdb->prepare( "group_id = %d", $this->query_vars['group_id'] );141 142 // If is_confirmed.143 $is_confirmed = ! empty( $this->query_vars['is_confirmed'] ) ? 1 : 0;144 $sql['where'][] = $wpdb->prepare( "is_confirmed = %d", $is_confirmed );145 130 146 // If invite_sent. 147 if ( ! is_null( $this->query_vars['invite_sent'] ) ) { 148 $invite_sent = ! empty( $this->query_vars['invite_sent'] ) ? 1 : 0; 149 $sql['where'][] = $wpdb->prepare( "invite_sent = %d", $invite_sent ); 150 } 151 152 // If inviter_id. 153 if ( ! is_null( $this->query_vars['inviter_id'] ) ) { 154 $inviter_id = $this->query_vars['inviter_id']; 131 /* 132 * Two overarching cases: 133 * 1. We're searching for invited/membership requested members. 134 * Then, 'is_confirmed', 'invite_sent' or 'inviter_id' will not be 135 * the default value. 136 * 2. We're searching for confirmed members of the group: 137 * members, mods, admins, and banned users. 138 */ 139 if ( ! $this->query_vars['is_confirmed'] || ! is_null( $this->query_vars['invite_sent'] ) || ! is_null( $this->query_vars['inviter_id'] ) ) { 140 141 // Case 1: Searching for invitations and requests. 142 $invite_args = array( 'type' => 'all' ); 143 144 // If invite_sent. 145 if ( ! is_null( $this->query_vars['invite_sent'] ) ) { 146 $invite_args['invite_sent'] = ! empty( $this->query_vars['invite_sent'] ) ? 'sent' : 'draft'; 147 // $sql['where'][] = $wpdb->prepare( "invite_sent = %d", $invite_sent ); 148 } 155 149 156 // Empty: inviter_id = 0. (pass false, 0, or empty array). 157 if ( empty( $inviter_id ) ) { 158 $sql['where'][] = "inviter_id = 0"; 150 // If inviter_id. 151 if ( ! is_null( $this->query_vars['inviter_id'] ) ) { 152 $inviter_id = $this->query_vars['inviter_id']; 153 154 // Empty: inviter_id = 0. (pass false, 0, or empty array). 155 if ( empty( $inviter_id ) ) { 156 $invite_args['type'] = 'request'; 157 158 /* 159 * The string 'any' matches any non-zero value (inviter_id != 0). 160 * These are invitations, not requests. 161 */ 162 } elseif ( 'any' === $inviter_id ) { 163 $invite_args['type'] = 'invite'; 164 165 166 // Assume that a list of inviter IDs has been passed. 167 } else { 168 $invite_args['type'] = 'invite'; 169 // Parse and sanitize. 170 $inviter_ids = wp_parse_id_list( $inviter_id ); 171 if ( ! empty( $inviter_ids ) ) { 172 $invite_args['inviter_id'] = $inviter_ids; 173 } 174 } 175 } 159 176 160 // The string 'any' matches any non-zero value (inviter_id != 0). 161 } elseif ( 'any' === $inviter_id ) { 162 $sql['where'][] = "inviter_id != 0"; 177 /* 178 * If first_joined is the "type" of query, sort the oldest 179 * requests and invitations to the top. 180 */ 181 if ( 'first_joined' === $this->query_vars['type'] ) { 182 $invite_args['sort_order'] = 'ASC'; 183 } 163 184 164 // Assume that a list of inviter IDs has been passed. 185 $invites = groups_get_invites_for_group_by_data( $this->query_vars['group_id'], $invite_args ); 186 if ( $invites['invites'] ) { 187 $this->group_member_ids = wp_list_pluck( $invites['invites'], 'user_id' ); 165 188 } else { 166 // Parse and sanitize. 167 $inviter_ids = wp_parse_id_list( $inviter_id ); 168 if ( ! empty( $inviter_ids ) ) { 169 $inviter_ids_sql = implode( ',', $inviter_ids ); 170 $sql['where'][] = "inviter_id IN ({$inviter_ids_sql})"; 171 } 189 $this->group_member_ids = array( 0 ); 172 190 } 173 }174 191 175 // Role information is stored as follows: admins have 176 // is_admin = 1, mods have is_mod = 1, banned have is_banned = 177 // 1, and members have all three set to 0. 178 $roles = !empty( $this->query_vars['group_role'] ) ? $this->query_vars['group_role'] : array(); 179 if ( is_string( $roles ) ) { 180 $roles = explode( ',', $roles ); 181 } 192 // Case 2: Searching for members. 193 } else { 194 $sql = array( 195 'select' => "SELECT user_id FROM {$bp->groups->table_name_members}", 196 'where' => array(), 197 'orderby' => '', 198 'order' => '', 199 ); 200 201 /* WHERE clauses *****************************************************/ 202 203 // Group id. 204 $sql['where'][] = $wpdb->prepare( "group_id = %d", $this->query_vars['group_id'] ); 205 206 // Role information is stored as follows: admins have 207 // is_admin = 1, mods have is_mod = 1, banned have is_banned = 208 // 1, and members have all three set to 0. 209 $roles = !empty( $this->query_vars['group_role'] ) ? $this->query_vars['group_role'] : array(); 210 if ( is_string( $roles ) ) { 211 $roles = explode( ',', $roles ); 212 } 182 213 183 // Sanitize: Only 'admin', 'mod', 'member', and 'banned' are valid. 184 $allowed_roles = array( 'admin', 'mod', 'member', 'banned' ); 185 foreach ( $roles as $role_key => $role_value ) { 186 if ( ! in_array( $role_value, $allowed_roles ) ) { 187 unset( $roles[ $role_key ] ); 214 // Sanitize: Only 'admin', 'mod', 'member', and 'banned' are valid. 215 $allowed_roles = array( 'admin', 'mod', 'member', 'banned' ); 216 foreach ( $roles as $role_key => $role_value ) { 217 if ( ! in_array( $role_value, $allowed_roles ) ) { 218 unset( $roles[ $role_key ] ); 219 } 188 220 } 189 }190 221 191 $roles = array_unique( $roles );222 $roles = array_unique( $roles ); 192 223 193 // When querying for a set of roles containing 'member' (for194 // which there is no dedicated is_ column), figure out a list195 // of columns *not* to match.196 $roles_sql = '';197 if ( in_array( 'member', $roles ) ) {198 $role_columns = array();199 foreach ( array_diff( $allowed_roles, $roles ) as $excluded_role ) {200 $role_columns[] = 'is_' . $excluded_role . ' = 0';201 }224 // When querying for a set of roles containing 'member' (for 225 // which there is no dedicated is_ column), figure out a list 226 // of columns *not* to match. 227 $roles_sql = ''; 228 if ( in_array( 'member', $roles ) ) { 229 $role_columns = array(); 230 foreach ( array_diff( $allowed_roles, $roles ) as $excluded_role ) { 231 $role_columns[] = 'is_' . $excluded_role . ' = 0'; 232 } 202 233 203 if ( ! empty( $role_columns ) ) {204 $roles_sql = '(' . implode( ' AND ', $role_columns ) . ')';205 }234 if ( ! empty( $role_columns ) ) { 235 $roles_sql = '(' . implode( ' AND ', $role_columns ) . ')'; 236 } 206 237 207 // When querying for a set of roles *not* containing 'member',208 // simply construct a list of is_* = 1 clauses.209 } else {210 $role_columns = array();211 foreach ( $roles as $role ) {212 $role_columns[] = 'is_' . $role . ' = 1';213 }238 // When querying for a set of roles *not* containing 'member', 239 // simply construct a list of is_* = 1 clauses. 240 } else { 241 $role_columns = array(); 242 foreach ( $roles as $role ) { 243 $role_columns[] = 'is_' . $role . ' = 1'; 244 } 214 245 215 if ( ! empty( $role_columns ) ) { 216 $roles_sql = '(' . implode( ' OR ', $role_columns ) . ')'; 246 if ( ! empty( $role_columns ) ) { 247 $roles_sql = '(' . implode( ' OR ', $role_columns ) . ')'; 248 } 217 249 } 218 }219 250 220 if ( ! empty( $roles_sql ) ) {221 $sql['where'][] = $roles_sql;222 }251 if ( ! empty( $roles_sql ) ) { 252 $sql['where'][] = $roles_sql; 253 } 223 254 224 $sql['where'] = ! empty( $sql['where'] ) ? 'WHERE ' . implode( ' AND ', $sql['where'] ) : '';255 $sql['where'] = ! empty( $sql['where'] ) ? 'WHERE ' . implode( ' AND ', $sql['where'] ) : ''; 225 256 226 // We fetch group members in order of last_joined, regardless227 // of 'type'. If the 'type' value is not 'last_joined' or228 // 'first_joined', the order will be overridden in229 // BP_Group_Member_Query::set_orderby().230 $sql['orderby'] = "ORDER BY date_modified";231 $sql['order'] = 'first_joined' === $this->query_vars['type'] ? 'ASC' : 'DESC';257 // We fetch group members in order of last_joined, regardless 258 // of 'type'. If the 'type' value is not 'last_joined' or 259 // 'first_joined', the order will be overridden in 260 // BP_Group_Member_Query::set_orderby(). 261 $sql['orderby'] = "ORDER BY date_modified"; 262 $sql['order'] = 'first_joined' === $this->query_vars['type'] ? 'ASC' : 'DESC'; 232 263 233 $this->group_member_ids = $wpdb->get_col( "{$sql['select']} {$sql['where']} {$sql['orderby']} {$sql['order']}" ); 264 $this->group_member_ids = $wpdb->get_col( "{$sql['select']} {$sql['where']} {$sql['orderby']} {$sql['order']}" ); 265 } 234 266 235 267 /** 236 268 * Filters the member IDs for the current group member query. … … class BP_Group_Member_Query extends BP_User_Query { 312 344 $bp = buddypress(); 313 345 $extras = $wpdb->get_results( $wpdb->prepare( "SELECT id, user_id, date_modified, is_admin, is_mod, comments, user_title, invite_sent, is_confirmed, inviter_id, is_banned FROM {$bp->groups->table_name_members} WHERE user_id IN ({$user_ids_sql}) AND group_id = %d", $this->query_vars['group_id'] ) ); 314 346 347 $pending_memberships = groups_get_invites_for_group_by_data( $this->query_vars['group_id'], array( 'type' => 'all' ) ); 348 $invites = $pending_memberships['invites']; 349 350 // Keep a running list of whose data we're trying to complete. 351 $user_ids = explode( ',', $user_ids_sql ); 352 315 353 foreach ( (array) $extras as $extra ) { 316 354 if ( isset( $this->results[ $extra->user_id ] ) ) { 317 355 // The user_id is provided for backward compatibility. … … class BP_Group_Member_Query extends BP_User_Query { 322 360 $this->results[ $extra->user_id ]->date_modified = $extra->date_modified; 323 361 $this->results[ $extra->user_id ]->user_title = $extra->user_title; 324 362 $this->results[ $extra->user_id ]->comments = $extra->comments; 325 $this->results[ $extra->user_id ]->invite_sent = (int) $extra->invite_sent;326 $this->results[ $extra->user_id ]->inviter_id = (int) $extra->inviter_id;327 363 $this->results[ $extra->user_id ]->is_confirmed = (int) $extra->is_confirmed; 328 364 $this->results[ $extra->user_id ]->membership_id = (int) $extra->id; 365 366 // This information is stored in the invitations table. 367 foreach ( $invites as $invite ) { 368 if ( $invite->user_id == $extra->user_id ) { 369 $this->results[ $extra->user_id ]->invite_sent = (int) $invite->invite_sent; 370 $this->results[ $extra->user_id ]->inviter_id = (int) $invite->inviter_id; 371 break; 372 } 373 } 374 375 // We no longer need to complete this user's info. 376 $user_ids = array_diff( $user_ids, array( $extra->user_id ) ); 377 } 378 } 379 380 // Now we build the results for the pending members that have no entry in the groups table. 381 if ( $user_ids ) { 382 foreach ( $invites as $invite ) { 383 384 if ( ! in_array( $invite->user_id, $user_ids ) ) { 385 continue; 386 } 387 388 // Skip unsent invites. 389 if ( 'invite' == $invite->type && ! $invite->invite_sent ) { 390 continue; 391 } 392 393 $this->results[ $invite->user_id ]->user_id = $invite->user_id; 394 $this->results[ $invite->user_id ]->is_admin = 0; 395 $this->results[ $invite->user_id ]->is_mod = 0; 396 $this->results[ $invite->user_id ]->is_banned = 0; 397 $this->results[ $invite->user_id ]->date_modified = $invite->date_modified; 398 $this->results[ $invite->user_id ]->user_title = ''; 399 $this->results[ $invite->user_id ]->comments = $invite->content; 400 $this->results[ $invite->user_id ]->is_confirmed = 0; 401 $this->results[ $invite->user_id ]->membership_id = null; 402 $this->results[ $invite->user_id ]->invitation_id = $invite->id; 403 404 // This information is stored in the invitations table. 405 $this->results[ $invite->user_id ]->invite_sent = (int) $invite->invite_sent; 406 $this->results[ $invite->user_id ]->inviter_id = $invite->inviter_id; 407 408 // We no longer need to complete this user's info. 409 $user_ids = array_diff( $user_ids, array( $invite->user_id ) ); 329 410 } 330 411 } 331 412 -
src/bp-groups/classes/class-bp-groups-group.php
diff --git src/bp-groups/classes/class-bp-groups-group.php src/bp-groups/classes/class-bp-groups-group.php index 8d29b0e..f7cf914 100644
class BP_Groups_Group { 474 474 * user but have not yet accepted. 475 475 */ 476 476 public static function get_invites( $user_id, $group_id ) { 477 global $wpdb; 477 $bp = buddypress(); 478 479 $args = array( 480 'component_name' => $bp->groups->id, 481 'component_action' => $bp->groups->id . '_invite', 482 'item_id' => $group_id, 483 'accepted' => 0 484 ); 485 $invites = bp_get_invitations_from_user( $user_id, $args ); 486 487 return wp_list_pluck( $invites, 'user_id' ); 488 } 489 490 /** 491 * Get invitations to a given group filtered by arguments. Cached. 492 * 493 * @since 2.7.0 494 * 495 * @param int $group_id ID of the group. 496 * @param array $args Invitation arguments. 497 * See `bp_invitations_get_invitations()` for list. 498 * 499 * @return array { 500 * array $invites Matching invitation objects. 501 * int $total_count Total number of invites to group. 502 * } 503 */ 504 public static function get_invitations_by_data( $group_id, $args ) { 478 505 479 506 $bp = buddypress(); 480 507 481 return $wpdb->get_col( $wpdb->prepare( "SELECT user_id FROM {$bp->groups->table_name_members} WHERE group_id = %d and is_confirmed = 0 AND inviter_id = %d", $group_id, $user_id ) ); 508 $r = bp_parse_args( $args, array( 509 'inviter_id' => false, 510 'secondary_item_id' => false, 511 'type' => 'invite', 512 'invite_sent' => 'all', 513 'accepted' => 'pending', 514 'orderby' => 'id', 515 'sort_order' => 'DESC', 516 'page' => false, 517 'per_page' => false 518 ), 'bp_get_group_invitations' ); 519 520 $invites = wp_cache_get( 'bp_membership_invitations_for_group_' . $group_id, 'bp' ); 521 522 if ( false === $invites ) { 523 $all_args = array( 524 'component_name' => $bp->groups->id, 525 'component_action' => $bp->groups->id . '_invite', 526 'item_id' => $group_id, 527 'type' => 'all' 528 ); 529 $invites = bp_invitations_get_invitations( $all_args ); 530 wp_cache_set( 'bp_membership_invitations_for_group_' . $group_id, $invites, 'bp' ); 531 } 532 533 $type_args = array( 'type' => $r['type'] ); 534 $invites_by_type = BP_Invitations_Invitation::filter_invitations_by_arguments( $invites, $type_args ); 535 $total_count = count( $invites_by_type ); 536 537 // Filter the results. 538 $invites = BP_Invitations_Invitation::filter_invitations_by_arguments( $invites, $r ); 539 540 return array( 'invites' => $invites, 'total' => $total_count ); 482 541 } 483 542 484 543 /** … … class BP_Groups_Group { 662 721 * } 663 722 */ 664 723 public static function get_membership_requests( $group_id, $limit = null, $page = null ) { 665 global $wpdb;724 $bp = buddypress(); 666 725 667 if ( !empty( $limit ) && !empty( $page ) ) { 668 $pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) ); 726 $args = array( 'type' => 'request' ); 727 if ( $limit ) { 728 $args['per_page'] = $limit; 729 } 730 if ( $page ) { 731 $args['page'] = $page; 669 732 } 670 733 671 $bp = buddypress(); 734 return self::get_invitations_by_data( $group_id, $args ); 735 736 // $requests = wp_cache_get( 'bp_membership_requests_for_group_' . $group_id, 'bp' ); 672 737 673 $paged_requests = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_confirmed = 0 AND inviter_id = 0{$pag_sql}", $group_id ) ); 674 $total_requests = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_confirmed = 0 AND inviter_id = 0", $group_id ) ); 738 // if ( false === $requests ) { 739 // $args = array( 740 // 'component_name' => $bp->groups->id, 741 // 'component_action' => $bp->groups->id . '_invite', 742 // 'item_id' => $group_id, 743 // ); 744 // $requests = bp_invitations_get_requests( $args ); 745 // wp_cache_set( 'bp_membership_requests_for_group_' . $group_id, $requests, 'bp' ); 746 // } 675 747 676 return array( 'requests' => $paged_requests, 'total' => $total_requests ); 748 // $total_count = count( $requests ); 749 750 // // Pagination filtering, if necessary 751 // if ( $limit || $page ) { 752 // $filter = array(); 753 // if ( $limit ) { 754 // $filter['per_page'] = $limit; 755 // } 756 // if ( $page ) { 757 // $filter['page'] = $page; 758 // } 759 // $requests = BP_Invitations_Invitation::filter_invitations_by_arguments( $requests, $filter ); 760 // } 761 762 // return array( 'requests' => $requests, 'total' => $total_count ); 677 763 } 678 764 679 765 /** … … class BP_Groups_Group { 1407 1493 1408 1494 // Fetch the logged-in user's status within each group. 1409 1495 if ( is_user_logged_in() ) { 1410 $user_status_results = $wpdb->get_results( $wpdb->prepare( "SELECT group_id, is_confirmed, invite_sent FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id IN ( {$group_ids} ) AND is_banned = 0", bp_loggedin_user_id() ) ); 1496 $user_status_results = $wpdb->get_results( $wpdb->prepare( "SELECT group_id, is_confirmed FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id IN ( {$group_ids} ) AND is_banned = 0", bp_loggedin_user_id() ) ); 1497 $invited_to_groups = groups_get_invited_to_group_ids(); 1498 $requested_groups = groups_get_membership_requested_group_ids(); 1411 1499 } else { 1412 1500 $user_status_results = array(); 1501 $invited_to_groups = array(); 1502 $requested_groups = array(); 1413 1503 } 1414 1504 1415 1505 // Reindex. … … class BP_Groups_Group { 1423 1513 $gid = $paged_groups[ $i ]->id; 1424 1514 1425 1515 if ( isset( $user_status[ $gid ] ) ) { 1426 1427 1516 // The is_confirmed means the user is a member. 1428 1517 if ( $user_status[ $gid ]->is_confirmed ) { 1429 1518 $is_member = '1'; 1430 1519 } 1431 1520 // The invite_sent means the user has been invited. 1432 } elseif ( $user_status[ $gid ]->invite_sent) {1521 } elseif ( in_array( $gid, $invited_to_groups ) ) { 1433 1522 $is_invited = '1'; 1434 1523 1435 1524 // User has sent request, but has not been confirmed. 1436 } else{1525 } elseif ( in_array( $gid, $requested_groups ) ) { 1437 1526 $is_pending = '1'; 1438 }1439 1527 } 1440 1528 1441 1529 $paged_groups[ $i ]->is_member = $is_member; … … class BP_Groups_Group { 1472 1560 * failure. 1473 1561 */ 1474 1562 public static function delete_all_invites( $group_id ) { 1475 global $wpdb;1476 1477 1563 $bp = buddypress(); 1478 1564 1479 return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->groups->table_name_members} WHERE group_id = %d AND invite_sent = 1", $group_id ) ); 1565 if ( empty( $group_id ) ) { 1566 return false; 1567 } 1568 1569 $args = array( 1570 'component_name' => $bp->groups->id, 1571 'component_action' => $bp->groups->id . '_invite', 1572 'item_id' => $group_id, 1573 'type' => 'invite' 1574 ); 1575 1576 return bp_invitations_delete_invitations( $args ); 1480 1577 } 1481 1578 1482 1579 /** -
src/bp-groups/classes/class-bp-groups-member.php
diff --git src/bp-groups/classes/class-bp-groups-member.php src/bp-groups/classes/class-bp-groups-member.php index 68d315e..a4934bc 100644
class BP_Groups_Member { 736 736 * } 737 737 */ 738 738 public static function get_invites( $user_id, $limit = false, $page = false, $exclude = false ) { 739 global $wpdb;740 739 741 $ pag_sql = ( !empty( $limit ) && !empty( $page ) ) ? $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) ) : '';740 $group_ids = self::get_invited_to_group_ids( $user_id ); 742 741 743 if ( !empty( $exclude ) ) { 744 $exclude = implode( ',', wp_parse_id_list( $exclude ) ); 745 $exclude_sql = " AND g.id NOT IN ({$exclude})"; 746 } else { 747 $exclude_sql = ''; 742 // Remove excluded groups. 743 if ( $exclude ) { 744 $group_ids = array_diff( $group_ids, wp_parse_id_list( $exclude ) ); 748 745 } 749 746 750 $bp = buddypress(); 747 // Avoid passing an empty array. 748 if ( ! $group_ids ) { 749 $group_ids = array( 0 ); 750 } 751 751 752 $paged_groups = $wpdb->get_results( $wpdb->prepare( "SELECT g.*, gm1.meta_value as total_member_count, gm2.meta_value as last_activity FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE g.id = m.group_id AND g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND m.is_confirmed = 0 AND m.inviter_id != 0 AND m.invite_sent = 1 AND m.user_id = %d {$exclude_sql} ORDER BY m.date_modified ASC {$pag_sql}", $user_id ) ); 752 // Get a filtered list of groups. 753 $args = array( 754 'include' => $group_ids, 755 'show_hidden' => true, 756 'per_page' => $limit, 757 'page' => $page, 758 ); 759 $groups = groups_get_groups( $args ); 753 760 754 return array( 'groups' => $ paged_groups, 'total' => self::get_invite_count_for_user( $user_id ) );761 return array( 'groups' => $groups['groups'], 'total' => groups_get_invite_count_for_user( $user_id ) ); 755 762 } 756 763 757 764 /** … … class BP_Groups_Member { 763 770 * @return int 764 771 */ 765 772 public static function get_invite_count_for_user( $user_id = 0 ) { 766 global $wpdb;773 $group_ids = self::get_invited_to_group_ids( $user_id ); 767 774 775 return count( array_unique( $group_ids ) ); 776 } 777 778 /** 779 * Get an array of group IDs to which a user is invited. 780 * 781 * @since 2.7.0 782 * 783 * @param int $user_id The user ID. 784 * 785 * @return array Array of group IDs. 786 */ 787 public static function get_invited_to_group_ids( $user_id = 0 ) { 768 788 $bp = buddypress(); 769 789 770 $count = wp_cache_get( $user_id, 'bp_group_invite_count' ); 790 // Get invites. 791 $args = array( 792 'component_name' => $bp->groups->id, 793 'component_action' => $bp->groups->id . '_invite', 794 'invite_sent' => 'sent', 795 ); 796 $invites = bp_get_user_invitations( $user_id, $args ); 771 797 772 if ( false === $count ) { 773 $count = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(DISTINCT m.group_id) FROM {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE m.group_id = g.id AND m.is_confirmed = 0 AND m.inviter_id != 0 AND m.invite_sent = 1 AND m.user_id = %d", $user_id ) ); 774 wp_cache_set( $user_id, $count, 'bp_group_invite_count' ); 798 if ( $invites ) { 799 $group_ids = array_unique( wp_list_pluck( $invites, 'item_id' ) ); 800 } else { 801 $group_ids = array(); 775 802 } 776 803 777 return $ count;804 return $group_ids; 778 805 } 779 806 780 807 /** … … class BP_Groups_Member { 789 816 * @return int|null The ID of the invitation if found, otherwise null. 790 817 */ 791 818 public static function check_has_invite( $user_id, $group_id, $type = 'sent' ) { 792 global $wpdb;819 $bp = buddypress(); 793 820 794 if ( empty( $user_id ) )821 if ( ! $user_id || ! $group_id ){ 795 822 return false; 823 } 796 824 797 $bp = buddypress(); 798 $sql = "SELECT id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d AND is_confirmed = 0 AND inviter_id != 0"; 825 $args = array( 826 'component_name' => $bp->groups->id, 827 'component_action' => $bp->groups->id . '_invite', 828 'item_id' => $group_id, 829 'invite_sent' => $type, 830 ); 831 $invites = bp_get_user_invitations( $user_id, $args ); 799 832 800 if ( 'sent' == $type ) 801 $sql .= " AND invite_sent = 1"; 833 if ( $invites ) { 834 return current( $invites )->id; 835 } else { 836 // If nothing found, mimic the previous behavior. 837 return 0; 838 } 839 } 840 841 /** 842 * Check whether a user has an outstanding invitation to a given group. 843 * 844 * @since 1.6.0 845 * 846 * @param int $user_id ID of the potential invitee. 847 * @param int $group_id ID of the group. 848 * @param int $inviter_id ID of the inviter. Defaults to logged-in user. 849 * @param string $type If 'sent', results are limited to those invitations 850 * that have actually been sent (non-draft). Default: 'sent'. 851 * @return int|null The ID of the invitation if found, otherwise null. 852 */ 853 public static function check_has_invite_from_user( $user_id, $group_id, $inviter_id, $type = 'sent' ) { 854 $bp = buddypress(); 802 855 803 return $wpdb->get_var( $wpdb->prepare( $sql, $user_id, $group_id ) ); 856 if ( ! $user_id || ! $group_id ){ 857 return false; 858 } 859 860 if ( ! $inviter_id ) { 861 $inviter_id = bp_loggedin_user_id(); 862 } 863 864 $args = array( 865 'inviter_id' => $inviter_id, 866 'component_name' => $bp->groups->id, 867 'component_action' => $bp->groups->id . '_invite', 868 'item_id' => $group_id, 869 'invite_sent' => $type, 870 ); 871 $invites = bp_get_user_invitations( $user_id, $args ); 872 873 if ( $invites ) { 874 return current( $invites )->id; 875 } else { 876 // If nothing found, mimic the previous behavior. 877 return 0; 878 } 804 879 } 805 880 806 881 /** … … class BP_Groups_Member { 810 885 * 811 886 * @global WPDB $wpdb 812 887 * 813 * @param int $user_id ID of the user. 814 * @param int $group_id ID of the group. 888 * @param int $user_id ID of the user. 889 * @param int $group_id ID of the group. 890 * @param int $inviter_id ID of the inviter. Specify if you want to delete 891 * a specific invite. Leave false if you want to 892 * delete all invites to this group. 815 893 * @return int Number of records deleted. 816 894 */ 817 public static function delete_invite( $user_id, $group_id ) { 818 global $wpdb; 895 public static function delete_invite( $user_id, $group_id, $inviter_id = false ) { 896 //@TODO: add inviter_id as argument. 897 $bp = buddypress(); 819 898 820 if ( empty( $user_id ) ) {899 if ( empty( $user_id ) || empty( $group_id ) ) { 821 900 return false; 822 901 } 823 902 824 $table_name = buddypress()->groups->table_name_members; 825 826 $sql = "DELETE FROM {$table_name} 827 WHERE user_id = %d 828 AND group_id = %d 829 AND is_confirmed = 0 830 AND inviter_id != 0"; 831 832 $prepared = $wpdb->prepare( $sql, $user_id, $group_id ); 903 $args = array( 904 'user_id' => $user_id, 905 'inviter_id' => $inviter_id, 906 'component_name' => $bp->groups->id, 907 'component_action' => $bp->groups->id . '_invite', 908 'item_id' => $group_id, 909 'type' => 'invite' 910 ); 833 911 834 return $wpdb->query( $prepared);912 return bp_invitations_delete_invitations( $args ); 835 913 } 836 914 837 915 /** … … class BP_Groups_Member { 844 922 * @return int Number of records deleted. 845 923 */ 846 924 public static function delete_request( $user_id, $group_id ) { 847 global $wpdb;925 $bp = buddypress(); 848 926 849 if ( empty( $user_id ) )927 if ( empty( $user_id ) || empty( $group_id ) ) { 850 928 return false; 929 } 851 930 852 $bp = buddypress(); 931 $args = array( 932 'user_id' => $user_id, 933 'component_name' => $bp->groups->id, 934 'component_action' => $bp->groups->id . '_invite', 935 'item_id' => $group_id, 936 ); 853 937 854 return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d AND is_confirmed = 0 AND inviter_id = 0 AND invite_sent = 0", $user_id, $group_id ));938 return bp_invitations_delete_requests( $args ); 855 939 } 856 940 857 941 /** … … class BP_Groups_Member { 965 1049 * @return int|null ID of the membership if found, otherwise false. 966 1050 */ 967 1051 public static function check_for_membership_request( $user_id, $group_id ) { 968 global $wpdb;1052 $bp = buddypress(); 969 1053 970 if ( empty( $user_id ) )1054 if ( ! $user_id || ! $group_id ){ 971 1055 return false; 1056 } 972 1057 1058 $args = array( 1059 'component_name' => $bp->groups->id, 1060 'component_action' => $bp->groups->id . '_invite', 1061 'item_id' => $group_id, 1062 ); 1063 $requests = bp_get_user_requests( $user_id, $args ); 1064 1065 if ( $requests ) { 1066 return current( $requests )->id; 1067 } else { 1068 // If nothing found, mimic the previous behavior. 1069 return 0; 1070 } 1071 } 1072 1073 /** 1074 * Get an array of group IDs to which a user has requested membership. 1075 * 1076 * @since 2.7.0 1077 * 1078 * @param int $user_id The user ID. 1079 * 1080 * @return array Array of group IDs. 1081 */ 1082 public static function get_membership_requested_group_ids( $user_id = 0 ) { 973 1083 $bp = buddypress(); 974 1084 975 return $wpdb->query( $wpdb->prepare( "SELECT id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d AND is_confirmed = 0 AND is_banned = 0 AND inviter_id = 0", $user_id, $group_id ) ); 1085 // Get invites. 1086 $args = array( 1087 'component_name' => $bp->groups->id, 1088 'component_action' => $bp->groups->id . '_invite', 1089 'invite_sent' => 'sent', 1090 ); 1091 $requests = bp_get_user_requests( $user_id, $args ); 1092 1093 if ( $requests ) { 1094 $group_ids = array_unique( wp_list_pluck( $requests, 'item_id' ) ); 1095 } else { 1096 $group_ids = array(); 1097 } 1098 1099 return $group_ids; 976 1100 } 977 1101 978 1102 /** … … class BP_Groups_Member { 1061 1185 * @return array IDs of users with outstanding membership requests. 1062 1186 */ 1063 1187 public static function get_all_membership_request_user_ids( $group_id ) { 1064 global $wpdb;1065 1066 1188 $bp = buddypress(); 1067 1189 1068 return $wpdb->get_col( $wpdb->prepare( "SELECT user_id FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_confirmed = 0 AND inviter_id = 0", $group_id ) ); 1190 $args = array( 1191 'component_name' => $bp->groups->id, 1192 'component_action' => $bp->groups->id . '_invite', 1193 'item_id' => $group_id, 1194 ); 1195 $requests = bp_invitations_get_requests( $args ); 1196 1197 return wp_list_pluck( $requests, 'user_id' ); 1069 1198 } 1070 1199 1071 1200 /** -
src/bp-groups/classes/class-bp-groups-membership-requests-template.php
diff --git src/bp-groups/classes/class-bp-groups-membership-requests-template.php src/bp-groups/classes/class-bp-groups-membership-requests-template.php index 0014840..d88a820 100644
class BP_Groups_Membership_Requests_Template { 133 133 // request must match the membership id, not the ID of 134 134 // the user (as it's returned by BP_Group_Member_Query). 135 135 $this->requests[ $rk ]->user_id = $rv->ID; 136 $this->requests[ $rk ]->id = $rv-> membership_id;136 $this->requests[ $rk ]->id = $rv->invitation_id; 137 137 138 138 // Miscellaneous values. 139 139 $this->requests[ $rk ]->group_id = $r['group_id']; -
src/bp-loader.php
diff --git src/bp-loader.php src/bp-loader.php index 4a744c4..9f9f001 100644
class BuddyPress { 503 503 require( $this->plugin_dir . 'bp-core/bp-core-moderation.php' ); 504 504 require( $this->plugin_dir . 'bp-core/bp-core-loader.php' ); 505 505 require( $this->plugin_dir . 'bp-core/bp-core-customizer-email.php' ); 506 require( $this->plugin_dir . 'bp-core/bp-core-invitations.php' ); 506 507 507 508 if ( ! $this->do_autoload ) { 508 509 require( $this->plugin_dir . 'bp-core/bp-core-classes.php' ); … … class BuddyPress { 578 579 'BP_Walker_Category_Checklist' => 'core', 579 580 'BP_Walker_Nav_Menu_Checklist' => 'core', 580 581 'BP_Walker_Nav_Menu' => 'core', 582 'BP_Invitations_Component' => 'core', 583 'BP_Invitations_Invitation' => 'core', 581 584 582 585 'BP_Core_Friends_Widget' => 'friends', 583 586 -
new file tests/phpunit/testcases/core/invitations.php
diff --git tests/phpunit/testcases/core/invitations.php tests/phpunit/testcases/core/invitations.php new file mode 100644 index 0000000..35e15a6
- + 1 <?php 2 /** 3 * @group core 4 * @group invitations 5 */ 6 class BP_Tests_Invitations extends BP_UnitTestCase { 7 public function test_bp_invitations_add_invitation_vanilla() { 8 global $wpdb; 9 $old_current_user = get_current_user_id(); 10 11 $u1 = $this->factory->user->create(); 12 $u2 = $this->factory->user->create(); 13 $u3 = $this->factory->user->create(); 14 $this->set_current_user( $u1 ); 15 16 // Create a couple of invitations. 17 $invite_args = array( 18 'user_id' => $u3, 19 'inviter_id' => $u1, 20 'component_name' => 'cakes', 21 'component_action' => 'cupcakes', 22 'item_id' => 1, 23 'invite_sent' => 1, 24 ); 25 $i1 = bp_invitations_add_invitation( $invite_args ); 26 $invite_args['inviter_id'] = $u2; 27 $i2 = bp_invitations_add_invitation( $invite_args ); 28 29 $get_invites = array( 30 'user_id' => $u3, 31 'component_name' => 'cakes', 32 ); 33 $invites = bp_invitations_get_invitations( $u3, $get_invites ); 34 $this->assertEqualSets( array( $i1, $i2 ), wp_list_pluck( $invites, 'id' ) ); 35 36 $this->set_current_user( $old_current_user ); 37 } 38 39 public function test_bp_invitations_add_invitation_avoid_duplicates() { 40 global $wpdb; 41 $old_current_user = get_current_user_id(); 42 43 $u1 = $this->factory->user->create(); 44 $u2 = $this->factory->user->create(); 45 $this->set_current_user( $u1 ); 46 47 // Create an invitation. 48 $invite_args = array( 49 'user_id' => $u2, 50 'inviter_id' => $u1, 51 'component_name' => 'blogs', 52 'component_action' => 'blog_invite', 53 'item_id' => 1, 54 'invite_sent' => 1, 55 ); 56 $i1 = bp_invitations_add_invitation( $invite_args ); 57 // Attempt to create a duplicate. 58 $this->assertFalse( bp_invitations_add_invitation( $invite_args ) ); 59 60 $this->set_current_user( $old_current_user ); 61 } 62 63 public function test_bp_invitations_add_invitation_invite_plus_request_should_accept() { 64 global $wpdb; 65 $old_current_user = get_current_user_id(); 66 67 $u1 = $this->factory->user->create(); 68 $u2 = $this->factory->user->create(); 69 $u3 = $this->factory->user->create(); 70 $this->set_current_user( $u1 ); 71 72 // Create an invitation. 73 $invite_args = array( 74 'user_id' => $u3, 75 'inviter_id' => $u1, 76 'component_name' => 'cakes', 77 'component_action' => 'cupcakes', 78 'item_id' => 1, 79 'invite_sent' => 1, 80 ); 81 $i1 = bp_invitations_add_invitation( $invite_args ); 82 83 // Create a request. 84 $request_args = array( 85 'user_id' => $u3, 86 'component_name' => 'cakes', 87 'component_action' => 'cupcakes', 88 'item_id' => 1, 89 ); 90 $r1 = bp_invitations_add_request( $request_args ); 91 92 $get_invites = array( 93 'user_id' => $u3, 94 'component_name' => 'cakes', 95 'component_action' => 'cupcakes', 96 'accepted' => 'accepted' 97 ); 98 $invites = bp_invitations_get_invitations( $get_invites ); 99 $this->assertEqualSets( array( $i1 ), wp_list_pluck( $invites, 'id' ) ); 100 101 $this->set_current_user( $old_current_user ); 102 } 103 104 public function test_bp_invitations_add_invitation_unsent_invite_plus_request_should_not_accept() { 105 global $wpdb; 106 $old_current_user = get_current_user_id(); 107 108 $u1 = $this->factory->user->create(); 109 $u2 = $this->factory->user->create(); 110 $u3 = $this->factory->user->create(); 111 $this->set_current_user( $u1 ); 112 113 // Create an invitation. 114 $invite_args = array( 115 'user_id' => $u3, 116 'inviter_id' => $u1, 117 'component_name' => 'cakes', 118 'component_action' => 'cupcakes', 119 'item_id' => 1, 120 'invite_sent' => 0, 121 ); 122 $i1 = bp_invitations_add_invitation( $invite_args ); 123 124 // Create a request. 125 $request_args = array( 126 'user_id' => $u3, 127 'component_name' => 'cakes', 128 'component_action' => 'cupcakes', 129 'item_id' => 1, 130 ); 131 $r1 = bp_invitations_add_request( $request_args ); 132 133 $get_invites = array( 134 'user_id' => $u3, 135 'component_name' => 'cakes', 136 'component_action' => 'cupcakes', 137 'accepted' => 'accepted' 138 ); 139 $invites = bp_invitations_get_invitations( $get_invites ); 140 $this->assertEqualSets( array(), wp_list_pluck( $invites, 'id' ) ); 141 142 $this->set_current_user( $old_current_user ); 143 } 144 145 public function test_bp_invitations_add_invitation_unsent_invite_plus_request_then_send_invite_should_accept() { 146 global $wpdb; 147 $old_current_user = get_current_user_id(); 148 149 $u1 = $this->factory->user->create(); 150 $u2 = $this->factory->user->create(); 151 $u3 = $this->factory->user->create(); 152 $this->set_current_user( $u1 ); 153 154 // Create an invitation. 155 $invite_args = array( 156 'user_id' => $u3, 157 'inviter_id' => $u1, 158 'component_name' => 'cakes', 159 'component_action' => 'cupcakes', 160 'item_id' => 1, 161 'invite_sent' => 0, 162 ); 163 $i1 = bp_invitations_add_invitation( $invite_args ); 164 165 // Create a request. 166 $request_args = array( 167 'user_id' => $u3, 168 'component_name' => 'cakes', 169 'component_action' => 'cupcakes', 170 'item_id' => 1, 171 ); 172 $r1 = bp_invitations_add_request( $request_args ); 173 174 bp_invitations_send_invitation_by_id( $i1 ); 175 176 $get_invites = array( 177 'user_id' => $u3, 178 'component_name' => 'cakes', 179 'component_action' => 'cupcakes', 180 'accepted' => 'accepted' 181 ); 182 $invites = bp_invitations_get_invitations( $get_invites ); 183 $this->assertEqualSets( array( $i1, $r1 ), wp_list_pluck( $invites, 'id' ) ); 184 185 $this->set_current_user( $old_current_user ); 186 } 187 188 public function test_bp_invitations_add_request_vanilla() { 189 global $wpdb; 190 $old_current_user = get_current_user_id(); 191 192 $u1 = $this->factory->user->create(); 193 $this->set_current_user( $u1 ); 194 195 // Create a couple of requests. 196 $request_args = array( 197 'user_id' => $u1, 198 'component_name' => 'cakes', 199 'component_action' => 'cupcakes', 200 'item_id' => 7, 201 ); 202 $r1 = bp_invitations_add_request( $request_args ); 203 $request_args['item_id'] = 4; 204 $r2 = bp_invitations_add_request( $request_args ); 205 206 $get_requests = array( 207 'user_id' => $u1, 208 'component_name' => 'cakes', 209 'component_action' => 'cupcakes', 210 ); 211 $requests = bp_invitations_get_requests( $get_requests ); 212 $this->assertEqualSets( array( $r1, $r2 ), wp_list_pluck( $requests, 'id' ) ); 213 214 $this->set_current_user( $old_current_user ); 215 } 216 217 public function test_bp_invitations_add_request_avoid_duplicates() { 218 global $wpdb; 219 $old_current_user = get_current_user_id(); 220 221 $u1 = $this->factory->user->create(); 222 $this->set_current_user( $u1 ); 223 224 // Create a couple of requests. 225 $request_args = array( 226 'user_id' => $u1, 227 'component_name' => 'cakes', 228 'component_action' => 'cupcakes', 229 'item_id' => 7, 230 ); 231 $r1 = bp_invitations_add_request( $request_args ); 232 // Attempt to create a duplicate. 233 $this->assertFalse( bp_invitations_add_request( $request_args ) ); 234 235 $this->set_current_user( $old_current_user ); 236 } 237 238 public function test_bp_invitations_add_request_request_plus_sent_invite_should_accept() { 239 global $wpdb; 240 $old_current_user = get_current_user_id(); 241 242 $u1 = $this->factory->user->create(); 243 $u2 = $this->factory->user->create(); 244 $this->set_current_user( $u1 ); 245 246 // Create a request. 247 $request_args = array( 248 'user_id' => $u2, 249 'component_name' => 'cakes', 250 'component_action' => 'cupcakes', 251 'item_id' => 1, 252 ); 253 $r1 = bp_invitations_add_request( $request_args ); 254 255 // Create an invitation. 256 $invite_args = array( 257 'user_id' => $u2, 258 'inviter_id' => $u1, 259 'component_name' => 'cakes', 260 'component_action' => 'cupcakes', 261 'item_id' => 1, 262 'invite_sent' => 1, 263 ); 264 $i1 = bp_invitations_add_invitation( $invite_args ); 265 266 $get_invites = array( 267 'user_id' => $u2, 268 'component_name' => 'cakes', 269 'component_action' => 'cupcakes', 270 'accepted' => 'accepted' 271 ); 272 $invites = bp_invitations_get_invitations( $get_invites ); 273 $this->assertEqualSets( array( $r1, $i1 ), wp_list_pluck( $invites, 'id' ) ); 274 275 $this->set_current_user( $old_current_user ); 276 } 277 278 public function test_bp_get_user_invitations_should_hit_cache() { 279 global $wpdb; 280 $old_current_user = get_current_user_id(); 281 282 $u1 = $this->factory->user->create(); 283 $u2 = $this->factory->user->create(); 284 $u3 = $this->factory->user->create(); 285 $this->set_current_user( $u1 ); 286 287 // Create a couple of invitations. 288 $invite_args = array( 289 'user_id' => $u3, 290 'inviter_id' => $u1, 291 'component_name' => 'blogs', 292 'component_action' => 'blog_invite', 293 'item_id' => 1, 294 'type' => 'invite', 295 'invite_sent' => 1, 296 ); 297 $i1 = bp_invitations_add_invitation( $invite_args ); 298 $invite_args['inviter_id'] = $u2; 299 $i2 = bp_invitations_add_invitation( $invite_args ); 300 301 // Get the invitations. 302 $invites = bp_get_user_invitations( $u3 ); 303 $num_queries = $wpdb->num_queries; 304 // Get them again. 305 $invites = bp_get_user_invitations( $u3 ); 306 $this->assertSame( $num_queries, $wpdb->num_queries ); 307 // Even changing the args shouldn't require a re-query. 308 $invites = bp_get_user_invitations( $u3, array( 'component_name' => 'beep_beep', 'invite_sent' => 'draft' ) ); 309 $this->assertSame( $num_queries, $wpdb->num_queries ); 310 311 $this->set_current_user( $old_current_user ); 312 } 313 } -
tests/phpunit/testcases/groups/class-bp-groups-member.php
diff --git tests/phpunit/testcases/groups/class-bp-groups-member.php tests/phpunit/testcases/groups/class-bp-groups-member.php index 7aea071..c10b7c3 100644
5 5 */ 6 6 class BP_Tests_BP_Groups_Member_TestCases extends BP_UnitTestCase { 7 7 public static function invite_user_to_group( $user_id, $group_id, $inviter_id ) { 8 $invite = new BP_Groups_Member; 9 $invite->group_id = $group_id; 10 $invite->user_id = $user_id; 11 $invite->date_modified = bp_core_current_time(); 12 $invite->inviter_id = $inviter_id; 13 $invite->is_confirmed = 0; 14 $invite->invite_sent = 1; 15 16 $invite->save(); 17 return $invite->id; 8 $bp = buddypress(); 9 10 $args = array( 11 'user_id' => $user_id, 12 'inviter_id' => $inviter_id, 13 'component_name' => $bp->groups->id, 14 'component_action' => $bp->groups->id . '_invite', 15 'item_id' => $group_id, 16 'invite_sent' => 1, 17 ); 18 return bp_invitations_add_invitation( $args ); 18 19 } 19 20 20 21 public static function create_group_membership_request( $user_id, $group_id ) { 21 $request = new BP_Groups_Member; 22 $request->group_id = $group_id; 23 $request->user_id = $user_id; 24 $request->date_modified = bp_core_current_time(); 25 $request->inviter_id = 0; 26 $request->is_confirmed = 0; 27 28 $request->save(); 29 return $request->id; 22 // $request = new BP_Groups_Member; 23 // $request->group_id = $group_id; 24 // $request->user_id = $user_id; 25 // $request->date_modified = bp_core_current_time(); 26 // $request->inviter_id = 0; 27 // $request->is_confirmed = 0; 28 29 // $request->save(); 30 // return $request->id; 31 32 $bp = buddypress(); 33 34 $args = array( 35 'user_id' => $user_id, 36 'component_name' => $bp->groups->id, 37 'component_action' => $bp->groups->id . '_invite', 38 'item_id' => $group_id, 39 ); 40 return bp_invitations_add_request( $args ); 30 41 } 31 42 32 43 public function test_get_recently_joined_with_filter() { … … class BP_Tests_BP_Groups_Member_TestCases extends BP_UnitTestCase { 990 1001 $this->assertTrue( is_numeric( $member ) && $member > 0 ); 991 1002 // Check that the invite has been removed. 992 1003 $invite = groups_check_user_has_invite( $u2, $g1, 'all' ); 993 $this->assert True( is_null( $invite ));1004 $this->assertEquals( $invite, 0 ); 994 1005 } 995 1006 996 1007 /** … … class BP_Tests_BP_Groups_Member_TestCases extends BP_UnitTestCase { 1024 1035 groups_accept_invite( $u2, $g1 ); 1025 1036 1026 1037 // Check that the membership request has been removed. 1027 $this->assert True( 0 == groups_check_for_membership_request( $u2, $g1 ));1038 $this->assertEquals( groups_check_for_membership_request( $u2, $g1 ), 0 ); 1028 1039 } 1029 1040 1030 1041 /** … … class BP_Tests_BP_Groups_Member_TestCases extends BP_UnitTestCase { 1178 1189 groups_send_membership_request( $u1, $g1 ); 1179 1190 1180 1191 // Get group invitations of any type, from any user in the group. 1181 $member = new BP_Groups_Member( $u1, $g1 );1192 // $member = new BP_Groups_Member( $u1, $g1 ); 1182 1193 1183 groups_accept_membership_request( $member->id);1194 groups_accept_membership_request( false, $u1, $g1 ); 1184 1195 1185 1196 // User should now be a group member. 1186 1197 $member = groups_is_user_member( $u1, $g1 ); -
tests/phpunit/testcases/groups/template.php
diff --git tests/phpunit/testcases/groups/template.php tests/phpunit/testcases/groups/template.php index 68988ea..14b4175 100644
class BP_Tests_Groups_Template extends BP_UnitTestCase { 688 688 // Check each expected value. If there are more in the results, 689 689 // that's OK 690 690 foreach ( get_object_vars( $expected ) as $k => $v ) { 691 $this->assertEquals( $v, $requests_template->requests[0]->{$k} );691 $this->assertEquals( $v, current( $requests_template->requests )->{$k} ); 692 692 } 693 693 } 694 694