Skip to:
Content

BuddyPress.org

Ticket #8582: 8582.3.diff

File 8582.3.diff, 59.9 KB (added by dcavins, 2 years ago)

New patch.

  • 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 b37b914ff..29d7ce4f5 100644
    function bp_admin_setting_callback_members_invitations() { 
    203203        do_action( 'bp_admin_settings_after_members_invitations' );
    204204}
    205205
     206/**
     207 * Allow new users to request membership to the network.
     208 *
     209 * @since 10.0.0
     210 */
     211function bp_admin_setting_callback_membership_requests() {
     212?>
     213        <input id="bp-enable-membership-requests" name="bp-enable-membership-requests" type="checkbox" value="1" <?php checked( bp_get_membership_requests_required( 'raw' ) ); ?> />
     214        <label for="bp-enable-membership-requests"><?php _e( 'Enable network membership requests. If enabled, an administrator must approve each new network membership.', 'buddypress' ); ?></label>
     215        <?php if ( bp_get_signup_allowed() ) : ?>
     216                <p class="description"><?php _e( 'Public registration is currently enabled. If you wish to require approval for new memberships, disable public registration and enable the membership requests feature.', 'buddypress' ); ?></p>
     217        <?php endif; ?>
     218        <?php
     219        /**
     220         * Fires after the output of the membership requests settings section.
     221         *
     222         * @since 10.0.0
     223         */
     224        do_action( 'bp_admin_settings_after_membership_requests' );
     225}
     226
    206227/** XProfile ******************************************************************/
    207228
    208229/**
  • src/bp-core/bp-core-functions.php

    diff --git src/bp-core/bp-core-functions.php src/bp-core/bp-core-functions.php
    index 3dbc32f11..b140fbf6d 100644
    function bp_core_replace_tokens_in_text( $text, $tokens ) { 
    38003800 * Get a list of emails for populating the email post type.
    38013801 *
    38023802 * @since 2.5.1
     3803 * @since 10.0.0 Added members-membership-request and
     3804 *               members-membership-request-rejected email types.
    38033805 *
    38043806 * @return array
    38053807 */
    function bp_email_get_schema() { 
    39603962                        /* translators: do not remove {} brackets or translate its contents. */
    39613963                        'post_excerpt' => __( "{{inviter.name}} has invited you to join the site \"{{site.name}}\".\n\n{{usermessage}}\n\nTo accept your invitation, visit: {{{invite.accept_url}}}\n\nTo learn more about the site, visit: {{{site.url}}}.\nTo view {{inviter.name}}'s profile, visit: {{{inviter.url}}}", 'buddypress' ),
    39623964                ),
     3965                'members-membership-request' => array(
     3966                        /* translators: do not remove {} brackets or translate its contents. */
     3967                        'post_title'   => __( '{{requesting-user.user_login}} would like to join {{site.name}}', 'buddypress' ),
     3968                        /* translators: do not remove {} brackets or translate its contents. */
     3969                        'post_content' => __( "{{requesting-user.user_login}} would like to join the site: &quot;{{site.name}}&quot;.\n\n<a href=\"{{{manage.url}}}\">Manage the request</a>.", 'buddypress' ),
     3970                        /* translators: do not remove {} brackets or translate its contents. */
     3971                        'post_excerpt' => __( "{{requesting-user.user_login}} would like to join the site \"{{site.name}}\".\n\nTo manage the request, visit: {{{manage.url}}}.", 'buddypress' ),
     3972                ),
     3973                'members-membership-request-rejected' => array(
     3974                        /* translators: do not remove {} brackets or translate its contents. */
     3975                        'post_title'   => __( 'Your request to join {{site.name}} has been declined', 'buddypress' ),
     3976                        /* translators: do not remove {} brackets or translate its contents. */
     3977                        'post_content' => __( "Sorry, your request to join the site &quot;{{site.name}}&quot; has been declined.", 'buddypress' ),
     3978                        /* translators: do not remove {} brackets or translate its contents. */
     3979                        'post_excerpt' => __( "Sorry, your request to join the site \"{{site.name}}\" has been declined.", 'buddypress' ),
     3980                ),
    39633981        ) );
    39643982}
    39653983
    function bp_email_get_type_schema( $field = 'description' ) { 
    41324150                ),
    41334151        );
    41344152
     4153        $members_membership_request= array(
     4154                'description'      => __( 'Someone has requested membership on this site.', 'buddypress' ),
     4155                'named_salutation' => true,
     4156                'unsubscribe'      => array(
     4157                        'meta_key' => 'notification_members_membership_request',
     4158                        'message'  => __( 'You will no longer receive emails when people submit requests to join this site.', 'buddypress' ),
     4159                ),
     4160        );
     4161
     4162        $members_membership_request_rejected= array(
     4163                'description'      => __( 'A site membership request has been rejected.', 'buddypress' ),
     4164                'named_salutation' => false,
     4165                'unsubscribe'      => false,
     4166        );
     4167
    41354168        $types = array(
    4136                 'activity-comment'                   => $activity_comment,
    4137                 'activity-comment-author'            => $activity_comment_author,
    4138                 'activity-at-message'                => $activity_at_message,
    4139                 'groups-at-message'                  => $groups_at_message,
    4140                 'core-user-registration'             => $core_user_registration,
    4141                 'core-user-registration-with-blog'   => $core_user_registration_with_blog,
    4142                 'friends-request'                    => $friends_request,
    4143                 'friends-request-accepted'           => $friends_request_accepted,
    4144                 'groups-details-updated'             => $groups_details_updated,
    4145                 'groups-invitation'                  => $groups_invitation,
    4146                 'groups-member-promoted'             => $groups_member_promoted,
    4147                 'groups-membership-request'          => $groups_membership_request,
    4148                 'messages-unread'                    => $messages_unread,
    4149                 'settings-verify-email-change'       => $settings_verify_email_change,
    4150                 'groups-membership-request-accepted' => $groups_membership_request_accepted,
    4151                 'groups-membership-request-rejected' => $groups_membership_request_rejected,
    4152                 'core-user-activation'               => $core_user_activation,
    4153                 'bp-members-invitation'              => $members_invitation,
     4169                'activity-comment'                    => $activity_comment,
     4170                'activity-comment-author'             => $activity_comment_author,
     4171                'activity-at-message'                 => $activity_at_message,
     4172                'groups-at-message'                   => $groups_at_message,
     4173                'core-user-registration'              => $core_user_registration,
     4174                'core-user-registration-with-blog'    => $core_user_registration_with_blog,
     4175                'friends-request'                     => $friends_request,
     4176                'friends-request-accepted'            => $friends_request_accepted,
     4177                'groups-details-updated'              => $groups_details_updated,
     4178                'groups-invitation'                   => $groups_invitation,
     4179                'groups-member-promoted'              => $groups_member_promoted,
     4180                'groups-membership-request'           => $groups_membership_request,
     4181                'messages-unread'                     => $messages_unread,
     4182                'settings-verify-email-change'        => $settings_verify_email_change,
     4183                'groups-membership-request-accepted'  => $groups_membership_request_accepted,
     4184                'groups-membership-request-rejected'  => $groups_membership_request_rejected,
     4185                'core-user-activation'                => $core_user_activation,
     4186                'bp-members-invitation'               => $members_invitation,
     4187                'members-membership-request'          => $members_membership_request,
     4188                'members-membership-request-rejected' => $members_membership_request_rejected,
    41544189        );
    41554190
    41564191        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 efb251957..87a16b7a6 100644
    function bp_get_title_parts( $seplocation = 'right' ) { 
    31923192
    31933193        // Sign up page.
    31943194        } elseif ( bp_is_register_page() ) {
    3195                 $bp_title_parts = array( __( 'Create an Account', 'buddypress' ) );
     3195                if ( bp_get_membership_requests_required() ) {
     3196                        $bp_title_parts = array( __( 'Request Membership', 'buddypress' ) );
     3197                } else {
     3198                        $bp_title_parts = array( __( 'Create an Account', 'buddypress' ) );
     3199                }
    31963200
    31973201        // Activation page.
    31983202        } elseif ( bp_is_activation_page() ) {
  • src/bp-core/bp-core-update.php

    diff --git src/bp-core/bp-core-update.php src/bp-core/bp-core-update.php
    index 03710213c..533efdb86 100644
    function bp_core_get_8_0_upgrade_email_schema( $emails ) { 
    704704        return $new_emails;
    705705}
    706706
     707/**
     708 * 10.0.0 update routine.
     709 *
     710 * - Explicitly set all signups to count_sent = 1 & sent_date to registered_date
     711 *
     712 * @since 10.0.0
     713 */
     714function bp_update_to_10_0() {
     715
     716        // @TODO: Explicitly set all signups to count_sent = 1 & sent_date to registered_date
     717        // Is there any way to update that meta in bulk? I think it will have to be one at a time.
     718
     719}
     720
    707721/**
    708722 * Updates the component field for new_members type.
    709723 *
  • 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 ee80328cc..191a8dfb8 100644
    class BP_Admin { 
    415415                if ( bp_is_active( 'members', 'invitations' ) ) {
    416416                        add_settings_field( 'bp-enable-members-invitations', __( 'Invitations', 'buddypress' ), 'bp_admin_setting_callback_members_invitations', 'buddypress', 'bp_members' );
    417417                        register_setting( 'buddypress', 'bp-enable-members-invitations', 'intval' );
     418
     419                        add_settings_field( 'bp-enable-membership-requests', __( 'Membership Requests', 'buddypress' ), 'bp_admin_setting_callback_membership_requests', 'buddypress', 'bp_members' );
     420                        register_setting( 'buddypress', 'bp-enable-membership-requests', 'intval' );
    418421                }
    419422
    420423                /* XProfile Section **************************************************/
  • src/bp-members/bp-members-filters.php

    diff --git src/bp-members/bp-members-filters.php src/bp-members/bp-members-filters.php
    index e1a0c69fd..938e0fc75 100644
    function bp_members_sanitize_invitation_property( $value = '', $property = '', $ 
    366366        return $value;
    367367}
    368368add_filter( 'bp_the_members_invitation_property', 'bp_members_sanitize_invitation_property', 10, 3 );
     369
     370/**
     371 * Filter the actions available on the signups list table.
     372 *
     373 * @since 10.0.0
     374 *
     375 * @param array  $actions       Array of actions and corresponding links.
     376 * @param object $signup_object The signup data object.
     377 */
     378function bp_members_membership_requests_filter_signup_row_actions( $actions, $signup_object ) {
     379        if ( bp_get_membership_requests_required() ) {
     380                // Rename the "email" resend option when membership requests are active.
     381                $email_link = add_query_arg(
     382                        array(
     383                                'page'      => 'bp-signups',
     384                                'signup_id' => $signup_object->id,
     385                                'action'    => 'resend',
     386                        ),
     387                        bp_get_admin_url( 'users.php' )
     388                );
     389
     390                $resend_label = ( 0 === $signup_object->count_sent ) ? __( 'Approve Request', 'buddypress' ) : __( 'Resend Approval', 'buddypress' );
     391
     392                $actions['resend'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $email_link ), $resend_label );
     393
     394                /*
     395                 * Add an "extended" link to the row action on the pending users table
     396                 * so admins can see what registration info the user supplied on the
     397                 * request membership form.
     398                 * http://bpdev.local/wp-admin/users.php?page=bp-profile-edit&user_id=40
     399                 http://bpdev.local/wp-admin/users.php?page=bp-signups&=http://bpdev.local/wp-admin/users.php?page=bp-profile-edit&user_id=38
     400                 *
     401                 */
     402                $user = get_user_by( 'email', $signup_object->user_email );
     403                if ( $user ) {
     404                        $edit_profile_args = array(
     405                                'page'    => 'bp-profile-edit',
     406                                'user_id' => $user->ID,
     407                        );
     408                        if ( is_network_admin() ) {
     409                                $base_edit_url = network_admin_url( 'users.php' );
     410                        } else {
     411                                $base_edit_url = admin_url( 'users.php' );
     412                        }
     413                        $edit_profile      = add_query_arg( $edit_profile_args, $base_edit_url );
     414                        $edit_profile_link = sprintf( '<a href="%1$s">%2$s</a>',  esc_url( $edit_profile ), esc_html__( 'Extended', 'buddypress' ) );
     415
     416                        $new_edit_actions = array( 'edit-profile' => $edit_profile_link );
     417
     418                        $actions = array_merge( $new_edit_actions, $actions );
     419                }
     420        }
     421        return $actions;
     422        //@TODO add help to manage signups screen:
     423        // Activate will activate the user immediately without requiring that they validate their email.
     424        // Approve Request will send the user an activation email, so they will still need to take action. This also will check that the user's email address is valid.
     425}
     426add_filter( 'bp_members_ms_signup_row_actions', 'bp_members_membership_requests_filter_signup_row_actions', 10, 2 );
     427
     428/**
     429 * Filter the bulk actions available on the signups list table.
     430 *
     431 * @since 10.0.0
     432 *
     433 * @param array  $actions       Array of actions and corresponding links.
     434 */
     435function bp_members_membership_requests_filter_signup_bulk_actions( $actions ) {
     436        if ( bp_get_membership_requests_required() ) {
     437                // Rename the "email" resend option when membership requests are active.
     438                $actions['resend'] = _x( 'Approve', 'Pending signup action', 'buddypress' );
     439        }
     440        return $actions;
     441}
     442add_filter( 'bp_members_ms_signup_bulk_actions', 'bp_members_membership_requests_filter_signup_bulk_actions' );
     443
     444/**
     445 * Filter the "Last Sent" column header on the pending users table.
     446 *
     447 * @since 10.0.0
     448 *
     449* @param array $value Array of columns to display.
     450 */
     451function bp_members_membership_requests_filter_signup_table_date_sent_header( $columns ) {
     452        if ( bp_get_membership_requests_required() ) {
     453                $columns['date_sent'] = __( 'Approved', 'buddypress' );
     454        }
     455        return $columns;
     456}
     457add_filter( 'bp_members_signup_columns', 'bp_members_membership_requests_filter_signup_table_date_sent_header' );
     458add_filter( 'bp_members_ms_signup_columns', 'bp_members_membership_requests_filter_signup_table_date_sent_header' );
     459
     460/**
     461 * Filter the "Last Sent" column message on the pending users table.
     462 *
     463 * @since 10.0.0
     464 *
     465 * @param string      $message "Not yet sent" message.
     466 * @param object|null $signup  Signup object instance.
     467 */
     468function bp_members_membership_requests_filter_signup_table_unsent_message( $message, $signup ) {
     469        if ( bp_get_membership_requests_required() && 0 === $signup->count_sent ) {
     470                $message = __( 'Not yet approved', 'buddypress' );
     471        }
     472        return $message;
     473}
     474add_filter( 'bp_members_signup_date_sent_unsent_message', 'bp_members_membership_requests_filter_signup_table_unsent_message', 10, 2 );
     475add_filter( 'bp_members_ms_signup_date_sent_unsent_message', 'bp_members_membership_requests_filter_signup_table_unsent_message', 10, 2 );
     476
     477/**
     478 * Filter the "Register" link from `wp_register()` as used in
     479 * `sidebar.php` and the WP Core meta widget.
     480 *
     481 * @since 10.0.0
     482 *
     483 * @param string $link The HTML code for the link to the Registration or Admin page.
     484 */
     485function bp_members_membership_requests_filter_sidebar_register_link( $link ) {
     486        // $link should be an empty string when public registration is disabled.
     487        if ( ! is_user_logged_in() && bp_get_membership_requests_required() && empty( $link ) ) {
     488                // @TODO: How can we know what before and after tags should be?
     489                $link = '<li><a href="' . esc_url( wp_registration_url() ) . '">' . __( 'Request Membership' ) . '</a><li>';
     490        }
     491        return $link;
     492}
     493add_filter( 'register', 'bp_members_membership_requests_filter_sidebar_register_link' );
     494
     495/**
     496 * Add a Request Membership link to the WP Toolbar.
     497 * Priority 21 should place it just after the "Log In" link.
     498 *
     499 * @since 10.0.0
     500 *
     501 * @param WP_Admin_Bar $wp_admin_bar WP_Admin_Bar instance, passed by reference
     502 */
     503function bp_members_membership_requests_add_toolbar_link( $wp_admin_bar ) {
     504        if ( is_user_logged_in() || ! bp_get_membership_requests_required() ) {
     505                return;
     506        }
     507
     508        $args = array(
     509                'id'    => 'bp-request-membership',
     510                'title' => __( 'Request Membership' ),
     511                'href'  => wp_registration_url(),
     512                'meta'  => array(
     513                        'class' => 'buddypress-request-membership',
     514                        'title' => __( 'Request Membership' )
     515                ),
     516        );
     517        $wp_admin_bar->add_node( $args );
     518}
     519add_action( 'admin_bar_menu', 'bp_members_membership_requests_add_toolbar_link', 21 );
     520
     521/**
     522 * Add a Request Membership link to the WP Login form.
     523 * This is not the ideal place, but WP Core doesn't offer a filer
     524 * in the #nav paragraph where the "Register" link would appear.
     525 *
     526 * @since 10.0.0
     527 *
     528 * @param string $link HTML link to the home URL of the current site.
     529 */
     530function bp_members_membership_requests_add_link_wp_login( $link ) {
     531        if ( bp_get_membership_requests_required() ) {
     532                return $link . '&ensp;|&ensp;' . '<a href="' . esc_url( wp_registration_url() ) . '">' . __( 'Request Membership' ) . '</a>';
     533        }
     534}
     535add_action( 'login_site_html_link', 'bp_members_membership_requests_add_link_wp_login' );
  • src/bp-members/bp-members-functions.php

    diff --git src/bp-members/bp-members-functions.php src/bp-members/bp-members-functions.php
    index 93fd7cafd..141c545fa 100644
    function bp_core_signup_send_validation_email( $user_id, $user_email, $key, $sal 
    23882388        bp_send_email( 'core-user-registration', $to, $args );
    23892389
    23902390        // Record that the activation email has been sent.
    2391         $signups = BP_Signup::get(
    2392                 array(
    2393                         'activation_key' => $key,
    2394                 )
    2395         );
     2391        $signup = bp_members_get_signup_by( 'activation_key', $key );
    23962392
    2397         if ( ! empty( $signups['signups'] ) ) {
    2398                 foreach ( $signups['signups'] as $signup ) {
    2399                         $meta = array(
    2400                                 'sent_date'  => current_time( 'mysql', true ),
    2401                                 'count_sent' => $signup->count_sent + 1
    2402                         );
     2393        if ( $signup ) {
     2394                $meta = array(
     2395                        'sent_date'  => current_time( 'mysql', true ),
     2396                        'count_sent' => $signup->count_sent + 1
     2397                );
    24032398
    2404                         BP_Signup::update( array(
    2405                                 'signup_id' => $signup->id,
    2406                                 'meta'      => $meta,
    2407                         ) );
    2408                 }
     2399                BP_Signup::update( array(
     2400                        'signup_id' => $signup->id,
     2401                        'meta'      => $meta,
     2402                ) );
    24092403        }
    24102404}
    24112405
    function bp_core_signup_disable_inactive( $user = null, $username = '', $passwor 
    24502444        }
    24512445
    24522446        // Unactivated user account found!
    2453         // Set up the feedback message.
    2454         $signup_id = $signup['signups'][0]->signup_id;
     2447        /*
     2448         * Don't allow users to resend their own activation email
     2449         * when membership requests are enabled.
     2450         */
     2451        if ( bp_get_membership_requests_required() ) {
     2452                return new WP_Error( 'bp_account_not_activated', __( '<strong>Error</strong>: Your membership request has not yet been approved.', 'buddypress' ) );
     2453        } else {
     2454                // Set up the feedback message.
     2455                $signup_id = $signup['signups'][0]->signup_id;
    24552456
    2456         $resend_url_params = array(
    2457                 'action' => 'bp-resend-activation',
    2458                 'id'     => $signup_id,
    2459         );
     2457                $resend_url_params = array(
     2458                        'action' => 'bp-resend-activation',
     2459                        'id'     => $signup_id,
     2460                );
    24602461
    2461         $resend_url = wp_nonce_url(
    2462                 add_query_arg( $resend_url_params, wp_login_url() ),
    2463                 'bp-resend-activation'
    2464         );
     2462                $resend_url = wp_nonce_url(
     2463                        add_query_arg( $resend_url_params, wp_login_url() ),
     2464                        'bp-resend-activation'
     2465                );
    24652466
    2466         $resend_string = '<br /><br />';
     2467                $resend_string = '<br /><br />';
    24672468
    2468         /* translators: %s: the activation url */
    2469         $resend_string .= sprintf( __( 'If you have not received an email yet, <a href="%s">click here to resend it</a>.', 'buddypress' ), esc_url( $resend_url ) );
     2469                /* translators: %s: the activation url */
     2470                $resend_string .= sprintf( __( 'If you have not received an email yet, <a href="%s">click here to resend it</a>.', 'buddypress' ), esc_url( $resend_url ) );
    24702471
    2471         return new WP_Error( 'bp_account_not_activated', __( '<strong>Error</strong>: Your account has not been activated. Check your email for the activation link.', 'buddypress' ) . $resend_string );
     2472                return new WP_Error( 'bp_account_not_activated', __( '<strong>Error</strong>: Your account has not been activated. Check your email for the activation link.', 'buddypress' ) . $resend_string );
     2473        }
    24722474}
    24732475add_filter( 'authenticate', 'bp_core_signup_disable_inactive', 30, 3 );
    24742476
    function bp_get_members_invitation_from_request() { 
    36943696         */
    36953697        return apply_filters( 'bp_get_members_invitation_from_request', $invite );
    36963698}
     3699
     3700/**
     3701 * Get WP_User object corresponding to a record in the signups table.
     3702 *
     3703 * @since 10.0.0
     3704 *
     3705 * @param string $field Which fields to search by. Possible values are
     3706 *                      activation_key, user_email, id.
     3707 * @param string $value Value to search by.
     3708 * @return bool|BP_Signup $signup Found signup, returns first found
     3709 *                                if more than one is found.
     3710 */
     3711function bp_members_get_signup_by( $field = 'activation_key', $value ) {
     3712        switch ( $field ) {
     3713                case 'activation_key':
     3714                case 'user_email':
     3715                        $key = $field;
     3716                        break;
     3717
     3718                case 'id':
     3719                default:
     3720                        $key = 'include';
     3721                        break;
     3722        }
     3723
     3724        $signups = BP_Signup::get(
     3725                array(
     3726                        $key => $value,
     3727                )
     3728        );
     3729
     3730        if ( ! empty( $signups['signups'] ) ) {
     3731                $signup = current( $signups['signups'] );
     3732        } else {
     3733                $signup = false;
     3734        }
     3735
     3736        return $signup;
     3737}
  • src/bp-members/bp-members-invitations.php

    diff --git src/bp-members/bp-members-invitations.php src/bp-members/bp-members-invitations.php
    index 73f50e09b..7e95c791d 100644
    function bp_members_invitations_delete_optedout_invites( $optout ) { 
    183183        );
    184184}
    185185add_action( 'bp_optout_after_save', 'bp_members_invitations_delete_optedout_invites' );
     186
     187/**
     188 * If a user submits a site membership request, but there's a
     189 * sent invitation to her, bypass the manual approval of the request.
     190 *
     191 * @since 10.0.0
     192 *
     193 * @param bool  $send    Whether or not this membership request should be approved
     194 *                       immediately and the activation email sent.
     195 *                       Default is `false` meaning that the request should be
     196 *                       manually approved by a site admin.
     197 * @param array $details The details of the request.
     198 */
     199function bp_members_invitations_maybe_bypass_request_approval( $send, $details ) {
     200        if ( ! bp_get_members_invitations_allowed() ) {
     201                return $send;
     202        }
     203
     204        // We'll need the prospective user's email address.
     205        if ( empty( $details['user_email'] ) ) {
     206                return $send;
     207        }
     208
     209        $invites = bp_members_invitations_get_invites(
     210                array(
     211                        'invitee_email' => $details['user_email'],
     212                        'invite_sent'   => 'sent'
     213                )
     214        );
     215        // If pending invitations exist, send the verification mail.
     216        if ( $invites ) {
     217                $send = true;
     218        }
     219        return $send;
     220}
     221add_filter( 'bp_members_membership_requests_bypass_manual_approval', 'bp_members_invitations_maybe_bypass_request_approval', 10, 2 );
  • new file src/bp-members/bp-members-membership-requests.php

    diff --git src/bp-members/bp-members-membership-requests.php src/bp-members/bp-members-membership-requests.php
    new file mode 100644
    index 000000000..e1ce2aab5
    - +  
     1<?php
     2/**
     3 * BuddyPress Membership Requests
     4 *
     5 * @package BuddyPress
     6 * @subpackage MembersMembershipRequest
     7 * @since 10.0.0
     8 */
     9
     10// Exit if accessed directly.
     11defined( 'ABSPATH' ) || exit;
     12
     13
     14/**
     15 * When a user creates a network membership request,
     16 * prevent the sending of the activation email so that
     17 * the site admins can send it later.
     18 *
     19 * @since 10.0.0
     20 *
     21 * @param bool   $send           Whether or not to send the activation key.
     22 * @param int    $user_id        User ID to send activation key to.
     23 * @param string $user_email     User email to send activation key to.
     24 * @param string $activation_key Activation key to be sent.
     25 * @param array  $usermeta       Miscellaneous metadata about the user (blog-specific
     26 *                               signup data, xprofile data, etc).
     27 * @return bool Whether or not to send the activation key.
     28 */
     29function bp_members_membership_requests_cancel_activation_email( $send, $user_id = 0, $user_email = '', $activation_key = '', $usermeta = array() ) {
     30
     31        if ( bp_get_membership_requests_required() ) {
     32                $details = array(
     33                        'user_id'        => $user_id,
     34                        'user_email'     => $user_email,
     35                        'activation_key' => $activation_key,
     36                        'usermeta'       => $usermeta,
     37                );
     38
     39                /**
     40                 * Allow some membership requests to be approved immediately.
     41                 * For example, you might want to approve all requests
     42                 * coming from users with certain email address domains.
     43                 * If `true` is returned the activation email will be sent to the user.
     44                 *
     45                 * @since 10.0.0
     46                 *
     47                 * @param bool  $send    Whether or not this membership request should be approved
     48                 *                       immediately and the activation email sent.
     49                 *                       Default is `false` meaning that the request should be
     50                 *                       manually approved by a site admin.
     51                 * @param array $details The details of the request.
     52                 */
     53                $send = apply_filters( 'bp_members_membership_requests_bypass_manual_approval', false, $details );
     54
     55                // If the registration process has been interrupted, this is a new membership request.
     56                if ( ! $send ) {
     57                        $signup = bp_members_get_signup_by( 'activation_key', $activation_key );
     58
     59                        /**
     60                         * Fires when a site membership request has been created and is pending.
     61                         *
     62                         * @since 10.0.0
     63                         *
     64                         * @param BP_Signup $signup  The signup object that has been created.
     65                         * @param array     $details The details of the request.
     66                         */
     67                        do_action( 'bp_members_membership_request_submitted', $signup, $details );
     68                }
     69        }
     70
     71        return $send;
     72}
     73add_filter( 'bp_core_signup_send_activation_key', 'bp_members_membership_requests_cancel_activation_email', 10, 5 );
     74
     75
     76/**
     77 * Notify site admins about a new membership request.
     78 *
     79 * @since 10.0.0
     80 *
     81 * @param BP_Signup $signup  The signup object that has been created.
     82 */
     83function bp_members_membership_requests_notify_site_admins( $signup ) {
     84
     85        $admins_query = new WP_User_Query( array(
     86                'role'   => 'administrator',
     87                'fields' => 'ids'
     88        ) );
     89        $admin_ids   = $admins_query->get_results();
     90
     91        foreach ( $admin_ids as $admin_id ) {
     92                // Trigger a BuddyPress Notification.
     93                if ( bp_is_active( 'notifications' ) ) {
     94                        bp_notifications_add_notification( array(
     95                                'user_id'           => $admin_id,
     96                                'item_id'           => $signup->signup_id,
     97                                'component_name'    => buddypress()->members->id,
     98                                'component_action'  => 'membership_request_submitted',
     99                                'date_notified'     => bp_core_current_time(),
     100                                'is_new'            => 1,
     101                        ) );
     102                }
     103
     104                // Bail if member opted out of receiving this email.
     105                if ( 'no' === bp_get_user_meta( $admin_id, 'notification_members_membership_request', true ) ) {
     106                        return;
     107                }
     108
     109                $unsubscribe_args = array(
     110                        'user_id'           => $admin_id,
     111                        'notification_type' => 'members-membership-request',
     112                );
     113                $manage_url = add_query_arg( array(
     114                        'mod_req'   => 1,
     115                        'page'      => 'bp-signups',
     116                        'signup_id' => $signup->signup_id,
     117                ), bp_get_admin_url( 'users.php' ) );
     118                $args  = array(
     119                        'tokens' => array(
     120                                'admin.id'                   => $admin_id,
     121                                'manage.url'                 => $manage_url,
     122                                'requesting-user.user_login' => $signup->user_login,
     123                                'unsubscribe'                => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ),
     124                        ),
     125                );
     126                bp_send_email( 'members-membership-request', (int) $admin_id, $args );
     127        }
     128
     129}
     130add_action( 'bp_members_membership_request_submitted', 'bp_members_membership_requests_notify_site_admins' );
     131
     132/**
     133 * Add "Request Membership" link to Widget login form.
     134 *
     135 * @since 10.0.0
     136 *
     137 * @return string $retval the HTML for the request membership link.
     138 */
     139function bp_members_membership_requests_add_link_to_widget_login_form() {
     140        if ( ! bp_get_membership_requests_required() ) {
     141                return;
     142        }
     143        ?>
     144        <span class="bp-login-widget-request-membership-link"><a href="<?php echo esc_url( bp_get_signup_page() ); ?>"><?php _e( 'Request Membership', 'buddypress' ); ?></a></span>
     145        <?php
     146}
     147add_action( 'bp_login_widget_form', 'bp_members_membership_requests_add_link_to_widget_login_form' );
     148
     149/**
     150 * In the Nouveau template pack, when membership requests are required,
     151 * change registration form submit button label to "Submit Request".
     152 *
     153 * @since 10.0.0
     154 *
     155 * @return string $retval the HTML for the request membership link.
     156 */
     157function bp_members_membership_requests_filter_complete_signup_button( $buttons ) {
     158        if ( bp_get_membership_requests_required() ) {
     159                $buttons['register']['attributes']['value'] = __( 'Submit Request', 'buddypress' );
     160        }
     161        return $buttons;
     162}
     163add_filter( 'bp_nouveau_get_submit_button', 'bp_members_membership_requests_filter_complete_signup_button' );
     164
     165/**
     166 * Send a message to the requesting user when his or her
     167 * site membership request has been rejected.
     168 *
     169 * @since 10.0.0
     170 *
     171 * @param array $signup_ids Array of pending IDs to delete.
     172 */
     173function bp_members_membership_requests_send_rejection_mail( $signup_ids ) {
     174        if ( bp_get_membership_requests_required() ) {
     175                $signups = BP_Signup::get(
     176                        array(
     177                                'include' => $signup_ids,
     178                        )
     179                );
     180                if ( empty( $signups['signups'] ) ) {
     181                        return;
     182                }
     183                foreach ( $signups['signups'] as $signup ) {
     184                        if ( ! empty( $signup->user_email ) ) {
     185                                bp_send_email( 'members-membership-request-rejected', $signup->user_email, $args );
     186                        }
     187                }
     188        }
     189}
     190add_filter( 'bp_core_signup_before_delete', 'bp_members_membership_requests_send_rejection_mail' );
     191
  • src/bp-members/bp-members-notifications.php

    diff --git src/bp-members/bp-members-notifications.php src/bp-members/bp-members-notifications.php
    index 93cee7b89..d63126341 100644
    function members_format_notifications( $action, $item_id, $secondary_item_id, $t 
    6161                                }
    6262                        }
    6363                        break;
     64
     65                case 'membership_request_submitted':
     66                        // $item_id is the id of the signup, not the user ID.
     67                        $signup = new BP_Signup( $item_id );
     68
     69                        // Set up the string and the filter.
     70                        if ( (int) $total_items > 1 ) {
     71                                $link   = bp_get_notifications_permalink();
     72                                $amount = 'multiple';
     73
     74                                $text = sprintf( __( '%d people have requested site membership.', 'buddypress' ), (int) $total_items );
     75                        } else {
     76                                $link   = add_query_arg( array(
     77                                        'mod_req'   => 1,
     78                                        'page'      => 'bp-signups',
     79                                        'signup_id' => $item_id,
     80
     81                                ), bp_get_admin_url( 'users.php' ) );
     82                                $amount = 'single';
     83
     84                                /* translators: %s: new user name */
     85                                $text = sprintf( __( '%s has requested site membership.', 'buddypress' ),  esc_html( $signup->user_login ) );
     86                        }
     87                        break;
    6488        }
    6589
    6690        // Return either an HTML link or an array, depending on the requested format.
    function bp_members_mark_read_accepted_invitation_notification() { 
    167191                        'is_new' => false,
    168192                ),
    169193                array(
    170                         'user_id' => bp_loggedin_user_id(),
    171                         'item_id' => bp_displayed_user_id(),
     194                        'user_id'           => bp_loggedin_user_id(),
     195                        'item_id'           => bp_displayed_user_id(),
     196                        'component_action'  => 'accepted_invitation',
    172197                )
    173198        );
    174199}
    175200add_action( 'bp_screens', 'bp_members_mark_read_accepted_invitation_notification' );
    176201
     202/**
     203 * Mark new membership request notifications as read when user visits Manage BP Signups screen.
     204 *
     205 * @since 10.0.0
     206 */
     207function bp_members_mark_read_submitted_membership_request_notification() {
     208        if ( ! wp_doing_ajax() && 'users_page_bp-signups' === get_current_screen()->base && ! empty( $_GET['mod_req'] ) && ! empty( $_GET['signup_id'] ) ) {
     209                // Mark notification as read.
     210                BP_Notifications_Notification::update(
     211                        array(
     212                                'is_new' => false,
     213                        ),
     214                        array(
     215                                'user_id'           => bp_loggedin_user_id(),
     216                                'item_id'           => $_GET['signup_id'],
     217                                'component_action'  => 'membership_request_submitted',
     218                        )
     219                );
     220        }
     221}
     222add_action( 'admin_footer', 'bp_members_mark_read_submitted_membership_request_notification' );
     223
    177224/**
    178225 * Add Members-related settings to the Settings > Notifications page.
    179226 *
    add_action( 'bp_screens', 'bp_members_mark_read_accepted_invitation_notification 
    181228 */
    182229function members_screen_notification_settings() {
    183230
    184         // Bail early if invitations are not allowed--they are the only members notification so far.
    185         if ( ! bp_get_members_invitations_allowed () ) {
     231        // Bail early if invitations and requests are not allowed--they are the only members notification so far.
     232        if ( ! bp_get_members_invitations_allowed() && ( ! bp_get_membership_requests_required() || ! user_can( bp_displayed_user_id(), 'bp_moderate' ) ) ) {
    186233                return;
    187234        }
    188 
    189         if ( ! $allow_acceptance_emails = bp_get_user_meta( bp_displayed_user_id(), 'notification_members_invitation_accepted', true ) ) {
    190                 $allow_acceptance_emails = 'yes';
    191         }
    192235        ?>
    193236
    194237        <table class="notification-settings" id="members-notification-settings">
    function members_screen_notification_settings() { 
    202245                </thead>
    203246
    204247                <tbody>
    205                         <tr id="members-notification-settings-invitation_accepted">
    206                                 <td></td>
    207                                 <td><?php _ex( 'Someone accepts your membership invitation', 'Member settings on notification settings page', 'buddypress' ) ?></td>
    208                                 <td class="yes"><input type="radio" name="notifications[notification_members_invitation_accepted]" id="notification-members-invitation-accepted-yes" value="yes" <?php checked( $allow_acceptance_emails, 'yes', true ) ?>/><label for="notification-members-invitation-accepted-yes" class="bp-screen-reader-text"><?php
    209                                         /* translators: accessibility text */
    210                                         _e( 'Yes, send email', 'buddypress' );
    211                                 ?></label></td>
    212                                 <td class="no"><input type="radio" name="notifications[notification_members_invitation_accepted]" id="notification-members-invitation-accepted-no" value="no" <?php checked( $allow_acceptance_emails, 'no', true ) ?>/><label for="notification-members-invitation-accepted-no" class="bp-screen-reader-text"><?php
    213                                         /* translators: accessibility text */
    214                                         _e( 'No, do not send email', 'buddypress' );
    215                                 ?></label></td>
    216                         </tr>
    217248
    218249                        <?php
     250                        if ( bp_get_members_invitations_allowed() ) :
     251                                if ( ! $allow_acceptance_emails = bp_get_user_meta( bp_displayed_user_id(), 'notification_members_invitation_accepted', true ) ) {
     252                                        $allow_acceptance_emails = 'yes';
     253                                }
     254                                ?>
     255                                <tr id="members-notification-settings-invitation_accepted">
     256                                        <td></td>
     257                                        <td><?php _ex( 'Someone accepts your membership invitation', 'Member settings on notification settings page', 'buddypress' ) ?></td>
     258                                        <td class="yes"><input type="radio" name="notifications[notification_members_invitation_accepted]" id="notification-members-invitation-accepted-yes" value="yes" <?php checked( $allow_acceptance_emails, 'yes', true ) ?>/><label for="notification-members-invitation-accepted-yes" class="bp-screen-reader-text"><?php
     259                                                /* translators: accessibility text */
     260                                                _e( 'Yes, send email', 'buddypress' );
     261                                        ?></label></td>
     262                                        <td class="no"><input type="radio" name="notifications[notification_members_invitation_accepted]" id="notification-members-invitation-accepted-no" value="no" <?php checked( $allow_acceptance_emails, 'no', true ) ?>/><label for="notification-members-invitation-accepted-no" class="bp-screen-reader-text"><?php
     263                                                /* translators: accessibility text */
     264                                                _e( 'No, do not send email', 'buddypress' );
     265                                        ?></label></td>
     266                                </tr>
     267                                <?php
     268                        endif;
     269
     270                        if ( bp_get_membership_requests_required() && user_can( bp_displayed_user_id(), 'bp_moderate' ) ) :
     271                                if ( ! $allow_request_emails = bp_get_user_meta( bp_displayed_user_id(), 'notification_members_membership_request', true ) ) {
     272                                        $allow_request_emails = 'yes';
     273                                }
     274                                ?>
     275                                <tr id="members-notification-settings-submitted_membership_request">
     276                                        <td></td>
     277                                        <td><?php _ex( 'Someone has requested site membership', 'Member settings on notification settings page', 'buddypress' ) ?></td>
     278                                        <td class="yes"><input type="radio" name="notifications[notification_members_membership_request]" id="notification-members-submitted_membership_request-yes" value="yes" <?php checked( $allow_request_emails, 'yes', true ) ?>/><label for="notification-members-submitted_membership_request-yes" class="bp-screen-reader-text"><?php
     279                                                /* translators: accessibility text */
     280                                                _e( 'Yes, send email', 'buddypress' );
     281                                        ?></label></td>
     282                                        <td class="no"><input type="radio" name="notifications[notification_members_membership_request]" id="notification-members-submitted_membership_request-no" value="no" <?php checked( $allow_request_emails, 'no', true ) ?>/><label for="notification-members-submitted_membership_request-no" class="bp-screen-reader-text"><?php
     283                                                /* translators: accessibility text */
     284                                                _e( 'No, do not send email', 'buddypress' );
     285                                        ?></label></td>
     286                                </tr>
     287                                <?php
     288                        endif;
    219289
    220290                        /**
    221291                         * Fires after the last table row on the members notification screen.
  • src/bp-members/bp-members-template.php

    diff --git src/bp-members/bp-members-template.php src/bp-members/bp-members-template.php
    index 39cfd6e65..32864d043 100644
    function bp_get_members_invitations_allowed() { 
    29252925        return apply_filters( 'bp_get_members_invitations_allowed', bp_is_active( 'members', 'invitations' ) && (bool) bp_get_option( 'bp-enable-members-invitations' ) );
    29262926}
    29272927
     2928/**
     2929 * Are membership requests required for joining this site?
     2930 *
     2931 * @since 10.0.0
     2932 *
     2933 * @param bool $context "raw" to fetch value from database,
     2934 *                      "site" to take "anyone can register" setting into account.
     2935 * @return bool
     2936 */
     2937function bp_get_membership_requests_required( $context = 'site' ) {
     2938        if ( 'raw' === $context ) {
     2939                $retval = bp_is_active( 'members', 'invitations' ) && (bool) bp_get_option( 'bp-enable-membership-requests' );
     2940        } else {
     2941                $retval = bp_is_active( 'members', 'invitations' ) && ! bp_get_signup_allowed() && (bool) bp_get_option( 'bp-enable-membership-requests' );
     2942        }
     2943
     2944        /**
     2945         * Filters whether or not prospective members may submit network membership requests.
     2946         *
     2947         * @since 10.0.0
     2948         *
     2949         * @param bool $retval Whether or not membership requests are required.
     2950         * @param bool $retval Whether this is the value stored in the database ('raw')
     2951         *                     or whether the site's "anyone can register" setting is
     2952         *                     being considered ('site' or anything else).
     2953         */
     2954        return apply_filters( 'bp_get_membership_requests_required', $retval, $context );
     2955}
     2956
    29282957/**
    29292958 * Should the system create and allow access
    29302959 * to the Register and Activate pages?
    function bp_get_members_invitations_allowed() { 
    29342963 * @return bool
    29352964 */
    29362965function bp_allow_access_to_registration_pages() {
    2937         $retval = bp_get_signup_allowed() || bp_get_members_invitations_allowed();
     2966        $retval = bp_get_signup_allowed() || bp_get_members_invitations_allowed() || bp_get_membership_requests_required();
    29382967
    29392968        /**
    29402969         * Filters whether or not the system should create and allow access
  • 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 19ec1946b..67dc6a828 100644
    class BP_Members_Admin { 
    21862186                ) );
    21872187
    21882188                $signups    = $signups_query['signups'];
    2189                 $signup_ids = wp_list_pluck( $signups, 'signup_id' );
     2189                $signup_ids = wp_list_pluck( $signups, 'id' );
    21902190
    21912191                // Set up strings.
    21922192                switch ( $action ) {
    class BP_Members_Admin { 
    22092209                                break;
    22102210
    22112211                        case 'resend' :
    2212                                 $header_text = __( 'Resend Activation Emails', 'buddypress' );
    2213                                 if ( 1 == count( $signup_ids ) ) {
    2214                                         $helper_text = __( 'You are about to resend an activation email to the following account:', 'buddypress' );
     2212
     2213                                if ( bp_get_membership_requests_required() ) {
     2214                                        $header_text = __( 'Approve Membership Requests', 'buddypress' );
     2215                                        if ( 1 == count( $signup_ids ) ) {
     2216                                                $helper_text = __( 'You are about to send an approval email to the following user:', 'buddypress' );
     2217                                        } else {
     2218                                                $helper_text = __( 'You are about to send approval emails to the following users:', 'buddypress' );
     2219                                        }
    22152220                                } else {
    2216                                         $helper_text = __( 'You are about to resend an activation email to the following accounts:', 'buddypress' );
     2221                                        $header_text = __( 'Resend Activation Emails', 'buddypress' );
     2222                                        if ( 1 == count( $signup_ids ) ) {
     2223                                                $helper_text = __( 'You are about to resend an activation email to the following account:', 'buddypress' );
     2224                                        } else {
     2225                                                $helper_text = __( 'You are about to resend an activation email to the following accounts:', 'buddypress' );
     2226                                        }
    22172227                                }
    22182228                                break;
     2229
    22192230                }
    22202231
    22212232                // These arguments are added to all URLs.
    class BP_Members_Admin { 
    22442255
    22452256                // Prefetch registration field data.
    22462257                $fdata = array();
    2247                 if ( 'activate' === $action && bp_is_active( 'xprofile' ) ) {
     2258                if ( bp_is_active( 'xprofile' ) && ( 'activate' == $action || ( 'resend' == $action && bp_get_membership_requests_required() ) ) ) {
    22482259                        $field_groups = bp_xprofile_get_groups( array(
    22492260                                'exclude_fields'    => 1,
    22502261                                'update_meta_cache' => false,
    class BP_Members_Admin { 
    22682279
    22692280                        <ol class="bp-signups-list">
    22702281                        <?php foreach ( $signups as $signup ) :
    2271                                 $last_notified = mysql2date( 'Y/m/d g:i:s a', $signup->date_sent );
     2282                                if ( $signup->count_sent > 0 ) {
     2283                                        $last_notified = mysql2date( 'Y/m/d g:i:s a', $signup->date_sent );
     2284                                } else {
     2285                                        $last_notified = __( 'Not yet notified', 'buddypress' );
     2286                                }
    22722287                                $profile_field_ids = array();
    22732288
    22742289                                // Get all xprofile field IDs except field 1.
    class BP_Members_Admin { 
    22802295                                <li>
    22812296                                        <strong><?php echo esc_html( $signup->user_login ) ?></strong>
    22822297
    2283                                         <?php if ( 'activate' == $action ) : ?>
     2298                                        <?php if ( 'activate' == $action || ( 'resend' == $action && bp_get_membership_requests_required() ) ) : ?>
    22842299                                                <table class="wp-list-table widefat fixed striped">
    22852300                                                        <tbody>
    22862301                                                                <tr>
  • 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 432e3ecce..2507c405b 100644
    class BP_Members_Component extends BP_Component { 
    6767                        'widgets',
    6868                        'cache',
    6969                        'invitations',
     70                        'membership-requests',
    7071                        'notifications',
    7172                );
    7273
  • src/bp-members/classes/class-bp-members-list-table.php

    diff --git src/bp-members/classes/class-bp-members-list-table.php src/bp-members/classes/class-bp-members-list-table.php
    index 8e7733b47..ddf4b6d02 100644
    class BP_Members_List_Table extends WP_Users_List_Table { 
    113113
    114114                // Reset the screen id.
    115115                $this->screen->id = $reset_screen_id;
     116
     117                // Use thickbox to display the extended profile information.
     118                if ( bp_is_active( 'xprofile' ) ) {
     119                        add_thickbox();
     120                }
    116121        }
    117122
    118123        /**
    class BP_Members_List_Table extends WP_Users_List_Table { 
    138143         */
    139144        public function get_columns() {
    140145
    141                 /**
    142                  * Filters the single site Members signup columns.
    143                  *
    144                  * @since 2.0.0
    145                  *
    146                  * @param array $value Array of columns to display.
    147                  */
    148                 return apply_filters( 'bp_members_signup_columns', array(
     146                $columns = array(
    149147                        'cb'         => '<input type="checkbox" />',
    150148                        'username'   => __( 'Username',    'buddypress' ),
    151149                        'name'       => __( 'Name',        'buddypress' ),
    class BP_Members_List_Table extends WP_Users_List_Table { 
    153151                        'registered' => __( 'Registered',  'buddypress' ),
    154152                        'date_sent'  => __( 'Last Sent',   'buddypress' ),
    155153                        'count_sent' => __( 'Emails Sent', 'buddypress' )
    156                 ) );
     154                );
     155
     156                if ( bp_is_active( 'xprofile' ) ) {
     157                        $profile_entry = array(
     158                                'extended_profile' => __( 'Profile Info', 'buddypress' )
     159                        );
     160                        $position = 4;
     161                        $columns = array_merge(
     162                                array_slice( $columns, 0, $position, true ),
     163                                $profile_entry,
     164                                array_slice( $columns, $position, count( $columns ) - 1, true )
     165                        );
     166
     167                }
     168
     169                /**
     170                 * Filters the single site Members signup columns.
     171                 *
     172                 * @since 2.0.0
     173                 *
     174                 * @param array $value Array of columns to display.
     175                 */
     176                return apply_filters( 'bp_members_signup_columns', $columns );
    157177        }
    158178
    159179        /**
    class BP_Members_List_Table extends WP_Users_List_Table { 
    171191                        $actions['delete'] = __( 'Delete', 'buddypress' );
    172192                }
    173193
    174                 return $actions;
     194                /**
     195                 * Filters the bulk actions for signups.
     196                 *
     197                 * @since 10.0.0
     198                 *
     199                 * @param array $actions Array of actions and corresponding labels.
     200                 */
     201                return apply_filters( 'bp_members_ms_signup_bulk_actions', $actions );
    175202        }
    176203
    177204        /**
    class BP_Members_List_Table extends WP_Users_List_Table { 
    183210         */
    184211        public function no_items() {
    185212
    186                 if ( bp_get_signup_allowed() ) {
     213                if ( bp_get_signup_allowed() || bp_get_membership_requests_required() ) {
    187214                        esc_html_e( 'No pending accounts found.', 'buddypress' );
    188215                } else {
    189216                        $link = false;
    class BP_Members_List_Table extends WP_Users_List_Table { 
    374401         * @param object|null $signup_object The signup data object.
    375402         */
    376403        public function column_date_sent( $signup_object = null ) {
    377                 echo mysql2date( 'Y/m/d', $signup_object->date_sent );
     404                if ( $signup_object->count_sent > 0 ) {
     405                        echo mysql2date( 'Y/m/d', $signup_object->date_sent );
     406                } else {
     407                        $message = __( 'Not yet notified', 'buddypress' );
     408
     409                        /**
     410                         * Filters the "not yet sent" message for "Last Sent"
     411                         * column in Manage Signups list table.
     412                         *
     413                         * @since 10.0.0
     414                         *
     415                         * @param string      $message       "Not yet sent" message.
     416                         * @param object|null $signup_object Signup object instance.
     417                         */
     418                        $message = apply_filters( 'bp_members_signup_date_sent_unsent_message', $message, $signup_object );
     419
     420                        echo esc_html( $message );
     421                }
    378422        }
    379423
    380424        /**
    381          * Display number of time an activation email has been sent.
     425         * Display number of times an activation email has been sent.
    382426         *
    383427         * @since 2.0.0
    384428         *
    class BP_Members_List_Table extends WP_Users_List_Table { 
    388432                echo absint( $signup_object->count_sent );
    389433        }
    390434
     435        /**
     436         * Display link to open a modal to show user's
     437         * submitted extended profile information.
     438         *
     439         * @since 10.0.0
     440         *
     441         * @param object|null $signup_object The signup data object.
     442         */
     443        public function column_extended_profile( $signup_object = null  ) {
     444           $profile_field_ids = array();
     445
     446                // Prefetch registration field data.
     447                $fdata = array();
     448                $field_groups = bp_xprofile_get_groups( array(
     449                        'exclude_fields'    => 1,
     450                        'update_meta_cache' => false,
     451                        'fetch_fields'      => true,
     452                ) );
     453
     454                foreach( $field_groups as $fg ) {
     455                        foreach( $fg->fields as $f ) {
     456                                $fdata[ $f->id ] = $f->name;
     457                        }
     458                }
     459
     460                // Get all xprofile field IDs except field 1.
     461                if ( ! empty( $signup_object->meta['profile_field_ids'] ) ) {
     462                        $profile_field_ids = array_flip( explode( ',', $signup_object->meta['profile_field_ids'] ) );
     463                        unset( $profile_field_ids[1] );
     464                }
     465                ?>
     466                <a href="#TB_inline?&inlineId=signup-info-modal-<?php echo $signup_object->id; ?>" class="thickbox"><?php echo esc_html__( 'View', 'buddypress' ); ?></a>
     467
     468                <div id="signup-info-modal-<?php echo $signup_object->id; ?>" style="display:none;">
     469                        <h1><?php printf( esc_html__( '%1$s (%2$s)', 'buddypress' ), esc_html( $signup_object->user_name ), esc_html( $signup_object->user_email ) ); ?></h1>
     470                        <h2><?php echo esc_html__( 'Extended Profile Information', 'buddypress' ); ?></h2>
     471
     472                        <table class="signup-profile-data-drawer wp-list-table widefat fixed striped">
     473                                <?php foreach ( $profile_field_ids as $pid => $noop ) :
     474                                        $field_value = isset( $signup_object->meta[ "field_{$pid}" ] ) ? $signup_object->meta[ "field_{$pid}" ] : ''; ?>
     475                                        <tr>
     476                                                <td class="column-fields"><?php echo esc_html( $fdata[ $pid ] ); ?></td>
     477                                                <td><?php echo $this->format_xprofile_field_for_display( $field_value ); ?></td>
     478                                        </tr>
     479
     480                                <?php endforeach;  ?>
     481                        </table>
     482                </div>
     483                <?php
     484        }
     485
    391486        /**
    392487         * Allow plugins to add their custom column.
    393488         *
    class BP_Members_List_Table extends WP_Users_List_Table { 
    409504                 */
    410505                return apply_filters( 'bp_members_signup_custom_column', '', $column_name, $signup_object );
    411506        }
     507
     508        /**
     509         * Formats a signup's xprofile field data for display.
     510         *
     511         * Operates recursively on arrays, which are then imploded with commas.
     512         *
     513         * @since 10.0.0
     514         * @see BP_Members_Admin::format_xprofile_field_for_display()
     515         *
     516         * @param string|array $value Field value.
     517         * @return string
     518         */
     519        protected function format_xprofile_field_for_display( $value ) {
     520                if ( is_array( $value ) ) {
     521                        $value = array_map( array( $this, 'format_xprofile_field_for_display' ), $value );
     522                        $value = implode( ', ', $value );
     523                } else {
     524                        $value = stripslashes( $value );
     525                        $value = esc_html( $value );
     526                }
     527
     528                return $value;
     529        }
    412530}
  • src/bp-members/classes/class-bp-members-ms-list-table.php

    diff --git src/bp-members/classes/class-bp-members-ms-list-table.php src/bp-members/classes/class-bp-members-ms-list-table.php
    index b8e86f906..557e58952 100644
    class BP_Members_MS_List_Table extends WP_MS_Users_List_Table { 
    114114
    115115                // Reset the screen id.
    116116                $this->screen->id = $reset_screen_id;
     117
     118                // Use thickbox to display the extended profile information.
     119                if ( bp_is_active( 'xprofile' ) ) {
     120                        add_thickbox();
     121                }
    117122        }
    118123
    119124        /**
    class BP_Members_MS_List_Table extends WP_MS_Users_List_Table { 
    125130         */
    126131        public function get_columns() {
    127132
    128                 /**
    129                  * Filters the multisite Members signup columns.
    130                  *
    131                  * @since 2.0.0
    132                  *
    133                  * @param array $value Array of columns to display.
    134                  */
    135                 return apply_filters( 'bp_members_ms_signup_columns', array(
     133                $columns = array(
    136134                        'cb'         => '<input type="checkbox" />',
    137135                        'username'   => __( 'Username',    'buddypress' ),
    138136                        'name'       => __( 'Name',        'buddypress' ),
    class BP_Members_MS_List_Table extends WP_MS_Users_List_Table { 
    140138                        'registered' => __( 'Registered',  'buddypress' ),
    141139                        'date_sent'  => __( 'Last Sent',   'buddypress' ),
    142140                        'count_sent' => __( 'Emails Sent', 'buddypress' )
    143                 ) );
     141                );
     142
     143                if ( bp_is_active( 'xprofile' ) ) {
     144                        $profile_entry = array(
     145                                'extended_profile' => __( 'Profile Info', 'buddypress' )
     146                        );
     147                        $position = 4;
     148                        $columns = array_merge(
     149                                array_slice( $columns, 0, $position, true ),
     150                                $profile_entry,
     151                                array_slice( $columns, $position, count( $columns ) - 1, true )
     152                        );
     153
     154                }
     155
     156                /**
     157                 * Filters the multisite Members signup columns.
     158                 *
     159                 * @since 2.0.0
     160                 *
     161                 * @param array $value Array of columns to display.
     162                 */
     163                return apply_filters( 'bp_members_ms_signup_columns', $columns );
    144164        }
    145165
    146166        /**
    class BP_Members_MS_List_Table extends WP_MS_Users_List_Table { 
    158178                        $actions['delete'] = __( 'Delete', 'buddypress' );
    159179                }
    160180
    161                 return $actions;
     181                /**
     182                 * Filters the bulk actions for signups.
     183                 *
     184                 * @since 10.0.0
     185                 *
     186                 * @param array $actions Array of actions and corresponding labels.
     187                 */
     188                return apply_filters( 'bp_members_ms_signup_bulk_actions', $actions );
    162189        }
    163190
    164191        /**
    class BP_Members_MS_List_Table extends WP_MS_Users_List_Table { 
    169196         * @since 2.0.0
    170197         */
    171198        public function no_items() {
    172                 if ( bp_get_signup_allowed() ) {
     199                if ( bp_get_signup_allowed() || bp_get_membership_requests_required() ) {
    173200                        esc_html_e( 'No pending accounts found.', 'buddypress' );
    174201                } else {
    175202                        $link = false;
    class BP_Members_MS_List_Table extends WP_MS_Users_List_Table { 
    376403                        $date = 'Y/m/d \<\b\r \/\> g:i:s a';
    377404                }
    378405
    379                 echo mysql2date( $date, $signup_object->date_sent );
     406                if ( $signup_object->count_sent > 0 ) {
     407                        echo mysql2date( $date, $signup_object->date_sent );
     408                } else {
     409                        $message = __( 'Not yet notified', 'buddypress' );
     410
     411                        /**
     412                         * Filters the "not yet sent" message for "Last Sent"
     413                         * column in Manage Signups list table.
     414                         *
     415                         * @since 10.0.0
     416                         *
     417                         * @param string      $message       "Not yet sent" message.
     418                         * @param object|null $signup_object Signup object instance.
     419                         */
     420                        $message = apply_filters( 'bp_members_ms_signup_date_sent_unsent_message', $message, $signup_object );
     421
     422                        echo esc_html( $message );
     423                }
    380424        }
    381425
    382426        /**
    class BP_Members_MS_List_Table extends WP_MS_Users_List_Table { 
    390434                echo absint( $signup_object->count_sent );
    391435        }
    392436
     437                /**
     438         * Display link to open a modal to show user's
     439         * submitted extended profile information.
     440         *
     441         * @since 10.0.0
     442         *
     443         * @param object|null $signup_object The signup data object.
     444         */
     445        public function column_extended_profile( $signup_object = null  ) {
     446           $profile_field_ids = array();
     447
     448                // Prefetch registration field data.
     449                $fdata = array();
     450                $field_groups = bp_xprofile_get_groups( array(
     451                        'exclude_fields'    => 1,
     452                        'update_meta_cache' => false,
     453                        'fetch_fields'      => true,
     454                ) );
     455
     456                foreach( $field_groups as $fg ) {
     457                        foreach( $fg->fields as $f ) {
     458                                $fdata[ $f->id ] = $f->name;
     459                        }
     460                }
     461
     462                // Get all xprofile field IDs except field 1.
     463                if ( ! empty( $signup_object->meta['profile_field_ids'] ) ) {
     464                        $profile_field_ids = array_flip( explode( ',', $signup_object->meta['profile_field_ids'] ) );
     465                        unset( $profile_field_ids[1] );
     466                }
     467                ?>
     468                <a href="#TB_inline?&inlineId=signup-info-modal-<?php echo $signup_object->id; ?>" class="thickbox"><?php echo esc_html__( 'View', 'buddypress' ); ?></a>
     469
     470                <div id="signup-info-modal-<?php echo $signup_object->id; ?>" style="display:none;">
     471                        <h1><?php printf( esc_html__( '%1$s (%2$s)', 'buddypress' ), esc_html( $signup_object->user_name ), esc_html( $signup_object->user_email ) ); ?></h1>
     472                        <h2><?php echo esc_html__( 'Extended Profile Information', 'buddypress' ); ?></h2>
     473
     474                        <table class="signup-profile-data-drawer wp-list-table widefat fixed striped">
     475                                <?php foreach ( $profile_field_ids as $pid => $noop ) :
     476                                        $field_value = isset( $signup_object->meta[ "field_{$pid}" ] ) ? $signup_object->meta[ "field_{$pid}" ] : ''; ?>
     477                                        <tr>
     478                                                <td class="column-fields"><?php echo esc_html( $fdata[ $pid ] ); ?></td>
     479                                                <td><?php echo $this->format_xprofile_field_for_display( $field_value ); ?></td>
     480                                        </tr>
     481
     482                                <?php endforeach;  ?>
     483                        </table>
     484                </div>
     485                <?php
     486        }
     487
    393488        /**
    394489         * Allow plugins to add their custom column.
    395490         *
    class BP_Members_MS_List_Table extends WP_MS_Users_List_Table { 
    411506                 */
    412507                return apply_filters( 'bp_members_ms_signup_custom_column', '', $column_name, $signup_object );
    413508        }
     509
     510        /**
     511         * Formats a signup's xprofile field data for display.
     512         *
     513         * Operates recursively on arrays, which are then imploded with commas.
     514         *
     515         * @since 10.0.0
     516         * @see BP_Members_Admin::format_xprofile_field_for_display()
     517         *
     518         * @param string|array $value Field value.
     519         * @return string
     520         */
     521        protected function format_xprofile_field_for_display( $value ) {
     522                if ( is_array( $value ) ) {
     523                        $value = array_map( array( $this, 'format_xprofile_field_for_display' ), $value );
     524                        $value = implode( ', ', $value );
     525                } else {
     526                        $value = stripslashes( $value );
     527                        $value = esc_html( $value );
     528                }
     529
     530                return $value;
     531        }
    414532}
  • src/bp-members/classes/class-bp-registration-theme-compat.php

    diff --git src/bp-members/classes/class-bp-registration-theme-compat.php src/bp-members/classes/class-bp-registration-theme-compat.php
    index 6a942a58b..f4e3e6855 100644
    class BP_Registration_Theme_Compat { 
    9797        public function dummy_post() {
    9898                // Registration page.
    9999                if ( bp_is_register_page() ) {
    100                         $title = __( 'Create an Account', 'buddypress' );
     100                        if ( bp_get_membership_requests_required() ) {
     101                                $title = __( 'Request Membership', 'buddypress' );
     102                        } else {
     103                                $title = __( 'Create an Account', 'buddypress' );
     104                        }
    101105
    102106                        if ( 'completed-confirmation' == bp_get_current_signup_step() ) {
    103                                 $title = __( 'Check Your Email To Activate Your Account!', 'buddypress' );
     107                                if ( bp_get_membership_requests_required() ) {
     108                                        $title = __( 'Your Membership Request has been submitted.', 'buddypress' );
     109                                } else {
     110                                        $title = __( 'Check Your Email To Activate Your Account!', 'buddypress' );
     111                                }
    104112                        }
    105113
    106114                // Activation page.
  • src/bp-members/classes/class-bp-signup.php

    diff --git src/bp-members/classes/class-bp-signup.php src/bp-members/classes/class-bp-signup.php
    index 9de2af9fe..c436c7262 100644
    class BP_Signup { 
    214214                        $this->date_sent = $signup->registered;
    215215                }
    216216
     217                // How many times has the activation email been sent?
     218                if ( isset( $this->meta['count_sent'] ) ) {
     219                        $this->count_sent = absint( $this->meta['count_sent'] );
     220                } else {
     221                        $this->count_sent = 0;
     222                }
     223
    217224                /**
    218225                 * Calculate a diff between now & last time
    219226                 * an activation link has been resent.
    class BP_Signup { 
    226233                 * Set a boolean to track whether an activation link
    227234                 * was sent in the last day.
    228235                 */
    229                 $this->recently_sent = ( $diff < 1 * DAY_IN_SECONDS );
     236                $this->recently_sent = $this->count_sent && ( $diff < 1 * DAY_IN_SECONDS );
    230237
    231                 // How many times has the activation email been sent?
    232                 if ( isset( $this->meta['count_sent'] ) ) {
    233                         $this->count_sent = absint( $this->meta['count_sent'] );
    234                 } else {
    235                         $this->count_sent = 0;
    236                 }
    237238        }
    238239
    239240        /** Static Methods *******************************************************/
  • src/bp-members/screens/register.php

    diff --git src/bp-members/screens/register.php src/bp-members/screens/register.php
    index 77929c442..40dd280dc 100644
    function bp_core_screen_signup() { 
    6161                }
    6262        }
    6363
    64         if ( ! bp_get_signup_allowed() && ! $active_invite ) {
     64        $requests_enabled = bp_get_membership_requests_required();
     65
     66        if ( ! bp_get_signup_allowed() && ! $active_invite && ! $requests_enabled ) {
    6567                $bp->signup->step = 'registration-disabled';
    6668                // If the signup page is submitted, validate and save.
    6769        } elseif ( isset( $_POST['signup_submit'] ) && bp_verify_nonce_request( 'bp_new_signup' ) ) {
  • src/bp-templates/bp-legacy/buddypress/members/register.php

    diff --git src/bp-templates/bp-legacy/buddypress/members/register.php src/bp-templates/bp-legacy/buddypress/members/register.php
    index d263470f2..dd6365b45 100644
     
    351351                         *
    352352                         * @since 1.1.0
    353353                         */
    354                         do_action( 'bp_before_registration_submit_buttons' ); ?>
     354                        do_action( 'bp_before_registration_submit_buttons' );
     355
     356                        if ( bp_get_membership_requests_required() ) {
     357                                $button_text = __( 'Submit Request', 'buddypress' );
     358                        } else {
     359                                $button_text = __( 'Complete Sign Up', 'buddypress' );
     360                        }
     361                        ?>
    355362
    356363                        <div class="submit">
    357                                 <input type="submit" name="signup_submit" id="signup_submit" value="<?php esc_attr_e( 'Complete Sign Up', 'buddypress' ); ?>" />
     364                                <input type="submit" name="signup_submit" id="signup_submit" value="<?php echo esc_attr( $button_text ); ?>" />
    358365                        </div>
    359366
    360367                        <?php
     
    390397                        do_action( 'bp_before_registration_confirmed' ); ?>
    391398
    392399                        <div id="template-notices" role="alert" aria-atomic="true">
    393                                 <?php if ( bp_registration_needs_activation() ) : ?>
     400                                <?php if ( bp_get_membership_requests_required() ) : ?>
     401                                        <p><?php _e( 'You have successfully submitted your membership request! Our site moderators will review your submission and send you an activation email if your request is approved.', 'buddypress' ); ?></p>
     402                                <?php elseif ( bp_registration_needs_activation() ) : ?>
    394403                                        <p><?php _e( 'You have successfully created your account! To begin using this site you will need to activate your account via the email we have just sent to your address.', 'buddypress' ); ?></p>
    395404                                <?php else : ?>
    396405                                        <p><?php _e( 'You have successfully created your account! Please log in using the username and password you have just created.', 'buddypress' ); ?></p>
  • src/bp-templates/bp-nouveau/includes/functions.php

    diff --git src/bp-templates/bp-nouveau/includes/functions.php src/bp-templates/bp-nouveau/includes/functions.php
    index 3d85eace9..5faa6b0f9 100644
    function bp_nouveau_get_user_feedback( $feedback_id = '' ) { 
    11221122        /*
    11231123         * Adjust some messages to the context.
    11241124         */
    1125         if ( 'completed-confirmation' === $feedback_id && bp_registration_needs_activation() ) {
     1125        if ( 'completed-confirmation' === $feedback_id && bp_get_membership_requests_required() ) {
     1126                $feedback_messages['completed-confirmation']['message'] = __( 'You have successfully submitted your membership request! Our site moderators will review your submission and send you an activation email if your request is approved.', 'buddypress' );
     1127        } elseif ( 'completed-confirmation' === $feedback_id && bp_registration_needs_activation() ) {
    11261128                $feedback_messages['completed-confirmation']['message'] = __( 'You have successfully created your account! To begin using this site you will need to activate your account via the email we have just sent to your address.', 'buddypress' );
    11271129        } elseif ( 'member-notifications-none' === $feedback_id ) {
    11281130                $is_myprofile = bp_is_my_profile();