Skip to:
Content

BuddyPress.org

Ticket #6210: 6210.01.patch

File 6210.01.patch, 158.5 KB (added by dcavins, 9 years ago)

Adds nw invitations table. Switches group invites to use new invitations API.

  • 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 ) { 
    5454        // Install the signups table.
    5555        bp_core_maybe_install_signups();
    5656
    57         // Notifications.
     57        // Create/update the invitations table.
     58        bp_core_install_invitations();
     59
     60        // Notifications
    5861        if ( !empty( $active_components['notifications'] ) ) {
    5962                bp_core_install_notifications();
    6063        }
    function bp_core_install_emails() { 
    564567         */
    565568        do_action( 'bp_core_install_emails' );
    566569}
     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 */
     580function 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'; 
    3030require dirname( __FILE__ ) . '/classes/class-bp-email.php';
    3131require dirname( __FILE__ ) . '/classes/class-bp-email-delivery.php';
    3232require dirname( __FILE__ ) . '/classes/class-bp-phpmailer.php';
     33require dirname( __FILE__ ) . '/classes/class-bp-invitations-component.php';
     34require 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.
     11defined( '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 */
     22function bp_setup_invitations_component() {
     23        buddypress()->invitations = new BP_Invitations_Component();
     24}
     25add_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 */
     56function 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
     132function 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 */
     194function 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 */
     297function 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 */
     362function 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 */
     411function 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 */
     446function 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
     516function 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 */
     558function 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 */
     620function 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 */
     662function 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 */
     705function 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 */
     718function 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 */
     751function 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 */
     764function 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 */
     797function 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 */
     814function 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 */
     852function 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 */
     892function 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 */
     910function 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 */
     929function 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 */
     960function 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}
     970add_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 */
     980function 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}
     999add_action( 'bp_invitation_before_update', 'bp_invitations_clear_user_caches_before_update' );
     1000add_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() { 
    275275                if ( $raw_db_version < 10440 ) {
    276276                        bp_update_to_2_5();
    277277                }
     278
     279                // 2.5.0
     280                if ( $raw_db_version < 10800 ) {
     281                        bp_update_to_2_6();
     282                }
    278283        }
    279284
    280285        /* All done! *************************************************************/
    function bp_update_to_2_5() { 
    514519}
    515520
    516521/**
     522 * 2.6.0 update routine.
     523 *
     524 * - Create invitations table.
     525 *
     526 * @since 2.6.0
     527 */
     528function bp_update_to_2_6() {
     529        bp_core_install_invitations();
     530}
     531
     532/**
    517533 * Updates the component field for new_members type.
    518534 *
    519535 * @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.
     11defined( 'ABSPATH' ) || exit;
     12
     13/**
     14 * Extends the component class to set up the Invitations component.
     15 */
     16class 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.
     13defined( '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 */
     22class 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() { 
    551551        ) );
    552552}
    553553add_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 */
     562function 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}
     576add_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 ) { 
    480480        if ( empty( $user_id ) )
    481481                $user_id = bp_loggedin_user_id();
    482482
    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 ) ) {
    485485                groups_delete_invite( $user_id, $group_id );
     486        }
    486487
    487488        // 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        }
    490492
    491493        // 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 ) ) {
    493495                return true;
     496        }
    494497
    495498        $new_member                = new BP_Groups_Member;
    496499        $new_member->group_id      = $group_id;
    function groups_join_group( $group_id, $user_id = 0 ) { 
    501504        $new_member->date_modified = bp_core_current_time();
    502505        $new_member->is_confirmed  = 1;
    503506
    504         if ( !$new_member->save() )
     507        if ( ! $new_member->save() )
    505508                return false;
    506509
    507510        $bp = buddypress();
    function groups_post_update( $args = '' ) { 
    10471050 */
    10481051function groups_get_invites_for_user( $user_id = 0, $limit = false, $page = false, $exclude = false ) {
    10491052
    1050         if ( empty( $user_id ) )
     1053        if ( empty( $user_id ) ) {
    10511054                $user_id = bp_loggedin_user_id();
     1055        }
    10521056
    10531057        return BP_Groups_Member::get_invites( $user_id, $limit, $page, $exclude );
    10541058}
    function groups_get_invites_for_user( $user_id = 0, $limit = false, $page = fals 
    10621066 * @return int
    10631067 */
    10641068function groups_get_invite_count_for_user( $user_id = 0 ) {
     1069
    10651070        if ( empty( $user_id ) ) {
    10661071                $user_id = bp_loggedin_user_id();
    10671072        }
    10681073
    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 */
     1093function 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 );
    10701100}
    10711101
    10721102/**
    10731103 * Invite a user to a group.
    10741104 *
    10751105 * @since 1.0.0
     1106 * @since 2.7.0 Added 'content' parameter.
    10761107 *
    10771108 * @param array|string $args {
    10781109 *     Array of arguments.
    function groups_get_invite_count_for_user( $user_id = 0 ) { 
    10821113 *                                 ID of the logged-in user.
    10831114 *     @type string $date_modified Optional. Modified date for the invitation.
    10841115 *                                 Default: current date/time.
     1116 *     @type string $content       Optional. Message to invitee.
    10851117 *     @type bool   $is_confirmed  Optional. Whether the invitation should be
    10861118 *                                 marked confirmed. Default: false.
    10871119 * }
    function groups_invite_user( $args = '' ) { 
    10941126                'group_id'      => false,
    10951127                'inviter_id'    => bp_loggedin_user_id(),
    10961128                'date_modified' => bp_core_current_time(),
     1129                'content'       => '',
    10971130                'is_confirmed'  => 0
    10981131        );
    10991132
    11001133        $args = wp_parse_args( $args, $defaults );
    1101         extract( $args, EXTR_SKIP );
    11021134
    1103         if ( ! $user_id || ! $group_id || ! $inviter_id ) {
     1135        if ( ! $args['user_id'] || ! $args['group_id'] || ! $args['inviter_id'] ) {
    11041136                return false;
    11051137        }
    11061138
    11071139        // 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'] );
    11101142
    11111143        // 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 ) ) {
    11211158                        return false;
     1159                }
    11221160
    11231161                /**
    11241162                 * Fires after the creation of a new group invite.
    function groups_invite_user( $args = '' ) { 
    11341172}
    11351173
    11361174/**
    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.
    11401176 *
    11411177 * @since 1.0.0
    11421178 *
    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 *
    11451183 * @return bool True on success, false on failure.
    11461184 */
    1147 function groups_uninvite_user( $user_id, $group_id ) {
     1185function groups_uninvite_user( $user_id, $group_id, $inviter_id = false ) {
    11481186
    1149         if ( ! BP_Groups_Member::delete_invite( $user_id, $group_id ) )
     1187        if ( ! BP_Groups_Member::delete_invite( $user_id, $group_id, $inviter_id ) ) {
    11501188                return false;
     1189        }
    11511190
    11521191        /**
    11531192         * Fires after uninviting a user from a group.
    11541193         *
    11551194         * @since 1.0.0
     1195         * @since 2.7.0 Added $inviter_id parameter
    11561196         *
    11571197         * @param int $group_id ID of the group being uninvited from.
    11581198         * @param int $user_id  ID of the user being uninvited.
    11591199         */
    1160         do_action( 'groups_uninvite_user', $group_id, $user_id );
     1200        do_action( 'groups_uninvite_user', $group_id, $user_id, $inviter_id );
    11611201
    11621202        return true;
    11631203}
    function groups_uninvite_user( $user_id, $group_id ) { 
    11741214 * @return bool True when the user is a member of the group, otherwise false.
    11751215 */
    11761216function 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        );
    11771224
    11781225        // If the user is already a member (because BP at one point allowed two invitations to
    11791226        // slip through), delete all existing invitations/requests and return true.
    11801227        if ( groups_is_user_member( $user_id, $group_id ) ) {
    11811228                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 );
    11831230                }
    11841231
    11851232                if ( groups_check_for_membership_request( $user_id, $group_id ) ) {
    function groups_accept_invite( $user_id, $group_id ) { 
    11921239        $member = new BP_Groups_Member( $user_id, $group_id );
    11931240        $member->accept_invite();
    11941241
    1195         if ( !$member->save() ) {
     1242        if ( ! $member->save() ) {
    11961243                return false;
    11971244        }
    11981245
    11991246        // 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 );
    12021249        }
    12031250
     1251        // Mark invitation as accepted.
     1252        bp_invitations_mark_accepted( $accept_args );
     1253
    12041254        // Modify group meta.
    12051255        groups_update_groupmeta( $group_id, 'last_activity', bp_core_current_time() );
    12061256
    function groups_accept_invite( $user_id, $group_id ) { 
    12221272 *
    12231273 * @since 1.0.0
    12241274 *
    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 *
    12271279 * @return bool True on success, false on failure.
    12281280 */
    1229 function groups_reject_invite( $user_id, $group_id ) {
    1230         if ( ! BP_Groups_Member::delete_invite( $user_id, $group_id ) )
     1281function groups_reject_invite( $user_id, $group_id, $inviter_id = false ) {
     1282        if ( ! BP_Groups_Member::delete_invite( $user_id, $group_id, $inviter_id ) ) {
    12311283                return false;
     1284        }
    12321285
    12331286        /**
    12341287         * Fires after a user rejects a group invitation.
    function groups_reject_invite( $user_id, $group_id ) { 
    12501303 *
    12511304 * @param int $user_id  ID of the invited user.
    12521305 * @param int $group_id ID of the group.
     1306 * @param int $inviter_id ID of the inviter.
     1307 *
    12531308 * @return bool True on success, false on failure.
    12541309 */
    1255 function groups_delete_invite( $user_id, $group_id ) {
    1256         if ( ! BP_Groups_Member::delete_invite( $user_id, $group_id ) )
     1310function groups_delete_invite( $user_id, $group_id, $inviter_id = false ) {
     1311        if ( ! BP_Groups_Member::delete_invite( $user_id, $group_id, $inviter_id ) ) {
    12571312                return false;
     1313        }
    12581314
    12591315        /**
    12601316         * Fires after the deletion of a group invitation.
    function groups_delete_invite( $user_id, $group_id ) { 
    12781334 * @param int $group_id ID of the group.
    12791335 */
    12801336function groups_send_invites( $user_id, $group_id ) {
     1337        $bp = buddypress();
    12811338
    1282         if ( empty( $user_id ) )
     1339        if ( empty( $user_id ) ) {
    12831340                $user_id = bp_loggedin_user_id();
     1341        }
    12841342
    12851343        // Send friend invites.
     1344        $success = 0;
    12861345        $invited_users = groups_get_invites_for_group( $user_id, $group_id );
    1287         $group = groups_get_group( array( 'group_id' => $group_id ) );
    12881346
    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        );
    12911353
    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 );
    12941357
    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                }
    12971362        }
    12981363
    12991364        /**
    function groups_send_invites( $user_id, $group_id ) { 
    13071372         * @param int   $user_id       ID of the inviting user.
    13081373         */
    13091374        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        }
    13101381}
    13111382
    13121383/**
    function groups_get_invites_for_group( $user_id, $group_id ) { 
    13241395}
    13251396
    13261397/**
     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 */
     1411function 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/**
    13271416 * Check to see whether a user has already been invited to a group.
    13281417 *
    13291418 * By default, the function checks for invitations that have been sent.
    function groups_check_user_has_invite( $user_id, $group_id, $type = 'sent' ) { 
    13431432}
    13441433
    13451434/**
     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 */
     1449function 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 */
     1464function 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/**
    13461486 * Delete all invitations to a given group.
    13471487 *
    13481488 * @since 1.0.0
    function groups_check_user_has_invite( $user_id, $group_id, $type = 'sent' ) { 
    13511491 * @return int|null Number of rows records deleted on success, null on failure.
    13521492 */
    13531493function groups_delete_all_group_invites( $group_id ) {
     1494        // DC: updated
    13541495        return BP_Groups_Group::delete_all_invites( $group_id );
    13551496}
    13561497
    function groups_send_membership_request( $requesting_user_id, $group_id ) { 
    15351676                groups_accept_invite( $requesting_user_id, $group_id );
    15361677                return true;
    15371678        }
     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        );
    15381688
    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 ) ) {
    15501690                $admins = groups_get_group_admins( $group_id );
    15511691
    15521692                // Saved okay, now send the email notification.
    15531693                for ( $i = 0, $count = count( $admins ); $i < $count; ++$i )
    1554                         groups_notification_new_membership_request( $requesting_user_id, $admins[$i]->user_id, $group_id, $requesting_user->id );
     1694                        groups_notification_new_membership_request( $requesting_user_id, $admins[$i]->user_id, $group_id, $request_id );
    15551695
    15561696                /**
    15571697                 * Fires after the creation of a new membership request.
    function groups_send_membership_request( $requesting_user_id, $group_id ) { 
    15631703                 * @param int   $group_id            ID of the group being requested to.
    15641704                 * @param int   $requesting_user->id ID of the user requesting membership.
    15651705                 */
    1566                 do_action( 'groups_membership_requested', $requesting_user_id, $admins, $group_id, $requesting_user->id );
     1706                do_action( 'groups_membership_requested', $requesting_user_id, $admins, $group_id, $request_id );
    15671707
    15681708                return true;
    15691709        }
    function groups_send_membership_request( $requesting_user_id, $group_id ) { 
    15751715 * Accept a pending group membership request.
    15761716 *
    15771717 * @since 1.0.0
     1718 * @since 2.7.0 Deprecated $membership_id argument.
    15781719 *
    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.
    15811722 *                           Provide this value along with $group_id to override
    15821723 *                           $membership_id.
    1583  * @param int $group_id      Optional. ID of the group to which membership is being
     1724 * @param int $group_id      ID of the group to which membership is being
    15841725 *                           requested. Provide this value along with $user_id to
    15851726 *                           override $membership_id.
    15861727 * @return bool True on success, false on failure.
    15871728 */
    15881729function groups_accept_membership_request( $membership_id, $user_id = 0, $group_id = 0 ) {
    15891730
    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__ ) );
    15941733        }
    15951734
     1735        if ( ! $user_id || ! $group_id ) {
     1736                return false;
     1737        }
     1738
     1739        $membership = new BP_Groups_Member( $user_id, $group_id );
     1740
    15961741        $membership->accept_request();
    15971742
    1598         if ( !$membership->save() ) {
     1743        if ( ! $membership->save() ) {
    15991744                return false;
    16001745        }
    16011746
    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 );
    16061756
    16071757        /**
    16081758         * Fires after a group membership request has been accepted.
    function groups_accept_membership_request( $membership_id, $user_id = 0, $group_ 
    16221772 * Reject a pending group membership request.
    16231773 *
    16241774 * @since 1.0.0
     1775 * @since 2.7.0 Deprecated $membership_id argument.
    16251776 *
    1626  * @param int $membership_id ID of the membership object.
     1777 * @param int $membership_id Deprecated 2.7.0. ID of the membership object.
    16271778 * @param int $user_id       Optional. ID of the user who requested membership.
    16281779 *                           Provide this value along with $group_id to override
    16291780 *                           $membership_id.
    function groups_accept_membership_request( $membership_id, $user_id = 0, $group_ 
    16331784 * @return bool True on success, false on failure.
    16341785 */
    16351786function 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 ) ) {
    16371792                return false;
    16381793        }
    16391794
    function groups_reject_membership_request( $membership_id, $user_id = 0, $group_ 
    16461801         * @param int  $group_id ID of the group that was rejected membership to.
    16471802         * @param bool $value    If membership was accepted.
    16481803         */
    1649         do_action( 'groups_membership_rejected', $membership->user_id, $membership->group_id, false );
     1804        do_action( 'groups_membership_rejected', $user_id, $group_id, false );
    16501805
    16511806        return true;
    16521807}
    function groups_reject_membership_request( $membership_id, $user_id = 0, $group_ 
    16551810 * Delete a pending group membership request.
    16561811 *
    16571812 * @since 1.2.0
     1813 * @since 2.7.0 Deprecated $membership_id argument.
    16581814 *
    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.
    16611817 *                           Provide this value along with $group_id to override
    16621818 *                           $membership_id.
    1663  * @param int $group_id      Optional. ID of the group to which membership is being
     1819 * @param int $group_id      ID of the group to which membership is being
    16641820 *                           requested. Provide this value along with $user_id to
    16651821 *                           override $membership_id.
    16661822 * @return bool True on success, false on failure.
    16671823 */
    16681824function 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        }
    16731828
    1674         if ( ! BP_Groups_Member::delete_request( $membership->user_id, $membership->group_id ) )
     1829        if ( ! BP_Groups_Member::delete_request( $user_id, $group_id ) ) {
    16751830                return false;
     1831        }
    16761832
    1677         return $membership;
     1833        return true;
    16781834}
    16791835
    16801836/**
    function groups_check_for_membership_request( $user_id, $group_id ) { 
    16911847}
    16921848
    16931849/**
     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 */
     1858function 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/**
    16941867 * Accept all pending membership requests to a group.
    16951868 *
    16961869 * @since 1.0.2
    function groups_check_for_membership_request( $user_id, $group_id ) { 
    17011874function groups_accept_all_pending_membership_requests( $group_id ) {
    17021875        $user_ids = BP_Groups_Member::get_all_membership_request_user_ids( $group_id );
    17031876
    1704         if ( !$user_ids )
     1877        if ( ! $user_ids ) {
    17051878                return false;
     1879        }
    17061880
    1707         foreach ( (array) $user_ids as $user_id )
     1881        foreach ( (array) $user_ids as $user_id ) {
    17081882                groups_accept_membership_request( false, $user_id, $group_id );
     1883        }
    17091884
    17101885        /**
    17111886         * 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 
    257257                return;
    258258        }
    259259
    260         // @todo $inviter_ud may be used for caching, test without it
    261         $inviter_ud      = bp_core_get_core_userdata( $inviter_user_id );
    262260        $invited_user_id = $member->user_id;
    263261
     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 */
     275function 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
    264287        // Trigger a BuddyPress Notification.
    265288        if ( bp_is_active( 'notifications' ) ) {
    266289                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,
    269292                        'component_name'   => buddypress()->groups->id,
    270293                        'component_action' => 'group_invite',
    271294                ) );
    function groups_notification_group_invites( &$group, &$member, $inviter_user_id 
    279302        $invited_link = bp_core_get_user_domain( $invited_user_id ) . bp_get_groups_slug();
    280303        $args         = array(
    281304                '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,
    289313                ),
    290314        );
     315
    291316        bp_send_email( 'groups-invitation', (int) $invited_user_id, $args );
    292317}
    293318
  • 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() { 
    12741274        }
    12751275
    12761276        $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();
    12781279
    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 ) ) {
    12811282
    12821283                        // Check the nonce first.
    1283                         if ( !check_admin_referer( 'groups_accept_membership_request' ) )
     1284                        if ( ! check_admin_referer( 'groups_accept_membership_request' ) ) {
    12841285                                return false;
     1286                        }
    12851287
    12861288                        // Accept the membership request.
    1287                         if ( !groups_accept_membership_request( $membership_id ) )
     1289                        if ( ! groups_accept_membership_request( false, $user_id, $group_id ) ) {
    12881290                                bp_core_add_message( __( 'There was an error accepting the membership request. Please try again.', 'buddypress' ), 'error' );
    1289                         else
     1291                        } else {
    12901292                                bp_core_add_message( __( 'Group membership request accepted', 'buddypress' ) );
     1293                        }
    12911294
    1292                 } elseif ( 'reject' == $request_action && is_numeric( $membership_id ) ) {
     1295                } elseif ( 'reject' == $request_action && is_numeric( $user_id ) ) {
    12931296                        /* Check the nonce first. */
    1294                         if ( !check_admin_referer( 'groups_reject_membership_request' ) )
     1297                        if ( ! check_admin_referer( 'groups_reject_membership_request' ) ) {
    12951298                                return false;
     1299                        }
    12961300
    12971301                        // Reject the membership request.
    1298                         if ( !groups_reject_membership_request( $membership_id ) )
     1302                        if ( ! groups_reject_membership_request(false, $user_id, $group_id ) ) {
    12991303                                bp_core_add_message( __( 'There was an error rejecting the membership request. Please try again.', 'buddypress' ), 'error' );
    1300                         else
     1304                        } else {
    13011305                                bp_core_add_message( __( 'Group membership request rejected', 'buddypress' ) );
     1306                        }
    13021307                }
    13031308
     1309                // Was the member added to the group?
     1310                $membership_id = groups_is_user_member( $user_id, $group_id );
     1311
    13041312                /**
    13051313                 * Fires before the redirect if a group membership request has been handled.
    13061314                 *
    13071315                 * @since 1.0.0
     1316                 * @since 2.7.0 Added user ID and group ID parameters.
    13081317                 *
    13091318                 * @param int    $id             ID of the group that was edited.
    13101319                 * @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.
    13121323                 */
    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 );
    13141325                bp_core_redirect( bp_get_group_permalink( groups_get_current_group() ) . 'admin/membership-requests/' );
    13151326        }
    13161327
  • 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() { 
    53175317                 *
    53185318                 * @param string $value URL to use to reject a membership request.
    53195319                 */
    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' ) );
    53215321        }
    53225322
    53235323/**
    function bp_group_request_accept_link() { 
    53415341                 *
    53425342                 * @param string $value URL to use to accept a membership request.
    53435343                 */
    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' ) );
    53455345        }
    53465346
    53475347/**
  • 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 { 
    127127                }
    128128
    129129                $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 );
    145130
    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                        }
    155149
    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                        }
    159176
    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                        }
    163184
    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' );
    165188                        } 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 );
    172190                        }
    173                 }
    174191
    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                        }
    182213
    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                                }
    188220                        }
    189                 }
    190221
    191                 $roles = array_unique( $roles );
     222                        $roles = array_unique( $roles );
    192223
    193                 // When querying for a set of roles containing 'member' (for
    194                 // which there is no dedicated is_ column), figure out a list
    195                 // 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                                }
    202233
    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                                }
    206237
    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                                }
    214245
    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                                }
    217249                        }
    218                 }
    219250
    220                 if ( ! empty( $roles_sql ) ) {
    221                         $sql['where'][] = $roles_sql;
    222                 }
     251                        if ( ! empty( $roles_sql ) ) {
     252                                $sql['where'][] = $roles_sql;
     253                        }
    223254
    224                 $sql['where'] = ! empty( $sql['where'] ) ? 'WHERE ' . implode( ' AND ', $sql['where'] ) : '';
     255                        $sql['where'] = ! empty( $sql['where'] ) ? 'WHERE ' . implode( ' AND ', $sql['where'] ) : '';
    225256
    226                 // We fetch group members in order of last_joined, regardless
    227                 // of 'type'. If the 'type' value is not 'last_joined' or
    228                 // 'first_joined', the order will be overridden in
    229                 // 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';
    232263
    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                }
    234266
    235267                /**
    236268                 * Filters the member IDs for the current group member query.
    class BP_Group_Member_Query extends BP_User_Query { 
    312344                $bp     = buddypress();
    313345                $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'] ) );
    314346
     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
    315353                foreach ( (array) $extras as $extra ) {
    316354                        if ( isset( $this->results[ $extra->user_id ] ) ) {
    317355                                // The user_id is provided for backward compatibility.
    class BP_Group_Member_Query extends BP_User_Query { 
    322360                                $this->results[ $extra->user_id ]->date_modified = $extra->date_modified;
    323361                                $this->results[ $extra->user_id ]->user_title    = $extra->user_title;
    324362                                $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;
    327363                                $this->results[ $extra->user_id ]->is_confirmed  = (int) $extra->is_confirmed;
    328364                                $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 ) );
    329410                        }
    330411                }
    331412
  • 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 { 
    474474         *               user but have not yet accepted.
    475475         */
    476476        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 ) {
    478505
    479506                $bp = buddypress();
    480507
    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 );
    482541        }
    483542
    484543        /**
    class BP_Groups_Group { 
    662721         * }
    663722         */
    664723        public static function get_membership_requests( $group_id, $limit = null, $page = null ) {
    665                 global $wpdb;
     724                $bp = buddypress();
    666725
    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;
    669732                }
    670733
    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' );
    672737
    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                // }
    675747
    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 );
    677763        }
    678764
    679765        /**
    class BP_Groups_Group { 
    14071493
    14081494                // Fetch the logged-in user's status within each group.
    14091495                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();
    14111499                } else {
    14121500                        $user_status_results = array();
     1501                        $invited_to_groups   = array();
     1502                        $requested_groups    = array();
    14131503                }
    14141504
    14151505                // Reindex.
    class BP_Groups_Group { 
    14231513                        $gid = $paged_groups[ $i ]->id;
    14241514
    14251515                        if ( isset( $user_status[ $gid ] ) ) {
    1426 
    14271516                                // The is_confirmed means the user is a member.
    14281517                                if ( $user_status[ $gid ]->is_confirmed ) {
    14291518                                        $is_member = '1';
    1430 
     1519                                }
    14311520                                // The invite_sent means the user has been invited.
    1432                                 } elseif ( $user_status[ $gid ]->invite_sent ) {
     1521                        } elseif ( in_array( $gid, $invited_to_groups ) ) {
    14331522                                        $is_invited = '1';
    14341523
    14351524                                // User has sent request, but has not been confirmed.
    1436                                 } else {
     1525                        } elseif ( in_array( $gid, $requested_groups ) ) {
    14371526                                        $is_pending = '1';
    1438                                 }
    14391527                        }
    14401528
    14411529                        $paged_groups[ $i ]->is_member = $is_member;
    class BP_Groups_Group { 
    14721560         *                  failure.
    14731561         */
    14741562        public static function delete_all_invites( $group_id ) {
    1475                 global $wpdb;
    1476 
    14771563                $bp = buddypress();
    14781564
    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 );
    14801577        }
    14811578
    14821579        /**
  • 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 { 
    736736         * }
    737737         */
    738738        public static function get_invites( $user_id, $limit = false, $page = false, $exclude = false ) {
    739                 global $wpdb;
    740739
    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 );
    742741
    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 ) );
    748745                }
    749746
    750                 $bp = buddypress();
     747                // Avoid passing an empty array.
     748                if ( ! $group_ids ) {
     749                        $group_ids = array( 0 );
     750                }
    751751
    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 );
    753760
    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 ) );
    755762        }
    756763
    757764        /**
    class BP_Groups_Member { 
    763770         * @return int
    764771         */
    765772        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 );
    767774
     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 ) {
    768788                $bp = buddypress();
    769789
    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 );
    771797
    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();
    775802                }
    776803
    777                 return $count;
     804                return $group_ids;
    778805        }
    779806
    780807        /**
    class BP_Groups_Member { 
    789816         * @return int|null The ID of the invitation if found, otherwise null.
    790817         */
    791818        public static function check_has_invite( $user_id, $group_id, $type = 'sent' ) {
    792                 global $wpdb;
     819                $bp = buddypress();
    793820
    794                 if ( empty( $user_id ) )
     821                if ( ! $user_id || ! $group_id ){
    795822                        return false;
     823                }
    796824
    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 );
    799832
    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();
    802855
    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                }
    804879        }
    805880
    806881        /**
    class BP_Groups_Member { 
    810885         *
    811886         * @global WPDB $wpdb
    812887         *
    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.
    815893         * @return int Number of records deleted.
    816894         */
    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();
    819898
    820                 if ( empty( $user_id ) ) {
     899                if ( empty( $user_id ) || empty( $group_id ) ) {
    821900                        return false;
    822901                }
    823902
    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                );
    833911
    834                 return $wpdb->query( $prepared );
     912                return bp_invitations_delete_invitations( $args );
    835913        }
    836914
    837915        /**
    class BP_Groups_Member { 
    844922         * @return int Number of records deleted.
    845923         */
    846924        public static function delete_request( $user_id, $group_id ) {
    847                 global $wpdb;
     925                $bp = buddypress();
    848926
    849                 if ( empty( $user_id ) )
     927                if ( empty( $user_id ) || empty( $group_id ) ) {
    850928                        return false;
     929                }
    851930
    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                );
    853937
    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 );
    855939        }
    856940
    857941        /**
    class BP_Groups_Member { 
    9651049         * @return int|null ID of the membership if found, otherwise false.
    9661050         */
    9671051        public static function check_for_membership_request( $user_id, $group_id ) {
    968                 global $wpdb;
     1052                $bp = buddypress();
    9691053
    970                 if ( empty( $user_id ) )
     1054                if ( ! $user_id || ! $group_id ){
    9711055                        return false;
     1056                }
    9721057
     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 ) {
    9731083                $bp = buddypress();
    9741084
    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;
    9761100        }
    9771101
    9781102        /**
    class BP_Groups_Member { 
    10611185         * @return array IDs of users with outstanding membership requests.
    10621186         */
    10631187        public static function get_all_membership_request_user_ids( $group_id ) {
    1064                 global $wpdb;
    1065 
    10661188                $bp = buddypress();
    10671189
    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' );
    10691198        }
    10701199
    10711200        /**
  • 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 { 
    133133                        // request must match the membership id, not the ID of
    134134                        // the user (as it's returned by BP_Group_Member_Query).
    135135                        $this->requests[ $rk ]->user_id = $rv->ID;
    136                         $this->requests[ $rk ]->id      = $rv->membership_id;
     136                        $this->requests[ $rk ]->id      = $rv->invitation_id;
    137137
    138138                        // Miscellaneous values.
    139139                        $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 { 
    503503                require( $this->plugin_dir . 'bp-core/bp-core-moderation.php'       );
    504504                require( $this->plugin_dir . 'bp-core/bp-core-loader.php'           );
    505505                require( $this->plugin_dir . 'bp-core/bp-core-customizer-email.php' );
     506                require( $this->plugin_dir . 'bp-core/bp-core-invitations.php'      );
    506507
    507508                if ( ! $this->do_autoload ) {
    508509                        require( $this->plugin_dir . 'bp-core/bp-core-classes.php' );
    class BuddyPress { 
    578579                        'BP_Walker_Category_Checklist' => 'core',
    579580                        'BP_Walker_Nav_Menu_Checklist' => 'core',
    580581                        'BP_Walker_Nav_Menu'           => 'core',
     582                        'BP_Invitations_Component'     => 'core',
     583                        'BP_Invitations_Invitation'    => 'core',
    581584
    582585                        'BP_Core_Friends_Widget' => 'friends',
    583586
  • 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 */
     6class 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
     
    55 */
    66class BP_Tests_BP_Groups_Member_TestCases extends BP_UnitTestCase {
    77        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 );
    1819        }
    1920
    2021        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 );
    3041        }
    3142
    3243        public function test_get_recently_joined_with_filter() {
    class BP_Tests_BP_Groups_Member_TestCases extends BP_UnitTestCase { 
    9901001                $this->assertTrue( is_numeric( $member ) && $member > 0 );
    9911002                // Check that the invite has been removed.
    9921003                $invite = groups_check_user_has_invite( $u2, $g1, 'all' );
    993                 $this->assertTrue( is_null( $invite ) );
     1004                $this->assertEquals( $invite, 0 );
    9941005        }
    9951006
    9961007        /**
    class BP_Tests_BP_Groups_Member_TestCases extends BP_UnitTestCase { 
    10241035                groups_accept_invite( $u2, $g1 );
    10251036
    10261037                // Check that the membership request has been removed.
    1027                 $this->assertTrue( 0 == groups_check_for_membership_request( $u2, $g1 ) );
     1038                $this->assertEquals( groups_check_for_membership_request( $u2, $g1 ), 0 );
    10281039        }
    10291040
    10301041        /**
    class BP_Tests_BP_Groups_Member_TestCases extends BP_UnitTestCase { 
    11781189                groups_send_membership_request( $u1, $g1 );
    11791190
    11801191                // 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 );
    11821193
    1183                 groups_accept_membership_request( $member->id );
     1194                groups_accept_membership_request( false, $u1, $g1 );
    11841195
    11851196                // User should now be a group member.
    11861197                $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 { 
    688688                // Check each expected value. If there are more in the results,
    689689                // that's OK
    690690                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} );
    692692                }
    693693        }
    694694