Skip to:
Content

BuddyPress.org

Ticket #8139: 8139.04.diff

File 8139.04.diff, 121.3 KB (added by dcavins, 4 months ago)

Member invitations are functional in legacy theme; admin management screen added at /wp-admin/users.php?page=bp-members-invitations. Fix many incorrect version notes.

  • src/bp-core/admin/bp-core-admin-functions.php

    diff --git src/bp-core/admin/bp-core-admin-functions.php src/bp-core/admin/bp-core-admin-functions.php
    index c9a5259e9..1b7ab5129 100644
    function bp_core_activation_notice() { 
    279279
    280280        // Activate and Register are special cases. They are not components but they need WP pages.
    281281        // If user registration is disabled, we can skip this step.
    282         if ( bp_get_signup_allowed() ) {
     282        if ( bp_get_signup_allowed() || bp_get_members_invitations_allowed() ) {
    283283                $wp_page_components[] = array(
    284284                        'id'   => 'activate',
    285285                        'name' => __( 'Activate', 'buddypress' ),
  • src/bp-core/admin/bp-core-admin-settings.php

    diff --git src/bp-core/admin/bp-core-admin-settings.php src/bp-core/admin/bp-core-admin-settings.php
    index c09f809ca..b37b914ff 100644
    function bp_admin_setting_callback_cover_image_uploads() { 
    182182<?php
    183183}
    184184
     185/**
     186 * Allow members to invite non-members to the network.
     187 *
     188 * @since 8.0.0
     189 */
     190function bp_admin_setting_callback_members_invitations() {
     191?>
     192        <input id="bp-enable-members-invitations" name="bp-enable-members-invitations" type="checkbox" value="1" <?php checked( bp_get_members_invitations_allowed() ); ?> />
     193        <label for="bp-enable-members-invitations"><?php _e( 'Allow registered members to invite people to join this network', 'buddypress' ); ?></label>
     194        <?php if ( ! bp_get_signup_allowed() ) : ?>
     195                <p class="description"><?php _e( 'Public registration is currently disabled. However, invitees will still be able to register if network invitations are enabled.', 'buddypress' ); ?></p>
     196        <?php endif; ?>
     197        <?php
     198        /**
     199         * Fires after the output of the invitations settings section.
     200         *
     201         * @since 8.0.0
     202         */
     203        do_action( 'bp_admin_settings_after_members_invitations' );
     204}
     205
    185206/** XProfile ******************************************************************/
    186207
    187208/**
  • src/bp-core/admin/bp-core-admin-slugs.php

    diff --git src/bp-core/admin/bp-core-admin-slugs.php src/bp-core/admin/bp-core-admin-slugs.php
    index 8fb9b9a40..52ef6e36c 100644
    function bp_core_admin_slugs_options() { 
    187187
    188188                <h3><?php _e( 'Registration', 'buddypress' ); ?></h3>
    189189
    190                 <?php if ( bp_get_signup_allowed() ) : ?>
     190                <?php if ( bp_get_signup_allowed() || bp_get_members_invitations_allowed() ) : ?>
    191191                        <p><?php _e( 'Associate WordPress Pages with the following BuddyPress Registration pages.', 'buddypress' ); ?></p>
    192192                <?php else : ?>
    193193                        <?php if ( is_multisite() ) : ?>
    function bp_core_admin_slugs_options() { 
    210210                <table class="form-table">
    211211                        <tbody>
    212212
    213                                 <?php if ( bp_get_signup_allowed() ) : foreach ( $static_pages as $name => $label ) : ?>
     213                                <?php if ( bp_get_signup_allowed() || bp_get_members_invitations_allowed() ) : foreach ( $static_pages as $name => $label ) : ?>
    214214
    215215                                        <tr valign="top">
    216216                                                <th scope="row">
  • src/bp-core/bp-core-filters.php

    diff --git src/bp-core/bp-core-filters.php src/bp-core/bp-core-filters.php
    index 735c7090a..219816b05 100644
    function bp_email_set_default_headers( $headers, $property, $transform, $email ) 
    10681068        // Add 'List-Unsubscribe' header if applicable.
    10691069        if ( ! empty( $tokens['unsubscribe'] ) && $tokens['unsubscribe'] !== wp_login_url() ) {
    10701070                $user = get_user_by( 'email', $tokens['recipient.email'] );
     1071                $user_id = isset( $user->ID ) ? $user->ID : 0;
    10711072
    1072                 $link = bp_email_get_unsubscribe_link( array(
    1073                         'user_id'           => $user->ID,
     1073                $args = array(
     1074                        'user_id'           => $user_id,
    10741075                        'notification_type' => $email->get( 'type' ),
    1075                 ) );
     1076                );
     1077                // If this email is not to a current member, include the nonmember's email address.
     1078                if ( ! $user_id ) {
     1079                        $args['email_address'] = $tokens['recipient.email'];
     1080                }
     1081
     1082                $link = bp_email_get_unsubscribe_link( $args );
    10761083
    10771084                if ( ! empty( $link ) ) {
    10781085                        $headers['List-Unsubscribe'] = sprintf( '<%s>', esc_url_raw( $link ) );
  • src/bp-core/bp-core-functions.php

    diff --git src/bp-core/bp-core-functions.php src/bp-core/bp-core-functions.php
    index 592f5b155..1131d8ec5 100644
    function bp_core_add_page_mappings( $components, $existing = 'keep' ) { 
    706706
    707707        // Register and Activate are not components, but need pages when
    708708        // registration is enabled.
    709         if ( bp_get_signup_allowed() ) {
     709        if ( bp_get_signup_allowed() || bp_get_members_invitations_allowed()  ) {
    710710                foreach ( array( 'register', 'activate' ) as $slug ) {
    711711                        if ( ! isset( $pages[ $slug ] ) ) {
    712712                                $pages_to_create[ $slug ] = $page_titles[ $slug ];
    function bp_send_email( $email_type, $to, $args = array() ) { 
    34283428        // From, subject, content are set automatically.
    34293429        if ( 'settings-verify-email-change' === $email_type && isset( $args['tokens']['displayname'] ) ) {
    34303430                $email->set_to( $to, $args['tokens']['displayname'] );
     3431        // Emails sent to nonmembers will have no recipient.name populated.
     3432        } else if ( 'bp-members-invitation' === $email_type ) {
     3433                $email->set_to( $to, $to );
    34313434        } else {
    34323435                $email->set_to( $to );
    34333436        }
    function bp_email_get_schema() { 
    37633766                        /* translators: do not remove {} brackets or translate its contents. */
    37643767                        'post_title'   => __( '[{{{site.name}}}] You have an invitation to the group: "{{group.name}}"', 'buddypress' ),
    37653768                        /* translators: do not remove {} brackets or translate its contents. */
    3766                         'post_content' => __( "<a href=\"{{{inviter.url}}}\">{{inviter.name}}</a> has invited you to join the group: &quot;{{group.name}}&quot;.\n{{invite.message}}\n<a href=\"{{{invites.url}}}\">Go here to accept your invitation</a> or <a href=\"{{{group.url}}}\">visit the group</a> to learn more.", 'buddypress' ),
     3769                        'post_content' => __( "<a href=\"{{{inviter.url}}}\">{{inviter.name}}</a> has invited you to join the group: &quot;{{group.name}}&quot;.\n\n{{invite.message}}\n\n<a href=\"{{{invites.url}}}\">Go here to accept your invitation</a> or <a href=\"{{{group.url}}}\">visit the group</a> to learn more.", 'buddypress' ),
    37673770                        /* translators: do not remove {} brackets or translate its contents. */
    3768                         'post_excerpt' => __( "{{inviter.name}} has invited you to join the group: \"{{group.name}}\".\n\nTo accept your invitation, visit: {{{invites.url}}}\n\nTo learn more about the group, visit: {{{group.url}}}.\nTo view {{inviter.name}}'s profile, visit: {{{inviter.url}}}", 'buddypress' ),
     3771                        'post_excerpt' => __( "{{inviter.name}} has invited you to join the group: \"{{group.name}}\".\n\n{{invite.message}}\n\nTo accept your invitation, visit: {{{invites.url}}}\n\nTo learn more about the group, visit: {{{group.url}}}.\nTo view {{inviter.name}}'s profile, visit: {{{inviter.url}}}", 'buddypress' ),
    37693772                ),
    37703773                'groups-member-promoted' => array(
    37713774                        /* translators: do not remove {} brackets or translate its contents. */
    function bp_email_get_schema() { 
    38153818                        /* translators: do not remove {} brackets or translate its contents. */
    38163819                        'post_excerpt' => __( "Your membership request for the group \"{{group.name}}\" has been rejected.\n\nTo request membership again, visit: {{{group.url}}}", 'buddypress' ),
    38173820                ),
     3821                'bp-members-invitation' => array(
     3822                        /* translators: do not remove {} brackets or translate its contents. */
     3823                        'post_title'   => __( '{{inviter.name}} has invited you to join {{site.name}}', 'buddypress' ),
     3824                        /* translators: do not remove {} brackets or translate its contents. */
     3825                        'post_content' => __( "<a href=\"{{{inviter.url}}}\">{{inviter.name}}</a> has invited you to join the site: &quot;{{site.name}}&quot;.\n\n{{usermessage}}\n\n<a href=\"{{{invite.accept_url}}}\">Accept your invitation</a> or <a href=\"{{{site.url}}}\">visit the site</a> to learn more.", 'buddypress' ),
     3826                        /* translators: do not remove {} brackets or translate its contents. */
     3827                        'post_excerpt' => __( "{{inviter.name}} has invited you to join the site: \"{{site.name}}\".\n\n{{usermessage}}\n\nTo accept your invitation, visit: {{{invite.accept_url}}}\n\nTo learn more about the site, visit: {{{site.url}}}.\nTo view {{inviter.name}}'s profile, visit: {{{inviter.url}}}", 'buddypress' ),
     3828                ),
    38183829        ) );
    38193830}
    38203831
    function bp_email_get_type_schema( $field = 'description' ) { 
    39563967                ),
    39573968        );
    39583969
     3970        $members_invitation = array(
     3971                'description'   => __( 'A site member has sent a site invitation to the recipient.', 'buddypress' ),
     3972                'unsubscribe'   => array(
     3973                        'meta_key'      => 'notification_bp_members_invite',
     3974                        'message'       => __( 'You will no longer receive emails when you are invited to join a site.', 'buddypress' ),
     3975                ),
     3976        );
     3977
    39593978        $types = array(
    39603979                'activity-comment'                   => $activity_comment,
    39613980                'activity-comment-author'            => $activity_comment_author,
    function bp_email_get_type_schema( $field = 'description' ) { 
    39733992                'settings-verify-email-change'       => $settings_verify_email_change,
    39743993                'groups-membership-request-accepted' => $groups_membership_request_accepted,
    39753994                'groups-membership-request-rejected' => $groups_membership_request_rejected,
     3995                'bp-members-invitation'              => $members_invitation,
    39763996        );
    39773997
    39783998        if ( $field !== 'all' ) {
    function bp_email_unsubscribe_handler() { 
    39924012        $raw_email_type = ! empty( $_GET['nt'] ) ? $_GET['nt'] : '';
    39934013        $raw_hash       = ! empty( $_GET['nh'] ) ? $_GET['nh'] : '';
    39944014        $raw_user_id    = ! empty( $_GET['uid'] ) ? absint( $_GET['uid'] ) : 0;
    3995         $new_hash       = hash_hmac( 'sha1', "{$raw_email_type}:{$raw_user_id}", bp_email_get_salt() );
     4015        $raw_user_email = ! empty( $_GET['uem'] ) ? $_GET['uem'] : '';
     4016
     4017        $new_hash = '';
     4018        if ( ! empty( $raw_user_id ) ) {
     4019                $new_hash = hash_hmac( 'sha1', "{$raw_email_type}:{$raw_user_id}", bp_email_get_salt() );
     4020        } else if ( ! empty( $raw_user_email ) ) {
     4021                $new_hash = hash_hmac( 'sha1', "{$raw_email_type}:{$raw_user_email}", bp_email_get_salt() );
     4022        }
    39964023
    39974024        // Check required values.
    3998         if ( ! $raw_user_id || ! $raw_email_type || ! $raw_hash || ! array_key_exists( $raw_email_type, $emails ) ) {
     4025        if ( ( ! $raw_user_id && ! $raw_user_email ) || ! $raw_email_type || ! $raw_hash || ! array_key_exists( $raw_email_type, $emails ) ) {
    39994026                $redirect_to = wp_login_url();
    40004027                $result_msg  = __( 'Something has gone wrong.', 'buddypress' );
    40014028                $unsub_msg   = __( 'Please log in and go to your settings to unsubscribe from notification emails.', 'buddypress' );
    function bp_email_unsubscribe_handler() { 
    40214048                        $redirect_to = bp_core_get_user_domain( get_current_user_id() );
    40224049                }
    40234050
     4051        // This is an unsubscribe request from a nonmember.
     4052        } else if ( $raw_user_email ) {
     4053                // Unsubscribe.
     4054                error_log( 'caught unsubscribe request {$raw_user_email}' );
     4055                // @TODO: Create opt-out once opt-out logic is in place.
     4056                $redirect_to = home_url();
     4057
     4058                $result_msg = $emails[ $raw_email_type ]['unsubscribe']['message'];
     4059                $unsub_msg  = __( 'You have been unsubscribed.' );
     4060        // This is an unsubscribe request from a current member.
    40244061        } else {
    40254062                if ( bp_is_active( 'settings' ) ) {
    40264063                        $redirect_to = sprintf(
    function bp_email_unsubscribe_handler() { 
    40484085        );
    40494086
    40504087        bp_core_add_message( $message );
    4051         bp_core_redirect( bp_core_get_user_domain( $raw_user_id ) );
     4088
     4089        $page_redirect = '';
     4090        if ( $raw_user_id  ) {
     4091                $page_redirect = bp_core_get_user_domain( $raw_user_id );
     4092        }
     4093
     4094        bp_core_redirect();
    40524095
    40534096        exit;
    40544097}
    function bp_email_unsubscribe_handler() { 
    40654108 *    @type string $notification_type Which notification type is being sent.
    40664109 *    @type string $user_id           The ID of the user to whom the notification is sent.
    40674110 *    @type string $redirect_to       Optional. The url to which the user will be redirected. Default is the activity directory.
     4111 *    @type string $email             Optional. The email address of the user to whom the notification is sent.
    40684112 * }
    40694113 * @return string The unsubscribe link.
    40704114 */
    function bp_email_get_unsubscribe_link( $args ) { 
    40844128                return '';
    40854129        }
    40864130
    4087         $link = add_query_arg(
    4088                 array(
    4089                         'action' => 'unsubscribe',
    4090                         'nh'     => hash_hmac( 'sha1', "{$email_type}:{$user_id}", bp_email_get_salt() ),
    4091                         'nt'     => $args['notification_type'],
    4092                         'uid'    => $user_id,
    4093                 ),
    4094                 $redirect_to
    4095         );
     4131        $link = '';
     4132        // Case where the recipient is a member of the site.
     4133        if ( ! empty( $user_id ) ) {
     4134                $link = add_query_arg(
     4135                        array(
     4136                                'action' => 'unsubscribe',
     4137                                'nh'     => hash_hmac( 'sha1', "{$email_type}:{$user_id}", bp_email_get_salt() ),
     4138                                'nt'     => $args['notification_type'],
     4139                                'uid'    => $user_id,
     4140                        ),
     4141                        $redirect_to
     4142                );
     4143        // Case where the recipient is not a member of the site.
     4144        } else if ( ! empty( $args['email_address'] ) ) {
     4145                $email_address = $args['email_address'];
     4146                $link = add_query_arg(
     4147                        array(
     4148                                'action' => 'unsubscribe',
     4149                                'nh'     => hash_hmac( 'sha1', "{$email_type}:{$email_address}", bp_email_get_salt() ),
     4150                                'nt'     => $args['notification_type'],
     4151                                'uid'    => $user_id,
     4152                                'uem'    => $email_address,
     4153                        ),
     4154                        $redirect_to
     4155                );
     4156        }
    40964157
    40974158        /**
    40984159         * Filters the unsubscribe link.
  • src/bp-core/bp-core-template.php

    diff --git src/bp-core/bp-core-template.php src/bp-core/bp-core-template.php
    index 799a69cdc..e840a7cd6 100644
    function bp_is_settings_component() { 
    22472247        return (bool) bp_is_current_component( 'settings' );
    22482248}
    22492249
     2250/**
     2251 * Check whether the current page is an Invitations screen.
     2252 *
     2253 * @since 8.0.0
     2254 *
     2255 * @return bool True if the current page is an Invitations screen.
     2256 */
     2257function bp_is_members_invitations_screen() {
     2258        return (bool) bp_is_current_component( bp_get_members_invitations_slug() );
     2259}
     2260
    22502261/**
    22512262 * Is the current component an active core component?
    22522263 *
    function bp_is_user_settings_profile() { 
    26472658        return (bool) ( bp_is_user_settings() && bp_is_current_action( 'profile' ) );
    26482659}
    26492660
     2661/**
     2662 * Is the current page a user's community invitations page?
     2663 *
     2664 * Eg http://example.com/members/cassie/invitations/ (or a subpage thereof).
     2665 *
     2666 * @since 8.0.0
     2667 *
     2668 * @return bool True if the current page is a user's community invitations page.
     2669 */
     2670function bp_is_user_members_invitations() {
     2671        return (bool) ( bp_is_user() && bp_is_members_invitations_screen() );
     2672}
     2673
     2674/**
     2675 * Is the current page a user's List Invites page?
     2676 *
     2677 * Eg http://example.com/members/cassie/invitations/list-invites/.
     2678 *
     2679 * @since 8.0.0
     2680 *
     2681 * @return bool True if the current page is a user's List Invites page.
     2682 */
     2683function bp_is_user_members_invitations_list() {
     2684        return (bool) ( bp_is_user_members_invitations() && bp_is_current_action( 'list-invites' ) );
     2685}
     2686
     2687/**
     2688 * Is the current page a user's Send Invites page?
     2689 *
     2690 * Eg http://example.com/members/cassie/invitations/send-invites/.
     2691 *
     2692 * @since 8.0.0
     2693 *
     2694 * @return bool True if the current page is a user's Send Invites page.
     2695 */
     2696function bp_is_user_members_invitations_send_screen() {
     2697        return (bool) ( bp_is_user_members_invitations() && bp_is_current_action( 'send-invites' ) );
     2698}
     2699
    26502700/** Groups ********************************************************************/
    26512701
    26522702/**
  • src/bp-core/classes/class-bp-admin.php

    diff --git src/bp-core/classes/class-bp-admin.php src/bp-core/classes/class-bp-admin.php
    index 32dd0768d..2463a1f73 100644
    class BP_Admin { 
    412412                        register_setting( 'buddypress', 'bp-disable-cover-image-uploads', 'intval' );
    413413                }
    414414
     415                // Community Invitations.
     416                if ( bp_is_active( 'members', 'invitations' ) ) {
     417                        add_settings_field( 'bp-enable-members-invitations', __( 'Invitations', 'buddypress' ), 'bp_admin_setting_callback_members_invitations', 'buddypress', 'bp_members' );
     418                        register_setting( 'buddypress', 'bp-enable-members-invitations', 'intval' );
     419                }
     420
    415421                /* XProfile Section **************************************************/
    416422
    417423                if ( bp_is_active( 'xprofile' ) ) {
  • src/bp-core/classes/class-bp-invitation-manager.php

    diff --git src/bp-core/classes/class-bp-invitation-manager.php src/bp-core/classes/class-bp-invitation-manager.php
    index 0b7d2f009..726a78da4 100644
    abstract class BP_Invitation_Manager { 
    9999                        return false;
    100100                }
    101101
     102                // If an email address is specified, it must be a valid email address.
     103                if ( $r['invitee_email'] && ! is_email( $r['invitee_email'] ) ) {
     104                        return false;
     105                }
     106
    102107                /**
    103108                 * Is this user allowed to extend invitations in this situation?
    104109                 *
    abstract class BP_Invitation_Manager { 
    157162         * @param int   $invitation_id ID of invitation to send.
    158163         * @param array $args          See BP_Invitation::mark_sent().
    159164         *
    160          * @return int|bool The number of rows updated, or false on error.
     165         * @return bool The result of `run_send_action()`.
    161166         */
    162167        public function send_invitation_by_id( $invitation_id = 0, $args = array() ) {
    163168                $updated = false;
    abstract class BP_Invitation_Manager { 
    195200                }
    196201
    197202                // Perform the send action.
    198                 $this->run_send_action( $invitation );
     203                $success = $this->run_send_action( $invitation );
    199204
    200                 $updated = BP_Invitation::mark_sent( $invitation->id, $args );
     205                if ( $success ) {
     206                        BP_Invitation::mark_sent( $invitation->id, $args );
     207                }
    201208
    202                 return $updated;
     209                return $success;
    203210        }
    204211
    205212        /**
    abstract class BP_Invitation_Manager { 
    309316         * @param int   $request_id ID of request to send.
    310317         * @param array $args       See BP_Invitation::mark_sent().
    311318         *
    312          * @return int|bool The number of rows updated, or false on error.
     319         * @return bool The result of `run_send_action()`.
    313320         */
    314321        public function send_request_notification_by_id( $request_id = 0, $args = array() ) {
    315322                $updated = false;
    abstract class BP_Invitation_Manager { 
    342349                }
    343350
    344351                // Perform the send action.
    345                 $this->run_send_action( $request );
     352                $success = $this->run_send_action( $request );
    346353
    347                 $updated = BP_Invitation::mark_sent( $request->id, $args );
     354                if ( $success ) {
     355                        BP_Invitation::mark_sent( $request->id, $args );
     356                }
    348357
    349                 return $updated;
     358                return $success;
    350359        }
    351360
    352361        /** Retrieve ******************************************************************/
    abstract class BP_Invitation_Manager { 
    383392                return BP_Invitation::get( $args );
    384393        }
    385394
     395        /**
     396         * Get a count of the number of invitations that match provided filter parameters.
     397         *
     398         * @since 8.0.0
     399         *
     400         * @see BP_Invitation::get_total_count() for a description of accepted parameters.
     401         *
     402         * @return int Total number of invitations.
     403         */
     404        public function get_invitations_total_count( $args = array() ) {
     405                // Default to returning invitations, not requests.
     406                if ( empty( $args['type'] ) ) {
     407                        $args['type'] = 'invite';
     408                }
     409                // Use the class_name property value.
     410                $args['class'] = $this->class_name;
     411
     412                return BP_Invitation::get_total_count( $args );
     413        }
     414
    386415        /**
    387416         * Get requests, based on provided filter parameters.
    388417         *
    abstract class BP_Invitation_Manager { 
    703732                ) );
    704733        }
    705734
     735        /**
     736         * Delete an invitation by id.
     737         *
     738         * @since 8.0.0
     739         *
     740         * @param int $id ID of the invitation to delete.
     741         * @return int|bool Number of rows deleted on success, false on failure.
     742         */
     743        public function delete_by_id( $id ) {
     744                // Ensure that the invitation exists and was created by this class.
     745                $invite = new BP_Invitation( $id );
     746                if ( ! $invite->id || sanitize_key( $this->class_name ) !== $invite->class ) {
     747                        return false;
     748                }
     749
     750                return BP_Invitation::delete_by_id( $id );
     751        }
     752
     753
     754
    706755        /**
    707756         * This is where custom actions are added (in child classes)
    708757         * to determine whether an invitation should be allowed.
  • src/bp-members/admin/bp-members-admin-classes.php

    diff --git src/bp-members/admin/bp-members-admin-classes.php src/bp-members/admin/bp-members-admin-classes.php
    index 96e339e7a..4e2e79b54 100644
    defined( 'ABSPATH' ) || exit; 
    1212
    1313if ( class_exists( 'WP_Users_List_Table' ) ) {
    1414        require dirname( dirname( __FILE__ ) ) . '/classes/class-bp-members-list-table.php';
     15        require dirname( dirname( __FILE__ ) ) . '/classes/class-bp-members-invitations-list-table.php';
    1516}
    1617
    1718if ( class_exists( 'WP_MS_Users_List_Table' ) ) {
  • src/bp-members/bp-members-filters.php

    diff --git src/bp-members/bp-members-filters.php src/bp-members/bp-members-filters.php
    index 5575ebef2..617b968a1 100644
    function bp_members_edit_profile_url( $url, $user_id, $scheme = 'admin' ) { 
    127127        return apply_filters( 'bp_members_edit_profile_url', $profile_link, $url, $user_id, $scheme );
    128128}
    129129add_filter( 'edit_profile_url', 'bp_members_edit_profile_url', 10, 3 );
     130
     131/**
     132 * Filter the bp_user_can value to determine what the user can do in the members component.
     133 *
     134 * @since 8.0.0
     135 *
     136 * @param bool   $retval     Whether or not the current user has the capability.
     137 * @param int    $user_id
     138 * @param string $capability The capability being checked for.
     139 * @param int    $site_id    Site ID. Defaults to the BP root blog.
     140 * @param array  $args       Array of extra arguments passed.
     141 *
     142 * @return bool
     143 */
     144function bp_members_user_can_filter( $retval, $user_id, $capability, $site_id, $args ) {
     145
     146        switch ( $capability ) {
     147                case 'bp_members_manage_membership_requests':
     148                        $retval = bp_user_can( $user_id, 'bp_moderate' );
     149                        break;
     150                case 'bp_members_send_invitation':
     151                        // @todo Add restrictions?
     152                        if ( bp_get_members_invitations_allowed() ) {
     153                                $retval = true;
     154                        }
     155                        break;
     156                case 'bp_members_receive_invitation':
     157                        if ( bp_get_members_invitations_allowed() ) {
     158                                $retval = true;
     159                                // The invited user must not already be a member of the network.
     160                                if ( empty( $args['invitee_email'] ) || false !== get_user_by( 'email', $args['invitee_email'] ) ) {
     161                                        $retval = false;
     162                                }
     163                        // @TODO: The invited user must not have opted out from receiving invitations.
     164                        }
     165
     166                        break;
     167        }
     168
     169        return $retval;
     170
     171}
     172add_filter( 'bp_user_can', 'bp_members_user_can_filter', 10, 5 );
     173
     174/**
     175 * Do not allow the new user to change the email address
     176 * if they are accepting a community invitation.
     177 *
     178 * @since 8.0.0
     179 *
     180 * @param array  $attributes The field attributes.
     181 * @param string $name       The field name.
     182 *
     183 * @return array $attributes The field attributes.
     184 */
     185function bp_members_invitations_make_registration_email_input_readonly_if_invite( $attributes, $name ) {
     186        if ( 'email' === $name && bp_get_members_invitations_allowed() ) {
     187                $invite = bp_get_members_invitation_from_request();
     188                if ( $invite->id ) {
     189                        $attributes['readonly'] = 'readonly';
     190                }
     191        }
     192        return $attributes;
     193}
     194add_filter( 'bp_get_form_field_attributes', 'bp_members_invitations_make_registration_email_input_readonly_if_invite', 10, 2 );
     195
     196/**
     197 * Provide a more-specific welcome message if the new user
     198 * is accepting a network invitation.
     199 *
     200 * @since 8.0.0
     201 *
     202 * @return string $message The message text.
     203 */
     204function bp_members_invitations_get_registration_welcome_message() {
     205        $message = '';
     206        if ( ! bp_get_members_invitations_allowed() ) {
     207                return $message;
     208        }
     209        $invite = bp_get_members_invitation_from_request();
     210        if ( ! $invite->id ) {
     211                return $message;
     212        }
     213
     214        // Fetch the display names of all inviters to personalize the welcome message.
     215        $all_invites = bp_members_invitations_get_invites(
     216                array(
     217                        'invitee_email' => $invite->invitee_email,
     218                        'invite_sent'   => 'sent',
     219                )
     220        );
     221        $inviters = array();
     222        foreach ( $all_invites as $inv ) {
     223                $inviters[] = bp_core_get_user_displayname( $inv->inviter_id );
     224        }
     225
     226        if ( ! empty( $inviters ) ) {
     227                $message = sprintf( _n( 'Welcome! You&#8217;ve been invited to join the site by the following user: %s. ', 'Welcome! You&#8217;ve been invited to join the site by the following users: %s. ', count( $inviters ), 'buddypress' ), implode( ', ', $inviters ) );
     228        } else {
     229                $message = __( 'Welcome! You&#8217;ve been invited to join the site. ', 'buddypress' );
     230        }
     231        return $message;
     232}
     233
     234/**
     235 * Provide a more-specific "registration is disabled" message
     236 * if registration is available by invitation only.
     237 * Also provide failure note if new user is trying to accept
     238 * a network invitation but there's a problem.
     239 *
     240 * @since 8.0.0
     241 *
     242 * @return string $message The message text.
     243 */
     244function bp_members_invitations_get_modified_registration_disabled_message() {
     245        $message = '';
     246        if ( bp_get_members_invitations_allowed() ) {
     247                $message = __( 'Member registration is allowed by invitation only.', 'buddypress' );
     248                // Is the user trying to accept an invitation but something is wrong?
     249                if ( ! empty( $_GET['inv'] ) ) {
     250                        $message .= __( ' It looks like there is a problem with your invitation. Please try again.', 'buddypress' );
     251                }
     252        }
     253        return $message;
     254}
  • src/bp-members/bp-members-functions.php

    diff --git src/bp-members/bp-members-functions.php src/bp-members/bp-members-functions.php
    index 165bc97c3..4afad7a7a 100644
    function bp_members_avatar_upload_dir( $directory = 'avatars', $user_id = 0 ) { 
    33063306                'error'   => false
    33073307        ) );
    33083308}
     3309
     3310/**
     3311 * Get invitations to the BP community filtered by arguments.
     3312 *
     3313 * @since 8.0.0
     3314 *
     3315 * @param array $args     Invitation arguments.
     3316 *                        See BP_Invitation::get() for list.
     3317 *
     3318 * @return array $invites     Matching BP_Invitation objects.
     3319 */
     3320function bp_members_invitations_get_invites( $args = array() ) {
     3321        $invites_class = new BP_Members_Invitation_Manager();
     3322        return $invites_class->get_invitations( $args );
     3323}
     3324
     3325/**
     3326 * Invite a user to a BP community.
     3327 *
     3328 * @since 8.0.0
     3329 *
     3330 * @param array|string $args {
     3331 *     Array of arguments.
     3332 *     @type int    $invitee_email Email address of the user being invited.
     3333 *     @type int    $network_id    ID of the network to which the user is being invited.
     3334 *     @type int    $inviter_id    Optional. ID of the inviting user. Default:
     3335 *                                 ID of the logged-in user.
     3336 *     @type string $date_modified Optional. Modified date for the invitation.
     3337 *                                 Default: current date/time.
     3338 *     @type string $content       Optional. Message to invitee.
     3339 *     @type bool   $send_invite   Optional. Whether the invitation should be
     3340 *                                 sent now. Default: false.
     3341 * }
     3342 * @return bool True on success, false on failure.
     3343 */
     3344function bp_members_invitations_invite_user( $args ) {
     3345        $r = bp_parse_args( $args, array(
     3346                'invitee_email' => '',
     3347                'network_id'    => get_current_network_id(),
     3348                'inviter_id'    => bp_loggedin_user_id(),
     3349                'date_modified' => bp_core_current_time(),
     3350                'content'       => '',
     3351                'send_invite'   => 0
     3352        ), 'community_invite_user' );
     3353
     3354        $inv_args = array(
     3355                'invitee_email' => $r['invitee_email'],
     3356                'item_id'       => $r['network_id'],
     3357                'inviter_id'    => $r['inviter_id'],
     3358                'date_modified' => $r['date_modified'],
     3359                'content'       => $r['content'],
     3360                'send_invite'   => $r['send_invite']
     3361        );
     3362
     3363        // Create the invitataion.
     3364        $invites_class = new BP_Members_Invitation_Manager();
     3365        $created       = $invites_class->add_invitation( $inv_args );
     3366
     3367        /**
     3368         * Fires after the creation of a new network invite.
     3369         *
     3370         * @since 8.0.0
     3371         *
     3372         * @param array    $r       Array of parsed arguments for the network invite.
     3373         * @param int|bool $created The ID of the invitation or false if it couldn't be created.
     3374         */
     3375        do_action( 'bp_members_invitations_invite_user', $r, $created );
     3376
     3377        return $created;
     3378}
     3379
     3380/**
     3381 * Resend a membership invitation email by id.
     3382 *
     3383 * @since 8.0.0
     3384 *
     3385 * @param int $id ID of the invitation to resend.
     3386 * @return bool True on success, false on failure.
     3387 */
     3388function bp_members_invitation_resend_by_id( $id = 0 ) {
     3389
     3390        // Find the invitation before deleting it.
     3391        $existing_invite = new BP_Invitation( $id );
     3392        $invites_class   = new BP_Members_Invitation_Manager();
     3393        $success         = $invites_class->send_invitation_by_id( $id );
     3394
     3395        if ( ! $success ) {
     3396                return $success;
     3397        }
     3398
     3399        /**
     3400         * Fires after the re-sending of a network invite.
     3401         *
     3402         * @since 8.0.0
     3403         *
     3404         * @param BP_Invitation $existing_invite The invitation that was resent.
     3405         */
     3406        do_action( 'bp_members_invitations_resend_invitation', $existing_invite );
     3407
     3408        return $success;
     3409}
     3410
     3411/**
     3412 * Delete a membership invitation by id.
     3413 *
     3414 * @since 8.0.0
     3415 *
     3416 * @param int $id ID of the invitation to delete.
     3417 * @return int|bool Number of rows deleted on success, false on failure.
     3418 */
     3419function bp_members_invitations_delete_by_id( $id = 0 ) {
     3420
     3421        // Find the invitation before deleting it.
     3422        $existing_invite = new BP_Invitation( $id );
     3423        $invites_class   = new BP_Members_Invitation_Manager();
     3424        $success         = $invites_class->delete_by_id( $id );
     3425
     3426        if ( ! $success ) {
     3427                return $success;
     3428        }
     3429
     3430        // Run a different action depending on the status of the invite.
     3431        if ( ! $existing_invite->invite_sent ) {
     3432                /**
     3433                 * Fires after the deletion of an unsent community invite.
     3434                 *
     3435                 * @since 8.0.0
     3436                 *
     3437                 * @param BP_Invitation $existing_invite The invitation to be deleted.
     3438                 */
     3439                do_action( 'bp_members_invitations_canceled_invitation', $existing_invite );
     3440        } else if ( ! $existing_invite->accepted ) {
     3441                /**
     3442                 * Fires after the deletion of a sent, but not yet accepted, community invite.
     3443                 *
     3444                 * @since 8.0.0
     3445                 *
     3446                 * @param BP_Invitation $existing_invite The invitation to be deleted.
     3447                 */
     3448                do_action( 'bp_members_invitations_revoked_invitation', $existing_invite );
     3449        } else {
     3450                /**
     3451                 * Fires after the deletion of a sent and accepted community invite.
     3452                 *
     3453                 * @since 8.0.0
     3454                 *
     3455                 * @param BP_Invitation $existing_invite The invitation to be deleted.
     3456                 */
     3457                do_action( 'bp_members_invitations_deleted_invitation', $existing_invite );
     3458        }
     3459
     3460        return $success;
     3461}
     3462
     3463/**
     3464 * Delete a membership invitation.
     3465 *
     3466 * @since 8.0.0
     3467 *
     3468 * @param intring $args {
     3469 *     Array of arguments.
     3470 *     @type int|array $id            Id(s) of the invitation(s) to remove.
     3471 *     @type int       $invitee_email Email address of the user being invited.
     3472 *     @type int       $network_id    ID of the network to which the user is being invited.
     3473 *     @type int       $inviter_id    ID of the inviting user.
     3474 *     @type int       $accepted      Whether the invitation has been accepted yet.
     3475 *     @type int       $invite_sent   Whether the invitation has been sent yet.
     3476 * }
     3477 * @return bool True if all were deleted.
     3478 */
     3479function bp_members_invitations_delete_invites( $args ) {
     3480        $r = bp_parse_args( $args, array(
     3481                'id'            => 0,
     3482                'invitee_email' => '',
     3483                'network_id'    => get_current_network_id(),
     3484                'inviter_id'    => null,
     3485                'accepted'      => null,
     3486                'invite_sent'   => null
     3487        ), 'community_invitation_delete_invites' );
     3488
     3489        $inv_args = array(
     3490                'id'            => $r['id'],
     3491                'invitee_email' => $r['invitee_email'],
     3492                'item_id'       => $r['network_id'],
     3493                'inviter_id'    => $r['inviter_id'],
     3494        );
     3495
     3496        // Find the invitation(s).
     3497        $invites       = bp_members_invitations_get_invites( $inv_args );
     3498        $total_count   = count( $invites );
     3499
     3500        // Loop through, deleting each invitation.
     3501        $deleted = 0;
     3502        foreach ( $invites as $invite ) {
     3503                $success = bp_members_invitations_delete_by_id( $invite->id );
     3504                if ( $success ) {
     3505                        $deleted++;
     3506                }
     3507        }
     3508
     3509        return $deleted === $total_count;
     3510}
     3511
     3512/**
     3513 * Get hash based on details of a membership invitation and the inviter.
     3514 *
     3515 * @since 8.0.0
     3516 *
     3517 * @param BP_Invitation object $invitation Invitation to create hash from.
     3518 *
     3519 * @return string $hash Calculated sha1 hash.
     3520 */
     3521function bp_members_invitations_get_hash( BP_Invitation $invitation ) {
     3522        $hash = false;
     3523
     3524        if ( ! empty( $invitation->id ) ) {
     3525                $inviter_ud = get_userdata( $invitation->inviter_id );
     3526                if ( $inviter_ud ) {
     3527                        /*
     3528                         * Use some inviter details as part of the hash so that invitations from
     3529                         * users who are subsequently marked as spam will be invalidated.
     3530                         */
     3531                        $hash = wp_hash( "{$invitation->inviter_id}:{$invitation->invitee_email}:{$inviter_ud->user_status}:{$inviter_ud->user_registered}" );
     3532                }
     3533        }
     3534
     3535        // If there's a problem, return a string that will change and thus fail.
     3536        if ( ! $hash ) {
     3537                $hash = wp_generate_password( 32, false );
     3538        }
     3539
     3540        /**
     3541         * Filters the hash calculated by the invitation details.
     3542         *
     3543         * @since 8.0.0
     3544         *
     3545         * @param string $hash Calculated sha1 hash.
     3546         * @param BP_Invitation object $invitation Invitation hash was created from.
     3547         */
     3548        return apply_filters( 'bp_members_invitations_get_hash', $hash, $invitation );
     3549}
     3550
     3551/**
     3552 * Get the current invitation specified by the $_GET parameters.
     3553 *
     3554 * @since 8.0.0
     3555 *
     3556 * @return BP_Invitation $invite Invitation specified by the $_GET parameters.
     3557 */
     3558function bp_get_members_invitation_from_request() {
     3559        $invites_class = new BP_Members_Invitation_Manager();
     3560        $invite        = $invites_class->get_by_id( 0 );
     3561
     3562        if ( bp_get_members_invitations_allowed() && ! empty( $_GET['inv'] ) ) {
     3563                // Check to make sure the passed hash matches a calculated hash.
     3564                $maybe_invite = $invites_class->get_by_id( absint( $_GET['inv'] ) );
     3565                $hash = bp_members_invitations_get_hash( $maybe_invite );
     3566                if ( $_GET['ih'] === $hash ) {
     3567                        $invite = $maybe_invite;
     3568                }
     3569        }
     3570
     3571        /**
     3572         * Filters the invitation specified by the $_GET parameters.
     3573         *
     3574         * @since 8.0.0
     3575         *
     3576         * @param BP_Invitation $invite Invitation specified by the $_GET parameters.
     3577         */
     3578        return apply_filters( 'bp_get_members_invitation_from_request', $invite );
     3579}
  • new file src/bp-members/bp-members-invitations.php

    diff --git src/bp-members/bp-members-invitations.php src/bp-members/bp-members-invitations.php
    new file mode 100644
    index 000000000..30dc91949
    - +  
     1<?php
     2/**
     3 * BuddyPress Membersip Invitations
     4 *
     5 * @package BuddyPress
     6 * @subpackage MembersInvitations
     7 * @since 8.0.0
     8 */
     9
     10// Exit if accessed directly.
     11defined( 'ABSPATH' ) || exit;
     12
     13function bp_members_invitations_setup_nav() {
     14        if ( ! bp_get_members_invitations_allowed() ) {
     15                return;
     16        }
     17
     18        $user_has_access = bp_user_has_access() && bp_user_can( bp_displayed_user_id(), 'bp_members_send_invitation' );
     19
     20        /* Add 'Invitations' to the main user profile navigation */
     21        bp_core_new_nav_item(
     22                array(
     23                        'name'                    => __( 'Invitations', 'buddypress' ),
     24                        'slug'                    => bp_get_members_invitations_slug(),
     25                        'position'                => 80,
     26                        'screen_function'         => 'members_screen_send_invites',
     27                        'default_subnav_slug'     => 'list-invites',
     28                        'show_for_displayed_user' => $user_has_access
     29                )
     30        );
     31
     32        $parent_link = trailingslashit( bp_displayed_user_domain() . bp_get_members_invitations_slug() );
     33
     34        /* Create two subnav items for community invitations */
     35        bp_core_new_subnav_item(
     36                array(
     37                        'name'            => __( 'Sent Invites', 'buddypress' ),
     38                        'slug'            => 'list-invites',
     39                        'parent_slug'     => bp_get_members_invitations_slug(),
     40                        'parent_url'      => $parent_link,
     41                        'screen_function' => 'members_screen_list_sent_invites',
     42                        'position'        => 10,
     43                        'user_has_access' => $user_has_access
     44                )
     45        );
     46
     47        bp_core_new_subnav_item(
     48                array(
     49                        'name'            => __( 'Invite New Members', 'buddypress' ),
     50                        'slug'            => 'send-invites',
     51                        'parent_slug'     => bp_get_members_invitations_slug(),
     52                        'parent_url'      => $parent_link,
     53                        'screen_function' => 'members_screen_send_invites',
     54                        'position'        => 20,
     55                        'user_has_access' => $user_has_access && bp_is_my_profile()
     56                )
     57        );
     58}
     59add_action( 'bp_setup_nav', 'bp_members_invitations_setup_nav' );
     60
     61/**
     62 * When a user joins the network via an invitation, skip sending the activation email.
     63 *
     64 * @param bool   $send           Whether or not to send the activation key.
     65 * @param int    $user_id        User ID to send activation key to.
     66 * @param string $user_email     User email to send activation key to.
     67 * @param string $activation_key Activation key to be sent.
     68 * @param array  $usermeta       Miscellaneous metadata about the user (blog-specific
     69 *                               signup data, xprofile data, etc).
     70 */
     71function bp_members_invitations_cancel_activation_email( $send, $user_id, $user_email, $activation_key, $usermeta ) {
     72
     73        $invite = bp_members_invitations_get_invites(
     74                array(
     75                        'invitee_email' => $user_email,
     76                        'invite_sent'   => 'sent'
     77                )
     78        );
     79
     80        if ( $invite ) {
     81                $send = false;
     82        }
     83
     84        return $send;
     85}
     86add_filter( 'bp_core_signup_send_activation_key', 'bp_members_invitations_cancel_activation_email', 10, 5 );
     87
     88
     89/**
     90 * When a user joins the network via an invitation:
     91 * - mark all invitations and requests as accepted
     92 * - activate the user upon signup
     93 *
     94 * @param bool|WP_Error   $user_id       True on success, WP_Error on failure.
     95 * @param string          $user_login    Login name requested by the user.
     96 * @param string          $user_password Password requested by the user.
     97 * @param string          $user_email    Email address requested by the user.
     98 */
     99function bp_members_invitations_complete_signup( $user_id, $user_login, $user_password, $user_email ) {
     100        if ( ! $user_id ) {
     101                return;
     102        }
     103
     104        // Is this new signup the result of an invitation?
     105        $invite = bp_members_invitations_get_invites(
     106                array(
     107                        'invitee_email' => $user_email,
     108                        'invite_sent'   => 'sent'
     109                )
     110        );
     111
     112
     113        if ( ! $invite ) {
     114                return;
     115        }
     116
     117        $invites_class = new BP_Members_Invitation_Manager();
     118        $args = array(
     119                'invitee_email' => $user_email,
     120                'item_id'       => get_current_network_id(),
     121                'type'          => 'all'
     122        );
     123        $invites_class->mark_accepted( $args );
     124
     125        // User has already verified their email by responding to the invitation, so we can activate.
     126        $key = bp_get_user_meta( $user_id, 'activation_key', true );
     127        if ( $key ) {
     128                /**
     129                 * Filters the activation signup.
     130                 *
     131                 * @since 1.1.0
     132                 *
     133                 * @param bool|int $value Value returned by activation.
     134                 *                        Integer on success, boolean on failure.
     135                 */
     136                $user = apply_filters( 'bp_core_activate_account', bp_core_activate_signup( $key ) );
     137
     138                // If there were errors, add a message and redirect.
     139                if ( ! empty( $user->errors ) ) {
     140                        bp_core_add_message( $user->get_error_message(), 'error' );
     141                        bp_core_redirect( trailingslashit( bp_get_root_domain() . '/' . $bp->pages->activate->slug ) );
     142                }
     143
     144                bp_core_add_message( __( 'Your account is now active!', 'buddypress' ) );
     145                bp_core_redirect( add_query_arg( 'activated', '1', bp_get_activation_page() ) );
     146        }
     147}
     148add_action( 'bp_core_signup_user', 'bp_members_invitations_complete_signup', 10, 4 );
     149 No newline at end of file
  • src/bp-members/bp-members-template.php

    diff --git src/bp-members/bp-members-template.php src/bp-members/bp-members-template.php
    index 5ceda3078..5b4021329 100644
    function bp_activate_slug() { 
    274274                return apply_filters( 'bp_get_activate_slug', $slug );
    275275        }
    276276
     277/**
     278 * Output the members invitation pane slug.
     279 *
     280 * @since 8.0.0
     281 *
     282 */
     283function bp_members_invitations_slug() {
     284        echo bp_get_members_invitations_slug();
     285}
     286        /**
     287         * Return the members invitations root slug.
     288         *
     289         * @since 8.0.0
     290         *
     291         * @return string
     292         */
     293        function bp_get_members_invitations_slug() {
     294
     295                /**
     296                 * Filters the Members invitations pane root slug.
     297                 *
     298                 * @since 8.0.0
     299                 *
     300                 * @param string $slug Members invitations pane root slug.
     301                 */
     302                return apply_filters( 'bp_get_members_invitations_slug', _x( 'invitations', 'Member profile invitations pane URL base', 'buddypress' ) );
     303        }
     304
    277305/**
    278306 * Initialize the members loop.
    279307 *
    function bp_signup_email_value() { 
    23812409         */
    23822410        function bp_get_signup_email_value() {
    23832411                $value = '';
    2384                 if ( isset( $_POST['signup_email'] ) )
     2412                if ( isset( $_POST['signup_email'] ) ) {
    23852413                        $value = $_POST['signup_email'];
     2414                } else if ( bp_get_members_invitations_allowed() ) {
     2415                        $invite = bp_get_members_invitation_from_request();
     2416                        if ( $invite ) {
     2417                                $value = $invite->invitee_email;
     2418                        }
     2419                }
    23862420
    23872421                /**
    23882422                 * Filters the email address submitted during signup.
    function bp_signup_allowed() { 
    27552789                return apply_filters( 'bp_get_signup_allowed', (bool) bp_get_option( 'users_can_register' ) );
    27562790        }
    27572791
     2792/**
     2793 * Are users allowed to invite users to join this site?
     2794 *
     2795 * @since 8.0.0
     2796 *
     2797 * @return bool
     2798 */
     2799function bp_get_members_invitations_allowed() {
     2800        /**
     2801         * Filters whether or not community invitations are allowed.
     2802         *
     2803         * @since 8.0.0
     2804         *
     2805         * @param bool $allowed Whether or not community invitations are allowed.
     2806         */
     2807        return apply_filters( 'bp_get_members_invitations_allowed', bp_is_active( 'members', 'invitations' ) && (bool) bp_get_option( 'bp-enable-members-invitations' ) );
     2808}
     2809
    27582810/**
    27592811 * Hook member activity feed to <head>.
    27602812 *
    function bp_avatar_delete_link() { 
    28612913                 */
    28622914                return apply_filters( 'bp_get_avatar_delete_link', wp_nonce_url( bp_displayed_user_domain() . bp_get_profile_slug() . '/change-avatar/delete-avatar/', 'bp_delete_avatar_link' ) );
    28632915        }
     2916
     2917
     2918/** The Members Invitations Loop ******************************************************************/
     2919
     2920/**
     2921 * Initialize the community invitations loop.
     2922 *
     2923 * Based on the $args passed, bp_has_invitations() populates
     2924 * buddypress()->invitations->query_loop global, enabling the use of BP
     2925 * templates and template functions to display a list of invitations.
     2926 *
     2927 * @since 8.0.0
     2928 *
     2929 * @param array|string $args {
     2930 *     Arguments for limiting the contents of the invitations loop. Can be
     2931 *     passed as an associative array, or as a URL query string.
     2932 *
     2933 *     See {@link BP_Invitations_Invitation::get()} for detailed
     2934 *     information on the arguments.  In addition, also supports:
     2935 *
     2936 *     @type int    $max      Optional. Max items to display. Default: false.
     2937 *     @type string $page_arg URL argument to use for pagination.
     2938 *                            Default: 'ipage'.
     2939 * }
     2940 * @return bool
     2941 */
     2942function bp_has_members_invitations( $args = '' ) {
     2943
     2944        // Get the user ID.
     2945        if ( bp_displayed_user_id() ) {
     2946                $user_id = bp_displayed_user_id();
     2947        } else {
     2948                $user_id = bp_loggedin_user_id();
     2949        }
     2950
     2951        // Set the search terms (by default an empty string to get all notifications)
     2952        $search_terms = '';
     2953
     2954        if ( isset( $_REQUEST['s'] ) ) {
     2955                $search_terms = stripslashes( $_REQUEST['s'] );
     2956        }
     2957
     2958        // Parse the args.
     2959        $r = bp_parse_args( $args, array(
     2960                'id'                => false,
     2961                'inviter_id'        => $user_id,
     2962                'invitee_email'     => false,
     2963                'item_id'           => false,
     2964                'type'              => 'invite',
     2965                'invite_sent'       => 'all',
     2966                'accepted'          => 'pending',
     2967                'search_terms'      => $search_terms,
     2968                'order_by'          => 'date_modified',
     2969                'sort_order'        => 'DESC',
     2970                'page'              => 1,
     2971                'per_page'          => 25,
     2972                'fields'            => 'all',
     2973
     2974                // These are additional arguments that are not available in
     2975                // BP_Invitations_Invitation::get().
     2976                'page_arg'          => 'ipage',
     2977        ), 'has_community_invitations' );
     2978
     2979        // Get the notifications.
     2980        $query_loop = new BP_Members_Invitations_Template( $r );
     2981
     2982        // Setup the global query loop.
     2983        buddypress()->members->invitations->query_loop = $query_loop;
     2984
     2985        /**
     2986         * Filters whether or not the user has network invitations to display.
     2987         *
     2988         * @since 8.0.0
     2989         *
     2990         * @param bool                      $value      Whether or not there are network invitations to display.
     2991         * @param BP_Notifications_Template $query_loop BP_Members_Invitations_Template object instance.
     2992         * @param array                     $r          Array of arguments passed into the BP_Members_Invitations_Template class.
     2993         */
     2994        return apply_filters( 'bp_has_members_invitations', $query_loop->has_invitations(), $query_loop, $r );
     2995}
     2996
     2997/**
     2998 * Get the network invitations returned by the template loop.
     2999 *
     3000 * @since 8.0.0
     3001 *
     3002 * @return array List of network invitations.
     3003 */
     3004function bp_the_members_invitations() {
     3005        return buddypress()->members->invitations->query_loop->invitations();
     3006}
     3007
     3008/**
     3009 * Get the current network invitation object in the loop.
     3010 *
     3011 * @since 8.0.0
     3012 *
     3013 * @return object The current network invitation within the loop.
     3014 */
     3015function bp_the_members_invitation() {
     3016        return buddypress()->members->invitations->query_loop->the_invitation();
     3017}
     3018
     3019/**
     3020 * Output the pagination count for the current network invitations loop.
     3021 *
     3022 * @since 8.0.0
     3023 */
     3024function bp_members_invitations_pagination_count() {
     3025        echo bp_get_members_invitations_pagination_count();
     3026}
     3027        /**
     3028         * Return the pagination count for the current network invitation loop.
     3029         *
     3030         * @since 8.0.0
     3031         *
     3032         * @return string HTML for the pagination count.
     3033         */
     3034        function bp_get_members_invitations_pagination_count() {
     3035                $query_loop = buddypress()->members->invitations->query_loop;
     3036                $start_num  = intval( ( $query_loop->pag_page - 1 ) * $query_loop->pag_num ) + 1;
     3037                $from_num   = bp_core_number_format( $start_num );
     3038                $to_num     = bp_core_number_format( ( $start_num + ( $query_loop->pag_num - 1 ) > $query_loop->total_invitation_count ) ? $query_loop->total_invitation_count : $start_num + ( $query_loop->pag_num - 1 ) );
     3039                $total      = bp_core_number_format( $query_loop->total_invitation_count );
     3040
     3041                if ( 1 == $query_loop->total_invitation_count ) {
     3042                        $pag = __( 'Viewing 1 invitation', 'buddypress' );
     3043                } else {
     3044                        /* translators: 1: notification from number. 2: notification to number. 3: total notifications. */
     3045                        $pag = sprintf( _n( 'Viewing %1$s - %2$s of %3$s invitation', 'Viewing %1$s - %2$s of %3$s invitations', $query_loop->total_invitation_count, 'buddypress' ), $from_num, $to_num, $total );
     3046                }
     3047
     3048                /**
     3049                 * Filters the pagination count for the current network invitation loop.
     3050                 *
     3051                 * @since 1.9.0
     3052                 *
     3053                 * @param string $pag HTML for the pagination count.
     3054                 */
     3055                return apply_filters( 'bp_get_members_invitations_pagination_count', $pag );
     3056        }
     3057
     3058/**
     3059 * Output the pagination links for the current network invitation loop.
     3060 *
     3061 * @since 8.0.0
     3062 */
     3063function bp_members_invitations_pagination_links() {
     3064        echo bp_get_members_invitations_pagination_links();
     3065}
     3066        /**
     3067         * Return the pagination links for the current network invitations loop.
     3068         *
     3069         * @since 8.0.0
     3070         *
     3071         * @return string HTML for the pagination links.
     3072         */
     3073        function bp_get_members_invitations_pagination_links() {
     3074
     3075                /**
     3076                 * Filters the pagination links for the current network invitations loop.
     3077                 *
     3078                 * @since 8.0.0
     3079                 *
     3080                 * @param string $pag_links HTML for the pagination links.
     3081                 */
     3082                return apply_filters( 'bp_get_members_invitations_pagination_links', buddypress()->members->invitations->query_loop->pag_links );
     3083        }
     3084
     3085/**
     3086 * Output the ID of the invitation currently being iterated on.
     3087 *
     3088 * @since 8.0.0
     3089 */
     3090function bp_the_members_invitation_property( $property ) {
     3091        echo bp_get_the_members_invitation_property( $property );
     3092}
     3093        /**
     3094         * Return the value for a property of the network invitation currently being iterated on.
     3095         *
     3096         * @since 8.0.0
     3097         *
     3098         * @return int ID of the current network invitation.
     3099         */
     3100        function bp_get_the_members_invitation_property( $property = 'id' ) {
     3101
     3102                switch ( $property ) {
     3103                        case 'id':
     3104                        case 'user_id':
     3105                        case 'item_id':
     3106                        case 'secondary_item_id':
     3107                        case 'invite_sent':
     3108                        case 'accepted':
     3109                                $value = 0;
     3110                                break;
     3111                        case 'invitee_email':
     3112                        case 'type':
     3113                        case 'content':
     3114                        case 'date_modified':
     3115                                $value = '';
     3116                                break;
     3117                        default:
     3118                                // A known property has not been specified.
     3119                                $property = null;
     3120                                $value = '';
     3121                                break;
     3122                }
     3123
     3124                if ( isset( buddypress()->members->invitations->query_loop->invitation->{$property} ) ) {
     3125                        $value = buddypress()->members->invitations->query_loop->invitation->{$property};
     3126                }
     3127
     3128                /**
     3129                 * Filters the property of the network invitation currently being iterated on.
     3130                 *
     3131                 * @since 8.0.0
     3132                 *
     3133                 * @param int|string $value Property value of the network invitation being iterated on.
     3134                 */
     3135                return apply_filters( 'bp_get_the_members_invitation_property_' . $property, $value );
     3136        }
     3137
     3138/**
     3139 * Output the action links for the current invitation.
     3140 *
     3141 * @since 8.0.0
     3142 *
     3143 * @param array|string $args Array of arguments.
     3144 */
     3145function bp_the_members_invitation_action_links( $args = '' ) {
     3146        echo bp_get_the_members_invitation_action_links( $args );
     3147}
     3148        /**
     3149         * Return the action links for the current invitation.
     3150         *
     3151         * @since 8.0.0
     3152         *
     3153         * @param array|string $args {
     3154         *     @type string $before  HTML before the links.
     3155         *     @type string $after   HTML after the links.
     3156         *     @type string $sep     HTML between the links.
     3157         *     @type array  $links   Array of links to implode by 'sep'.
     3158         *     @type int    $user_id User ID to fetch action links for. Defaults to displayed user ID.
     3159         * }
     3160         * @return string HTML links for actions to take on single notifications.
     3161         */
     3162        function bp_get_the_members_invitation_action_links( $args = '' ) {
     3163                // Set default user ID to use.
     3164                $inviter_id = isset( $args['inviter_id'] ) ? $args['inviter_id'] : bp_displayed_user_id();
     3165
     3166                // Parse.
     3167                $r = wp_parse_args( $args, array(
     3168                        'before' => '',
     3169                        'after'  => '',
     3170                        'sep'    => ' | ',
     3171                        'links'  => array(
     3172                                bp_get_the_members_invitation_resend_link( $inviter_id ),
     3173                                bp_get_the_members_invitation_delete_link( $inviter_id )
     3174                        )
     3175                ) );
     3176
     3177                // Build the links.
     3178                $retval = $r['before'] . implode( $r['sep'], $r['links'] ) . $r['after'];
     3179
     3180                /**
     3181                 * Filters the action links for the current notification.
     3182                 *
     3183                 * @since 1.9.0
     3184                 * @since 2.6.0 Added the `$r` parameter.
     3185                 *
     3186                 * @param string $retval HTML links for actions to take on single notifications.
     3187                 * @param array  $r      Array of parsed arguments.
     3188                 */
     3189                return apply_filters( 'bp_get_the_members_invitation_action_links', $retval, $r );
     3190        }
     3191
     3192/**
     3193 * Output the resend link for the current invitation.
     3194 *
     3195 * @since 8.0.0
     3196 *
     3197 * @param int $user_id The user ID.
     3198 */
     3199function bp_the_members_invitations_resend_link( $user_id = 0 ) {
     3200        echo bp_get_the_members_invitation_delete_link( $user_id );
     3201}
     3202        /**
     3203         * Return the resend link for the current notification.
     3204         *
     3205         * @since 78.0.0
     3206         *
     3207         * @param int $user_id The user ID.
     3208         * @return string
     3209         */
     3210        function bp_get_the_members_invitation_resend_link( $user_id = 0 ) {
     3211                // Set default user ID to use.
     3212                $user_id = 0 === $user_id ? bp_displayed_user_id() : $user_id;
     3213
     3214                // Don't allow resending of accepted invitations.
     3215                if ( bp_get_the_members_invitation_property( 'accepted' ) ) {
     3216                        return;
     3217                }
     3218
     3219                $retval = sprintf( '<a href="%1$s" class="resend secondary confirm bp-tooltip">%2$s</a>', esc_url( bp_get_the_members_invitations_resend_url( $user_id ) ), __( 'Resend', 'buddypress' ) );
     3220
     3221                /**
     3222                 * Filters the resend link for the current invitation.
     3223                 *
     3224                 * @since 8.0.0
     3225                 *
     3226                 * @param string $retval  HTML for the delete link for the current notification.
     3227                 * @param int    $user_id The user ID.
     3228                 */
     3229                return apply_filters( 'bp_get_the_members_invitation_resend_link', $retval, $user_id );
     3230        }
     3231
     3232/**
     3233 * Output the URL used for resending a single invitation.
     3234 *
     3235 * Since this function directly outputs a URL, it is escaped.
     3236 *
     3237 * @since 8.0.0
     3238 *
     3239 * @param int $user_id The user ID.
     3240 */
     3241function bp_the_members_invitations_resend_url( $user_id = 0 ) {
     3242        echo esc_url( bp_get_the_members_invitations_resend_url( $user_id ) );
     3243}
     3244        /**
     3245         * Return the URL used for resending a single invitation.
     3246         *
     3247         * @since 8.0.0
     3248         *
     3249         * @param int $user_id The user ID.
     3250         * @return string
     3251         */
     3252        function bp_get_the_members_invitations_resend_url( $user_id = 0 ) {
     3253                // Set default user ID to use.
     3254                $user_id = 0 === $user_id ? bp_displayed_user_id() : $user_id;
     3255                $link = bp_get_members_invitations_list_invites_permalink( $user_id );
     3256
     3257                // Get the ID.
     3258                $id = bp_get_the_members_invitation_property( 'id' );
     3259
     3260                // Get the args to add to the URL.
     3261                $args = array(
     3262                        'action'        => 'resend',
     3263                        'invitation_id' => $id
     3264                );
     3265
     3266                // Add the args.
     3267                $url = add_query_arg( $args, $link );
     3268
     3269                // Add the nonce.
     3270                $url = wp_nonce_url( $url, 'bp_network_invitation_resend_' . $id );
     3271
     3272                /**
     3273                 * Filters the URL used for resending a single invitation.
     3274                 *
     3275                 * @since 8.0.0
     3276                 *
     3277                 * @param string $url     URL used for deleting a single invitation.
     3278                 * @param int    $user_id The user ID.
     3279                 */
     3280                return apply_filters( 'bp_get_the_members_invitations_resend_url', $url, $user_id );
     3281        }
     3282
     3283/**
     3284 * Output the delete link for the current invitation.
     3285 *
     3286 * @since 8.0.0
     3287 *
     3288 * @param int $user_id The user ID.
     3289 */
     3290function bp_the_members_invitations_delete_link( $user_id = 0 ) {
     3291        echo bp_get_the_members_invitation_delete_link( $user_id );
     3292}
     3293        /**
     3294         * Return the delete link for the current invitation.
     3295         *
     3296         * @since 8.0.0
     3297         *
     3298         * @param int $user_id The user ID.
     3299         * @return string
     3300         */
     3301        function bp_get_the_members_invitation_delete_link( $user_id = 0 ) {
     3302                // Set default user ID to use.
     3303                $user_id = 0 === $user_id ? bp_displayed_user_id() : $user_id;
     3304
     3305                // Modify the message for accepted/not accepted invitatons.
     3306                if ( bp_get_the_members_invitation_property( 'accepted' ) ) {
     3307                        $message = __( 'Delete', 'buddypress' );
     3308                } else {
     3309                        $message = __( 'Cancel', 'buddypress' );
     3310                }
     3311
     3312                $retval = sprintf( '<a href="%1$s" class="delete secondary confirm bp-tooltip">%2$s</a>', esc_url( bp_get_the_members_invitations_delete_url( $user_id ) ), $message );
     3313
     3314                /**
     3315                 * Filters the delete link for the current invitation.
     3316                 *
     3317                 * @since 8.0.0
     3318                 *
     3319                 * @param string $retval  HTML for the delete link for the current notification.
     3320                 * @param int    $user_id The user ID.
     3321                 */
     3322                return apply_filters( 'bp_get_the_members_invitation_delete_link', $retval, $user_id );
     3323        }
     3324
     3325/**
     3326 * Output the URL used for deleting a single invitation.
     3327 *
     3328 * Since this function directly outputs a URL, it is escaped.
     3329 *
     3330 * @since 8.0.0
     3331 *
     3332 * @param int $user_id The user ID.
     3333 */
     3334function bp_the_members_invitations_delete_url( $user_id = 0 ) {
     3335        echo esc_url( bp_get_the_members_invitations_delete_url( $user_id ) );
     3336}
     3337        /**
     3338         * Return the URL used for deleting a single invitation.
     3339         *
     3340         * @since 8.0.0
     3341         *
     3342         * @param int $user_id The user ID.
     3343         * @return string
     3344         */
     3345        function bp_get_the_members_invitations_delete_url( $user_id = 0 ) {
     3346                // Set default user ID to use.
     3347                $user_id = 0 === $user_id ? bp_displayed_user_id() : $user_id;
     3348                $link = bp_get_members_invitations_list_invites_permalink( $user_id );
     3349
     3350                // Get the ID.
     3351                $id = bp_get_the_members_invitation_property( 'id' );
     3352
     3353                // Get the args to add to the URL.
     3354                $args = array(
     3355                        'action'        => 'cancel',
     3356                        'invitation_id' => $id
     3357                );
     3358
     3359                // Add the args.
     3360                $url = add_query_arg( $args, $link );
     3361
     3362                // Add the nonce.
     3363                $url = wp_nonce_url( $url, 'bp_members_invitations_cancel_' . $id );
     3364
     3365                /**
     3366                 * Filters the URL used for deleting a single invitation.
     3367                 *
     3368                 * @since 8.0.0
     3369                 *
     3370                 * @param string $url     URL used for deleting a single invitation.
     3371                 * @param int    $user_id The user ID.
     3372                 */
     3373                return apply_filters( 'bp_get_the_members_invitations_delete_url', $url, $user_id );
     3374        }
     3375
     3376/**
     3377 * Output the members invitations list permalink for a user.
     3378 *
     3379 * @since 8.0.0
     3380 *
     3381 * @param int $user_id The user ID.
     3382 */
     3383function bp_members_invitations_list_invites_permalink( $user_id = 0 ) {
     3384        echo bp_get_members_invitations_list_invites_permalink( $user_id );
     3385}
     3386        /**
     3387         * Return the members invitations list permalink for a user.
     3388         *
     3389         * @since 8.0.0
     3390         *
     3391         * @return string Members invitations list permalink for a user.
     3392         */
     3393        function bp_get_members_invitations_list_invites_permalink( $user_id = 0 ) {
     3394                if ( 0 === $user_id ) {
     3395                        $user_id = bp_loggedin_user_id();
     3396                        $domain  = bp_loggedin_user_domain();
     3397                } else {
     3398                        $domain = bp_core_get_user_domain( (int) $user_id );
     3399                }
     3400
     3401                $retval = trailingslashit( $domain . bp_get_members_invitations_slug() . '/list-invites' );
     3402
     3403                /**
     3404                 * Filters the members invitations list permalink for a user.
     3405                 *
     3406                 * @since 8.0.0
     3407                 *
     3408                 * @param string $retval  Permalink for the sent invitation list screen.
     3409                 * @param int    $user_id The user ID.
     3410                 */
     3411                return apply_filters( 'bp_get_members_invitations_list_invites_permalink', $retval, $user_id );
     3412        }
     3413
     3414/**
     3415 * Output the send invitation permalink for a user.
     3416 *
     3417 * @since 8.0.0
     3418 *
     3419 * @param int $user_id The user ID.
     3420 */
     3421function bp_members_invitations_send_invites_permalink( $user_id = 0 ) {
     3422        echo bp_get_members_invitations_send_invites_permalink( $user_id );
     3423}
     3424        /**
     3425         * Return the send invitations permalink.
     3426         *
     3427         * @since 8.0.0
     3428         *
     3429         * @return string Read notifications permalink.
     3430         */
     3431        function bp_get_members_invitations_send_invites_permalink( $user_id = 0 ) {
     3432                if ( 0 === $user_id ) {
     3433                        $user_id = bp_loggedin_user_id();
     3434                        $domain  = bp_loggedin_user_domain();
     3435                } else {
     3436                        $domain = bp_core_get_user_domain( (int) $user_id );
     3437                }
     3438
     3439                $retval = trailingslashit( $domain . bp_get_members_invitations_slug() . '/send-invites' );
     3440
     3441                /**
     3442                 * Filters the read notifications permalink.
     3443                 *
     3444                 * @since 8.0.0
     3445                 *
     3446                 * @param string $retval  Permalink for the sent invitation list screen.
     3447                 * @param int    $user_id The user ID.
     3448                 */
     3449                return apply_filters( 'bp_get_members_invitations_send_invites_permalink', $retval, $user_id );
     3450        }
     3451 No newline at end of file
  • src/bp-members/classes/class-bp-members-admin.php

    diff --git src/bp-members/classes/class-bp-members-admin.php src/bp-members/classes/class-bp-members-admin.php
    index c999cb923..574952589 100644
    class BP_Members_Admin { 
    140140                $this->users_url    = bp_get_admin_url( 'users.php' );
    141141                $this->users_screen = bp_core_do_network_admin() ? 'users-network' : 'users';
    142142
     143                $this->members_invites_page = '';
     144
    143145                // Specific config: BuddyPress is not network activated.
    144146                $this->subsite_activated = (bool) is_multisite() && ! bp_is_network_activated();
    145147
    class BP_Members_Admin { 
    248250         * @param string $value
    249251         */
    250252        public function multisite_registration_on( $option_name, $value ) {
    251                 if ( 'user' === $value || 'all' === $value ) {
     253                // Is registration enabled or are network invitations enabled?
     254                if ( ( 'user' === $value || 'all' === $value )
     255                        || bp_get_members_invitations_allowed() ) {
    252256                        bp_core_add_page_mappings( array(
    253257                                'register' => 1,
    254258                                'activate' => 1
    class BP_Members_Admin { 
    266270         */
    267271        public function single_site_registration_on( $old_value, $value ) {
    268272                // Single site.
    269                 if ( ! is_multisite() && ! empty( $value ) ) {
     273                if ( ! is_multisite() && ( ! empty( $value ) || bp_get_members_invitations_allowed() ) ) {
    270274                        bp_core_add_page_mappings( array(
    271275                                'register' => 1,
    272276                                'activate' => 1
    class BP_Members_Admin { 
    488492                                'bp-signups',
    489493                                array( $this, 'signups_admin' )
    490494                        );
     495
     496                        // Manage invitations.
     497                        $hooks['members_invitations'] = $this->members_invites_page = add_users_page(
     498                                __( 'Manage Invitations',  'buddypress' ),
     499                                __( 'Manage Invitations',  'buddypress' ),
     500                                $this->capability,
     501                                'bp-members-invitations',
     502                                array( $this, 'invitations_admin' )
     503                        );
    491504                }
    492505
    493506                $edit_page         = 'user-edit';
    class BP_Members_Admin { 
    509522                        $this->user_page    .= '-network';
    510523                        $this->users_page   .= '-network';
    511524                        $this->signups_page .= '-network';
     525
     526                        $this->members_invites_page .= '-network';
    512527                }
    513528
    514529                // Setup the screen ID's.
    class BP_Members_Admin { 
    25642579
    25652580                return $value;
    25662581        }
     2582
     2583        /**
     2584         * Set up the signups admin page.
     2585         *
     2586         * Loaded before the page is rendered, this function does all initial
     2587         * setup, including: processing form requests, registering contextual
     2588         * help, and setting up screen options.
     2589         *
     2590         * @since 8.0.0
     2591         *
     2592         * @global $bp_members_invitations_list_table
     2593         */
     2594        public function members_invitations_admin_load() {
     2595                global $bp_members_invitations_list_table;
     2596
     2597                // Build redirection URL.
     2598                $redirect_to = remove_query_arg( array( 'action', 'error', 'updated', 'activated', 'notactivated', 'deleted', 'notdeleted', 'resent', 'notresent', 'do_delete', 'do_resend', 'do_activate', '_wpnonce', 'signup_ids' ), $_SERVER['REQUEST_URI'] );
     2599                $doaction    = bp_admin_list_table_current_bulk_action();
     2600
     2601                /**
     2602                 * Fires at the start of the member invitations admin load.
     2603                 *
     2604                 * @since 8.0.0
     2605                 *
     2606                 * @param string $doaction Current bulk action being processed.
     2607                 * @param array  $_REQUEST Current $_REQUEST global.
     2608                 */
     2609                do_action( 'bp_members_invitations_admin_load', $doaction, $_REQUEST );
     2610
     2611                /**
     2612                 * Filters the allowed actions for use in the user signups admin page.
     2613                 *
     2614                 * @since 8.0.0
     2615                 *
     2616                 * @param array $value Array of allowed actions to use.
     2617                 */
     2618                $allowed_actions = apply_filters( 'bp_members_invitations_admin_allowed_actions', array( 'do_delete',  'do_resend' ) );
     2619
     2620                // Prepare the display of the Community Profile screen.
     2621                if ( ! in_array( $doaction, $allowed_actions ) || ( -1 == $doaction ) ) {
     2622
     2623                        $bp_members_invitations_list_table = self::get_list_table_class( 'BP_Members_Invitations_List_Table', 'users' );
     2624
     2625                        // The per_page screen option.
     2626                        add_screen_option( 'per_page', array( 'label' => _x( 'Members Invitations', 'Members Invitations per page (screen options)', 'buddypress' ) ) );
     2627
     2628                        get_current_screen()->add_help_tab( array(
     2629                                'id'      => 'bp-members-invitations-overview',
     2630                                'title'   => __( 'Overview', 'buddypress' ),
     2631                                'content' =>
     2632                                '<p>' . __( 'This is the administration screen for member invitations on your site.', 'buddypress' ) . '</p>' .
     2633                                '<p>' . __( 'From the screen options, you can customize the displayed columns and the pagination of this screen.', 'buddypress' ) . '</p>' .
     2634                                '<p>' . __( 'You can reorder the list of invitations by clicking on the Invitee, Inviter, Date Modified, Email Sent or Accepted column headers.', 'buddypress' ) . '</p>' .
     2635                                '<p>' . __( 'Using the search form, you can find specific invitations more easily. The Invitee Email field will be included in the search.', 'buddypress' ) . '</p>'
     2636                        ) );
     2637
     2638                        get_current_screen()->add_help_tab( array(
     2639                                'id'      => 'bp-members-invitations-actions',
     2640                                'title'   => __( 'Actions', 'buddypress' ),
     2641                                'content' =>
     2642                                '<p>' . __( 'Hovering over a row in the pending accounts list will display action links that allow you to manage pending accounts. You can perform the following actions:', 'buddypress' ) . '</p>' .
     2643                                '<ul><li>' . __( '"Send" or "Resend" takes you to the confirmation screen before being able to send or resend the invitation email to the desired pending invitee.', 'buddypress' ) . '</li>' .
     2644                                '<li>' . __( '"Delete" allows you to delete an unsent or accepted invitation from your site; "Cancel" allows you to cancel a sent, but not yet accepted, invitation. You will be asked to confirm this deletion.', 'buddypress' ) . '</li></ul>' .
     2645                                '<p>' . __( 'Bulk actions allow you to perform these actions for the selected rows.', 'buddypress' ) . '</p>'
     2646                        ) );
     2647
     2648                        // Help panel - sidebar links.
     2649                        get_current_screen()->set_help_sidebar(
     2650                                '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
     2651                                '<p>' . __( '<a href="https://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'
     2652                        );
     2653
     2654                        // Add accessible hidden headings and text for the Pending Users screen.
     2655                        get_current_screen()->set_screen_reader_content( array(
     2656                                /* translators: accessibility text */
     2657                                'heading_views'      => __( 'Filter invitations list', 'buddypress' ),
     2658                                /* translators: accessibility text */
     2659                                'heading_pagination' => __( 'Invitation list navigation', 'buddypress' ),
     2660                                /* translators: accessibility text */
     2661                                'heading_list'       => __( 'Invitations list', 'buddypress' ),
     2662                        ) );
     2663
     2664                } else {
     2665                        if ( empty( $_REQUEST['invite_ids' ] ) ) {
     2666                                return;
     2667                        }
     2668                        $invite_ids = wp_parse_id_list( $_REQUEST['invite_ids' ] );
     2669
     2670                        // Handle resent invitations.
     2671                        if ( 'do_resend' == $doaction ) {
     2672
     2673                                // Nonce check.
     2674                                check_admin_referer( 'invitations_resend' );
     2675
     2676                                $success = 0;
     2677                                foreach ( $invite_ids as $invite_id ) {
     2678                                        if ( bp_members_invitation_resend_by_id( $invite_id ) ) {
     2679                                                $success++;
     2680                                        }
     2681                                }
     2682
     2683                                $query_arg = array( 'updated' => 'resent' );
     2684
     2685                                if ( ! empty( $success ) ) {
     2686                                        $query_arg['resent'] = $success;
     2687                                }
     2688
     2689                                $not_sent = count( $invite_ids ) - $success;
     2690                                if ( $not_sent > 0 ) {
     2691                                        $query_arg['notsent'] = $not_sent;
     2692                                }
     2693
     2694                                $redirect_to = add_query_arg( $query_arg, $redirect_to );
     2695
     2696                                bp_core_redirect( $redirect_to );
     2697
     2698                        // Handle invitation deletion.
     2699                        } elseif ( 'do_delete' == $doaction ) {
     2700
     2701                                // Nonce check.
     2702                                check_admin_referer( 'invitations_delete' );
     2703
     2704                                $success = 0;
     2705                                foreach ( $invite_ids as $invite_id ) {
     2706                                        if ( bp_members_invitations_delete_by_id( $invite_id ) ) {
     2707                                                $success++;
     2708                                        }
     2709                                }
     2710
     2711                                $query_arg = array( 'updated' => 'deleted' );
     2712
     2713                                if ( ! empty( $success ) ) {
     2714                                        $query_arg['deleted'] = $success;
     2715                                }
     2716
     2717                                $notdeleted = count( $invite_ids ) - $success;
     2718                                if ( $notdeleted > 0 ) {
     2719                                        $query_arg['notdeleted'] = $notdeleted;
     2720                                }
     2721
     2722                                $redirect_to = add_query_arg( $query_arg, $redirect_to );
     2723
     2724                                bp_core_redirect( $redirect_to );
     2725
     2726                        // Plugins can update other stuff from here.
     2727                        } else {
     2728                                $this->redirect = $redirect_to;
     2729
     2730                                /**
     2731                                 * Fires at end of member invitations admin load
     2732                                 * if doaction does not match any actions.
     2733                                 *
     2734                                 * @since 2.0.0
     2735                                 *
     2736                                 * @param string $doaction Current bulk action being processed.
     2737                                 * @param array  $_REQUEST Current $_REQUEST global.
     2738                                 * @param string $redirect Determined redirect url to send user to.
     2739                                 */
     2740                                do_action( 'bp_members_admin_update_invitations', $doaction, $_REQUEST, $this->redirect );
     2741
     2742                                bp_core_redirect( $this->redirect );
     2743                        }
     2744                }
     2745        }
     2746
     2747        /**
     2748         * Get admin notice when viewing the invitations management page.
     2749         *
     2750         * @since 8.0.0
     2751         *
     2752         * @return array
     2753         */
     2754        private function get_members_invitations_notice() {
     2755
     2756                // Setup empty notice for return value.
     2757                $notice = array();
     2758
     2759                // Updates.
     2760                if ( ! empty( $_REQUEST['updated'] ) ) {
     2761                        switch ( $_REQUEST['updated'] ) {
     2762                                case 'resent':
     2763                                        $notice = array(
     2764                                                'class'   => 'updated',
     2765                                                'message' => ''
     2766                                        );
     2767
     2768                                        if ( ! empty( $_REQUEST['resent'] ) ) {
     2769                                                $notice['message'] .= sprintf(
     2770                                                        /* translators: %s: number of invitation emails sent */
     2771                                                        _nx( '%s invtitation email successfully sent! ', '%s invitation emails successfully sent! ',
     2772                                                         absint( $_REQUEST['resent'] ),
     2773                                                         'members invitation resent',
     2774                                                         'buddypress'
     2775                                                        ),
     2776                                                        number_format_i18n( absint( $_REQUEST['resent'] ) )
     2777                                                );
     2778                                        }
     2779
     2780                                        if ( ! empty( $_REQUEST['notsent'] ) ) {
     2781                                                $notice['message'] .= sprintf(
     2782                                                        /* translators: %s: number of unsent invitation emails */
     2783                                                        _nx( '%s invitation email was not sent.', '%s invitation emails were not sent.',
     2784                                                         absint( $_REQUEST['notsent'] ),
     2785                                                         'members invitation notsent',
     2786                                                         'buddypress'
     2787                                                        ),
     2788                                                        number_format_i18n( absint( $_REQUEST['notsent'] ) )
     2789                                                );
     2790
     2791                                                if ( empty( $_REQUEST['resent'] ) ) {
     2792                                                        $notice['class'] = 'error';
     2793                                                }
     2794                                        }
     2795
     2796                                        break;
     2797
     2798                                case 'deleted':
     2799                                        $notice = array(
     2800                                                'class'   => 'updated',
     2801                                                'message' => ''
     2802                                        );
     2803
     2804                                        if ( ! empty( $_REQUEST['deleted'] ) ) {
     2805                                                $notice['message'] .= sprintf(
     2806                                                        /* translators: %s: number of deleted invitations */
     2807                                                        _nx( '%s invitation successfully deleted!', '%s invitations successfully deleted!',
     2808                                                         absint( $_REQUEST['deleted'] ),
     2809                                                         'members invitation deleted',
     2810                                                         'buddypress'
     2811                                                        ),
     2812                                                        number_format_i18n( absint( $_REQUEST['deleted'] ) )
     2813                                                );
     2814                                        }
     2815
     2816                                        if ( ! empty( $_REQUEST['notdeleted'] ) ) {
     2817                                                $notice['message'] .= sprintf(
     2818                                                        /* translators: %s: number of invitations that failed to be deleted */
     2819                                                        _nx( '%s invitation was not deleted.', '%s invitations were not deleted.',
     2820                                                         absint( $_REQUEST['notdeleted'] ),
     2821                                                         'members invitation notdeleted',
     2822                                                         'buddypress'
     2823                                                        ),
     2824                                                        number_format_i18n( absint( $_REQUEST['notdeleted'] ) )
     2825                                                );
     2826
     2827                                                if ( empty( $_REQUEST['deleted'] ) ) {
     2828                                                        $notice['class'] = 'error';
     2829                                                }
     2830                                        }
     2831
     2832                                        break;
     2833                        }
     2834                }
     2835
     2836                // Errors.
     2837                if ( ! empty( $_REQUEST['error'] ) ) {
     2838                        switch ( $_REQUEST['error'] ) {
     2839                                case 'do_resend':
     2840                                        $notice = array(
     2841                                                'class'   => 'error',
     2842                                                'message' => esc_html__( 'There was a problem sending the invitation emails. Please try again.', 'buddypress' ),
     2843                                        );
     2844                                        break;
     2845
     2846                                case 'do_delete':
     2847                                        $notice = array(
     2848                                                'class'   => 'error',
     2849                                                'message' => esc_html__( 'There was a problem deleting invitations. Please try again.', 'buddypress' ),
     2850                                        );
     2851                                        break;
     2852                        }
     2853                }
     2854
     2855                return $notice;
     2856        }
     2857
     2858        /**
     2859         * Member invitations admin page router.
     2860         *
     2861         * Depending on the context, display
     2862         * - the list of invitations,
     2863         * - or the delete confirmation screen,
     2864         * - or the "resend" email confirmation screen.
     2865         *
     2866         * Also prepare the admin notices.
     2867         *
     2868         * @since 8.0.0
     2869         */
     2870        public function invitations_admin() {
     2871                $doaction = bp_admin_list_table_current_bulk_action();
     2872
     2873                // Prepare notices for admin.
     2874                $notice = $this->get_members_invitations_notice();
     2875
     2876                // Display notices.
     2877                if ( ! empty( $notice ) ) :
     2878                        if ( 'updated' === $notice['class'] ) : ?>
     2879
     2880                                <div id="message" class="<?php echo esc_attr( $notice['class'] ); ?> notice is-dismissible">
     2881
     2882                        <?php else: ?>
     2883
     2884                                <div class="<?php echo esc_attr( $notice['class'] ); ?> notice is-dismissible">
     2885
     2886                        <?php endif; ?>
     2887
     2888                                <p><?php echo $notice['message']; ?></p>
     2889                        </div>
     2890
     2891                <?php endif;
     2892
     2893                // Show the proper screen.
     2894                switch ( $doaction ) {
     2895                        case 'delete' :
     2896                        case 'resend' :
     2897                                $this->invitations_admin_manage( $doaction );
     2898                                break;
     2899
     2900                        default:
     2901                                $this->invitations_admin_index();
     2902                                break;
     2903                }
     2904        }
     2905
     2906        /**
     2907         * This is the list of invitations.
     2908         *
     2909         * @since 8.0.0
     2910         *
     2911         * @global $plugin_page
     2912         * @global $bp_members_invitations_list_table
     2913         */
     2914        public function invitations_admin_index() {
     2915                global $plugin_page, $bp_members_invitations_list_table;
     2916
     2917                $usersearch = ! empty( $_REQUEST['s'] ) ? stripslashes( $_REQUEST['s'] ) : '';
     2918
     2919                // Prepare the group items for display.
     2920                $bp_members_invitations_list_table->prepare_items();
     2921
     2922                if ( is_network_admin() ) {
     2923                        $form_url = network_admin_url( 'users.php' );
     2924                } else {
     2925                        $form_url = bp_get_admin_url( 'users.php' );
     2926                }
     2927
     2928                $form_url = add_query_arg(
     2929                        array(
     2930                                'page' => 'bp-members-invitations',
     2931                        ),
     2932                        $form_url
     2933                );
     2934
     2935                $search_form_url = remove_query_arg(
     2936                        array(
     2937                                'action',
     2938                                'deleted',
     2939                                'notdeleted',
     2940                                'error',
     2941                                'updated',
     2942                                'delete',
     2943                                'activate',
     2944                                'activated',
     2945                                'notactivated',
     2946                                'resend',
     2947                                'resent',
     2948                                'notresent',
     2949                                'do_delete',
     2950                                'do_activate',
     2951                                'do_resend',
     2952                                'action2',
     2953                                '_wpnonce',
     2954                                'invite_ids'
     2955                        ), $_SERVER['REQUEST_URI']
     2956                );
     2957
     2958                ?>
     2959
     2960                <div class="wrap">
     2961                        <h1 class="wp-heading-inline"><?php _e( 'Invitations', 'buddypress' ); ?></h1>
     2962
     2963                        <?php
     2964                        if ( $usersearch ) {
     2965                                printf( '<span class="subtitle">' . __( 'Search results for &#8220;%s&#8221;', 'buddypress' ) . '</span>', esc_html( $usersearch ) );
     2966                        }
     2967                        ?>
     2968
     2969                        <hr class="wp-header-end">
     2970
     2971                        <?php // Display each invitation on its own row. ?>
     2972                        <?php $bp_members_invitations_list_table->views(); ?>
     2973
     2974                        <form id="bp-members-invitations-search-form" action="<?php echo esc_url( $search_form_url ) ;?>">
     2975                                <input type="hidden" name="page" value="<?php echo esc_attr( $plugin_page ); ?>" />
     2976                                <?php $bp_members_invitations_list_table->search_box( __( 'Search Invitations', 'buddypress' ), 'bp-members-invitations' ); ?>
     2977                        </form>
     2978
     2979                        <form id="bp-members-invitations-form" action="<?php echo esc_url( $form_url );?>" method="post">
     2980                                <?php $bp_members_invitations_list_table->display(); ?>
     2981                        </form>
     2982                </div>
     2983        <?php
     2984        }
     2985
     2986        /**
     2987         * This is the confirmation screen for actions.
     2988         *
     2989         * @since 2.0.0
     2990         *
     2991         * @param string $action Delete or resend invitation.
     2992         *
     2993         * @return null|false
     2994         */
     2995        public function invitations_admin_manage( $action = '' ) {
     2996                if ( ! current_user_can( $this->capability ) || empty( $action ) ) {
     2997                        die( '-1' );
     2998                }
     2999
     3000                // Get the IDs from the URL.
     3001                $ids = false;
     3002                if ( ! empty( $_POST['invite_ids'] ) ) {
     3003                        $ids = wp_parse_id_list( $_POST['invite_ids'] );
     3004                } elseif ( ! empty( $_GET['invite_id'] ) ) {
     3005                        $ids = absint( $_GET['invite_id'] );
     3006                }
     3007
     3008
     3009                if ( empty( $ids ) ) {
     3010                        return false;
     3011                }
     3012
     3013                // Check invite IDs and set up strings.
     3014                switch ( $action ) {
     3015                        case 'delete' :
     3016                                // Query for matching invites, and filter out bad IDs.
     3017                                $args = array(
     3018                                        'id'          => $ids,
     3019                                        'invite_sent' => 'all',
     3020                                        'accepted'    => 'all',
     3021                                        'fields'      => 'ids',
     3022                                );
     3023                                $invite_ids = bp_members_invitations_get_invites( $args );
     3024
     3025                                $header_text = __( 'Delete Invitations', 'buddypress' );
     3026                                if ( 1 == count( $invite_ids ) ) {
     3027                                        $helper_text = __( 'You are about to delete the following invitation:', 'buddypress' );
     3028                                } else {
     3029                                        $helper_text = __( 'You are about to delete the following invitations:', 'buddypress' );
     3030                                }
     3031                                break;
     3032
     3033                        case 'resend' :
     3034                                /**
     3035                                 * Query for matching invites, and filter out bad IDs
     3036                                 * or those that have already been accepted.
     3037                                 */
     3038                                $args = array(
     3039                                        'id'          => $ids,
     3040                                        'invite_sent' => 'all',
     3041                                        'accepted'    => 'pending',
     3042                                );
     3043                                $invites    = bp_members_invitations_get_invites( $args );
     3044                                $invite_ids = wp_list_pluck( $invites, 'id' );
     3045
     3046                                $header_text = __( 'Resend Invitation Emails', 'buddypress' );
     3047                                if ( 1 == count( $invite_ids ) ) {
     3048                                        $helper_text = __( 'You are about to resend an invitation email to the following address:', 'buddypress' );
     3049                                } else {
     3050                                        $helper_text = __( 'You are about to resend an invitation email to the following addresses:', 'buddypress' );
     3051                                }
     3052                                break;
     3053                }
     3054
     3055                // These arguments are added to all URLs.
     3056                $url_args = array( 'page' => 'bp-members-invitations' );
     3057
     3058                // These arguments are only added when performing an action.
     3059                $action_args = array(
     3060                        'action'     => 'do_' . $action,
     3061                        'invite_ids' => implode( ',', $invite_ids )
     3062                );
     3063
     3064                if ( is_network_admin() ) {
     3065                        $base_url = network_admin_url( 'users.php' );
     3066                } else {
     3067                        $base_url = bp_get_admin_url( 'users.php' );
     3068                }
     3069
     3070                $cancel_url = add_query_arg( $url_args, $base_url );
     3071                $action_url = wp_nonce_url(
     3072                        add_query_arg(
     3073                                array_merge( $url_args, $action_args ),
     3074                                $base_url
     3075                        ),
     3076                        'invitations_' . $action
     3077                );
     3078
     3079                ?>
     3080
     3081                <div class="wrap">
     3082                        <h1 class="wp-heading-inline"><?php echo esc_html( $header_text ); ?></h1>
     3083                        <hr class="wp-header-end">
     3084
     3085                        <p><?php echo esc_html( $helper_text ); ?></p>
     3086
     3087                        <ol class="bp-invitations-list">
     3088                        <?php foreach ( $invites as $invite ) :
     3089                                if ( $invite->invite_sent ) {
     3090                                        $last_notified = mysql2date( 'Y/m/d g:i:s a', $invite->date_modified );
     3091                                } else {
     3092                                        $last_notified = __( 'Not yet notified', 'buddypress');
     3093                                }
     3094                                ?>
     3095
     3096                                <li>
     3097                                        <strong><?php echo esc_html( $invite->invitee_email ) ?></strong>
     3098
     3099                                        <?php if ( 'resend' == $action ) : ?>
     3100
     3101                                                <p class="description">
     3102                                                        <?php
     3103                                                        /* translators: %s: notification date */
     3104                                                        printf( esc_html__( 'Last notified: %s', 'buddypress'), $last_notified );
     3105                                                        ?>
     3106                                                </p>
     3107
     3108                                        <?php endif; ?>
     3109
     3110                                </li>
     3111
     3112                        <?php endforeach; ?>
     3113                        </ol>
     3114
     3115                        <?php if ( 'delete' === $action ) : ?>
     3116
     3117                                <p><strong><?php esc_html_e( 'This action cannot be undone.', 'buddypress' ) ?></strong></p>
     3118
     3119                        <?php endif ; ?>
     3120
     3121                        <a class="button-primary" href="<?php echo esc_url( $action_url ); ?>"><?php esc_html_e( 'Confirm', 'buddypress' ); ?></a>
     3122                        <a class="button" href="<?php echo esc_url( $cancel_url ); ?>"><?php esc_html_e( 'Cancel', 'buddypress' ) ?></a>
     3123                </div>
     3124
     3125                <?php
     3126        }
     3127
    25673128}
    25683129endif; // End class_exists check.
  • src/bp-members/classes/class-bp-members-component.php

    diff --git src/bp-members/classes/class-bp-members-component.php src/bp-members/classes/class-bp-members-component.php
    index 77777d645..2b91ee1ff 100644
    class BP_Members_Component extends BP_Component { 
    3939                        buddypress()->plugin_dir,
    4040                        array(
    4141                                'adminbar_myaccount_order' => 20,
    42                                 'search_query_arg' => 'members_search',
     42                                'search_query_arg'         => 'members_search',
     43                                'features'                 => array( 'invitations' )
    4344                        )
    4445                );
    4546        }
    class BP_Members_Component extends BP_Component { 
    6465                        'blocks',
    6566                        'widgets',
    6667                        'cache',
     68                        'invitations',
    6769                );
    6870
    6971                if ( bp_is_active( 'activity' ) ) {
    class BP_Members_Component extends BP_Component { 
    137139                        // Theme compatibility.
    138140                        new BP_Registration_Theme_Compat();
    139141                }
     142
     143                // Invitations.
     144                if ( is_user_logged_in() && bp_is_user_members_invitations() ) {
     145                        if ( bp_is_user_members_invitations_send_screen() ) {
     146                                require $this->path . 'bp-members/screens/send-invites.php';
     147                        } else {
     148                                require $this->path . 'bp-members/screens/list-invites.php';
     149                        }
     150                }
    140151        }
    141152
    142153        /**
    class BP_Members_Component extends BP_Component { 
    232243                        $bp->profile->slug = 'profile';
    233244                        $bp->profile->id   = 'profile';
    234245                }
     246
     247                /** Network Invitations **************************************************
     248                 */
     249
     250                $bp->members->invitations = new stdClass;
    235251        }
    236252
    237253        /**
    class BP_Members_Component extends BP_Component { 
    467483                        }
    468484                }
    469485
    470 
    471486                parent::setup_nav( $main_nav, $sub_nav );
    472487        }
    473488
  • new file src/bp-members/classes/class-bp-members-invitation-manager.php

    diff --git src/bp-members/classes/class-bp-members-invitation-manager.php src/bp-members/classes/class-bp-members-invitation-manager.php
    new file mode 100644
    index 000000000..139caf279
    - +  
     1<?php
     2/**
     3 * Membership invitations class.
     4 *
     5 * @package BuddyPress
     6 * @subpackage Core
     7 * @since 8.0.0
     8 */
     9
     10// Exit if accessed directly.
     11defined( 'ABSPATH' ) || exit;
     12
     13/**
     14 * Membership invitations class.
     15 *
     16 * An extension of the core Invitations class that adapts the
     17 * core logic to accommodate site membership invitation behavior.
     18 *
     19 * @since 8.0.0
     20 */
     21class BP_Members_Invitation_Manager extends BP_Invitation_Manager {
     22        /**
     23         * Construct parameters.
     24         *
     25         * @since 8.0.0
     26         *
     27         * @param array|string $args.
     28         */
     29        public function __construct( $args = '' ) {
     30                parent::__construct();
     31        }
     32
     33        /**
     34         * This is where custom actions are added to run when notifications of an
     35         * invitation or request need to be generated & sent.
     36         *
     37         * @since 8.0.0
     38         *
     39         * @param obj BP_Invitation $invitation The invitation to send.
     40         * @return bool True on success, false on failure.
     41         */
     42        public function run_send_action( BP_Invitation $invitation ) {
     43                // Notify site admins of the pending request
     44                if ( 'request' === $invitation->type ) {
     45                        // @TODO
     46                        return true;
     47                // Notify the invitee of the invitation.
     48                } else {
     49                        // Stop if the invitation has already been accepted.
     50                        if ( $invitation->accepted ) {
     51                                return false;
     52                        }
     53
     54                        $inviter_ud = bp_core_get_core_userdata( $invitation->inviter_id );
     55
     56                        $invite_url = esc_url(
     57                                add_query_arg(
     58                                        array(
     59                                                'inv' => $invitation->id,
     60                                                'ih'  => bp_members_invitations_get_hash( $invitation ),
     61                                        ), bp_get_signup_page()
     62                                )
     63                        );
     64                        $unsubscribe_args = array(
     65                                'user_id'           => 0,
     66                                'email_address'     => $invitation->invitee_email,
     67                                'notification_type' => 'bp-members-invitation',
     68                        );
     69
     70                        $args = array(
     71                                'tokens' => array(
     72                                        'inviter.name'        => bp_core_get_userlink( $invitation->inviter_id, true, false, true ),
     73                                        'inviter.url'         => bp_core_get_user_domain( $invitation->inviter_id ),
     74                                        'inviter.id'          => $invitation->inviter_id,
     75                                        'invite.accept_url'   => esc_url( $invite_url ),
     76                                        'usermessage'         => $invitation->content,
     77                                        'unsubscribe'         => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
     78                                ),
     79                        );
     80
     81                        return bp_send_email( 'bp-members-invitation', $invitation->invitee_email, $args );
     82                }
     83        }
     84
     85        /**
     86         * This is where custom actions are added to run when an invitation
     87         * or request is accepted.
     88         *
     89         * @since 8.0.0
     90         *
     91         * @param string $type Are we accepting an invitation or request?
     92         * @param array  $r    Parameters that describe the invitation being accepted.
     93         * @return bool True on success, false on failure.
     94         */
     95        public function run_acceptance_action( $type = 'invite', $r  ) {
     96                // If the user is already a member (because BP at one point allowed two invitations to
     97                // slip through), return early.
     98
     99                if ( 'request' === $type ) {
     100                        /**
     101                         * Fires after a network membership request has been accepted.
     102                         *
     103                         * @since 8.0.0
     104                         *
     105                         * @param int  $user_id    ID of the user who accepted membership.
     106                         * @param int  $network_id ID of the network that was accepted membership to.
     107                         */
     108                        do_action( 'network_membership_request_accepted', $r['user_id'], $r['item_id'] );
     109                } else {
     110                        /**
     111                         * Fires after a user has accepted a site membership invite.
     112                         *
     113                         * @since 8.0.0
     114                         *
     115                         * @param int $user_id    ID of the user who accepted the membership invite.
     116                         * @param int $inviter_id ID of the user who invited this user to the group.
     117                         */
     118                        do_action( 'network_membership_invite_accepted', $r['user_id'], $inviter_id );
     119                }
     120
     121
     122                return true;
     123        }
     124
     125        /**
     126         * Should this invitation be created?
     127         *
     128         * @since 8.0.0
     129         *
     130         * @param array $args.
     131         * @return bool
     132         */
     133        public function allow_invitation( $args ) {
     134                // Does the inviter have this capability?
     135                if ( ! bp_user_can( $args['inviter_id'], 'bp_members_send_invitation' ) ) {
     136                        return false;
     137                }
     138
     139                // Is the invited user eligible to receive an invitation? Hasn't opted out?
     140                if ( ! bp_user_can( 0, 'bp_members_receive_invitation', $args ) ) {
     141                        return false;
     142                }
     143
     144                return true;
     145        }
     146
     147        /**
     148         * Should this request be created?
     149         *
     150         * @since 8.0.0
     151         *
     152         * @param array $args.
     153         * @return bool.
     154         */
     155        public function allow_request( $args ) {
     156                // Does the requester have this capability?
     157                if ( ! bp_user_can( 0, 'bp_network_request_membership', $args ) ) {
     158                        return false;
     159                }
     160
     161                return true;
     162        }
     163}
  • new file src/bp-members/classes/class-bp-members-invitations-list-table.php

    diff --git src/bp-members/classes/class-bp-members-invitations-list-table.php src/bp-members/classes/class-bp-members-invitations-list-table.php
    new file mode 100644
    index 000000000..90f35d921
    - +  
     1<?php
     2/**
     3 * BuddyPress Membership Invitation List Table class.
     4 *
     5 * @package BuddyPress
     6 * @subpackage MembersAdminClasses
     7 * @since 8.0.0
     8 */
     9
     10// Exit if accessed directly.
     11defined( 'ABSPATH' ) || exit;
     12
     13/**
     14 * List table class for signups admin page.
     15 *
     16 * @since 8.0.0
     17 */
     18class BP_Members_Invitations_List_Table extends WP_Users_List_Table {
     19
     20        /**
     21         * The type of view currently being displayed.
     22         *
     23         * E.g. "All", "Pending", "Sent", "Unsent"...
     24         *
     25         * @since 8.0.0
     26         * @var string
     27         */
     28        public $active_filters = array();
     29
     30        /**
     31         * Signup counts.
     32         *
     33         * @since 8.0.0
     34         *
     35         * @var int
     36         */
     37        public $total_items = 0;
     38
     39        /**
     40         * Constructor.
     41         *
     42         * @since 8.0.0
     43         */
     44        public function __construct() {
     45                // Define singular and plural labels, as well as whether we support AJAX.
     46                parent::__construct( array(
     47                        'ajax'     => false,
     48                        'plural'   => 'invitations',
     49                        'singular' => 'invitation',
     50                        'screen'   => get_current_screen()->id,
     51                ) );
     52        }
     53
     54        /**
     55         * Set up items for display in the list table.
     56         *
     57         * Handles filtering of data, sorting, pagination, and any other data
     58         * manipulation required prior to rendering.
     59         *
     60         * @since 8.0.0
     61         */
     62        public function prepare_items() {
     63                global $usersearch;
     64
     65                $search   = isset( $_REQUEST['s'] ) ? $_REQUEST['s'] : '';
     66                $per_page = $this->get_items_per_page( str_replace( '-', '_', "{$this->screen->id}_per_page" ) );
     67                $paged    = $this->get_pagenum();
     68
     69                $args = array(
     70                        'invite_sent'       => 'all',
     71                        'accepted'          => 'all',
     72                        'search_terms'      => $search,
     73                        'order_by'          => 'date_modified',
     74                        'sort_order'        => 'DESC',
     75                        'page'              => $paged,
     76                        'per_page'          => $per_page,
     77                );
     78
     79                if ( isset( $_REQUEST['accepted'] ) && in_array( $_REQUEST['accepted'], array( 'pending', 'accepted' ), true ) ) {
     80                        $args['accepted']       = $_REQUEST['accepted'];
     81                        $this->active_filters[] = $_REQUEST['accepted'];
     82                }
     83                if ( isset( $_REQUEST['sent'] ) && in_array( $_REQUEST['sent'], array( 'draft', 'sent' ), true ) ) {
     84                        $args['invite_sent']    = $_REQUEST['sent'];
     85                        $this->active_filters[] = $_REQUEST['sent'];
     86                }
     87
     88                if ( isset( $_REQUEST['orderby'] ) ) {
     89                        $args['order_by'] = $_REQUEST['orderby'];
     90                }
     91
     92                if ( isset( $_REQUEST['order'] ) ) {
     93                        $args['sort_order'] = $_REQUEST['order'];
     94                }
     95
     96                $invites_class     = new BP_Members_Invitation_Manager();
     97                $this->items       = $invites_class->get_invitations( $args );
     98                $this->total_items = $invites_class->get_invitations_total_count( $args );
     99
     100                $this->set_pagination_args( array(
     101                        'total_items' => $this->total_items,
     102                        'per_page'    => $per_page,
     103                ) );
     104        }
     105
     106        /**
     107         * Get the list of views available on this table (e.g. "all", "public").
     108         *
     109         * @since 8.0.0
     110         */
     111        public function views() {
     112                $url_base = add_query_arg(
     113                        array(
     114                                'page' => 'bp-members-invitations',
     115                        ),
     116                        bp_get_admin_url( 'users.php' )
     117                );
     118
     119                ?>
     120
     121                <h2 class="screen-reader-text"><?php
     122                        /* translators: accessibility text */
     123                        _e( 'Filter invitations list', 'buddypress' );
     124                ?></h2>
     125                <ul class="subsubsub">
     126                        <li class="all">
     127                                <a href="<?php echo esc_url( $url_base ); ?>" class="<?php if ( empty( $this->active_filters ) ) echo 'current'; ?>">
     128                                        <?php esc_html_e( 'All', 'buddypress' ); ?>
     129                                </a> |
     130                        </li>
     131                        <li class="pending">
     132                                <a href="<?php echo esc_url( add_query_arg( 'accepted', 'pending', $url_base ) ); ?>" class="<?php if ( in_array( 'pending', $this->active_filters, true ) ) echo 'current'; ?>">
     133                                        <?php esc_html_e( 'Pending', 'buddypress' ); ?>
     134                                </a> |
     135                        </li>
     136                        <li class="accepted">
     137                                <a href="<?php echo esc_url( add_query_arg( 'accepted', 'accepted', $url_base ) ); ?>" class="<?php if ( in_array( 'accepted', $this->active_filters, true ) ) echo 'current'; ?>">
     138                                        <?php esc_html_e( 'Accepted', 'buddypress' ); ?>
     139                                </a> |
     140                        </li>
     141                        <li class="draft">
     142                                <a href="<?php echo esc_url( add_query_arg( 'sent', 'draft', $url_base ) ); ?>" class="<?php if ( in_array( 'draft', $this->active_filters, true ) ) echo 'current'; ?>">
     143                                        <?php esc_html_e( 'Draft (Unsent)', 'buddypress' ); ?>
     144                                </a> |
     145                        </li>
     146                        <li class="sent">
     147                                <a href="<?php echo esc_url( add_query_arg( 'sent', 'sent', $url_base ) ); ?>" class="<?php if ( in_array( 'sent', $this->active_filters, true ) ) echo 'current'; ?>">
     148                                        <?php esc_html_e( 'Sent', 'buddypress' ); ?>
     149                                </a> |
     150                        </li>
     151
     152                        <?php
     153
     154                        /**
     155                         * Fires inside listing of views so plugins can add their own.
     156                         *
     157                         * @since 8.0.0
     158                         *
     159                         * @param string $url_base       Current URL base for view.
     160                         * @param array  $active_filters Current filters being requested.
     161                         */
     162                        do_action( 'bp_members_invitations_list_table_get_views', $url_base, $this->active_filters ); ?>
     163                </ul>
     164        <?php
     165        }
     166
     167        /**
     168         * Get rid of the extra nav.
     169         *
     170         * WP_Users_List_Table will add an extra nav to change user's role.
     171         * As we're dealing with invitations, we don't need this.
     172         *
     173         * @since 8.0.0
     174         *
     175         * @param array $which Current table nav item.
     176         */
     177        public function extra_tablenav( $which ) {
     178                return;
     179        }
     180
     181        /**
     182         * Specific signups columns.
     183         *
     184         * @since 8.0.0
     185         *
     186         * @return array
     187         */
     188        public function get_columns() {
     189
     190                /**
     191                 * Filters the single site Members signup columns.
     192                 *
     193                 * @since 8.0.0
     194                 *
     195                 * @param array $value Array of columns to display.
     196                 */
     197                return apply_filters( 'bp_members_invitations_list_columns', array(
     198                        'cb'                       => '<input type="checkbox" />',
     199                        'invitee_email'            => __( 'Invitee',    'buddypress' ),
     200                        'username'                 => __( 'Inviter',        'buddypress' ),
     201                        'inviter_registered_date'  => __( 'Inviter Registered',  'buddypress' ),
     202                        'invitation_date_modified' => __( 'Date Modified',   'buddypress' ),
     203                        'invitation_sent'          => __( 'Email Sent', 'buddypress' ),
     204                        'invitation_accepted'      => __( 'Accepted', 'buddypress' )
     205                ) );
     206        }
     207
     208        /**
     209         * Specific bulk actions for signups.
     210         *
     211         * @since 8.0.0
     212         */
     213        public function get_bulk_actions() {
     214                $actions = array(
     215                        'resend' => _x( 'Resend Email', 'Pending invitation action', 'buddypress' ),
     216                );
     217
     218                if ( current_user_can( 'delete_users' ) ) {
     219                        $actions['delete'] = _x( 'Delete', 'Pending invitation action', 'buddypress' );
     220                }
     221
     222                return $actions;
     223        }
     224
     225        /**
     226         * The text shown when no items are found.
     227         *
     228         * Nice job, clean sheet!
     229         *
     230         * @since 8.0.0
     231         */
     232        public function no_items() {
     233
     234                if ( bp_get_members_invitations_allowed() ) {
     235                        esc_html_e( 'No pending invitations found.', 'buddypress' );
     236                } else {
     237                        $link = sprintf( '<a href="%1$s">%2$s</a>', esc_url( bp_get_admin_url( add_query_arg( array( 'page' => 'bp-settings' ), 'admin.php' ) ) ), esc_html__( 'Edit settings', 'buddypress' ) );
     238
     239                        /* translators: %s: url to site settings */
     240                        printf( __( 'Invitations are not allowed. %s', 'buddypress' ), $link );
     241                }
     242
     243        }
     244
     245        /**
     246         * The columns invitations can be reordered by.
     247         *
     248         * @since 8.0.0
     249         */
     250        public function get_sortable_columns() {
     251                return array(
     252                        'invitee_email'            => 'invitee_email',
     253                        'username'                 => 'inviter_id',
     254                        'invitation_date_modified' => 'date_modified',
     255                        'invitation_sent'          => 'invite_sent',
     256                        'invitation_accepted'      => 'accepted',
     257                );
     258        }
     259
     260        /**
     261         * Display invitation rows.
     262         *
     263         * @since 8.0.0
     264         */
     265        public function display_rows() {
     266                $style = '';
     267                foreach ( $this->items as $invite ) {
     268                        $style = ( ' class="alternate"' == $style ) ? '' : ' class="alternate"';
     269                        echo "\n\t" . $this->single_row( $invite, $style );
     270                }
     271        }
     272
     273        /**
     274         * Display an invitation row.
     275         *
     276         * @since 8.0.0
     277         *
     278         * @see WP_List_Table::single_row() for explanation of params.
     279         *
     280         * @param BP_Invitation $invite   BP_Invitation object.
     281         * @param string        $style    Styles for the row.
     282         * @param string        $role     Role to be assigned to user.
     283         * @param int           $numposts Number of posts.
     284         * @return void
     285         */
     286        public function single_row( $invite = null, $style = '', $role = '', $numposts = 0 ) {
     287                echo '<tr' . $style . ' id="invitation-' . esc_attr( $invite->id ) . '">';
     288                echo $this->single_row_columns( $invite );
     289                echo '</tr>';
     290        }
     291
     292        /**
     293         * Markup for the checkbox used to select items for bulk actions.
     294         *
     295         * @since 8.0.0
     296         *
     297         * @param BP_Invitation $invite BP_Invitation object.
     298         */
     299        public function column_cb( $invite = null ) {
     300        ?>
     301                <label class="screen-reader-text" for="invitation_<?php echo intval( $invite->id ); ?>"><?php
     302                        /* translators: accessibility text */
     303                        printf( esc_html__( 'Select invitation: %s', 'buddypress' ), $invite->id );
     304                ?></label>
     305                <input type="checkbox" id="invitation_<?php echo intval( $invite->id ) ?>" name="invite_ids[]" value="<?php echo esc_attr( $invite->id ) ?>" />
     306                <?php
     307        }
     308
     309        /**
     310         * Markup for the checkbox used to select items for bulk actions.
     311         *
     312         * @since 8.0.0
     313         *
     314         * @param BP_Invitation $invite BP_Invitation object.
     315         */
     316        public function column_invitee_email( $invite = null ) {
     317                echo esc_html( $invite->invitee_email );
     318
     319                $actions = array();
     320
     321                // Resend action only if pending
     322                if ( ! $invite->accepted ) {
     323                        // Resend invitation email link.
     324                        $email_link = add_query_arg(
     325                                array(
     326                                        'page'      => 'bp-members-invitations',
     327                                        'invite_id' => $invite->id,
     328                                        'action'    => 'resend',
     329                                ),
     330                                bp_get_admin_url( 'users.php' )
     331                        );
     332                        if ( ! $invite->invite_sent ) {
     333                                $resend_label = __( 'Send', 'buddypress' );
     334                        } else {
     335                                $resend_label = __( 'Resend', 'buddypress' );
     336                        }
     337                        $actions['resend'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $email_link ), $resend_label );
     338                }
     339
     340                // Delete link. Could be cleanup or revoking the invitation.
     341                $delete_link = add_query_arg(
     342                        array(
     343                                'page'      => 'bp-members-invitations',
     344                                'invite_id' => $invite->id,
     345                                'action'    => 'delete',
     346                        ),
     347                        bp_get_admin_url( 'users.php' )
     348                );
     349                // Two cases: unsent and accepted (cleanup), and pending (cancels invite).
     350                if ( ! $invite->invite_sent || $invite->accepted ) {
     351                        $actions['delete'] = sprintf( '<a href="%1$s" class="delete">%2$s</a>', esc_url( $delete_link ), __( 'Delete', 'buddypress' ) );
     352                } else {
     353                        $actions['delete'] = sprintf( '<a href="%1$s" class="delete">%2$s</a>', esc_url( $delete_link ), __( 'Cancel', 'buddypress' ) );
     354                }
     355
     356                /**
     357                 * Filters the row actions for each invitation in list.
     358                 *
     359                 * @since 8.0.0
     360                 *
     361                 * @param array  $actions Array of actions and corresponding links.
     362                 * @param object $invite  The BP_Invitation.
     363                 */
     364                $actions = apply_filters( 'bp_members_invitations_management_row_actions', $actions, $invite );
     365
     366                echo $this->row_actions( $actions );
     367        }
     368
     369        /**
     370         * Display invited user's email address.
     371         *
     372         * @since 8.0.0
     373         *
     374         * @param BP_Invitation $invite BP_Invitation object.
     375         */
     376        public function column_email( $invite = null ) {
     377                printf( '<a href="mailto:%1$s">%2$s</a>', esc_attr( $invite->user_email ), esc_html( $invite->user_email ) );
     378        }
     379
     380        /**
     381         * The inviter.
     382         *
     383         * @since 8.0.0
     384         *
     385         * @param BP_Invitation $invite BP_Invitation object.
     386         */
     387        public function column_username( $invite = null ) {
     388                $avatar = get_avatar( $invite->inviter_id, 32 );
     389                $inviter = get_user_by( 'id', $invite->inviter_id );
     390                if ( ! $inviter ) {
     391                        return;
     392                }
     393                $user_link = bp_core_get_user_domain( $invite->inviter_id );
     394                echo $avatar . sprintf( '<strong><a href="%1$s" class="edit">%2$s</a></strong><br/>', esc_url( $user_link ), $inviter->user_login );
     395        }
     396
     397        /**
     398         * Display invitation date.
     399         *
     400         * @since 8.0.0
     401         *
     402         * @param BP_Invitation $invite BP_Invitation object.
     403         */
     404        public function column_inviter_registered_date( $invite = null ) {
     405                $inviter = get_user_by( 'id', $invite->inviter_id );
     406                if ( ! $inviter ) {
     407                        return;
     408                }
     409                echo esc_html( $inviter->user_registered );
     410        }
     411
     412        /**
     413         * Display invitation date.
     414         *
     415         * @since 8.0.0
     416         *
     417         * @param BP_Invitation $invite BP_Invitation object.
     418         */
     419        public function column_invitation_date_modified( $invite = null ) {
     420                echo esc_html( $invite->date_modified );
     421        }
     422
     423        /**
     424         * Display invitation date.
     425         *
     426         * @since 8.0.0
     427         *
     428         * @param BP_Invitation $invite BP_Invitation object.
     429         */
     430        public function column_invitation_sent( $invite = null ) {
     431                if ( $invite->invite_sent) {
     432                        esc_html_e( 'Yes', 'buddypress' );
     433                } else {
     434                        esc_html_e( 'No', 'buddypress' );
     435                }
     436        }
     437
     438        /**
     439         * Display invitation acceptance status.
     440         *
     441         * @since 8.0.0
     442         *
     443         * @param BP_Invitation $invite BP_Invitation object.
     444         */
     445        public function column_invitation_accepted( $invite = null ) {
     446                if ( $invite->accepted ) {
     447                        esc_html_e( 'Yes', 'buddypress' );
     448                } else {
     449                        esc_html_e( 'No', 'buddypress' );
     450                }
     451        }
     452
     453        /**
     454         * Allow plugins to add their custom column.
     455         *
     456         * @since 8.0.0
     457         *
     458         * @param BP_Invitation $invite      BP_Invitation object.
     459         * @param string        $column_name The column name.
     460         * @return string
     461         */
     462        function column_default( $invite = null, $column_name = '' ) {
     463
     464                /**
     465                 * Filters the single site custom columns for plugins.
     466                 *
     467                 * @since 8.0.0
     468                 *
     469                 * @param string $column_name The column name.
     470                 * @param object $invite      The BP_Invitation object..
     471                 */
     472                return apply_filters( 'bp_members_invitations_management_custom_column', '', $column_name, $invite );
     473        }
     474}
  • new file src/bp-members/classes/class-bp-members-invitations-template.php

    diff --git src/bp-members/classes/class-bp-members-invitations-template.php src/bp-members/classes/class-bp-members-invitations-template.php
    new file mode 100644
    index 000000000..3ac8e17fb
    - +  
     1<?php
     2/**
     3 * BuddyPress Members Invitation Template Loop Class.
     4 *
     5 * @package BuddyPress
     6 * @subpackage TonificationsTemplate
     7 * @since 8.0.0
     8 */
     9
     10// Exit if accessed directly.
     11defined( 'ABSPATH' ) || exit;
     12
     13/**
     14 * The main membership invitations template loop class.
     15 *
     16 * Responsible for loading a group of membership invitations into a loop for display.
     17 *
     18 * @since 8.0.0
     19 */
     20class BP_Members_Invitations_Template {
     21
     22        /**
     23         * The loop iterator.
     24         *
     25         * @since 8.0.0
     26         * @var int
     27         */
     28        public $current_invitation = -1;
     29
     30        /**
     31         * The number of invitations returned by the paged query.
     32         *
     33         * @since 8.0.0
     34         * @var int
     35         */
     36        public $current_invitation_count;
     37
     38        /**
     39         * Total number of invitations matching the query.
     40         *
     41         * @since 8.0.0
     42         * @var int
     43         */
     44        public $total_invitation_count;
     45
     46        /**
     47         * Array of network invitations located by the query.
     48         *
     49         * @since 8.0.0
     50         * @var array
     51         */
     52        public $invitations;
     53
     54        /**
     55         * The invitation object currently being iterated on.
     56         *
     57         * @since 8.0.0
     58         * @var object
     59         */
     60        public $invitation;
     61
     62        /**
     63         * A flag for whether the loop is currently being iterated.
     64         *
     65         * @since 8.0.0
     66         * @var bool
     67         */
     68        public $in_the_loop;
     69
     70        /**
     71         * The ID of the user to whom the displayed invitations were sent.
     72         *
     73         * @since 8.0.0
     74         * @var int
     75         */
     76        public $user_id;
     77
     78        /**
     79         * The ID of the user to whom the displayed invitations belong.
     80         *
     81         * @since 8.0.0
     82         * @var int
     83         */
     84        public $inviter_id;
     85
     86        /**
     87         * The page number being requested.
     88         *
     89         * @since 8.0.0
     90         * @var int
     91         */
     92        public $pag_page;
     93
     94        /**
     95         * The $_GET argument used in URLs for determining pagination.
     96         *
     97         * @since 8.0.0
     98         * @var int
     99         */
     100        public $pag_arg;
     101
     102        /**
     103         * The number of items to display per page of results.
     104         *
     105         * @since 8.0.0
     106         * @var int
     107         */
     108        public $pag_num;
     109
     110        /**
     111         * An HTML string containing pagination links.
     112         *
     113         * @since 8.0.0
     114         * @var string
     115         */
     116        public $pag_links;
     117
     118        /**
     119         * A string to match against.
     120         *
     121         * @since 8.0.0
     122         * @var string
     123         */
     124        public $search_terms;
     125
     126        /**
     127         * A database column to order the results by.
     128         *
     129         * @since 8.0.0
     130         * @var string
     131         */
     132        public $order_by;
     133
     134        /**
     135         * The direction to sort the results (ASC or DESC).
     136         *
     137         * @since 8.0.0
     138         * @var string
     139         */
     140        public $sort_order;
     141
     142        /**
     143         * Array of variables used in this invitation query.
     144         *
     145         * @since 2.2.2
     146         * @var array
     147         */
     148        public $query_vars;
     149
     150        /**
     151         * Constructor method.
     152         *
     153         * @see bp_has_members_invitations() For information on the array format.
     154         *
     155         * @since 8.0.0
     156         *
     157         * @param array $args {
     158         *     An array of arguments. See {@link bp_has_members_invitations()}
     159         *     for more details.
     160         * }
     161         */
     162        public function __construct( $args = array() ) {
     163
     164                // Parse arguments.
     165                $r = wp_parse_args( $args, array(
     166                        'id'                => false,
     167                        'user_id'           => false,
     168                        'inviter_id'        => false,
     169                        'invitee_email'     => false,
     170                        'item_id'           => false,
     171                        'type'              => 'invite',
     172                        'invite_sent'       => 'all',
     173                        'accepted'          => 'all',
     174                        'search_terms'      => '',
     175                        'order_by'          => 'date_modified',
     176                        'sort_order'        => 'DESC',
     177                        'page'              => 1,
     178                        'per_page'          => 25,
     179                        'fields'            => 'all',
     180                        'page_arg'          => 'ipage',
     181                ) );
     182
     183                // Sort order direction.
     184                $orders = array( 'ASC', 'DESC' );
     185                if ( ! empty( $_GET['sort_order'] ) && in_array( $_GET['sort_order'], $orders ) ) {
     186                        $r['sort_order'] = $_GET['sort_order'];
     187                } else {
     188                        $r['sort_order'] = in_array( $r['sort_order'], $orders ) ? $r['sort_order'] : 'DESC';
     189                }
     190
     191                // Setup variables.
     192                $this->pag_arg      = sanitize_key( $r['page_arg'] );
     193                $this->pag_page     = bp_sanitize_pagination_arg( $this->pag_arg, $r['page']     );
     194                $this->pag_num      = bp_sanitize_pagination_arg( 'num',          $r['per_page'] );
     195                $this->user_id      = $r['user_id'];
     196                $this->search_terms = $r['search_terms'];
     197                $this->order_by     = $r['order_by'];
     198                $this->sort_order   = $r['sort_order'];
     199                $this->query_vars   = array(
     200                        'id'                => $r['id'],
     201                        'user_id'           => $r['user_id'],
     202                        'inviter_id'        => $r['inviter_id'],
     203                        'invitee_email'     => $r['invitee_email'],
     204                        'item_id'           => $r['item_id'],
     205                        'type'              => $r['type'],
     206                        'invite_sent'       => $r['invite_sent'],
     207                        'accepted'          => $r['accepted'],
     208                        'search_terms'      => $this->search_terms,
     209                        'order_by'          => $this->order_by,
     210                        'sort_order'        => $this->sort_order,
     211                        'page'              => $this->pag_page,
     212                        'per_page'          => $this->pag_num,
     213                );
     214
     215                // Setup the invitations to loop through.
     216                $invites_class = new BP_Members_Invitation_Manager();
     217
     218                $this->invitations              = $invites_class->get_invitations( $this->query_vars );
     219                $this->current_invitation_count = count( $this->invitations );
     220                $this->total_invitation_count   = $invites_class->get_invitations_total_count( $this->query_vars );
     221
     222                if ( (int) $this->total_invitation_count && (int) $this->pag_num ) {
     223                        $add_args = array(
     224                                'sort_order' => $this->sort_order,
     225                        );
     226
     227                        $this->pag_links = paginate_links( array(
     228                                'base'      => add_query_arg( $this->pag_arg, '%#%' ),
     229                                'format'    => '',
     230                                'total'     => ceil( (int) $this->total_invitation_count / (int) $this->pag_num ),
     231                                'current'   => $this->pag_page,
     232                                'prev_text' => _x( '&larr;', 'Network invitation pagination previous text', 'buddypress' ),
     233                                'next_text' => _x( '&rarr;', 'Network invitation pagination next text',     'buddypress' ),
     234                                'mid_size'  => 1,
     235                                'add_args'  => $add_args,
     236                        ) );
     237                }
     238        }
     239
     240        /**
     241         * Whether there are invitations available in the loop.
     242         *
     243         * @since 8.0.0
     244         *
     245         * @see bp_has_members_invitations()
     246         *
     247         * @return bool True if there are items in the loop, otherwise false.
     248         */
     249        public function has_invitations() {
     250                if ( $this->current_invitation_count ) {
     251                        return true;
     252                }
     253
     254                return false;
     255        }
     256
     257        /**
     258         * Set up the next invitation and iterate index.
     259         *
     260         * @since 8.0.0
     261         *
     262         * @return object The next invitation to iterate over.
     263         */
     264        public function next_invitation() {
     265
     266                $this->current_invitation++;
     267
     268                $this->invitation = $this->invitations[ $this->current_invitation ];
     269
     270                return $this->invitation;
     271        }
     272
     273        /**
     274         * Rewind the blogs and reset blog index.
     275         *
     276         * @since 8.0.0
     277         */
     278        public function rewind_invitations() {
     279
     280                $this->current_invitation = -1;
     281
     282                if ( $this->current_invitation_count > 0 ) {
     283                        $this->invitation = $this->invitations[0];
     284                }
     285        }
     286
     287        /**
     288         * Whether there are invitations left in the loop to iterate over.
     289         *
     290         * This method is used by {@link bp_members_invitations()} as part of the
     291         * while loop that controls iteration inside the invitations loop, eg:
     292         *     while ( bp_members_invitations() ) { ...
     293         *
     294         * @since 8.0.0
     295         *
     296         * @see bp_members_invitations()
     297         *
     298         * @return bool True if there are more invitations to show,
     299         *              otherwise false.
     300         */
     301        public function invitations() {
     302
     303                if ( $this->current_invitation + 1 < $this->current_invitation_count ) {
     304                        return true;
     305
     306                } elseif ( $this->current_invitation + 1 == $this->current_invitation_count ) {
     307
     308                        /**
     309                         * Fires right before the rewinding of invitation posts.
     310                         *
     311                         * @since 8.0.0
     312                         */
     313                        do_action( 'members_invitations_loop_end');
     314
     315                        $this->rewind_invitations();
     316                }
     317
     318                $this->in_the_loop = false;
     319                return false;
     320        }
     321
     322        /**
     323         * Set up the current invitation inside the loop.
     324         *
     325         * Used by {@link bp_the_invitation()} to set up the current
     326         * invitation data while looping, so that template tags used during
     327         * that iteration make reference to the current invitation.
     328         *
     329         * @since 8.0.0
     330         *
     331         * @see bp_the_invitation()
     332         */
     333        public function the_invitation() {
     334                $this->in_the_loop  = true;
     335                $this->invitation = $this->next_invitation();
     336
     337                // Loop has just started.
     338                if ( 0 === $this->current_invitation ) {
     339
     340                        /**
     341                         * Fires if the current invitation item is the first in the invitation loop.
     342                         *
     343                         * @since 8.0.0
     344                         */
     345                        do_action( 'members_invitations_loop_start' );
     346                }
     347        }
     348}
  • new file src/bp-members/screens/list-invites.php

    diff --git src/bp-members/screens/list-invites.php src/bp-members/screens/list-invites.php
    new file mode 100644
    index 000000000..8242dd279
    - +  
     1<?php
     2/**
     3 * Members: Sent Invitations Status
     4 *
     5 * @package BuddyPress
     6 * @subpackage MembersScreens
     7 * @since 8.0.0
     8 */
     9
     10/**
     11 * Catch and process the Send Invites page.
     12 *
     13 * @since 8.0.0
     14 */
     15function members_screen_list_sent_invites() {
     16
     17        /**
     18         * Fires before the loading of template for the send membership invitations page.
     19         *
     20         * @since 8.0.0
     21         */
     22        do_action( 'members_screen_list_sent_invites' );
     23
     24        /**
     25         * Filters the template used to display the send membership invitations page.
     26         *
     27         * @since 8.0.0
     28         *
     29         * @param string $template Path to the send membership invitations template to load.
     30         */
     31        bp_core_load_template( apply_filters( 'members_template_list_sent_invites', 'members/single/invitations' ) );
     32}
     33
     34/**
     35 * Handle canceling or resending single invitations.
     36 *
     37 * @since 8.0.0
     38 *
     39 * @return bool
     40 */
     41function bp_members_invitations_action_handling() {
     42
     43        // Bail if not the read screen.
     44        if ( ! bp_is_user_members_invitations_list() ) {
     45                return false;
     46        }
     47
     48        // Get the action.
     49        $action = ! empty( $_GET['action']          ) ? $_GET['action']          : '';
     50        $nonce  = ! empty( $_GET['_wpnonce']        ) ? $_GET['_wpnonce']        : '';
     51        $id     = ! empty( $_GET['invitation_id']   ) ? $_GET['invitation_id']   : '';
     52
     53        // Bail if no action or no ID.
     54        if ( empty( $action ) || empty( $id ) ) {
     55                return false;
     56        }
     57
     58        if ( 'cancel' === $action ) {
     59                // Check the nonce and delete the invitation.
     60                if ( bp_verify_nonce_request( 'bp_members_invitations_cancel_' . $id ) && bp_members_invitations_delete_by_id( $id ) ) {
     61                        bp_core_add_message( __( 'Invitation successfully canceled.', 'buddypress' )          );
     62                } else {
     63                        bp_core_add_message( __( 'There was a problem canceling that invitation.', 'buddypress' ), 'error' );
     64                }
     65        } else if ( 'resend' === $action ) {
     66                // Check the nonce and resend the invitation.
     67                if ( bp_verify_nonce_request( 'bp_network_invitation_resend_' . $id ) && bp_members_invitation_resend_by_id( $id ) ) {
     68                        bp_core_add_message( __( 'Invitation successfully resent.', 'buddypress' )          );
     69                } else {
     70                        bp_core_add_message( __( 'There was a problem resending that invitation.', 'buddypress' ), 'error' );
     71                }
     72        } else {
     73                return false;
     74        }
     75
     76        // Redirect.
     77        $user_id = bp_displayed_user_id();
     78        bp_core_redirect( bp_get_members_invitations_list_invites_permalink( $user_id ) );
     79}
     80add_action( 'bp_actions', 'bp_members_invitations_action_handling' );
  • src/bp-members/screens/register.php

    diff --git src/bp-members/screens/register.php src/bp-members/screens/register.php
    index 54b6facd5..b08f6ece8 100644
    function bp_core_screen_signup() { 
    4242
    4343        $bp->signup->step = 'request-details';
    4444
    45         if ( !bp_get_signup_allowed() ) {
    46                 $bp->signup->step = 'registration-disabled';
     45        // Could the user be accepting an invitation?
     46        $active_invite = false;
     47        if ( bp_get_members_invitations_allowed() ) {
     48                // Check to see if there's a valid invitation.
     49                $maybe_invite = bp_get_members_invitation_from_request();
     50                if ( $maybe_invite->id ) {
     51                        $active_invite = true;
     52                }
     53        }
    4754
     55        if ( ! bp_get_signup_allowed() && ! $active_invite ) {
     56                $bp->signup->step = 'registration-disabled';
    4857                // If the signup page is submitted, validate and save.
    4958        } elseif ( isset( $_POST['signup_submit'] ) && bp_verify_nonce_request( 'bp_new_signup' ) ) {
    5059
  • new file src/bp-members/screens/send-invites.php

    diff --git src/bp-members/screens/send-invites.php src/bp-members/screens/send-invites.php
    new file mode 100644
    index 000000000..cc78d33c3
    - +  
     1<?php
     2/**
     3 * Members: Send Invitations
     4 *
     5 * @package BuddyPress
     6 * @subpackage MembersScreens
     7 * @since 8.0.0
     8 */
     9
     10/**
     11 * Catch and process the Send Invites page.
     12 *
     13 * @since 8.0.0
     14 */
     15function members_screen_send_invites() {
     16
     17        /**
     18         * Fires before the loading of template for the send membership invitations page.
     19         *
     20         * @since 8.0.0
     21         */
     22        do_action( 'members_screen_send_invites' );
     23
     24        /**
     25         * Filters the template used to display the send membership invitations page.
     26         *
     27         * @since 8.0.0
     28         *
     29         * @param string $template Path to the send membership invitations template to load.
     30         */
     31        bp_core_load_template( apply_filters( 'members_template_send_invites', 'members/single/invitations' ) );
     32}
     33
     34/**
     35 * Handle sending invitations.
     36 *
     37 * @since 8.0.0
     38 *
     39 * @return bool
     40 */
     41function bp_network_invitations_catch_send_action() {
     42
     43        // Bail if not the read screen.
     44        if ( ! bp_is_user_members_invitations_send_screen() ) {
     45                return false;
     46        }
     47
     48        // Get the action.
     49        $action  = ! empty( $_REQUEST['action']          ) ? $_REQUEST['action']          : '';
     50        $nonce   = ! empty( $_REQUEST['_wpnonce']        ) ? $_REQUEST['_wpnonce']        : '';
     51        $email   = ! empty( $_REQUEST['invitee_email']   ) ? $_REQUEST['invitee_email']   : '';
     52        $message = ! empty( $_REQUEST['invite_message']  ) ? $_REQUEST['invite_message']  : '';
     53
     54        // Bail if missing required info.
     55        if ( ( 'send-invite' !== $action ) ) {
     56                return false;
     57        }
     58
     59        $invite_args = array(
     60                'invitee_email' => $email,
     61                'inviter_id'    => bp_displayed_user_id(),
     62                'content'       => $message,
     63                'send_invite'   => 1
     64        );
     65
     66        // Check the nonce and delete the invitation.
     67        if ( bp_verify_nonce_request( 'bp_network_invitation_send_' . bp_displayed_user_id() ) && bp_members_invitations_invite_user( $invite_args ) ) {
     68                bp_core_add_message( __( 'Invitation successfully sent!', 'buddypress' )          );
     69        } else {
     70                bp_core_add_message( __( 'There was a problem sending that invitation.', 'buddypress' ), 'error' );
     71        }
     72
     73        // Redirect.
     74        $user_id = bp_displayed_user_id();
     75        bp_core_redirect( bp_get_members_invitations_send_invites_permalink( $user_id ) );
     76}
     77add_action( 'bp_actions', 'bp_network_invitations_catch_send_action' );
     78 No newline at end of file
  • src/bp-templates/bp-legacy/buddypress-functions.php

    diff --git src/bp-templates/bp-legacy/buddypress-functions.php src/bp-templates/bp-legacy/buddypress-functions.php
    index f4a3e1016..03c09ac00 100644
    function bp_legacy_theme_group_manage_members_add_search() { 
    20142014                <?php
    20152015        endif;
    20162016}
     2017
     2018/**
     2019 * Modify welcome message in Legacy template pack when
     2020 * community invitations are enabled.
     2021 *
     2022 * @since 8.0.0
     2023 *
     2024 * @return string $message The message text.
     2025 */
     2026function bp_members_invitations_add_legacy_welcome_message() {
     2027        $message = bp_members_invitations_get_registration_welcome_message();
     2028        if ( $message ) {
     2029                echo '<p>' . esc_html( $message ) . '</p>';
     2030        }
     2031}
     2032add_action( 'bp_before_register_page', 'bp_members_invitations_add_legacy_welcome_message' );
     2033
     2034
     2035/**
     2036 * Modify "registration disabled" message in Legacy template pack when
     2037 * community invitations are enabled.
     2038 *
     2039 * @since 8.0.0
     2040 *
     2041 * @return string $message The message text.
     2042 */
     2043function bp_members_invitations_add_legacy_registration_disabled_message() {
     2044        $message = bp_members_invitations_get_modified_registration_disabled_message();
     2045        if ( $message ) {
     2046                echo '<p>' . esc_html( $message ) . '</p>';
     2047        }
     2048}
     2049add_action( 'bp_after_registration_disabled', 'bp_members_invitations_add_legacy_registration_disabled_message' );
  • src/bp-templates/bp-legacy/buddypress/members/single/home.php

    diff --git src/bp-templates/bp-legacy/buddypress/members/single/home.php src/bp-templates/bp-legacy/buddypress/members/single/home.php
    index f56af6e9c..bed9da1bf 100644
     
    8989                elseif ( bp_is_user_notifications() ) :
    9090                        bp_get_template_part( 'members/single/notifications' );
    9191
     92                elseif ( bp_is_user_members_invitations() ) :
     93                        bp_get_template_part( 'members/single/invitations' );
     94
    9295                elseif ( bp_is_user_settings() ) :
    9396                        bp_get_template_part( 'members/single/settings' );
    9497
  • new file src/bp-templates/bp-legacy/buddypress/members/single/invitations.php

    diff --git src/bp-templates/bp-legacy/buddypress/members/single/invitations.php src/bp-templates/bp-legacy/buddypress/members/single/invitations.php
    new file mode 100644
    index 000000000..876a2e314
    - +  
     1<?php
     2/**
     3 * BuddyPress - membership invitations
     4 *
     5 * @package BuddyPress
     6 * @subpackage bp-legacy
     7 * @version 8.0.0
     8 */
     9
     10?>
     11
     12<div class="item-list-tabs no-ajax" id="subnav" aria-label="<?php esc_attr_e( 'Member secondary navigation', 'buddypress' ); ?>" role="navigation">
     13        <ul>
     14                <?php bp_get_options_nav(); ?>
     15        </ul>
     16</div>
     17
     18<?php
     19switch ( bp_current_action() ) :
     20
     21        case 'send-invites' :
     22                bp_get_template_part( 'members/single/invitations/send-invites' );
     23                break;
     24
     25        case 'list-invites' :
     26        default :
     27                bp_get_template_part( 'members/single/invitations/list-invites' );
     28                break;
     29
     30endswitch;
     31
  • new file src/bp-templates/bp-legacy/buddypress/members/single/invitations/invitations-loop.php

    diff --git src/bp-templates/bp-legacy/buddypress/members/single/invitations/invitations-loop.php src/bp-templates/bp-legacy/buddypress/members/single/invitations/invitations-loop.php
    new file mode 100644
    index 000000000..c02b7c56a
    - +  
     1<?php
     2/**
     3 * BuddyPress - Membership Invitations Loop
     4 *
     5 * @package BuddyPress
     6 * @subpackage bp-legacy
     7 * @version 8.0.0
     8 */
     9
     10?>
     11<form action="" method="post" id="invitations-bulk-management">
     12        <table class="invitations">
     13                <thead>
     14                        <tr>
     15                                <th class="icon"></th>
     16                                <th class="bulk-select-all"><input id="select-all-invitations" type="checkbox"><label class="bp-screen-reader-text" for="select-all-invitations"><?php
     17                                        /* translators: accessibility text */
     18                                        _e( 'Select all', 'buddypress' );
     19                                ?></label></th>
     20                                <th class="title"><?php _e( 'Invitee', 'buddypress' ); ?></th>
     21                                <th class="content"><?php _e( 'Message', 'buddypress' ); ?></th>
     22                                <th class="sent"><?php _e( 'Sent', 'buddypress' ); ?></th>
     23                                <th class="accepted"><?php _e( 'Accepted', 'buddypress' ); ?></th>
     24                                <th class="date"><?php _e( 'Date Modified', 'buddypress' ); ?></th>
     25                                <th class="actions"><?php _e( 'Actions',    'buddypress' ); ?></th>
     26                        </tr>
     27                </thead>
     28
     29                <tbody>
     30
     31                        <?php while ( bp_the_members_invitations() ) : bp_the_members_invitation(); ?>
     32
     33                                <tr>
     34                                        <td></td>
     35                                        <td class="bulk-select-check"><label for="<?php bp_the_members_invitation_property( 'id' ); ?>"><input id="<?php bp_the_members_invitation_property( 'id' ); ?>" type="checkbox" name="network_invitations[]" value="<?php bp_the_members_invitation_property( 'id' ); ?>" class="invitation-check"><span class="bp-screen-reader-text"><?php
     36                                                /* translators: accessibility text */
     37                                                _e( 'Select this invitation', 'buddypress' );
     38                                        ?></span></label></td>
     39                                        <td class="invitation-invitee"><?php bp_the_members_invitation_property( 'invitee_email' );  ?></td>
     40                                        <td class="invitation-content"><?php wptexturize( bp_the_members_invitation_property( 'content' ) );  ?></td>
     41                                        <td class="invitation-sent"><?php bp_the_members_invitation_property( 'invite_sent' );  ?></td>
     42                                        <td class="invitation-accepted"><?php bp_the_members_invitation_property( 'accepted' );  ?></td>
     43                                        <td class="invitation-date-modified"><?php bp_the_members_invitation_property( 'date_modified' );   ?></td>
     44                                        <td class="invitation-actions"><?php bp_the_members_invitation_action_links(); ?></td>
     45                                </tr>
     46
     47                        <?php endwhile; ?>
     48
     49                </tbody>
     50        </table>
     51
     52        <div class="invitations-options-nav">
     53                <?php // @TODO //bp_invitations_bulk_management_dropdown(); ?>
     54        </div><!-- .invitations-options-nav -->
     55
     56        <?php wp_nonce_field( 'invitations_bulk_nonce', 'invitations_bulk_nonce' ); ?>
     57</form>
  • new file src/bp-templates/bp-legacy/buddypress/members/single/invitations/list-invites.php

    diff --git src/bp-templates/bp-legacy/buddypress/members/single/invitations/list-invites.php src/bp-templates/bp-legacy/buddypress/members/single/invitations/list-invites.php
    new file mode 100644
    index 000000000..f5a4ba80f
    - +  
     1<?php
     2/**
     3 * BuddyPress - Sent Membership Invitations
     4 *
     5 * @package BuddyPress
     6 * @subpackage bp-legacy
     7 * @version 8.0.0
     8 */
     9?>
     10
     11<?php if ( bp_has_members_invitations() ) : ?>
     12
     13        <h2 class="bp-screen-reader-text"><?php
     14                /* translators: accessibility text */
     15                _e( 'Invitations', 'buddypress' );
     16        ?></h2>
     17
     18        <div id="pag-top" class="pagination no-ajax">
     19                <div class="pag-count" id="invitations-count-top">
     20                        <?php bp_members_invitations_pagination_count(); ?>
     21                </div>
     22
     23                <div class="pagination-links" id="invitations-pag-top">
     24                        <?php bp_members_invitations_pagination_links(); ?>
     25                </div>
     26        </div>
     27
     28        <?php bp_get_template_part( 'members/single/invitations/invitations-loop' ); ?>
     29
     30        <div id="pag-bottom" class="pagination no-ajax">
     31                <div class="pag-count" id="invitations-count-bottom">
     32                        <?php bp_members_invitations_pagination_count(); ?>
     33                </div>
     34
     35                <div class="pagination-links" id="invitations-pag-bottom">
     36                        <?php bp_members_invitations_pagination_links(); ?>
     37                </div>
     38        </div>
     39
     40<?php else : ?>
     41
     42        <p><?php _e( 'There are no invitations to display.', 'buddypress' ); ?></p>
     43
     44<?php endif;
  • new file src/bp-templates/bp-legacy/buddypress/members/single/invitations/send-invites.php

    diff --git src/bp-templates/bp-legacy/buddypress/members/single/invitations/send-invites.php src/bp-templates/bp-legacy/buddypress/members/single/invitations/send-invites.php
    new file mode 100644
    index 000000000..c27f4abc6
    - +  
     1<?php
     2/**
     3 * BuddyPress - Sent Membership Invitations
     4 *
     5 * @package BuddyPress
     6 * @subpackage bp-legacy
     7 * @version 8.0.0
     8 */
     9?>
     10<h2 class="bp-screen-reader-text"><?php
     11        /* translators: accessibility text */
     12        _e( 'Send Invitations', 'buddypress' );
     13?></h2>
     14
     15<form class="standard-form network-invitation-form" id="network-invitation-form" method="post">
     16        <label for="bp_network_invitation_invitee_email"><?php _e( 'Email address of new user', 'buddypress' ); ?></label>
     17        <input id="bp_network_invitation_invitee_email" type="email" name="invitee_email" required="required">
     18
     19        <label for="bp_network_invitation_message"><?php _e( 'Add a personalized message to the invitation (optional)', 'buddypress' ); ?></label>
     20        <textarea id="bp_network_invitation_message" name="invite_message"></textarea>
     21
     22        <input type="hidden" name="action" value="send-invite">
     23
     24        <?php wp_nonce_field( 'bp_network_invitation_send_' . bp_displayed_user_id() ) ?>
     25        <p>
     26                <input id="submit" type="submit" name="submit" class="submit" value="<?php esc_attr_e( 'Send Invitation', 'buddypress' ) ?>" />
     27        </p>
     28</form>
  • src/bp-templates/bp-nouveau/buddypress-functions.php

    diff --git src/bp-templates/bp-nouveau/buddypress-functions.php src/bp-templates/bp-nouveau/buddypress-functions.php
    index 892bf2e33..f93134f74 100644
    class BP_Nouveau extends BP_Theme_Compat { 
    195195                // Set the BP Uri for the Ajax customizer preview.
    196196                add_filter( 'bp_uri', array( $this, 'customizer_set_uri' ), 10, 1 );
    197197
     198                // Modify "registration disabled" and welcome message if invitations are enabled.
     199                add_action( 'bp_nouveau_feedback_messages', array( $this, 'filter_registration_messages' ), 99 );
     200
    198201                /** Override **********************************************************/
    199202
    200203                /**
    class BP_Nouveau extends BP_Theme_Compat { 
    676679
    677680                return $path;
    678681        }
     682        /**
     683         * Modify "registration disabled" message in Nouveau template pack.
     684         * Modify welcome message in Nouveau template pack.
     685         *
     686         * @since 8.0.0
     687         *
     688         * @param array $messages The list of feedback messages.
     689         *
     690         * @return array $messages
     691         */
     692        function filter_registration_messages( $messages ) {
     693                // Change the "registration is disabled" message.
     694                $disallowed_message = bp_members_invitations_get_modified_registration_disabled_message();
     695                if ( $disallowed_message ) {
     696                        $messages['registration-disabled']['message'] = $disallowed_message;
     697                }
     698                // Add information about invitations to the welcome block.
     699                $welcome_message = bp_members_invitations_get_registration_welcome_message();
     700                if ( $welcome_message ) {
     701                        $messages['request-details']['message'] = $welcome_message . $messages['request-details']['message'];
     702                }
     703                return $messages;
     704        }
    679705}
    680706
    681707/**
  • new file src/bp-templates/bp-nouveau/buddypress/members/single/invitations.php

    diff --git src/bp-templates/bp-nouveau/buddypress/members/single/invitations.php src/bp-templates/bp-nouveau/buddypress/members/single/invitations.php
    new file mode 100644
    index 000000000..90211f0e2
    - +  
     1<?php
     2/**
     3 * BuddyPress - Membership invitations
     4 *
     5 * @since 8.0.0
     6 * @version 8.0.0
     7 */
     8// @TODO
     9?>
     10
     11<nav class="<?php bp_nouveau_single_item_subnav_classes(); ?>" id="subnav" role="navigation" aria-label="<?php esc_attr_e( 'Groups menu', 'buddypress' ); ?>">
     12        <ul class="subnav">
     13
     14                <?php if ( bp_is_my_profile() ) : ?>
     15
     16                        <?php bp_get_template_part( 'members/single/parts/item-subnav' ); ?>
     17
     18                <?php endif; ?>
     19
     20        </ul>
     21</nav><!-- .bp-navs -->
     22
     23<?php bp_get_template_part( 'common/search-and-filters-bar' ); ?>
     24eh?
     25<?php
     26if ( 'sent-invites' === bp_current_action() ) {
     27        echo "send invites";
     28} else {
     29        echo "default";
     30}
     31
  • src/class-buddypress.php

    diff --git src/class-buddypress.php src/class-buddypress.php
    index 3dd1d483c..d3801b8e0 100644
    class BuddyPress { 
    620620                        'BP_REST_Attachments_Member_Avatar_Endpoint' => 'members',
    621621                        'BP_REST_Attachments_Member_Cover_Endpoint'  => 'members',
    622622                        'BP_REST_Signup_Endpoint'                    => 'members',
     623                        'BP_Members_Invitation_Manager'              => 'members',
     624                        'BP_Members_Invitations_Template'            => 'members',
    623625
    624626                        'BP_REST_Messages_Endpoint' => 'messages',
    625627