Skip to:
Content

BuddyPress.org

Ticket #8139: 8139.02.diff

File 8139.02.diff, 122.1 KB (added by dcavins, 10 months ago)

Same functionality as 8139.01, but incorporates naming suggestions and other improvements suggested by imath.

  • 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 b50ad98c6..8f4a98a2b 100644
    function bp_core_activation_notice() { 
    278278
    279279        // Activate and Register are special cases. They are not components but they need WP pages.
    280280        // If user registration is disabled, we can skip this step.
    281         if ( bp_get_signup_allowed() ) {
     281        if ( bp_get_signup_allowed() || bp_get_members_invitations_allowed() ) {
    282282                $wp_page_components[] = array(
    283283                        'id'   => 'activate',
    284284                        '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 cf8d43468..550e6a26a 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 7.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 7.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 8831e7189..3b85b950f 100644
    function bp_core_admin_slugs_options() { 
    186186
    187187                <h3><?php _e( 'Registration', 'buddypress' ); ?></h3>
    188188
    189                 <?php if ( bp_get_signup_allowed() ) : ?>
     189                <?php if ( bp_get_signup_allowed() || bp_get_members_invitations_allowed() ) : ?>
    190190                        <p><?php _e( 'Associate WordPress Pages with the following BuddyPress Registration pages.', 'buddypress' ); ?></p>
    191191                <?php else : ?>
    192192                        <?php if ( is_multisite() ) : ?>
    function bp_core_admin_slugs_options() { 
    209209                <table class="form-table">
    210210                        <tbody>
    211211
    212                                 <?php if ( bp_get_signup_allowed() ) : foreach ( $static_pages as $name => $label ) : ?>
     212                                <?php if ( bp_get_signup_allowed() || bp_get_members_invitations_allowed() ) : foreach ( $static_pages as $name => $label ) : ?>
    213213
    214214                                        <tr valign="top">
    215215                                                <th scope="row">
  • src/bp-core/bp-core-functions.php

    diff --git src/bp-core/bp-core-functions.php src/bp-core/bp-core-functions.php
    index c1481135e..d626a38da 100644
    function bp_core_add_page_mappings( $components, $existing = 'keep' ) { 
    693693
    694694        // Register and Activate are not components, but need pages when
    695695        // registration is enabled.
    696         if ( bp_get_signup_allowed() ) {
     696        if ( bp_get_signup_allowed() || bp_get_members_invitations_allowed()  ) {
    697697                foreach ( array( 'register', 'activate' ) as $slug ) {
    698698                        if ( ! isset( $pages[ $slug ] ) ) {
    699699                                $pages_to_create[ $slug ] = $page_titles[ $slug ];
    function bp_send_email( $email_type, $to, $args = array() ) { 
    31533153        // From, subject, content are set automatically.
    31543154        if ( 'settings-verify-email-change' === $email_type && isset( $args['tokens']['displayname'] ) ) {
    31553155                $email->set_to( $to, $args['tokens']['displayname'] );
     3156        // Emails sent to nonmembers will have no recipient.name populated.
     3157        } else if ( 'bp-members-invitation' === $email_type ) {
     3158                $email->set_to( $to, $to );
    31563159        } else {
    31573160                $email->set_to( $to );
    31583161        }
    function bp_email_get_schema() { 
    34883491                        /* translators: do not remove {} brackets or translate its contents. */
    34893492                        'post_title'   => __( '[{{{site.name}}}] You have an invitation to the group: "{{group.name}}"', 'buddypress' ),
    34903493                        /* translators: do not remove {} brackets or translate its contents. */
    3491                         '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' ),
     3494                        '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' ),
    34923495                        /* translators: do not remove {} brackets or translate its contents. */
    3493                         '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' ),
     3496                        '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' ),
    34943497                ),
    34953498                'groups-member-promoted' => array(
    34963499                        /* translators: do not remove {} brackets or translate its contents. */
    function bp_email_get_schema() { 
    35403543                        /* translators: do not remove {} brackets or translate its contents. */
    35413544                        'post_excerpt' => __( "Your membership request for the group \"{{group.name}}\" has been rejected.\n\nTo request membership again, visit: {{{group.url}}}", 'buddypress' ),
    35423545                ),
     3546                'bp-members-invitation' => array(
     3547                        /* translators: do not remove {} brackets or translate its contents. */
     3548                        'post_title'   => __( '[{{{site.name}}}] You have an invitation to the site: "{{network.name}}"', 'buddypress' ),
     3549                        /* translators: do not remove {} brackets or translate its contents. */
     3550                        'post_content' => __( "<a href=\"{{{inviter.url}}}\">{{inviter.name}}</a> has invited you to join the site: &quot;{{network.name}}&quot;.\n\n{{invite.message}}\n\n<a href=\"{{{invites.url}}}\">Go here to accept your invitation</a> or <a href=\"{{{network.url}}}\">visit the site</a> to learn more.", 'buddypress' ),
     3551                        /* translators: do not remove {} brackets or translate its contents. */
     3552                        'post_excerpt' => __( "{{inviter.name}} has invited you to join the site: \"{{network.name}}\".\n\n{{invite.message}}\n\nTo accept your invitation, visit: {{{invites.url}}}\n\nTo learn more about the site, visit: {{{network.url}}}.\nTo view {{inviter.name}}'s profile, visit: {{{inviter.url}}}", 'buddypress' ),
     3553                ),
    35433554        ) );
    35443555}
    35453556
    function bp_email_get_type_schema( $field = 'description' ) { 
    36813692                ),
    36823693        );
    36833694
     3695        $members_invitation = array(
     3696                'description'   => __( 'A site member has sent a site invitation to the recipient.', 'buddypress' ),
     3697                'unsubscribe'   => array(
     3698                        'meta_key'      => 'notification_bp_members_invite',
     3699                        'message'       => __( 'You will no longer receive emails when you are invited to join a site.', 'buddypress' ),
     3700                ),
     3701        );
     3702
    36843703        $types = array(
    36853704                'activity-comment'                   => $activity_comment,
    36863705                'activity-comment-author'            => $activity_comment_author,
    function bp_email_get_type_schema( $field = 'description' ) { 
    36983717                'settings-verify-email-change'       => $settings_verify_email_change,
    36993718                'groups-membership-request-accepted' => $groups_membership_request_accepted,
    37003719                'groups-membership-request-rejected' => $groups_membership_request_rejected,
     3720                'bp-members-invitation'              => $members_invitation,
    37013721        );
    37023722
    37033723        if ( $field !== 'all' ) {
  • src/bp-core/bp-core-template.php

    diff --git src/bp-core/bp-core-template.php src/bp-core/bp-core-template.php
    index 9fc92249a..c462cc799 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 6.0.0
     2254 *
     2255 * @return bool True if the current page is an Invitations screen.
     2256 */
     2257function bp_is_community_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 7.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_community_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 7.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 7.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 5457a816c..36ec1e0f3 100644
    class BP_Admin { 
    409409                        register_setting( 'buddypress', 'bp-disable-cover-image-uploads', 'intval' );
    410410                }
    411411
     412                // Community Invitations.
     413                if ( bp_is_active( 'members', 'invitations' ) ) {
     414                        add_settings_field( 'bp-enable-members-invitations', __( 'Invitations', 'buddypress' ), 'bp_admin_setting_callback_members_invitations', 'buddypress', 'bp_members' );
     415                        register_setting( 'buddypress', 'bp-enable-members-invitations', 'intval' );
     416                }
     417
    412418                /* XProfile Section **************************************************/
    413419
    414420                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 904fe3e4e..a8a128bfb 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 { 
    156161         *
    157162         * @param int $invitation_id ID of invitation to send.
    158163         *
    159          * @return int|bool The number of rows updated, or false on error.
     164         * @return bool The result of `run_send_action()`.
    160165         */
    161166        public function send_invitation_by_id( $invitation_id = 0 ) {
    162167                $updated = false;
    abstract class BP_Invitation_Manager { 
    194199                }
    195200
    196201                // Perform the send action.
    197                 $this->run_send_action( $invitation );
     202                $success = $this->run_send_action( $invitation );
    198203
    199                 $updated = BP_Invitation::mark_sent( $invitation->id );
     204                if ( $success ) {
     205                        BP_Invitation::mark_sent( $invitation->id );
     206                }
    200207
    201                 return $updated;
     208                return $success;
    202209        }
    203210
    204211        /**
    abstract class BP_Invitation_Manager { 
    307314         *
    308315         * @param int $request_id ID of request to send.
    309316         *
    310          * @return int|bool The number of rows updated, or false on error.
     317         * @return bool The result of `run_send_action()`.
    311318         */
    312319        public function send_request_notification_by_id( $request_id = 0 ) {
    313320                $updated = false;
    abstract class BP_Invitation_Manager { 
    340347                }
    341348
    342349                // Perform the send action.
    343                 $this->run_send_action( $request );
     350                $success = $this->run_send_action( $request );
    344351
    345                 $updated = BP_Invitation::mark_sent( $request->id );
     352                if ( $success ) {
     353                        BP_Invitation::mark_sent( $request->id );
     354                }
    346355
    347                 return $updated;
     356                return $success;
    348357        }
    349358
    350359        /** Retrieve ******************************************************************/
    abstract class BP_Invitation_Manager { 
    381390                return BP_Invitation::get( $args );
    382391        }
    383392
     393        /**
     394         * Get a count of the number of invitations that match provided filter parameters.
     395         *
     396         * @since 7.0.0
     397         *
     398         * @see BP_Invitation::get_total_count() for a description of accepted parameters.
     399         *
     400         * @return int Total number of invitations.
     401         */
     402        public function get_invitations_total_count( $args = array() ) {
     403                // Default to returning invitations, not requests.
     404                if ( empty( $args['type'] ) ) {
     405                        $args['type'] = 'invite';
     406                }
     407                // Use the class_name property value.
     408                $args['class'] = $this->class_name;
     409
     410                return BP_Invitation::get_total_count( $args );
     411        }
     412
    384413        /**
    385414         * Get requests, based on provided filter parameters.
    386415         *
    abstract class BP_Invitation_Manager { 
    688717                ) );
    689718        }
    690719
     720        /**
     721         * Delete an invitation by id.
     722         *
     723         * @since 7.0.0
     724         *
     725         * @param int $id ID of the invitation to delete.
     726         * @return int|bool Number of rows deleted on success, false on failure.
     727         */
     728        public function delete_by_id( $id ) {
     729                // Ensure that the invitation exists and was created by this class.
     730                $invite = new BP_Invitation( $id );
     731                if ( ! $invite->id || sanitize_key( $this->class_name ) !== $invite->class ) {
     732                        return false;
     733                }
     734
     735                return BP_Invitation::delete_by_id( $id );
     736        }
     737
     738
     739
    691740        /**
    692741         * This is where custom actions are added (in child classes)
    693742         * 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..40156dac9 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 7.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 * If the signup is the result of a member request, do not send the
     176 * activation email. We will send the activation email once the
     177 * the request has ben approved.
     178 *
     179 * @since 7.0.0
     180 *
     181 * @param array  $usermeta The field attributes.
     182 *
     183 * @return array $usermeta The field attributes.
     184 */
     185function bp_members_invitations_prevent_activation_emails_for_requests( $usermeta ) {
     186        // Stop the activation email from being sent if registration is by request only.
     187        // if "anyone can join is not true,"
     188        // @TODO
     189        if ( true ) {
     190
     191        }
     192        return $usermeta;
     193}
     194add_filter( 'bp_signup_usermeta', 'bp_members_invitations_prevent_activation_emails_for_requests', 10, 1 );
     195
     196/**
     197 * Do not allow the new user to change the email address
     198 * if they are accepting a community invitation.
     199 *
     200 * @since 7.0.0
     201 *
     202 * @param array  $attributes The field attributes.
     203 * @param string $name       The field name.
     204 *
     205 * @return array $attributes The field attributes.
     206 */
     207function bp_members_invitations_make_registration_email_input_readonly_if_invite( $attributes, $name ) {
     208        if ( 'email' === $name && bp_get_members_invitations_allowed() ) {
     209                $invite = bp_get_members_invitation_from_request();
     210                if ( $invite->id ) {
     211                        $attributes['readonly'] = 'readonly';
     212                }
     213        }
     214        return $attributes;
     215}
     216add_filter( 'bp_get_form_field_attributes', 'bp_members_invitations_make_registration_email_input_readonly_if_invite', 10, 2 );
     217
     218/**
     219 * Provide a more-specific welcome message if the new user
     220 * is accepting a network invitation.
     221 *
     222 * @since 7.0.0
     223 *
     224 * @return string $message The message text.
     225 */
     226function bp_members_invitations_get_registration_welcome_message() {
     227        $message = '';
     228        if ( ! bp_get_members_invitations_allowed() ) {
     229                return $message;
     230        }
     231        $invite = bp_get_members_invitation_from_request();
     232        if ( ! $invite->id ) {
     233                return $message;
     234        }
     235
     236        // Fetch the display names of all inviters to personalize the welcome message.
     237        $all_invites = bp_members_invitations_get_invites(
     238                array(
     239                        'invitee_email' => $invite->invitee_email,
     240                        'invite_sent'   => 'sent',
     241                )
     242        );
     243        $inviters = array();
     244        foreach ( $all_invites as $inv ) {
     245                $inviters[] = bp_core_get_user_displayname( $inv->inviter_id );
     246        }
     247
     248        if ( ! empty( $inviters ) ) {
     249                $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 ) );
     250        } else {
     251                $message = __( 'Welcome! You&#8217;ve been invited to join the site. ', 'buddypress' );
     252        }
     253        return $message;
     254}
     255
     256/**
     257 * Provide a more-specific "registration is disabled" message
     258 * if registration is available by invitation only.
     259 * Also provide failure note if new user is trying to accept
     260 * a network invitation but there's a problem.
     261 *
     262 * @since 7.0.0
     263 *
     264 * @return string $message The message text.
     265 */
     266function bp_members_invitations_get_modified_registration_disabled_message() {
     267        $message = '';
     268        if ( bp_get_members_invitations_allowed() ) {
     269                $message = __( 'Member registration is allowed by invitation only.', 'buddypress' );
     270                // Is the user trying to accept an invitation but something is wrong?
     271                if ( ! empty( $_GET['inv'] ) ) {
     272                        $message .= __( ' It looks like there is a problem with your invitation. Please try again.', 'buddypress' );
     273                }
     274        }
     275        return $message;
     276}
  • src/bp-members/bp-members-functions.php

    diff --git src/bp-members/bp-members-functions.php src/bp-members/bp-members-functions.php
    index 925759030..8f7f5c55b 100644
    function bp_members_avatar_upload_dir( $directory = 'avatars', $user_id = 0 ) { 
    30463046                'error'   => false
    30473047        ) );
    30483048}
     3049
     3050/**
     3051 * Get invitations to the BP community filtered by arguments.
     3052 *
     3053 * @since 7.0.0
     3054 *
     3055 * @param array $args     Invitation arguments.
     3056 *                        See BP_Invitation::get() for list.
     3057 *
     3058 * @return array $invites     Matching BP_Invitation objects.
     3059 */
     3060function bp_members_invitations_get_invites( $args = array() ) {
     3061        $invites_class = new BP_Members_Invitation_Manager();
     3062        return $invites_class->get_invitations( $args );
     3063}
     3064
     3065/**
     3066 * Invite a user to a BP community.
     3067 *
     3068 * @since 7.0.0
     3069 *
     3070 * @param array|string $args {
     3071 *     Array of arguments.
     3072 *     @type int    $invitee_email Email address of the user being invited.
     3073 *     @type int    $network_id    ID of the network to which the user is being invited.
     3074 *     @type int    $inviter_id    Optional. ID of the inviting user. Default:
     3075 *                                 ID of the logged-in user.
     3076 *     @type string $date_modified Optional. Modified date for the invitation.
     3077 *                                 Default: current date/time.
     3078 *     @type string $content       Optional. Message to invitee.
     3079 *     @type bool   $send_invite   Optional. Whether the invitation should be
     3080 *                                 sent now. Default: false.
     3081 * }
     3082 * @return bool True on success, false on failure.
     3083 */
     3084function bp_members_invitations_invite_user( $args ) {
     3085        $r = bp_parse_args( $args, array(
     3086                'invitee_email' => '',
     3087                'network_id'    => get_current_network_id(),
     3088                'inviter_id'    => bp_loggedin_user_id(),
     3089                'date_modified' => bp_core_current_time(),
     3090                'content'       => '',
     3091                'send_invite'   => 0
     3092        ), 'community_invite_user' );
     3093
     3094        $inv_args = array(
     3095                'invitee_email' => $r['invitee_email'],
     3096                'item_id'       => $r['network_id'],
     3097                'inviter_id'    => $r['inviter_id'],
     3098                'date_modified' => $r['date_modified'],
     3099                'content'       => $r['content'],
     3100                'send_invite'   => $r['send_invite']
     3101        );
     3102
     3103        // Create the invitataion.
     3104        $invites_class = new BP_Members_Invitation_Manager();
     3105        $created       = $invites_class->add_invitation( $inv_args );
     3106
     3107        /**
     3108         * Fires after the creation of a new network invite.
     3109         *
     3110         * @since 7.0.0
     3111         *
     3112         * @param array    $r       Array of parsed arguments for the network invite.
     3113         * @param int|bool $created The ID of the invitation or false if it couldn't be created.
     3114         */
     3115        do_action( 'bp_members_invitations_invite_user', $r, $created );
     3116
     3117        return $created;
     3118}
     3119
     3120/**
     3121 * Resend a community invitation email by id.
     3122 *
     3123 * @since 7.0.0
     3124 *
     3125 * @param int $id ID of the invitation to resend.
     3126 * @return bool True on success, false on failure.
     3127 */
     3128function bp_members_invitation_resend_by_id( $id = 0 ) {
     3129
     3130        // Find the invitation before deleting it.
     3131        $existing_invite = new BP_Invitation( $id );
     3132        $invites_class   = new BP_Members_Invitation_Manager();
     3133        $success         = $invites_class->send_invitation_by_id( $id );
     3134
     3135        if ( ! $success ) {
     3136                return $success;
     3137        }
     3138
     3139        /**
     3140         * Fires after the re-sending of a network invite.
     3141         *
     3142         * @since 7.0.0
     3143         *
     3144         * @param BP_Invitation $existing_invite The invitation that was resent.
     3145         */
     3146        do_action( 'bp_members_invitations_resend_invitation', $existing_invite );
     3147
     3148        return $success;
     3149}
     3150
     3151/**
     3152 * Delete a community invitation by id.
     3153 *
     3154 * @since 7.0.0
     3155 *
     3156 * @param int $id ID of the invitation to delete.
     3157 * @return int|bool Number of rows deleted on success, false on failure.
     3158 */
     3159function bp_members_invitations_delete_by_id( $id = 0 ) {
     3160
     3161        // Find the invitation before deleting it.
     3162        $existing_invite = new BP_Invitation( $id );
     3163        $invites_class   = new BP_Members_Invitation_Manager();
     3164        $success         = $invites_class->delete_by_id( $id );
     3165
     3166        if ( ! $success ) {
     3167                return $success;
     3168        }
     3169
     3170        // Run a different action depending on the status of the invite.
     3171        if ( ! $existing_invite->invite_sent ) {
     3172                /**
     3173                 * Fires after the deletion of an unsent community invite.
     3174                 *
     3175                 * @since 7.0.0
     3176                 *
     3177                 * @param BP_Invitation $existing_invite The invitation to be deleted.
     3178                 */
     3179                do_action( 'bp_members_invitations_canceled_invitation', $existing_invite );
     3180        } else if ( ! $existing_invite->accepted ) {
     3181                /**
     3182                 * Fires after the deletion of a sent, but not yet accepted, community invite.
     3183                 *
     3184                 * @since 7.0.0
     3185                 *
     3186                 * @param BP_Invitation $existing_invite The invitation to be deleted.
     3187                 */
     3188                do_action( 'bp_members_invitations_revoked_invitation', $existing_invite );
     3189        } else {
     3190                /**
     3191                 * Fires after the deletion of a sent and accepted community invite.
     3192                 *
     3193                 * @since 7.0.0
     3194                 *
     3195                 * @param BP_Invitation $existing_invite The invitation to be deleted.
     3196                 */
     3197                do_action( 'bp_members_invitations_deleted_invitation', $existing_invite );
     3198        }
     3199
     3200        return $success;
     3201}
     3202
     3203/**
     3204 * Delete a network invitation.
     3205 *
     3206 * @since 7.0.0
     3207 *
     3208 * @param intring $args {
     3209 *     Array of arguments.
     3210 *     @type int|array $id            Id(s) of the invitation(s) to remove.
     3211 *     @type int       $invitee_email Email address of the user being invited.
     3212 *     @type int       $network_id    ID of the network to which the user is being invited.
     3213 *     @type int       $inviter_id    ID of the inviting user.
     3214 *     @type int       $accepted      Whether the invitation has been accepted yet.
     3215 *     @type int       $invite_sent   Whether the invitation has been sent yet.
     3216 * }
     3217 * @return bool True if all were deleted.
     3218 */
     3219function bp_members_invitations_delete_invites( $args ) {
     3220        $r = bp_parse_args( $args, array(
     3221                'id'            => 0,
     3222                'invitee_email' => '',
     3223                'network_id'    => get_current_network_id(),
     3224                'inviter_id'    => null,
     3225                'accepted'      => null,
     3226                'invite_sent'   => null
     3227        ), 'community_invitation_delete_invites' );
     3228
     3229        $inv_args = array(
     3230                'id'            => $r['id'],
     3231                'invitee_email' => $r['invitee_email'],
     3232                'item_id'       => $r['network_id'],
     3233                'inviter_id'    => $r['inviter_id'],
     3234        );
     3235
     3236        // Find the invitation(s).
     3237        $invites_class = new BP_Members_Invitation_Manager();
     3238        $invites       = $invites_class->get_invitations( $inv_args );
     3239        $total_count   = count( $invites );
     3240
     3241        // Loop through, deleting each invitation.
     3242        $deleted = 0;
     3243        foreach ( $invites as $invite ) {
     3244                $success = bp_members_invitations_delete_by_id( $invite->id );
     3245                if ( $success ) {
     3246                        $deleted++;
     3247                }
     3248        }
     3249
     3250        return $deleted === $total_count;
     3251}
     3252
     3253/**
     3254 * Get hash based on details of a community invitation and the inviter.
     3255 *
     3256 * @since 7.0.0
     3257 *
     3258 * @param BP_Invitation object $invitation Invitation to create hash from.
     3259 *
     3260 * @return string $hash Calculated sha1 hash.
     3261 */
     3262function bp_members_invitations_get_hash( BP_Invitation $invitation ) {
     3263        $hash = false;
     3264
     3265        if ( ! empty( $invitation->id ) ) {
     3266                $inviter_ud = get_userdata( $invitation->inviter_id );
     3267                if ( $inviter_ud ) {
     3268                        /*
     3269                         * Use some inviter details as part of the salt so that invitations from
     3270                         * users who are subsequently marked as spam will be invalidated.
     3271                         */
     3272                        $hash = wp_hash( "{$invitation->inviter_id}:{$invitation->date_modified}", "{$inviter_ud->user_status}:{$inviter_ud->user_registered}" );
     3273                }
     3274        }
     3275
     3276        // If there's a problem, return a string that will change and thus fail.
     3277        if ( ! $hash ) {
     3278                $hash = wp_generate_password( 32, false );
     3279        }
     3280
     3281        /**
     3282         * Filters the hash calculated by the invitation details.
     3283         *
     3284         * @since 7.0.0
     3285         *
     3286         * @param string $hash Calculated sha1 hash.
     3287         * @param BP_Invitation object $invitation Invitation hash was created from.
     3288         */
     3289        return apply_filters( 'bp_members_invitations_get_hash', $hash, $invitation );
     3290}
     3291
     3292/**
     3293 * Get the current invitation specified by the $_GET parameters.
     3294 *
     3295 * @since 7.0.0
     3296 *
     3297 * @return BP_Invitation $invite Invitation specified by the $_GET parameters.
     3298 */
     3299function bp_get_members_invitation_from_request() {
     3300        $invites_class = new BP_Members_Invitation_Manager();
     3301        $invite        = $invites_class->get_by_id( 0 );
     3302
     3303        if ( bp_get_members_invitations_allowed() && ! empty( $_GET['inv'] ) ) {
     3304                // Check to make sure the passed hash matches a calculated hash.
     3305                $maybe_invite = $invites_class->get_by_id( absint( $_GET['inv'] ) );
     3306                $hash = bp_members_invitations_get_hash( $maybe_invite );
     3307                if ( $_GET['ih'] === $hash ) {
     3308                        $invite = $maybe_invite;
     3309                }
     3310        }
     3311
     3312        /**
     3313         * Filters the invitation specified by the $_GET parameters.
     3314         *
     3315         * @since 7.0.0
     3316         *
     3317         * @param BP_Invitation $invite Invitation specified by the $_GET parameters.
     3318         */
     3319        return apply_filters( 'bp_get_members_invitation_from_request', $invite );
     3320}
  • 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..a91d82377
    - +  
     1<?php
     2/**
     3 * BuddyPress Member Activity
     4 *
     5 * @package BuddyPress
     6 * @subpackage MembersActivity
     7 * @since 2.2.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
  • new file src/bp-members/bp-members-notifications.php

    diff --git src/bp-members/bp-members-notifications.php src/bp-members/bp-members-notifications.php
    new file mode 100644
    index 000000000..c544e87d8
    - +  
     1<?php
     2/**
     3 * BuddyPress Members Notification Functions.
     4 *
     5 * These functions handle the recording, deleting and formatting of notifications
     6 * for the user and for this specific component.
     7 *
     8 * @package BuddyPress
     9 * @subpackage Members
     10 * @since 1.0.0
     11 */
     12
     13// Exit if accessed directly.
     14defined( 'ABSPATH' ) || exit;
     15
     16/** Emails ********************************************************************/
     17
     18/**
     19 * Notify site admins about new membership request.
     20 *
     21 * @since 1.0.0
     22 *
     23 * @param int $requesting_user_id ID of the user requesting site membership.
     24 * @param int $admin_id           ID of the site admin.
     25 * @param int $invitation_id      ID of the network invitation object.
     26 */
     27function bp_members_new_membership_request( $requesting_user_id = 0, $admin_id = 0, $membership_id = 0 ) {
     28
     29        // @TODO
     30        return;
     31
     32        // Trigger a BuddyPress Notification.
     33        if ( bp_is_active( 'notifications' ) ) {
     34                bp_notifications_add_notification( array(
     35                        'user_id'           => $admin_id,
     36                        'item_id'           => $group_id,
     37                        'secondary_item_id' => $requesting_user_id,
     38                        'component_name'    => buddypress()->members->id,
     39                        'component_action'  => 'new_membership_request',
     40                ) );
     41        }
     42
     43        // Bail if member opted out of receiving this email.
     44        if ( 'no' === bp_get_user_meta( $admin_id, 'notification_members_membership_request', true ) ) {
     45                return;
     46        }
     47
     48        $unsubscribe_args = array(
     49                'user_id'           => $admin_id,
     50                'notification_type' => 'members-membership-request',
     51        );
     52
     53        $request_message = '';
     54        $requests = groups_get_requests( $args = array(
     55                'user_id'    => $requesting_user_id,
     56                'item_id'    => $group_id,
     57        ) );
     58        if ( $requests ) {
     59                $request_message = current( $requests )->content;
     60        }
     61
     62        $group = groups_get_group( $group_id );
     63        $args  = array(
     64                'tokens' => array(
     65                        'admin.id'             => $admin_id,
     66                        'group'                => $group,
     67                        'group.name'           => $group->name,
     68                        'group.id'             => $group_id,
     69                        'group-requests.url'   => esc_url( bp_get_group_permalink( $group ) . 'admin/membership-requests' ),
     70                        'profile.url'          => esc_url( bp_core_get_user_domain( $requesting_user_id ) ),
     71                        'requesting-user.id'   => $requesting_user_id,
     72                        'requesting-user.name' => bp_core_get_user_displayname( $requesting_user_id ),
     73                        'request.message'      => $request_message,
     74                        'unsubscribe'          => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
     75                ),
     76        );
     77        bp_send_email( 'network-membership-request', (int) $admin_id, $args );
     78}
     79
     80/**
     81 * Notify member about their group membership request.
     82 *
     83 * @since 1.0.0
     84 *
     85 * @param int  $requesting_user_id ID of the user requesting group membership.
     86 * @param int  $group_id           ID of the group.
     87 * @param bool $accepted           Optional. Whether the membership request was accepted.
     88 *                                 Default: true.
     89 */
     90function bp_members_membership_request_completed( $requesting_user_id = 0, $group_id = 0, $accepted = true ) {
     91
     92        // @TODO
     93        return;
     94
     95        // Trigger a BuddyPress Notification.
     96        if ( bp_is_active( 'notifications' ) ) {
     97
     98                // What type of acknowledgement.
     99                $type = ! empty( $accepted ) ? 'membership_request_accepted' : 'membership_request_rejected';
     100
     101                bp_notifications_add_notification( array(
     102                        'user_id'           => $requesting_user_id,
     103                        'item_id'           => $group_id,
     104                        'component_name'    => buddypress()->groups->id,
     105                        'component_action'  => $type,
     106                ) );
     107        }
     108
     109        // Bail if member opted out of receiving this email.
     110        if ( 'no' === bp_get_user_meta( $requesting_user_id, 'notification_membership_request_completed', true ) ) {
     111                return;
     112        }
     113
     114        $group = groups_get_group( $group_id );
     115        $args  = array(
     116                'tokens' => array(
     117                        'group'              => $group,
     118                        'group.id'           => $group_id,
     119                        'group.name'         => $group->name,
     120                        'group.url'          => esc_url( bp_get_group_permalink( $group ) ),
     121                        'requesting-user.id' => $requesting_user_id,
     122                ),
     123        );
     124
     125        if ( ! empty( $accepted ) ) {
     126
     127                $unsubscribe_args = array(
     128                        'user_id'           => $requesting_user_id,
     129                        'notification_type' => 'groups-membership-request-accepted',
     130                );
     131
     132                $args['tokens']['unsubscribe'] = esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) );
     133
     134                bp_send_email( 'groups-membership-request-accepted', (int) $requesting_user_id, $args );
     135
     136        } else {
     137
     138                $unsubscribe_args = array(
     139                        'user_id'           => $requesting_user_id,
     140                        'notification_type' => 'groups-membership-request-rejected',
     141                );
     142
     143                $args['tokens']['unsubscribe'] = esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) );
     144
     145                bp_send_email( 'groups-membership-request-rejected', (int) $requesting_user_id, $args );
     146        }
     147}
     148// @TODO
     149// add_action( 'groups_membership_accepted', 'groups_notification_membership_request_completed', 10, 3 );
     150// add_action( 'groups_membership_rejected', 'groups_notification_membership_request_completed', 10, 3 );
     151
     152/** Notifications *************************************************************/
     153
     154/**
     155 * Format notifications for the Groups component.
     156 *
     157 * @since 1.0.0
     158 *
     159 * @param string $action            The kind of notification being rendered.
     160 * @param int    $item_id           The primary item ID.
     161 * @param int    $secondary_item_id The secondary item ID.
     162 * @param int    $total_items       The total number of messaging-related notifications
     163 *                                  waiting for the user.
     164 * @param string $format            'string' for BuddyBar-compatible notifications; 'array'
     165 *                                  for WP Toolbar. Default: 'string'.
     166 * @return string
     167 */
     168function bp_members_format_notifications( $action, $item_id, $secondary_item_id, $total_items, $format = 'string' ) {
     169
     170        // @TODO
     171        switch ( $action ) {
     172                case 'new_membership_request':
     173                        $group_id = $item_id;
     174                        $requesting_user_id = $secondary_item_id;
     175
     176                        $group = groups_get_group( $group_id );
     177                        $group_link = bp_get_group_permalink( $group );
     178                        $amount = 'single';
     179
     180                        // Set up the string and the filter
     181                        // because different values are passed to the filters,
     182                        // we'll return values inline.
     183                        if ( (int) $total_items > 1 ) {
     184                                $text = sprintf( __( '%1$d new membership requests for the group "%2$s"', 'buddypress' ), (int) $total_items, $group->name );
     185                                $amount = 'multiple';
     186                                $notification_link = $group_link . 'admin/membership-requests/?n=1';
     187
     188                                if ( 'string' == $format ) {
     189
     190                                        /**
     191                                         * Filters groups multiple new membership request notification for string format.
     192                                         *
     193                                         * This is a dynamic filter that is dependent on item count and action.
     194                                         * Complete filter - bp_groups_multiple_new_membership_requests_notification.
     195                                         *
     196                                         * @since 1.0.0
     197                                         *
     198                                         * @param string $string            HTML anchor tag for request.
     199                                         * @param string $group_link        The permalink for the group.
     200                                         * @param int    $total_items       Total number of membership requests.
     201                                         * @param string $group->name       Name of the group.
     202                                         * @param string $text              Notification content.
     203                                         * @param string $notification_link The permalink for notification.
     204                                         */
     205                                        return apply_filters( 'bp_groups_' . $amount . '_' . $action . 's_notification', '<a href="' . $notification_link . '">' . $text . '</a>', $group_link, $total_items, $group->name, $text, $notification_link );
     206                                } else {
     207
     208                                        /**
     209                                         * Filters groups multiple new membership request notification for any non-string format.
     210                                         *
     211                                         * This is a dynamic filter that is dependent on item count and action.
     212                                         * Complete filter - bp_groups_multiple_new_membership_requests_notification.
     213                                         *
     214                                         * @since 1.0.0
     215                                         *
     216                                         * @param array  $array             Array holding permalink and content for notification.
     217                                         * @param string $group_link        The permalink for the group.
     218                                         * @param int    $total_items       Total number of membership requests.
     219                                         * @param string $group->name       Name of the group.
     220                                         * @param string $text              Notification content.
     221                                         * @param string $notification_link The permalink for notification.
     222                                         */
     223                                        return apply_filters( 'bp_groups_' . $amount . '_' . $action . 's_notification', array(
     224                                                'link' => $notification_link,
     225                                                'text' => $text
     226                                        ), $group_link, $total_items, $group->name, $text, $notification_link );
     227                                }
     228                        } else {
     229                                $user_fullname = bp_core_get_user_displayname( $requesting_user_id );
     230                                $text = sprintf( __( '%s requests group membership', 'buddypress' ), $user_fullname );
     231                                $notification_link = $group_link . 'admin/membership-requests/?n=1';
     232
     233                                if ( 'string' == $format ) {
     234
     235                                        /**
     236                                         * Filters groups single new membership request notification for string format.
     237                                         *
     238                                         * This is a dynamic filter that is dependent on item count and action.
     239                                         * Complete filter - bp_groups_single_new_membership_request_notification.
     240                                         *
     241                                         * @since 1.0.0
     242                                         *
     243                                         * @param string $string            HTML anchor tag for request.
     244                                         * @param string $group_link        The permalink for the group.
     245                                         * @param string $user_fullname     Full name of requesting user.
     246                                         * @param string $group->name       Name of the group.
     247                                         * @param string $text              Notification content.
     248                                         * @param string $notification_link The permalink for notification.
     249                                         */
     250                                        return apply_filters( 'bp_groups_' . $amount . '_' . $action . '_notification', '<a href="' . $notification_link . '">' . $text . '</a>', $group_link, $user_fullname, $group->name, $text, $notification_link );
     251                                } else {
     252
     253                                        /**
     254                                         * Filters groups single new membership request notification for any non-string format.
     255                                         *
     256                                         * This is a dynamic filter that is dependent on item count and action.
     257                                         * Complete filter - bp_groups_single_new_membership_request_notification.
     258                                         *
     259                                         * @since 1.0.0
     260                                         *
     261                                         * @param array  $array             Array holding permalink and content for notification.
     262                                         * @param string $group_link        The permalink for the group.
     263                                         * @param string $user_fullname     Full name of requesting user.
     264                                         * @param string $group->name       Name of the group.
     265                                         * @param string $text              Notification content.
     266                                         * @param string $notification_link The permalink for notification.
     267                                         */
     268                                        return apply_filters( 'bp_groups_' . $amount . '_' . $action . '_notification', array(
     269                                                'link' => $notification_link,
     270                                                'text' => $text
     271                                        ), $group_link, $user_fullname, $group->name, $text, $notification_link );
     272                                }
     273                        }
     274
     275                        break;
     276
     277                case 'membership_request_accepted':
     278                        $group_id = $item_id;
     279
     280                        $group = groups_get_group( $group_id );
     281                        $group_link = bp_get_group_permalink( $group );
     282                        $amount = 'single';
     283
     284                        if ( (int) $total_items > 1 ) {
     285                                $text = sprintf( __( '%d accepted group membership requests', 'buddypress' ), (int) $total_items, $group->name );
     286                                $amount = 'multiple';
     287                                $notification_link = trailingslashit( bp_loggedin_user_domain() . bp_get_groups_slug() ) . '?n=1';
     288
     289                                if ( 'string' == $format ) {
     290
     291                                        /**
     292                                         * Filters multiple accepted group membership requests notification for string format.
     293                                         * Complete filter - bp_groups_multiple_membership_request_accepted_notification.
     294                                         *
     295                                         * @since 1.0.0
     296                                         *
     297                                         * @param string $string            HTML anchor tag for notification.
     298                                         * @param int    $total_items       Total number of accepted requests.
     299                                         * @param string $group->name       Name of the group.
     300                                         * @param string $text              Notification content.
     301                                         * @param string $notification_link The permalink for notification.
     302                                         */
     303                                        return apply_filters( 'bp_groups_' . $amount . '_' . $action . '_notification', '<a href="' . $notification_link . '">' . $text . '</a>', $total_items, $group->name, $text, $notification_link );
     304                                } else {
     305
     306                                        /**
     307                                         * Filters multiple accepted group membership requests notification for non-string format.
     308                                         * Complete filter - bp_groups_multiple_membership_request_accepted_notification.
     309                                         *
     310                                         * @since 1.0.0
     311                                         *
     312                                         * @param array  $array             Array holding permalink and content for notification
     313                                         * @param int    $total_items       Total number of accepted requests.
     314                                         * @param string $group->name       Name of the group.
     315                                         * @param string $text              Notification content.
     316                                         * @param string $notification_link The permalink for notification.
     317                                         */
     318                                        return apply_filters( 'bp_groups_' . $amount . '_' . $action . '_notification', array(
     319                                                'link' => $notification_link,
     320                                                'text' => $text
     321                                        ), $total_items, $group->name, $text, $notification_link );
     322                                }
     323                        } else {
     324                                $text = sprintf( __( 'Membership for group "%s" accepted', 'buddypress' ), $group->name );
     325                                $filter = 'bp_groups_single_membership_request_accepted_notification';
     326                                $notification_link = $group_link . '?n=1';
     327
     328                                if ( 'string' == $format ) {
     329
     330                                        /**
     331                                         * Filters single accepted group membership request notification for string format.
     332                                         * Complete filter - bp_groups_single_membership_request_accepted_notification.
     333                                         *
     334                                         * @since 1.0.0
     335                                         *
     336                                         * @param string $string            HTML anchor tag for notification.
     337                                         * @param string $group_link        The permalink for the group.
     338                                         * @param string $group->name       Name of the group.
     339                                         * @param string $text              Notification content.
     340                                         * @param string $notification_link The permalink for notification.
     341                                         */
     342                                        return apply_filters( 'bp_groups_' . $amount . '_' . $action . '_notification', '<a href="' . $notification_link . '">' . $text . '</a>', $group_link, $group->name, $text, $notification_link );
     343                                } else {
     344
     345                                        /**
     346                                         * Filters single accepted group membership request notification for non-string format.
     347                                         * Complete filter - bp_groups_single_membership_request_accepted_notification.
     348                                         *
     349                                         * @since 1.0.0
     350                                         *
     351                                         * @param array  $array             Array holding permalink and content for notification.
     352                                         * @param string $group_link        The permalink for the group.
     353                                         * @param string $group->name       Name of the group.
     354                                         * @param string $text              Notification content.
     355                                         * @param string $notification_link The permalink for notification.
     356                                         */
     357                                        return apply_filters( $filter, array(
     358                                                'link' => $notification_link,
     359                                                'text' => $text
     360                                        ), $group_link, $group->name, $text, $notification_link );
     361                                }
     362                        }
     363
     364                        break;
     365
     366                case 'membership_request_rejected':
     367                        $group_id = $item_id;
     368
     369                        $group = groups_get_group( $group_id );
     370                        $group_link = bp_get_group_permalink( $group );
     371                        $amount = 'single';
     372
     373                        if ( (int) $total_items > 1 ) {
     374                                $text = sprintf( __( '%d rejected group membership requests', 'buddypress' ), (int) $total_items, $group->name );
     375                                $amount = 'multiple';
     376                                $notification_link = trailingslashit( bp_loggedin_user_domain() . bp_get_groups_slug() ) . '?n=1';
     377
     378                                if ( 'string' == $format ) {
     379
     380                                        /**
     381                                         * Filters multiple rejected group membership requests notification for string format.
     382                                         * Complete filter - bp_groups_multiple_membership_request_rejected_notification.
     383                                         *
     384                                         * @since 1.0.0
     385                                         *
     386                                         * @param string $string            HTML anchor tag for notification.
     387                                         * @param int    $total_items       Total number of rejected requests.
     388                                         * @param string $group->name       Name of the group.
     389                                         * @param string $text              Notification content.
     390                                         * @param string $notification_link The permalink for notification.
     391                                         */
     392                                        return apply_filters( 'bp_groups_' . $amount . '_' . $action . '_notification', '<a href="' . $notification_link . '">' . $text . '</a>', $total_items, $group->name );
     393                                } else {
     394
     395                                        /**
     396                                         * Filters multiple rejected group membership requests notification for non-string format.
     397                                         * Complete filter - bp_groups_multiple_membership_request_rejected_notification.
     398                                         *
     399                                         * @since 1.0.0
     400                                         *
     401                                         * @param array  $array             Array holding permalink and content for notification.
     402                                         * @param int    $total_items       Total number of rejected requests.
     403                                         * @param string $group->name       Name of the group.
     404                                         * @param string $text              Notification content.
     405                                         * @param string $notification_link The permalink for notification.
     406                                         */
     407                                        return apply_filters( 'bp_groups_' . $amount . '_' . $action . '_notification', array(
     408                                                'link' => $notification_link,
     409                                                'text' => $text
     410                                        ), $total_items, $group->name, $text, $notification_link );
     411                                }
     412                        } else {
     413                                $text = sprintf( __( 'Membership for group "%s" rejected', 'buddypress' ), $group->name );
     414                                $notification_link = $group_link . '?n=1';
     415
     416                                if ( 'string' == $format ) {
     417
     418                                        /**
     419                                         * Filters single rejected group membership requests notification for string format.
     420                                         * Complete filter - bp_groups_single_membership_request_rejected_notification.
     421                                         *
     422                                         * @since 1.0.0
     423                                         *
     424                                         * @param string $string            HTML anchor tag for notification.
     425                                         * @param int    $group_link        The permalink for the group.
     426                                         * @param string $group->name       Name of the group.
     427                                         * @param string $text              Notification content.
     428                                         * @param string $notification_link The permalink for notification.
     429                                         */
     430                                        return apply_filters( 'bp_groups_' . $amount . '_' . $action . '_notification', '<a href="' . $notification_link . '">' . $text . '</a>', $group_link, $group->name, $text, $notification_link );
     431                                } else {
     432
     433                                        /**
     434                                         * Filters single rejected group membership requests notification for non-string format.
     435                                         * Complete filter - bp_groups_single_membership_request_rejected_notification.
     436                                         *
     437                                         * @since 1.0.0
     438                                         *
     439                                         * @param array  $array             Array holding permalink and content for notification.
     440                                         * @param int    $group_link        The permalink for the group.
     441                                         * @param string $group->name       Name of the group.
     442                                         * @param string $text              Notification content.
     443                                         * @param string $notification_link The permalink for notification.
     444                                         */
     445                                        return apply_filters( 'bp_groups_' . $amount . '_' . $action . '_notification', array(
     446                                                'link' => $notification_link,
     447                                                'text' => $text
     448                                        ), $group_link, $group->name, $text, $notification_link );
     449                                }
     450                        }
     451
     452                        break;
     453
     454                default:
     455
     456                        /**
     457                         * Filters plugin-added group-related custom component_actions.
     458                         *
     459                         * @since 2.4.0
     460                         *
     461                         * @param string $notification      Null value.
     462                         * @param int    $item_id           The primary item ID.
     463                         * @param int    $secondary_item_id The secondary item ID.
     464                         * @param int    $total_items       The total number of messaging-related notifications
     465                         *                                  waiting for the user.
     466                         * @param string $format            'string' for BuddyBar-compatible notifications;
     467                         *                                  'array' for WP Toolbar.
     468                         */
     469                        $custom_action_notification = apply_filters( 'bp_members_' . $action . '_notification', null, $item_id, $secondary_item_id, $total_items, $format );
     470
     471                        if ( ! is_null( $custom_action_notification ) ) {
     472                                return $custom_action_notification;
     473                        }
     474
     475                        break;
     476        }
     477
     478        /**
     479         * Fires right before returning the formatted group notifications.
     480         *
     481         * @since 1.0.0
     482         *
     483         * @param string $action            The type of notification being rendered.
     484         * @param int    $item_id           The primary item ID.
     485         * @param int    $secondary_item_id The secondary item ID.
     486         * @param int    $total_items       Total amount of items to format.
     487         */
     488        do_action( 'members_format_notifications', $action, $item_id, $secondary_item_id, $total_items );
     489
     490        return false;
     491}
     492
     493/**
     494 * Mark notifications read when a member's group membership request is granted.
     495 *
     496 * @since 2.8.0
     497 *
     498 * @param int $user_id  ID of the user.
     499 * @param int $group_id ID of the group.
     500 */
     501function bp_members_accept_request_mark_notifications( $user_id, $group_id ) {
     502        // @TODO
     503        if ( bp_is_active( 'notifications' ) ) {
     504                // First null parameter marks read for all admins.
     505                bp_notifications_mark_notifications_by_item_id( null, $group_id, buddypress()->groups->id, 'new_membership_request', $user_id );
     506        }
     507}
     508// @TODO
     509// add_action( 'groups_membership_accepted', 'bp_groups_accept_request_mark_notifications', 10, 2 );
     510// add_action( 'groups_membership_rejected', 'bp_groups_accept_request_mark_notifications', 10, 2 );
     511
     512/**
     513 * Render the group settings fields on the Notification Settings page.
     514 *
     515 * @since 6.0.0
     516 */
     517function bp_members_screen_notification_settings() {
     518
     519        if ( ! bp_user_can( bp_displayed_user_id(), 'manage_network_membership_requests' ) ) {
     520                return;
     521        }
     522
     523        if ( ! $network_membership_request = bp_get_user_meta( bp_displayed_user_id(), 'notification_network_membership_request', true ) ) {
     524                $network_membership_request = 'yes';
     525        }
     526
     527        ?>
     528
     529        <table class="notification-settings" id="bp-members-notification-settings">
     530                <thead>
     531                        <tr>
     532                                <th class="icon"></th>
     533                                <th class="title"><?php _ex( 'Members', 'Member component settings on notification settings page', 'buddypress' ) ?></th>
     534                                <th class="yes"><?php _e( 'Yes', 'buddypress' ) ?></th>
     535                                <th class="no"><?php _e( 'No', 'buddypress' )?></th>
     536                        </tr>
     537                </thead>
     538
     539                <tbody>
     540                        <tr id="bp-members-notification-settings-invitation">
     541                                <td></td>
     542                                <td><?php _ex( 'A user requests membership on this network', 'Member component settings on notification settings page','buddypress' ) ?></td>
     543                                <td class="yes"><input type="radio" name="notifications[notification_network_membership_request]" id="notification_network_membership_request-yes" value="yes" <?php checked( $network_membership_request, 'yes', true ) ?>/><label for="notification_network_membership_request-yes" class="bp-screen-reader-text"><?php
     544                                        /* translators: accessibility text */
     545                                        _e( 'Yes, send email', 'buddypress' );
     546                                ?></label></td>
     547                                <td class="no"><input type="radio" name="notifications[notification_network_membership_request]" id="notification_network_membership_request-no" value="no" <?php checked( $network_membership_request, 'no', true ) ?>/><label for="notification_network_membership_request-no" class="bp-screen-reader-text"><?php
     548                                        /* translators: accessibility text */
     549                                        _e( 'No, do not send email', 'buddypress' );
     550                                ?></label></td>
     551                        </tr>
     552
     553                        <?php
     554
     555                        /**
     556                         * Fires at the end of the available group settings fields on Notification Settings page.
     557                         *
     558                         * @since 6.0.0
     559                         */
     560                        do_action( 'bp_members_screen_notification_settings' ); ?>
     561
     562                </tbody>
     563        </table>
     564
     565<?php
     566}
     567add_action( 'bp_notification_settings', 'bp_members_screen_notification_settings' );
  • src/bp-members/bp-members-template.php

    diff --git src/bp-members/bp-members-template.php src/bp-members/bp-members-template.php
    index b6dac6b9e..a0bf4f5a2 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 7.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 7.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 7.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() { 
    21942222         */
    21952223        function bp_get_signup_email_value() {
    21962224                $value = '';
    2197                 if ( isset( $_POST['signup_email'] ) )
     2225                if ( isset( $_POST['signup_email'] ) ) {
    21982226                        $value = $_POST['signup_email'];
     2227                } else if ( bp_get_members_invitations_allowed() ) {
     2228                        $invite = bp_get_members_invitation_from_request();
     2229                        if ( $invite ) {
     2230                                $value = $invite->invitee_email;
     2231                        }
     2232                }
    21992233
    22002234                /**
    22012235                 * Filters the email address submitted during signup.
    function bp_signup_allowed() { 
    25682602                return apply_filters( 'bp_get_signup_allowed', (bool) bp_get_option( 'users_can_register' ) );
    25692603        }
    25702604
     2605/**
     2606 * Are users allowed to invite users to join this site?
     2607 *
     2608 * @since 7.0.0
     2609 *
     2610 * @return bool
     2611 */
     2612function bp_get_members_invitations_allowed() {
     2613        /**
     2614         * Filters whether or not community invitations are allowed.
     2615         *
     2616         * @since 7.0.0
     2617         *
     2618         * @param bool $allowed Whether or not community invitations are allowed.
     2619         */
     2620        return apply_filters( 'bp_get_members_invitations_allowed', bp_is_active( 'members', 'invitations' ) && (bool) bp_get_option( 'bp-enable-members-invitations' ) );
     2621}
     2622
    25712623/**
    25722624 * Hook member activity feed to <head>.
    25732625 *
    function bp_avatar_delete_link() { 
    26742726                 */
    26752727                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' ) );
    26762728        }
     2729
     2730
     2731/** The Members Invitations Loop ******************************************************************/
     2732
     2733/**
     2734 * Initialize the community invitations loop.
     2735 *
     2736 * Based on the $args passed, bp_has_invitations() populates
     2737 * buddypress()->invitations->query_loop global, enabling the use of BP
     2738 * templates and template functions to display a list of invitations.
     2739 *
     2740 * @since 7.0.0
     2741 *
     2742 * @param array|string $args {
     2743 *     Arguments for limiting the contents of the invitations loop. Can be
     2744 *     passed as an associative array, or as a URL query string.
     2745 *
     2746 *     See {@link BP_Invitations_Invitation::get()} for detailed
     2747 *     information on the arguments.  In addition, also supports:
     2748 *
     2749 *     @type int    $max      Optional. Max items to display. Default: false.
     2750 *     @type string $page_arg URL argument to use for pagination.
     2751 *                            Default: 'ipage'.
     2752 * }
     2753 * @return bool
     2754 */
     2755function bp_has_members_invitations( $args = '' ) {
     2756
     2757        // Get the user ID.
     2758        if ( bp_displayed_user_id() ) {
     2759                $user_id = bp_displayed_user_id();
     2760        } else {
     2761                $user_id = bp_loggedin_user_id();
     2762        }
     2763
     2764        // Set the search terms (by default an empty string to get all notifications)
     2765        $search_terms = '';
     2766
     2767        if ( isset( $_REQUEST['s'] ) ) {
     2768                $search_terms = stripslashes( $_REQUEST['s'] );
     2769        }
     2770
     2771        // Parse the args.
     2772        $r = bp_parse_args( $args, array(
     2773                'id'                => false,
     2774                'inviter_id'        => $user_id,
     2775                'invitee_email'     => false,
     2776                'item_id'           => false,
     2777                'type'              => 'invite',
     2778                'invite_sent'       => 'all',
     2779                'accepted'          => 'pending',
     2780                'search_terms'      => $search_terms,
     2781                'order_by'          => 'date_modified',
     2782                'sort_order'        => 'DESC',
     2783                'page'              => 1,
     2784                'per_page'          => 25,
     2785                'fields'            => 'all',
     2786
     2787                // These are additional arguments that are not available in
     2788                // BP_Invitations_Invitation::get().
     2789                'page_arg'          => 'ipage',
     2790        ), 'has_community_invitations' );
     2791
     2792        // Get the notifications.
     2793        $query_loop = new BP_Members_Invitations_Template( $r );
     2794
     2795        // Setup the global query loop.
     2796        buddypress()->members->invitations->query_loop = $query_loop;
     2797
     2798        /**
     2799         * Filters whether or not the user has network invitations to display.
     2800         *
     2801         * @since 7.0.0
     2802         *
     2803         * @param bool                      $value      Whether or not there are network invitations to display.
     2804         * @param BP_Notifications_Template $query_loop BP_Members_Invitations_Template object instance.
     2805         * @param array                     $r          Array of arguments passed into the BP_Members_Invitations_Template class.
     2806         */
     2807        return apply_filters( 'bp_has_members_invitations', $query_loop->has_invitations(), $query_loop, $r );
     2808}
     2809
     2810/**
     2811 * Get the network invitations returned by the template loop.
     2812 *
     2813 * @since 7.0.0
     2814 *
     2815 * @return array List of network invitations.
     2816 */
     2817function bp_the_members_invitations() {
     2818        return buddypress()->members->invitations->query_loop->invitations();
     2819}
     2820
     2821/**
     2822 * Get the current network invitation object in the loop.
     2823 *
     2824 * @since 7.0.0
     2825 *
     2826 * @return object The current network invitation within the loop.
     2827 */
     2828function bp_the_members_invitation() {
     2829        return buddypress()->members->invitations->query_loop->the_invitation();
     2830}
     2831
     2832/**
     2833 * Output the pagination count for the current network invitations loop.
     2834 *
     2835 * @since 7.0.0
     2836 */
     2837function bp_members_invitations_pagination_count() {
     2838        echo bp_get_members_invitations_pagination_count();
     2839}
     2840        /**
     2841         * Return the pagination count for the current network invitation loop.
     2842         *
     2843         * @since 7.0.0
     2844         *
     2845         * @return string HTML for the pagination count.
     2846         */
     2847        function bp_get_members_invitations_pagination_count() {
     2848                $query_loop = buddypress()->members->invitations->query_loop;
     2849                $start_num  = intval( ( $query_loop->pag_page - 1 ) * $query_loop->pag_num ) + 1;
     2850                $from_num   = bp_core_number_format( $start_num );
     2851                $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 ) );
     2852                $total      = bp_core_number_format( $query_loop->total_invitation_count );
     2853
     2854                if ( 1 == $query_loop->total_invitation_count ) {
     2855                        $pag = __( 'Viewing 1 invitation', 'buddypress' );
     2856                } else {
     2857                        /* translators: 1: notification from number. 2: notification to number. 3: total notifications. */
     2858                        $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 );
     2859                }
     2860
     2861                /**
     2862                 * Filters the pagination count for the current network invitation loop.
     2863                 *
     2864                 * @since 1.9.0
     2865                 *
     2866                 * @param string $pag HTML for the pagination count.
     2867                 */
     2868                return apply_filters( 'bp_get_members_invitations_pagination_count', $pag );
     2869        }
     2870
     2871/**
     2872 * Output the pagination links for the current network invitation loop.
     2873 *
     2874 * @since 7.0.0
     2875 */
     2876function bp_members_invitations_pagination_links() {
     2877        echo bp_get_members_invitations_pagination_links();
     2878}
     2879        /**
     2880         * Return the pagination links for the current network invitations loop.
     2881         *
     2882         * @since 7.0.0
     2883         *
     2884         * @return string HTML for the pagination links.
     2885         */
     2886        function bp_get_members_invitations_pagination_links() {
     2887
     2888                /**
     2889                 * Filters the pagination links for the current network invitations loop.
     2890                 *
     2891                 * @since 7.0.0
     2892                 *
     2893                 * @param string $pag_links HTML for the pagination links.
     2894                 */
     2895                return apply_filters( 'bp_get_members_invitations_pagination_links', buddypress()->members->invitations->query_loop->pag_links );
     2896        }
     2897
     2898/**
     2899 * Output the ID of the invitation currently being iterated on.
     2900 *
     2901 * @since 7.0.0
     2902 */
     2903function bp_the_members_invitation_property( $property ) {
     2904        echo bp_get_the_members_invitation_property( $property );
     2905}
     2906        /**
     2907         * Return the value for a property of the network invitation currently being iterated on.
     2908         *
     2909         * @since 7.0.0
     2910         *
     2911         * @return int ID of the current network invitation.
     2912         */
     2913        function bp_get_the_members_invitation_property( $property = 'id' ) {
     2914
     2915                switch ( $property ) {
     2916                        case 'id':
     2917                        case 'user_id':
     2918                        case 'item_id':
     2919                        case 'secondary_item_id':
     2920                        case 'invite_sent':
     2921                        case 'accepted':
     2922                                $value = 0;
     2923                                break;
     2924                        case 'invitee_email':
     2925                        case 'type':
     2926                        case 'content':
     2927                        case 'date_modified':
     2928                                $value = '';
     2929                                break;
     2930                        default:
     2931                                // A known property has not been specified.
     2932                                $property = null;
     2933                                $value = '';
     2934                                break;
     2935                }
     2936
     2937                if ( isset( buddypress()->members->invitations->query_loop->invitation->{$property} ) ) {
     2938                        $value = buddypress()->members->invitations->query_loop->invitation->{$property};
     2939                }
     2940
     2941                /**
     2942                 * Filters the property of the network invitation currently being iterated on.
     2943                 *
     2944                 * @since 7.0.0
     2945                 *
     2946                 * @param int|string $value Property value of the network invitation being iterated on.
     2947                 */
     2948                return apply_filters( 'bp_get_the_members_invitation_property_' . $property, $value );
     2949        }
     2950
     2951/**
     2952 * Output the action links for the current invitation.
     2953 *
     2954 * @since 7.0.0
     2955 *
     2956 * @param array|string $args Array of arguments.
     2957 */
     2958function bp_the_members_invitation_action_links( $args = '' ) {
     2959        echo bp_get_the_members_invitation_action_links( $args );
     2960}
     2961        /**
     2962         * Return the action links for the current invitation.
     2963         *
     2964         * @since 7.0.0
     2965         *
     2966         * @param array|string $args {
     2967         *     @type string $before  HTML before the links.
     2968         *     @type string $after   HTML after the links.
     2969         *     @type string $sep     HTML between the links.
     2970         *     @type array  $links   Array of links to implode by 'sep'.
     2971         *     @type int    $user_id User ID to fetch action links for. Defaults to displayed user ID.
     2972         * }
     2973         * @return string HTML links for actions to take on single notifications.
     2974         */
     2975        function bp_get_the_members_invitation_action_links( $args = '' ) {
     2976                // Set default user ID to use.
     2977                $inviter_id = isset( $args['inviter_id'] ) ? $args['inviter_id'] : bp_displayed_user_id();
     2978
     2979                // Parse.
     2980                $r = wp_parse_args( $args, array(
     2981                        'before' => '',
     2982                        'after'  => '',
     2983                        'sep'    => ' | ',
     2984                        'links'  => array(
     2985                                bp_get_the_members_invitation_resend_link( $inviter_id ),
     2986                                bp_get_the_members_invitation_delete_link( $inviter_id )
     2987                        )
     2988                ) );
     2989
     2990                // Build the links.
     2991                $retval = $r['before'] . implode( $r['sep'], $r['links'] ) . $r['after'];
     2992
     2993                /**
     2994                 * Filters the action links for the current notification.
     2995                 *
     2996                 * @since 1.9.0
     2997                 * @since 2.6.0 Added the `$r` parameter.
     2998                 *
     2999                 * @param string $retval HTML links for actions to take on single notifications.
     3000                 * @param array  $r      Array of parsed arguments.
     3001                 */
     3002                return apply_filters( 'bp_get_the_members_invitation_action_links', $retval, $r );
     3003        }
     3004
     3005/**
     3006 * Output the resend link for the current invitation.
     3007 *
     3008 * @since 7.0.0
     3009 *
     3010 * @param int $user_id The user ID.
     3011 */
     3012function bp_the_members_invitations_resend_link( $user_id = 0 ) {
     3013        echo bp_get_the_members_invitation_delete_link( $user_id );
     3014}
     3015        /**
     3016         * Return the resend link for the current notification.
     3017         *
     3018         * @since 7.0.0
     3019         *
     3020         * @param int $user_id The user ID.
     3021         * @return string
     3022         */
     3023        function bp_get_the_members_invitation_resend_link( $user_id = 0 ) {
     3024                // Set default user ID to use.
     3025                $user_id = 0 === $user_id ? bp_displayed_user_id() : $user_id;
     3026
     3027                // Don't allow resending of accepted invitations.
     3028                if ( bp_get_the_members_invitation_property( 'accepted' ) ) {
     3029                        return;
     3030                }
     3031
     3032                $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' ) );
     3033
     3034                /**
     3035                 * Filters the resend link for the current invitation.
     3036                 *
     3037                 * @since 7.0.0
     3038                 *
     3039                 * @param string $retval  HTML for the delete link for the current notification.
     3040                 * @param int    $user_id The user ID.
     3041                 */
     3042                return apply_filters( 'bp_get_the_members_invitation_resend_link', $retval, $user_id );
     3043        }
     3044
     3045/**
     3046 * Output the URL used for resending a single invitation.
     3047 *
     3048 * Since this function directly outputs a URL, it is escaped.
     3049 *
     3050 * @since 7.0.0
     3051 *
     3052 * @param int $user_id The user ID.
     3053 */
     3054function bp_the_members_invitations_resend_url( $user_id = 0 ) {
     3055        echo esc_url( bp_get_the_members_invitations_resend_url( $user_id ) );
     3056}
     3057        /**
     3058         * Return the URL used for resending a single invitation.
     3059         *
     3060         * @since 7.0.0
     3061         *
     3062         * @param int $user_id The user ID.
     3063         * @return string
     3064         */
     3065        function bp_get_the_members_invitations_resend_url( $user_id = 0 ) {
     3066                // Set default user ID to use.
     3067                $user_id = 0 === $user_id ? bp_displayed_user_id() : $user_id;
     3068                $link = bp_get_members_invitations_list_invites_permalink( $user_id );
     3069
     3070                // Get the ID.
     3071                $id = bp_get_the_members_invitation_property( 'id' );
     3072
     3073                // Get the args to add to the URL.
     3074                $args = array(
     3075                        'action'        => 'resend',
     3076                        'invitation_id' => $id
     3077                );
     3078
     3079                // Add the args.
     3080                $url = add_query_arg( $args, $link );
     3081
     3082                // Add the nonce.
     3083                $url = wp_nonce_url( $url, 'bp_network_invitation_resend_' . $id );
     3084
     3085                /**
     3086                 * Filters the URL used for resending a single invitation.
     3087                 *
     3088                 * @since 7.0.0
     3089                 *
     3090                 * @param string $url     URL used for deleting a single invitation.
     3091                 * @param int    $user_id The user ID.
     3092                 */
     3093                return apply_filters( 'bp_get_the_members_invitations_resend_url', $url, $user_id );
     3094        }
     3095
     3096/**
     3097 * Output the delete link for the current invitation.
     3098 *
     3099 * @since 7.0.0
     3100 *
     3101 * @param int $user_id The user ID.
     3102 */
     3103function bp_the_members_invitations_delete_link( $user_id = 0 ) {
     3104        echo bp_get_the_members_invitation_delete_link( $user_id );
     3105}
     3106        /**
     3107         * Return the delete link for the current invitation.
     3108         *
     3109         * @since 7.0.0
     3110         *
     3111         * @param int $user_id The user ID.
     3112         * @return string
     3113         */
     3114        function bp_get_the_members_invitation_delete_link( $user_id = 0 ) {
     3115                // Set default user ID to use.
     3116                $user_id = 0 === $user_id ? bp_displayed_user_id() : $user_id;
     3117
     3118                // Modify the message for accepted/not accepted invitatons.
     3119                if ( bp_get_the_members_invitation_property( 'accepted' ) ) {
     3120                        $message = __( 'Delete', 'buddypress' );
     3121                } else {
     3122                        $message = __( 'Cancel', 'buddypress' );
     3123                }
     3124
     3125                $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 );
     3126
     3127                /**
     3128                 * Filters the delete link for the current invitation.
     3129                 *
     3130                 * @since 7.0.0
     3131                 *
     3132                 * @param string $retval  HTML for the delete link for the current notification.
     3133                 * @param int    $user_id The user ID.
     3134                 */
     3135                return apply_filters( 'bp_get_the_members_invitation_delete_link', $retval, $user_id );
     3136        }
     3137
     3138/**
     3139 * Output the URL used for deleting a single invitation.
     3140 *
     3141 * Since this function directly outputs a URL, it is escaped.
     3142 *
     3143 * @since 7.0.0
     3144 *
     3145 * @param int $user_id The user ID.
     3146 */
     3147function bp_the_members_invitations_delete_url( $user_id = 0 ) {
     3148        echo esc_url( bp_get_the_members_invitations_delete_url( $user_id ) );
     3149}
     3150        /**
     3151         * Return the URL used for deleting a single invitation.
     3152         *
     3153         * @since 7.0.0
     3154         *
     3155         * @param int $user_id The user ID.
     3156         * @return string
     3157         */
     3158        function bp_get_the_members_invitations_delete_url( $user_id = 0 ) {
     3159                // Set default user ID to use.
     3160                $user_id = 0 === $user_id ? bp_displayed_user_id() : $user_id;
     3161                $link = bp_get_members_invitations_list_invites_permalink( $user_id );
     3162
     3163                // Get the ID.
     3164                $id = bp_get_the_members_invitation_property( 'id' );
     3165
     3166                // Get the args to add to the URL.
     3167                $args = array(
     3168                        'action'        => 'cancel',
     3169                        'invitation_id' => $id
     3170                );
     3171
     3172                // Add the args.
     3173                $url = add_query_arg( $args, $link );
     3174
     3175                // Add the nonce.
     3176                $url = wp_nonce_url( $url, 'bp_members_invitations_cancel_' . $id );
     3177
     3178                /**
     3179                 * Filters the URL used for deleting a single invitation.
     3180                 *
     3181                 * @since 7.0.0
     3182                 *
     3183                 * @param string $url     URL used for deleting a single invitation.
     3184                 * @param int    $user_id The user ID.
     3185                 */
     3186                return apply_filters( 'bp_get_the_members_invitations_delete_url', $url, $user_id );
     3187        }
     3188
     3189/**
     3190 * Output the members invitations list permalink for a user.
     3191 *
     3192 * @since 7.0.0
     3193 *
     3194 * @param int $user_id The user ID.
     3195 */
     3196function bp_members_invitations_list_invites_permalink( $user_id = 0 ) {
     3197        echo bp_get_members_invitations_list_invites_permalink( $user_id );
     3198}
     3199        /**
     3200         * Return the members invitations list permalink for a user.
     3201         *
     3202         * @since 7.0.0
     3203         *
     3204         * @return string Members invitations list permalink for a user.
     3205         */
     3206        function bp_get_members_invitations_list_invites_permalink( $user_id = 0 ) {
     3207                if ( 0 === $user_id ) {
     3208                        $user_id = bp_loggedin_user_id();
     3209                        $domain  = bp_loggedin_user_domain();
     3210                } else {
     3211                        $domain = bp_core_get_user_domain( (int) $user_id );
     3212                }
     3213
     3214                $retval = trailingslashit( $domain . bp_get_members_invitations_slug() . '/list-invites' );
     3215
     3216                /**
     3217                 * Filters the members invitations list permalink for a user.
     3218                 *
     3219                 * @since 7.0.0
     3220                 *
     3221                 * @param string $retval  Permalink for the sent invitation list screen.
     3222                 * @param int    $user_id The user ID.
     3223                 */
     3224                return apply_filters( 'bp_get_members_invitations_list_invites_permalink', $retval, $user_id );
     3225        }
     3226
     3227/**
     3228 * Output the send invitation permalink for a user.
     3229 *
     3230 * @since 7.0.0
     3231 *
     3232 * @param int $user_id The user ID.
     3233 */
     3234function bp_members_invitations_send_invites_permalink( $user_id = 0 ) {
     3235        echo bp_get_members_invitations_send_invites_permalink( $user_id );
     3236}
     3237        /**
     3238         * Return the send invitations permalink.
     3239         *
     3240         * @since 7.0.0
     3241         *
     3242         * @return string Read notifications permalink.
     3243         */
     3244        function bp_get_members_invitations_send_invites_permalink( $user_id = 0 ) {
     3245                if ( 0 === $user_id ) {
     3246                        $user_id = bp_loggedin_user_id();
     3247                        $domain  = bp_loggedin_user_domain();
     3248                } else {
     3249                        $domain = bp_core_get_user_domain( (int) $user_id );
     3250                }
     3251
     3252                $retval = trailingslashit( $domain . bp_get_members_invitations_slug() . '/send-invites' );
     3253
     3254                /**
     3255                 * Filters the read notifications permalink.
     3256                 *
     3257                 * @since 7.0.0
     3258                 *
     3259                 * @param string $retval  Permalink for the sent invitation list screen.
     3260                 * @param int    $user_id The user ID.
     3261                 */
     3262                return apply_filters( 'bp_get_members_invitations_send_invites_permalink', $retval, $user_id );
     3263        }
     3264 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 4846b8837..6ea9b3a4a 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 { 
    25882603
    25892604                return $value;
    25902605        }
     2606
     2607        /**
     2608         * Set up the signups admin page.
     2609         *
     2610         * Loaded before the page is rendered, this function does all initial
     2611         * setup, including: processing form requests, registering contextual
     2612         * help, and setting up screen options.
     2613         *
     2614         * @since 7.0.0
     2615         *
     2616         * @global $bp_members_signup_list_table
     2617         */
     2618        public function members_invitations_admin_load() {
     2619                // @TODO
     2620        }
     2621
     2622        /**
     2623         * Network invitations admin page router.
     2624         *
     2625         * Depending on the context, display
     2626         * - the list of invitations,
     2627         * - or the delete confirmation screen,
     2628         * - or the activate confirmation screen,
     2629         * - or the "resend" email confirmation screen.
     2630         *
     2631         * Also prepare the admin notices.
     2632         *
     2633         * @since 7.0.0
     2634         */
     2635        public function invitations_admin() {
     2636                // @TODO
     2637                echo "<p>Coming Soon? :)</p>";
     2638        }
    25912639}
    25922640endif; // 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 daebb2ab2..2faf9723d 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                        'notifications',
     69                        'invitations',
    6770                );
    6871
    6972                if ( bp_is_active( 'activity' ) ) {
    class BP_Members_Component extends BP_Component { 
    137140                        // Theme compatibility.
    138141                        new BP_Registration_Theme_Compat();
    139142                }
     143
     144                // Invitations.
     145                if ( is_user_logged_in() && bp_is_user_members_invitations() ) {
     146                        if ( bp_is_user_members_invitations_send_screen() ) {
     147                                require $this->path . 'bp-members/screens/send-invites.php';
     148                        } else {
     149                                require $this->path . 'bp-members/screens/list-invites.php';
     150                        }
     151                }
    140152        }
    141153
    142154        /**
    class BP_Members_Component extends BP_Component { 
    231243                        $bp->profile->slug = 'profile';
    232244                        $bp->profile->id   = 'profile';
    233245                }
     246
     247                /** Network Invitations **************************************************
     248                 */
     249
     250                $bp->members->invitations = new stdClass;
    234251        }
    235252
    236253        /**
    class BP_Members_Component extends BP_Component { 
    466483                        }
    467484                }
    468485
    469 
    470486                parent::setup_nav( $main_nav, $sub_nav );
    471487        }
    472488
  • 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..11647fcfe
    - +  
     1<?php
     2/**
     3 * Group invitations class.
     4 *
     5 * @package BuddyPress
     6 * @subpackage Core
     7 * @since 7.0.0
     8 */
     9
     10// Exit if accessed directly.
     11defined( 'ABSPATH' ) || exit;
     12
     13/**
     14 * Group invitations class.
     15 *
     16 * An extension of the core Invitations class that adapts the
     17 * core logic to accommodate group invitation behavior.
     18 *
     19 * @since 7.0.0
     20 */
     21class BP_Members_Invitation_Manager extends BP_Invitation_Manager {
     22        /**
     23         * Construct parameters.
     24         *
     25         * @since 7.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 7.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                        $inviter_ud = bp_core_get_core_userdata( $invitation->inviter_id );
     50
     51                        // @TODO: Handle unsubscribes differently since these are not members?
     52                        $unsubscribe_args = array(
     53                                'user_id'           => 0,
     54                                'notification_type' => 'bp-members-invitation',
     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
     65                        $args = array(
     66                                'tokens' => array(
     67                                        'displayname'         => $invitation->invitee_email,
     68                                        'network.url'         => get_site_url( bp_get_root_blog_id() ),
     69                                        'network.name'        => get_bloginfo( 'name' ),
     70                                        'network.description' => get_bloginfo( 'description' ),
     71                                        'inviter.name'        => bp_core_get_userlink( $invitation->inviter_id, true, false, true ),
     72                                        'inviter.url'         => bp_core_get_user_domain( $invitation->inviter_id ),
     73                                        'inviter.id'          => $invitation->inviter_id,
     74                                        'invites.url'         => esc_url( $invite_url ),
     75                                        'invite.message'      => $invitation->content,
     76                                        // @TODO: add unsubscribe method that isn't reliant on user being a member of the site.
     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 7.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 1.0.0
     104                         *
     105                         * @param int  $user_id  ID of the user who accepted membership.
     106                         * @param int  $group_id ID of the group 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 group invite.
     112                         *
     113                         * @since 1.0.0
     114                         * @since 2.8.0 The $inviter_id arg was added.
     115                         *
     116                         * @param int $user_id    ID of the user who accepted the membership invite.
     117                         * @param int $inviter_id ID of the user who invited this user to the group.
     118                         */
     119                        do_action( 'network_membership_invite_accepted', $r['user_id'], $inviter_id );
     120                }
     121
     122
     123                return true;
     124        }
     125
     126        /**
     127         * Should this invitation be created?
     128         *
     129         * @since 7.0.0
     130         *
     131         * @param array $args.
     132         * @return bool
     133         */
     134        public function allow_invitation( $args ) {
     135                // Does the inviter have this capability?
     136                if ( ! bp_user_can( $args['inviter_id'], 'bp_members_send_invitation' ) ) {
     137                        return false;
     138                }
     139
     140                // Is the invited user eligible to receive an invitation? Hasn't opted out?
     141                if ( ! bp_user_can( 0, 'bp_members_receive_invitation', $args ) ) {
     142                        return false;
     143                }
     144
     145                return true;
     146        }
     147
     148        /**
     149         * Should this request be created?
     150         *
     151         * @since 7.0.0
     152         *
     153         * @param array $args.
     154         * @return bool.
     155         */
     156        public function allow_request( $args ) {
     157                // Does the requester have this capability?
     158                if ( ! bp_user_can( 0, 'bp_network_request_membership', $args ) ) {
     159                        return false;
     160                }
     161
     162                return true;
     163        }
     164}
  • 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..dcdccc0b7
    - +  
     1<?php
     2/**
     3 * BuddyPress Members List Table class.
     4 *
     5 * @package BuddyPress
     6 * @subpackage MembersAdminClasses
     7 * @since 2.3.0
     8 */
     9
     10// Exit if accessed directly.
     11defined( 'ABSPATH' ) || exit;
     12
     13/**
     14 * List table class for signups admin page.
     15 *
     16 * @since 2.0.0
     17 */
     18class BP_Members_Invitations_List_Table extends WP_Users_List_Table {
     19
     20        /**
     21         * Signup counts.
     22         *
     23         * @since 2.0.0
     24         *
     25         * @var int
     26         */
     27        public $total_items = 0;
     28
     29        /**
     30         * Constructor.
     31         *
     32         * @since 2.0.0
     33         */
     34        public function __construct() {
     35                // Define singular and plural labels, as well as whether we support AJAX.
     36                parent::__construct( array(
     37                        'ajax'     => false,
     38                        'plural'   => 'invitations',
     39                        'singular' => 'invitation',
     40                        'screen'   => get_current_screen()->id,
     41                ) );
     42        }
     43
     44        /**
     45         * Set up items for display in the list table.
     46         *
     47         * Handles filtering of data, sorting, pagination, and any other data
     48         * manipulation required prior to rendering.
     49         *
     50         * @since 2.0.0
     51         */
     52        public function prepare_items() {
     53                global $usersearch;
     54
     55                $search       = isset( $_REQUEST['s'] ) ? $_REQUEST['s'] : '';
     56                $per_page = $this->get_items_per_page( str_replace( '-', '_', "{$this->screen->id}_per_page" ) );
     57                $paged            = $this->get_pagenum();
     58
     59                $args = array(
     60                        'invite_sent'       => 'all',
     61                        'accepted'          => 'all',
     62                        'search_terms'      => $search,
     63                        'order_by'          => 'date_modified',
     64                        'sort_order'        => 'DESC',
     65                        'page'              => $paged,
     66                        'per_page'          => $per_page,
     67                );
     68
     69                if ( isset( $_REQUEST['orderby'] ) ) {
     70                        $args['order_by'] = $_REQUEST['orderby'];
     71                }
     72
     73                if ( isset( $_REQUEST['order'] ) ) {
     74                        $args['sort_order'] = $_REQUEST['order'];
     75                }
     76
     77                $invites_class = new BP_Members_Invitation_Manager();
     78                $this->items = $invites_class->get_invitations( $args );
     79                $this->total_items = $invites_class->get_invitations_total_count( $args );
     80
     81                $this->set_pagination_args( array(
     82                        'total_items' => $this->total_items,
     83                        'per_page'    => $per_page,
     84                ) );
     85        }
     86
     87        /**
     88         * Display the users screen views
     89         *
     90         * @since 2.5.0
     91         *
     92         * @global string $role The name of role the users screens is filtered by
     93         */
     94        public function views() {
     95                global $role;
     96
     97                // Used to reset the role.
     98                $reset_role = $role;
     99
     100                // Temporarly set the role to registered.
     101                $role = 'registered';
     102
     103                // Used to reset the screen id once views are displayed.
     104                $reset_screen_id = $this->screen->id;
     105
     106                // Temporarly set the screen id to the users one.
     107                $this->screen->id = 'users';
     108
     109                // Use the parent function so that other plugins can safely add views.
     110                parent::views();
     111
     112                // Reset the role.
     113                $role = $reset_role;
     114
     115                // Reset the screen id.
     116                $this->screen->id = $reset_screen_id;
     117        }
     118
     119        /**
     120         * Get rid of the extra nav.
     121         *
     122         * WP_Users_List_Table will add an extra nav to change user's role.
     123         * As we're dealing with signups, we don't need this.
     124         *
     125         * @since 2.0.0
     126         *
     127         * @param array $which Current table nav item.
     128         */
     129        public function extra_tablenav( $which ) {
     130                return;
     131        }
     132
     133        /**
     134         * Specific signups columns.
     135         *
     136         * @since 2.0.0
     137         *
     138         * @return array
     139         */
     140        public function get_columns() {
     141
     142                /**
     143                 * Filters the single site Members signup columns.
     144                 *
     145                 * @since 2.0.0
     146                 *
     147                 * @param array $value Array of columns to display.
     148                 */
     149                return apply_filters( 'bp_members_signup_columns', array(
     150                        'cb'         => '<input type="checkbox" />',
     151                        'username'   => __( 'Username',    'buddypress' ),
     152                        'name'       => __( 'Name',        'buddypress' ),
     153                        'email'      => __( 'Email',       'buddypress' ),
     154                        'registered' => __( 'Registered',  'buddypress' ),
     155                        'date_sent'  => __( 'Last Sent',   'buddypress' ),
     156                        'count_sent' => __( 'Emails Sent', 'buddypress' )
     157                ) );
     158        }
     159
     160        /**
     161         * Specific bulk actions for signups.
     162         *
     163         * @since 2.0.0
     164         */
     165        public function get_bulk_actions() {
     166                $actions = array(
     167                        'activate' => _x( 'Activate', 'Pending signup action', 'buddypress' ),
     168                        'resend'   => _x( 'Email',    'Pending signup action', 'buddypress' ),
     169                );
     170
     171                if ( current_user_can( 'delete_users' ) ) {
     172                        $actions['delete'] = __( 'Delete', 'buddypress' );
     173                }
     174
     175                return $actions;
     176        }
     177
     178        /**
     179         * The text shown when no items are found.
     180         *
     181         * Nice job, clean sheet!
     182         *
     183         * @since 2.0.0
     184         */
     185        public function no_items() {
     186
     187                if ( bp_get_signup_allowed() ) {
     188                        esc_html_e( 'No pending accounts found.', 'buddypress' );
     189                } else {
     190                        $link = false;
     191
     192                        // Specific case when BuddyPress is not network activated.
     193                        if ( is_multisite() && current_user_can( 'manage_network_users') ) {
     194                                $link = sprintf( '<a href="%1$s">%2$s</a>', esc_url( network_admin_url( 'settings.php'       ) ), esc_html__( 'Edit settings', 'buddypress' ) );
     195                        } elseif ( current_user_can( 'manage_options' ) ) {
     196                                $link = sprintf( '<a href="%1$s">%2$s</a>', esc_url( bp_get_admin_url( 'options-general.php' ) ), esc_html__( 'Edit settings', 'buddypress' ) );
     197                        }
     198
     199                        /* translators: %s: url to site settings */
     200                        printf( __( 'Registration is disabled. %s', 'buddypress' ), $link );
     201                }
     202
     203        }
     204
     205        /**
     206         * The columns signups can be reordered with.
     207         *
     208         * @since 2.0.0
     209         */
     210        public function get_sortable_columns() {
     211                return array(
     212                        'username'   => 'login',
     213                        'email'      => 'email',
     214                        'registered' => 'signup_id',
     215                );
     216        }
     217
     218        /**
     219         * Display signups rows.
     220         *
     221         * @since 2.0.0
     222         */
     223        public function display_rows() {
     224                $style = '';
     225                foreach ( $this->items as $userid => $signup_object ) {
     226
     227                        // Avoid a notice error appearing since 4.3.0.
     228                        if ( isset( $signup_object->id ) ) {
     229                                $signup_object->ID = $signup_object->id;
     230                        }
     231
     232                        $style = ( ' class="alternate"' == $style ) ? '' : ' class="alternate"';
     233                        echo "\n\t" . $this->single_row( $signup_object, $style );
     234                }
     235        }
     236
     237        /**
     238         * Display a signup row.
     239         *
     240         * @since 2.0.0
     241         *
     242         * @see WP_List_Table::single_row() for explanation of params.
     243         *
     244         * @param object|null $signup_object Signup user object.
     245         * @param string      $style         Styles for the row.
     246         * @param string      $role          Role to be assigned to user.
     247         * @param int         $numposts      Numper of posts.
     248         * @return void
     249         */
     250        public function single_row( $signup_object = null, $style = '', $role = '', $numposts = 0 ) {
     251                echo '<tr' . $style . ' id="signup-' . esc_attr( $signup_object->id ) . '">';
     252                echo $this->single_row_columns( $signup_object );
     253                echo '</tr>';
     254        }
     255
     256        /**
     257         * Markup for the checkbox used to select items for bulk actions.
     258         *
     259         * @since 2.0.0
     260         *
     261         * @param object|null $signup_object The signup data object.
     262         */
     263        public function column_cb( $signup_object = null ) {
     264        ?>
     265                <label class="screen-reader-text" for="signup_<?php echo intval( $signup_object->id ); ?>"><?php
     266                        /* translators: accessibility text */
     267                        printf( esc_html__( 'Select user: %s', 'buddypress' ), $signup_object->user_login );
     268                ?></label>
     269                <input type="checkbox" id="signup_<?php echo intval( $signup_object->id ) ?>" name="allsignups[]" value="<?php echo esc_attr( $signup_object->id ) ?>" />
     270                <?php
     271        }
     272
     273        /**
     274         * The row actions (delete/activate/email).
     275         *
     276         * @since 2.0.0
     277         *
     278         * @param object|null $signup_object The signup data object.
     279         */
     280        public function column_username( $signup_object = null ) {
     281                $avatar = get_avatar( $signup_object->user_email, 32 );
     282
     283                // Activation email link.
     284                $email_link = add_query_arg(
     285                        array(
     286                                'page'      => 'bp-signups',
     287                                'signup_id' => $signup_object->id,
     288                                'action'    => 'resend',
     289                        ),
     290                        bp_get_admin_url( 'users.php' )
     291                );
     292
     293                // Activate link.
     294                $activate_link = add_query_arg(
     295                        array(
     296                                'page'      => 'bp-signups',
     297                                'signup_id' => $signup_object->id,
     298                                'action'    => 'activate',
     299                        ),
     300                        bp_get_admin_url( 'users.php' )
     301                );
     302
     303                // Delete link.
     304                $delete_link = add_query_arg(
     305                        array(
     306                                'page'      => 'bp-signups',
     307                                'signup_id' => $signup_object->id,
     308                                'action'    => 'delete',
     309                        ),
     310                        bp_get_admin_url( 'users.php' )
     311                );
     312
     313                echo $avatar . sprintf( '<strong><a href="%1$s" class="edit">%2$s</a></strong><br/>', esc_url( $activate_link ), $signup_object->user_login );
     314
     315                $actions = array();
     316
     317                $actions['activate'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $activate_link ), __( 'Activate', 'buddypress' ) );
     318                $actions['resend']   = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $email_link ), __( 'Email', 'buddypress' ) );
     319
     320                if ( current_user_can( 'delete_users' ) ) {
     321                        $actions['delete'] = sprintf( '<a href="%1$s" class="delete">%2$s</a>', esc_url( $delete_link ), __( 'Delete', 'buddypress' ) );
     322                }
     323
     324                /**
     325                 * Filters the multisite row actions for each user in list.
     326                 *
     327                 * @since 2.0.0
     328                 *
     329                 * @param array  $actions       Array of actions and corresponding links.
     330                 * @param object $signup_object The signup data object.
     331                 */
     332                $actions = apply_filters( 'bp_members_ms_signup_row_actions', $actions, $signup_object );
     333
     334                echo $this->row_actions( $actions );
     335        }
     336
     337        /**
     338         * Display user name, if any.
     339         *
     340         * @since 2.0.0
     341         *
     342         * @param object|null $signup_object The signup data object.
     343         */
     344        public function column_name( $signup_object = null ) {
     345                echo esc_html( $signup_object->user_name );
     346        }
     347
     348        /**
     349         * Display user email.
     350         *
     351         * @since 2.0.0
     352         *
     353         * @param object|null $signup_object The signup data object.
     354         */
     355        public function column_email( $signup_object = null ) {
     356                printf( '<a href="mailto:%1$s">%2$s</a>', esc_attr( $signup_object->user_email ), esc_html( $signup_object->user_email ) );
     357        }
     358
     359        /**
     360         * Display registration date.
     361         *
     362         * @since 2.0.0
     363         *
     364         * @param object|null $signup_object The signup data object.
     365         */
     366        public function column_registered( $signup_object = null ) {
     367                echo mysql2date( 'Y/m/d', $signup_object->registered );
     368        }
     369
     370        /**
     371         * Display the last time an activation email has been sent.
     372         *
     373         * @since 2.0.0
     374         *
     375         * @param object|null $signup_object The signup data object.
     376         */
     377        public function column_date_sent( $signup_object = null ) {
     378                echo mysql2date( 'Y/m/d', $signup_object->date_sent );
     379        }
     380
     381        /**
     382         * Display number of time an activation email has been sent.
     383         *
     384         * @since 2.0.0
     385         *
     386         * @param object|null $signup_object Signup object instance.
     387         */
     388        public function column_count_sent( $signup_object = null ) {
     389                echo absint( $signup_object->count_sent );
     390        }
     391
     392        /**
     393         * Allow plugins to add their custom column.
     394         *
     395         * @since 2.1.0
     396         *
     397         * @param object|null $signup_object The signup data object.
     398         * @param string      $column_name   The column name.
     399         * @return string
     400         */
     401        function column_default( $signup_object = null, $column_name = '' ) {
     402
     403                /**
     404                 * Filters the single site custom columns for plugins.
     405                 *
     406                 * @since 2.1.0
     407                 *
     408                 * @param string $column_name   The column name.
     409                 * @param object $signup_object The signup data object.
     410                 */
     411                return apply_filters( 'bp_members_signup_custom_column', '', $column_name, $signup_object );
     412        }
     413}
  • 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..b8fcebd76
    - +  
     1<?php
     2/**
     3 * BuddyPress Members Invitation Template Loop Class.
     4 *
     5 * @package BuddyPress
     6 * @subpackage TonificationsTemplate
     7 * @since 1.9.0
     8 */
     9
     10// Exit if accessed directly.
     11defined( 'ABSPATH' ) || exit;
     12
     13/**
     14 * The main network_invitations template loop class.
     15 *
     16 * Responsible for loading a group of network_invitations into a loop for display.
     17 *
     18 * @since 1.9.0
     19 */
     20class BP_Members_Invitations_Template {
     21
     22        /**
     23         * The loop iterator.
     24         *
     25         * @since 1.9.0
     26         * @var int
     27         */
     28        public $current_invitation = -1;
     29
     30        /**
     31         * The number of network_invitations returned by the paged query.
     32         *
     33         * @since 1.9.0
     34         * @var int
     35         */
     36        public $current_invitation_count;
     37
     38        /**
     39         * Total number of network_invitations matching the query.
     40         *
     41         * @since 1.9.0
     42         * @var int
     43         */
     44        public $total_invitation_count;
     45
     46        /**
     47         * Array of network invitations located by the query.
     48         *
     49         * @since 1.9.0
     50         * @var array
     51         */
     52        public $invitations;
     53
     54        /**
     55         * The invitation object currently being iterated on.
     56         *
     57         * @since 1.9.0
     58         * @var object
     59         */
     60        public $invitation;
     61
     62        /**
     63         * A flag for whether the loop is currently being iterated.
     64         *
     65         * @since 1.9.0
     66         * @var bool
     67         */
     68        public $in_the_loop;
     69
     70        /**
     71         * The ID of the user to whom the displayed network_invitations were sent.
     72         *
     73         * @since 1.9.0
     74         * @var int
     75         */
     76        public $user_id;
     77
     78        /**
     79         * The ID of the user to whom the displayed network_invitations belong.
     80         *
     81         * @since 1.9.0
     82         * @var int
     83         */
     84        public $inviter_id;
     85
     86        /**
     87         * The page number being requested.
     88         *
     89         * @since 1.9.0
     90         * @var int
     91         */
     92        public $pag_page;
     93
     94        /**
     95         * The $_GET argument used in URLs for determining pagination.
     96         *
     97         * @since 1.9.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 1.9.0
     106         * @var int
     107         */
     108        public $pag_num;
     109
     110        /**
     111         * An HTML string containing pagination links.
     112         *
     113         * @since 1.9.0
     114         * @var string
     115         */
     116        public $pag_links;
     117
     118        /**
     119         * A string to match against.
     120         *
     121         * @since 1.9.0
     122         * @var string
     123         */
     124        public $search_terms;
     125
     126        /**
     127         * A database column to order the results by.
     128         *
     129         * @since 1.9.0
     130         * @var string
     131         */
     132        public $order_by;
     133
     134        /**
     135         * The direction to sort the results (ASC or DESC).
     136         *
     137         * @since 1.9.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 1.9.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 network_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 network_invitations available in the loop.
     242         *
     243         * @since 1.9.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 1.9.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 1.9.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 network_invitations left in the loop to iterate over.
     289         *
     290         * This method is used by {@link bp_network_invitations()} as part of the
     291         * while loop that controls iteration inside the network_invitations loop, eg:
     292         *     while ( bp_network_invitations() ) { ...
     293         *
     294         * @since 1.9.0
     295         *
     296         * @see bp_network_invitations()
     297         *
     298         * @return bool True if there are more network_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 1.9.0
     312                         */
     313                        do_action( 'network_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 1.9.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 1.9.0
     344                         */
     345                        do_action( 'network_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..d1eeddd8f
    - +  
     1<?php
     2/**
     3 * Members: Sent Invitations Status
     4 *
     5 * @package BuddyPress
     6 * @subpackage MembersScreens
     7 * @since 6.0.0
     8 */
     9
     10/**
     11 * Catch and process the Send Invites page.
     12 *
     13 * @since 1.0.0
     14 */
     15function members_screen_list_sent_invites() {
     16
     17        /**
     18         * Fires before the loading of template for the My Friends page.
     19         *
     20         * @since 1.0.0
     21         */
     22        do_action( 'members_screen_list_sent_invites' );
     23
     24        /**
     25         * Filters the template used to display the My Friends page.
     26         *
     27         * @since 1.0.0
     28         *
     29         * @param string $template Path to the my friends template to load.
     30         */
     31        bp_core_load_template( apply_filters( 'members_template_list_sent_invites', 'members/single/invitations' ) );
     32}
     33
     34/**
     35 * Handle marking single notifications as unread.
     36 *
     37 * @since 1.9.0
     38 *
     39 * @return bool
     40 */
     41function bp_network_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_network_invitations_action_handling' );
  • src/bp-members/screens/register.php

    diff --git src/bp-members/screens/register.php src/bp-members/screens/register.php
    index f954f3f41..5cb76a097 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..61ddc0d3f
    - +  
     1<?php
     2/**
     3 * Members: Send Invitations
     4 *
     5 * @package BuddyPress
     6 * @subpackage MembersScreens
     7 * @since 3.0.0
     8 */
     9
     10/**
     11 * Catch and process the Send Invites page.
     12 *
     13 * @since 1.0.0
     14 */
     15function members_screen_send_invites() {
     16
     17        /**
     18         * Fires before the loading of template for the My Friends page.
     19         *
     20         * @since 1.0.0
     21         */
     22        do_action( 'members_screen_send_invites' );
     23
     24        /**
     25         * Filters the template used to display the My Friends page.
     26         *
     27         * @since 1.0.0
     28         *
     29         * @param string $template Path to the my friends template to load.
     30         */
     31        bp_core_load_template( apply_filters( 'members_template_send_invites', 'members/single/invitations' ) );
     32}
     33
     34/**
     35 * Handle marking single notifications as unread.
     36 *
     37 * @since 1.9.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..e3d0f63fb 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 7.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 7.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..0933b896d
    - +  
     1<?php
     2/**
     3 * BuddyPress - Users Notifications
     4 *
     5 * @package BuddyPress
     6 * @subpackage bp-legacy
     7 * @version 3.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..61bc68001
    - +  
     1<?php
     2/**
     3 * BuddyPress - Members Invitations Loop
     4 *
     5 * @package BuddyPress
     6 * @subpackage bp-legacy
     7 * @version 3.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..50810d424
    - +  
     1<?php
     2/**
     3 * BuddyPress - Members Sent Network Invitations
     4 *
     5 * @package BuddyPress
     6 * @subpackage bp-legacy
     7 * @version 3.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..e3fec5519
    - +  
     1<?php
     2/**
     3 * BuddyPress - Members Sent Network Invitations
     4 *
     5 * @package BuddyPress
     6 * @subpackage bp-legacy
     7 * @version 3.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 e2c6535e9..47db49706 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 { 
    649652
    650653                return $path;
    651654        }
     655        /**
     656         * Modify "registration disabled" message in Nouveau template pack.
     657         * Modify welcome message in Nouveau template pack.
     658         *
     659         * @since 7.0.0
     660         *
     661         * @param array $messages The list of feedback messages.
     662         *
     663         * @return array $messages
     664         */
     665        function filter_registration_messages( $messages ) {
     666                // Change the "registration is disabled" message.
     667                $disallowed_message = bp_members_invitations_get_modified_registration_disabled_message();
     668                if ( $disallowed_message ) {
     669                        $messages['registration-disabled']['message'] = $disallowed_message;
     670                }
     671                // Add information about invitations to the welcome block.
     672                $welcome_message = bp_members_invitations_get_registration_welcome_message();
     673                if ( $welcome_message ) {
     674                        $messages['request-details']['message'] = $welcome_message . $messages['request-details']['message'];
     675                }
     676                return $messages;
     677        }
    652678}
    653679
    654680/**
  • 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..1cf1d8d6a
    - +  
     1<?php
     2/**
     3 * BuddyPress - Users Groups
     4 *
     5 * @since 3.0.0
     6 * @version 3.0.0
     7 */
     8?>
     9
     10<nav class="<?php bp_nouveau_single_item_subnav_classes(); ?>" id="subnav" role="navigation" aria-label="<?php esc_attr_e( 'Groups menu', 'buddypress' ); ?>">
     11        <ul class="subnav">
     12
     13                <?php if ( bp_is_my_profile() ) : ?>
     14
     15                        <?php bp_get_template_part( 'members/single/parts/item-subnav' ); ?>
     16
     17                <?php endif; ?>
     18
     19        </ul>
     20</nav><!-- .bp-navs -->
     21
     22<?php bp_get_template_part( 'common/search-and-filters-bar' ); ?>
     23eh?
     24<?php
     25if ( 'sent-invites' === bp_current_action() ) {
     26                echo "send tinvites";
     27} else {
     28                echo "default";
     29
     30}
     31
  • src/class-buddypress.php

    diff --git src/class-buddypress.php src/class-buddypress.php
    index 5464e5c4a..5b222cff2 100644
    class BuddyPress { 
    615615                        'BP_REST_Attachments_Member_Avatar_Endpoint' => 'members',
    616616                        'BP_REST_Attachments_Member_Cover_Endpoint'  => 'members',
    617617                        'BP_REST_Signup_Endpoint'                    => 'members',
     618                        'BP_Members_Invitation_Manager'              => 'members',
     619                        'BP_Members_Invitations_Template'            => 'members',
    618620
    619621                        'BP_REST_Messages_Endpoint' => 'messages',
    620622