Ticket #8139: 8139.04.diff
File 8139.04.diff, 121.3 KB (added by , 3 years ago) |
---|
-
src/bp-core/admin/bp-core-admin-functions.php
diff --git src/bp-core/admin/bp-core-admin-functions.php src/bp-core/admin/bp-core-admin-functions.php index c9a5259e9..1b7ab5129 100644
function bp_core_activation_notice() { 279 279 280 280 // Activate and Register are special cases. They are not components but they need WP pages. 281 281 // If user registration is disabled, we can skip this step. 282 if ( bp_get_signup_allowed() ) {282 if ( bp_get_signup_allowed() || bp_get_members_invitations_allowed() ) { 283 283 $wp_page_components[] = array( 284 284 'id' => 'activate', 285 285 'name' => __( 'Activate', 'buddypress' ), -
src/bp-core/admin/bp-core-admin-settings.php
diff --git src/bp-core/admin/bp-core-admin-settings.php src/bp-core/admin/bp-core-admin-settings.php index c09f809ca..b37b914ff 100644
function bp_admin_setting_callback_cover_image_uploads() { 182 182 <?php 183 183 } 184 184 185 /** 186 * Allow members to invite non-members to the network. 187 * 188 * @since 8.0.0 189 */ 190 function bp_admin_setting_callback_members_invitations() { 191 ?> 192 <input id="bp-enable-members-invitations" name="bp-enable-members-invitations" type="checkbox" value="1" <?php checked( bp_get_members_invitations_allowed() ); ?> /> 193 <label for="bp-enable-members-invitations"><?php _e( 'Allow registered members to invite people to join this network', 'buddypress' ); ?></label> 194 <?php if ( ! bp_get_signup_allowed() ) : ?> 195 <p class="description"><?php _e( 'Public registration is currently disabled. However, invitees will still be able to register if network invitations are enabled.', 'buddypress' ); ?></p> 196 <?php endif; ?> 197 <?php 198 /** 199 * Fires after the output of the invitations settings section. 200 * 201 * @since 8.0.0 202 */ 203 do_action( 'bp_admin_settings_after_members_invitations' ); 204 } 205 185 206 /** XProfile ******************************************************************/ 186 207 187 208 /** -
src/bp-core/admin/bp-core-admin-slugs.php
diff --git src/bp-core/admin/bp-core-admin-slugs.php src/bp-core/admin/bp-core-admin-slugs.php index 8fb9b9a40..52ef6e36c 100644
function bp_core_admin_slugs_options() { 187 187 188 188 <h3><?php _e( 'Registration', 'buddypress' ); ?></h3> 189 189 190 <?php if ( bp_get_signup_allowed() ) : ?>190 <?php if ( bp_get_signup_allowed() || bp_get_members_invitations_allowed() ) : ?> 191 191 <p><?php _e( 'Associate WordPress Pages with the following BuddyPress Registration pages.', 'buddypress' ); ?></p> 192 192 <?php else : ?> 193 193 <?php if ( is_multisite() ) : ?> … … function bp_core_admin_slugs_options() { 210 210 <table class="form-table"> 211 211 <tbody> 212 212 213 <?php if ( bp_get_signup_allowed() ) : foreach ( $static_pages as $name => $label ) : ?>213 <?php if ( bp_get_signup_allowed() || bp_get_members_invitations_allowed() ) : foreach ( $static_pages as $name => $label ) : ?> 214 214 215 215 <tr valign="top"> 216 216 <th scope="row"> -
src/bp-core/bp-core-filters.php
diff --git src/bp-core/bp-core-filters.php src/bp-core/bp-core-filters.php index 735c7090a..219816b05 100644
function bp_email_set_default_headers( $headers, $property, $transform, $email ) 1068 1068 // Add 'List-Unsubscribe' header if applicable. 1069 1069 if ( ! empty( $tokens['unsubscribe'] ) && $tokens['unsubscribe'] !== wp_login_url() ) { 1070 1070 $user = get_user_by( 'email', $tokens['recipient.email'] ); 1071 $user_id = isset( $user->ID ) ? $user->ID : 0; 1071 1072 1072 $ link = bp_email_get_unsubscribe_link(array(1073 'user_id' => $user ->ID,1073 $args = array( 1074 'user_id' => $user_id, 1074 1075 'notification_type' => $email->get( 'type' ), 1075 ) ); 1076 ); 1077 // If this email is not to a current member, include the nonmember's email address. 1078 if ( ! $user_id ) { 1079 $args['email_address'] = $tokens['recipient.email']; 1080 } 1081 1082 $link = bp_email_get_unsubscribe_link( $args ); 1076 1083 1077 1084 if ( ! empty( $link ) ) { 1078 1085 $headers['List-Unsubscribe'] = sprintf( '<%s>', esc_url_raw( $link ) ); -
src/bp-core/bp-core-functions.php
diff --git src/bp-core/bp-core-functions.php src/bp-core/bp-core-functions.php index 592f5b155..1131d8ec5 100644
function bp_core_add_page_mappings( $components, $existing = 'keep' ) { 706 706 707 707 // Register and Activate are not components, but need pages when 708 708 // registration is enabled. 709 if ( bp_get_signup_allowed() ) {709 if ( bp_get_signup_allowed() || bp_get_members_invitations_allowed() ) { 710 710 foreach ( array( 'register', 'activate' ) as $slug ) { 711 711 if ( ! isset( $pages[ $slug ] ) ) { 712 712 $pages_to_create[ $slug ] = $page_titles[ $slug ]; … … function bp_send_email( $email_type, $to, $args = array() ) { 3428 3428 // From, subject, content are set automatically. 3429 3429 if ( 'settings-verify-email-change' === $email_type && isset( $args['tokens']['displayname'] ) ) { 3430 3430 $email->set_to( $to, $args['tokens']['displayname'] ); 3431 // Emails sent to nonmembers will have no recipient.name populated. 3432 } else if ( 'bp-members-invitation' === $email_type ) { 3433 $email->set_to( $to, $to ); 3431 3434 } else { 3432 3435 $email->set_to( $to ); 3433 3436 } … … function bp_email_get_schema() { 3763 3766 /* translators: do not remove {} brackets or translate its contents. */ 3764 3767 'post_title' => __( '[{{{site.name}}}] You have an invitation to the group: "{{group.name}}"', 'buddypress' ), 3765 3768 /* translators: do not remove {} brackets or translate its contents. */ 3766 'post_content' => __( "<a href=\"{{{inviter.url}}}\">{{inviter.name}}</a> has invited you to join the group: "{{group.name}}".\n {{invite.message}}\n<a href=\"{{{invites.url}}}\">Go here to accept your invitation</a> or <a href=\"{{{group.url}}}\">visit the group</a> to learn more.", 'buddypress' ),3769 'post_content' => __( "<a href=\"{{{inviter.url}}}\">{{inviter.name}}</a> has invited you to join the group: "{{group.name}}".\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' ), 3767 3770 /* translators: do not remove {} brackets or translate its contents. */ 3768 'post_excerpt' => __( "{{inviter.name}} has invited you to join the group: \"{{group.name}}\".\n\n To accept your invitation, visit: {{{invites.url}}}\n\nTo learn more about the group, visit: {{{group.url}}}.\nTo view {{inviter.name}}'s profile, visit: {{{inviter.url}}}", 'buddypress' ),3771 'post_excerpt' => __( "{{inviter.name}} has invited you to join the group: \"{{group.name}}\".\n\n{{invite.message}}\n\nTo accept your invitation, visit: {{{invites.url}}}\n\nTo learn more about the group, visit: {{{group.url}}}.\nTo view {{inviter.name}}'s profile, visit: {{{inviter.url}}}", 'buddypress' ), 3769 3772 ), 3770 3773 'groups-member-promoted' => array( 3771 3774 /* translators: do not remove {} brackets or translate its contents. */ … … function bp_email_get_schema() { 3815 3818 /* translators: do not remove {} brackets or translate its contents. */ 3816 3819 'post_excerpt' => __( "Your membership request for the group \"{{group.name}}\" has been rejected.\n\nTo request membership again, visit: {{{group.url}}}", 'buddypress' ), 3817 3820 ), 3821 'bp-members-invitation' => array( 3822 /* translators: do not remove {} brackets or translate its contents. */ 3823 'post_title' => __( '{{inviter.name}} has invited you to join {{site.name}}', 'buddypress' ), 3824 /* translators: do not remove {} brackets or translate its contents. */ 3825 'post_content' => __( "<a href=\"{{{inviter.url}}}\">{{inviter.name}}</a> has invited you to join the site: "{{site.name}}".\n\n{{usermessage}}\n\n<a href=\"{{{invite.accept_url}}}\">Accept your invitation</a> or <a href=\"{{{site.url}}}\">visit the site</a> to learn more.", 'buddypress' ), 3826 /* translators: do not remove {} brackets or translate its contents. */ 3827 'post_excerpt' => __( "{{inviter.name}} has invited you to join the site: \"{{site.name}}\".\n\n{{usermessage}}\n\nTo accept your invitation, visit: {{{invite.accept_url}}}\n\nTo learn more about the site, visit: {{{site.url}}}.\nTo view {{inviter.name}}'s profile, visit: {{{inviter.url}}}", 'buddypress' ), 3828 ), 3818 3829 ) ); 3819 3830 } 3820 3831 … … function bp_email_get_type_schema( $field = 'description' ) { 3956 3967 ), 3957 3968 ); 3958 3969 3970 $members_invitation = array( 3971 'description' => __( 'A site member has sent a site invitation to the recipient.', 'buddypress' ), 3972 'unsubscribe' => array( 3973 'meta_key' => 'notification_bp_members_invite', 3974 'message' => __( 'You will no longer receive emails when you are invited to join a site.', 'buddypress' ), 3975 ), 3976 ); 3977 3959 3978 $types = array( 3960 3979 'activity-comment' => $activity_comment, 3961 3980 'activity-comment-author' => $activity_comment_author, … … function bp_email_get_type_schema( $field = 'description' ) { 3973 3992 'settings-verify-email-change' => $settings_verify_email_change, 3974 3993 'groups-membership-request-accepted' => $groups_membership_request_accepted, 3975 3994 'groups-membership-request-rejected' => $groups_membership_request_rejected, 3995 'bp-members-invitation' => $members_invitation, 3976 3996 ); 3977 3997 3978 3998 if ( $field !== 'all' ) { … … function bp_email_unsubscribe_handler() { 3992 4012 $raw_email_type = ! empty( $_GET['nt'] ) ? $_GET['nt'] : ''; 3993 4013 $raw_hash = ! empty( $_GET['nh'] ) ? $_GET['nh'] : ''; 3994 4014 $raw_user_id = ! empty( $_GET['uid'] ) ? absint( $_GET['uid'] ) : 0; 3995 $new_hash = hash_hmac( 'sha1', "{$raw_email_type}:{$raw_user_id}", bp_email_get_salt() ); 4015 $raw_user_email = ! empty( $_GET['uem'] ) ? $_GET['uem'] : ''; 4016 4017 $new_hash = ''; 4018 if ( ! empty( $raw_user_id ) ) { 4019 $new_hash = hash_hmac( 'sha1', "{$raw_email_type}:{$raw_user_id}", bp_email_get_salt() ); 4020 } else if ( ! empty( $raw_user_email ) ) { 4021 $new_hash = hash_hmac( 'sha1', "{$raw_email_type}:{$raw_user_email}", bp_email_get_salt() ); 4022 } 3996 4023 3997 4024 // Check required values. 3998 if ( ! $raw_user_id|| ! $raw_email_type || ! $raw_hash || ! array_key_exists( $raw_email_type, $emails ) ) {4025 if ( ( ! $raw_user_id && ! $raw_user_email ) || ! $raw_email_type || ! $raw_hash || ! array_key_exists( $raw_email_type, $emails ) ) { 3999 4026 $redirect_to = wp_login_url(); 4000 4027 $result_msg = __( 'Something has gone wrong.', 'buddypress' ); 4001 4028 $unsub_msg = __( 'Please log in and go to your settings to unsubscribe from notification emails.', 'buddypress' ); … … function bp_email_unsubscribe_handler() { 4021 4048 $redirect_to = bp_core_get_user_domain( get_current_user_id() ); 4022 4049 } 4023 4050 4051 // This is an unsubscribe request from a nonmember. 4052 } else if ( $raw_user_email ) { 4053 // Unsubscribe. 4054 error_log( 'caught unsubscribe request {$raw_user_email}' ); 4055 // @TODO: Create opt-out once opt-out logic is in place. 4056 $redirect_to = home_url(); 4057 4058 $result_msg = $emails[ $raw_email_type ]['unsubscribe']['message']; 4059 $unsub_msg = __( 'You have been unsubscribed.' ); 4060 // This is an unsubscribe request from a current member. 4024 4061 } else { 4025 4062 if ( bp_is_active( 'settings' ) ) { 4026 4063 $redirect_to = sprintf( … … function bp_email_unsubscribe_handler() { 4048 4085 ); 4049 4086 4050 4087 bp_core_add_message( $message ); 4051 bp_core_redirect( bp_core_get_user_domain( $raw_user_id ) ); 4088 4089 $page_redirect = ''; 4090 if ( $raw_user_id ) { 4091 $page_redirect = bp_core_get_user_domain( $raw_user_id ); 4092 } 4093 4094 bp_core_redirect(); 4052 4095 4053 4096 exit; 4054 4097 } … … function bp_email_unsubscribe_handler() { 4065 4108 * @type string $notification_type Which notification type is being sent. 4066 4109 * @type string $user_id The ID of the user to whom the notification is sent. 4067 4110 * @type string $redirect_to Optional. The url to which the user will be redirected. Default is the activity directory. 4111 * @type string $email Optional. The email address of the user to whom the notification is sent. 4068 4112 * } 4069 4113 * @return string The unsubscribe link. 4070 4114 */ … … function bp_email_get_unsubscribe_link( $args ) { 4084 4128 return ''; 4085 4129 } 4086 4130 4087 $link = add_query_arg( 4088 array( 4089 'action' => 'unsubscribe', 4090 'nh' => hash_hmac( 'sha1', "{$email_type}:{$user_id}", bp_email_get_salt() ), 4091 'nt' => $args['notification_type'], 4092 'uid' => $user_id, 4093 ), 4094 $redirect_to 4095 ); 4131 $link = ''; 4132 // Case where the recipient is a member of the site. 4133 if ( ! empty( $user_id ) ) { 4134 $link = add_query_arg( 4135 array( 4136 'action' => 'unsubscribe', 4137 'nh' => hash_hmac( 'sha1', "{$email_type}:{$user_id}", bp_email_get_salt() ), 4138 'nt' => $args['notification_type'], 4139 'uid' => $user_id, 4140 ), 4141 $redirect_to 4142 ); 4143 // Case where the recipient is not a member of the site. 4144 } else if ( ! empty( $args['email_address'] ) ) { 4145 $email_address = $args['email_address']; 4146 $link = add_query_arg( 4147 array( 4148 'action' => 'unsubscribe', 4149 'nh' => hash_hmac( 'sha1', "{$email_type}:{$email_address}", bp_email_get_salt() ), 4150 'nt' => $args['notification_type'], 4151 'uid' => $user_id, 4152 'uem' => $email_address, 4153 ), 4154 $redirect_to 4155 ); 4156 } 4096 4157 4097 4158 /** 4098 4159 * Filters the unsubscribe link. -
src/bp-core/bp-core-template.php
diff --git src/bp-core/bp-core-template.php src/bp-core/bp-core-template.php index 799a69cdc..e840a7cd6 100644
function bp_is_settings_component() { 2247 2247 return (bool) bp_is_current_component( 'settings' ); 2248 2248 } 2249 2249 2250 /** 2251 * Check whether the current page is an Invitations screen. 2252 * 2253 * @since 8.0.0 2254 * 2255 * @return bool True if the current page is an Invitations screen. 2256 */ 2257 function bp_is_members_invitations_screen() { 2258 return (bool) bp_is_current_component( bp_get_members_invitations_slug() ); 2259 } 2260 2250 2261 /** 2251 2262 * Is the current component an active core component? 2252 2263 * … … function bp_is_user_settings_profile() { 2647 2658 return (bool) ( bp_is_user_settings() && bp_is_current_action( 'profile' ) ); 2648 2659 } 2649 2660 2661 /** 2662 * Is the current page a user's community invitations page? 2663 * 2664 * Eg http://example.com/members/cassie/invitations/ (or a subpage thereof). 2665 * 2666 * @since 8.0.0 2667 * 2668 * @return bool True if the current page is a user's community invitations page. 2669 */ 2670 function bp_is_user_members_invitations() { 2671 return (bool) ( bp_is_user() && bp_is_members_invitations_screen() ); 2672 } 2673 2674 /** 2675 * Is the current page a user's List Invites page? 2676 * 2677 * Eg http://example.com/members/cassie/invitations/list-invites/. 2678 * 2679 * @since 8.0.0 2680 * 2681 * @return bool True if the current page is a user's List Invites page. 2682 */ 2683 function bp_is_user_members_invitations_list() { 2684 return (bool) ( bp_is_user_members_invitations() && bp_is_current_action( 'list-invites' ) ); 2685 } 2686 2687 /** 2688 * Is the current page a user's Send Invites page? 2689 * 2690 * Eg http://example.com/members/cassie/invitations/send-invites/. 2691 * 2692 * @since 8.0.0 2693 * 2694 * @return bool True if the current page is a user's Send Invites page. 2695 */ 2696 function bp_is_user_members_invitations_send_screen() { 2697 return (bool) ( bp_is_user_members_invitations() && bp_is_current_action( 'send-invites' ) ); 2698 } 2699 2650 2700 /** Groups ********************************************************************/ 2651 2701 2652 2702 /** -
src/bp-core/classes/class-bp-admin.php
diff --git src/bp-core/classes/class-bp-admin.php src/bp-core/classes/class-bp-admin.php index 32dd0768d..2463a1f73 100644
class BP_Admin { 412 412 register_setting( 'buddypress', 'bp-disable-cover-image-uploads', 'intval' ); 413 413 } 414 414 415 // Community Invitations. 416 if ( bp_is_active( 'members', 'invitations' ) ) { 417 add_settings_field( 'bp-enable-members-invitations', __( 'Invitations', 'buddypress' ), 'bp_admin_setting_callback_members_invitations', 'buddypress', 'bp_members' ); 418 register_setting( 'buddypress', 'bp-enable-members-invitations', 'intval' ); 419 } 420 415 421 /* XProfile Section **************************************************/ 416 422 417 423 if ( bp_is_active( 'xprofile' ) ) { -
src/bp-core/classes/class-bp-invitation-manager.php
diff --git src/bp-core/classes/class-bp-invitation-manager.php src/bp-core/classes/class-bp-invitation-manager.php index 0b7d2f009..726a78da4 100644
abstract class BP_Invitation_Manager { 99 99 return false; 100 100 } 101 101 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 102 107 /** 103 108 * Is this user allowed to extend invitations in this situation? 104 109 * … … abstract class BP_Invitation_Manager { 157 162 * @param int $invitation_id ID of invitation to send. 158 163 * @param array $args See BP_Invitation::mark_sent(). 159 164 * 160 * @return int|bool The number of rows updated, or false on error.165 * @return bool The result of `run_send_action()`. 161 166 */ 162 167 public function send_invitation_by_id( $invitation_id = 0, $args = array() ) { 163 168 $updated = false; … … abstract class BP_Invitation_Manager { 195 200 } 196 201 197 202 // Perform the send action. 198 $ this->run_send_action( $invitation );203 $success = $this->run_send_action( $invitation ); 199 204 200 $updated = BP_Invitation::mark_sent( $invitation->id, $args ); 205 if ( $success ) { 206 BP_Invitation::mark_sent( $invitation->id, $args ); 207 } 201 208 202 return $ updated;209 return $success; 203 210 } 204 211 205 212 /** … … abstract class BP_Invitation_Manager { 309 316 * @param int $request_id ID of request to send. 310 317 * @param array $args See BP_Invitation::mark_sent(). 311 318 * 312 * @return int|bool The number of rows updated, or false on error.319 * @return bool The result of `run_send_action()`. 313 320 */ 314 321 public function send_request_notification_by_id( $request_id = 0, $args = array() ) { 315 322 $updated = false; … … abstract class BP_Invitation_Manager { 342 349 } 343 350 344 351 // Perform the send action. 345 $ this->run_send_action( $request );352 $success = $this->run_send_action( $request ); 346 353 347 $updated = BP_Invitation::mark_sent( $request->id, $args ); 354 if ( $success ) { 355 BP_Invitation::mark_sent( $request->id, $args ); 356 } 348 357 349 return $ updated;358 return $success; 350 359 } 351 360 352 361 /** Retrieve ******************************************************************/ … … abstract class BP_Invitation_Manager { 383 392 return BP_Invitation::get( $args ); 384 393 } 385 394 395 /** 396 * Get a count of the number of invitations that match provided filter parameters. 397 * 398 * @since 8.0.0 399 * 400 * @see BP_Invitation::get_total_count() for a description of accepted parameters. 401 * 402 * @return int Total number of invitations. 403 */ 404 public function get_invitations_total_count( $args = array() ) { 405 // Default to returning invitations, not requests. 406 if ( empty( $args['type'] ) ) { 407 $args['type'] = 'invite'; 408 } 409 // Use the class_name property value. 410 $args['class'] = $this->class_name; 411 412 return BP_Invitation::get_total_count( $args ); 413 } 414 386 415 /** 387 416 * Get requests, based on provided filter parameters. 388 417 * … … abstract class BP_Invitation_Manager { 703 732 ) ); 704 733 } 705 734 735 /** 736 * Delete an invitation by id. 737 * 738 * @since 8.0.0 739 * 740 * @param int $id ID of the invitation to delete. 741 * @return int|bool Number of rows deleted on success, false on failure. 742 */ 743 public function delete_by_id( $id ) { 744 // Ensure that the invitation exists and was created by this class. 745 $invite = new BP_Invitation( $id ); 746 if ( ! $invite->id || sanitize_key( $this->class_name ) !== $invite->class ) { 747 return false; 748 } 749 750 return BP_Invitation::delete_by_id( $id ); 751 } 752 753 754 706 755 /** 707 756 * This is where custom actions are added (in child classes) 708 757 * 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; 12 12 13 13 if ( class_exists( 'WP_Users_List_Table' ) ) { 14 14 require dirname( dirname( __FILE__ ) ) . '/classes/class-bp-members-list-table.php'; 15 require dirname( dirname( __FILE__ ) ) . '/classes/class-bp-members-invitations-list-table.php'; 15 16 } 16 17 17 18 if ( class_exists( 'WP_MS_Users_List_Table' ) ) { -
src/bp-members/bp-members-filters.php
diff --git src/bp-members/bp-members-filters.php src/bp-members/bp-members-filters.php index 5575ebef2..617b968a1 100644
function bp_members_edit_profile_url( $url, $user_id, $scheme = 'admin' ) { 127 127 return apply_filters( 'bp_members_edit_profile_url', $profile_link, $url, $user_id, $scheme ); 128 128 } 129 129 add_filter( 'edit_profile_url', 'bp_members_edit_profile_url', 10, 3 ); 130 131 /** 132 * Filter the bp_user_can value to determine what the user can do in the members component. 133 * 134 * @since 8.0.0 135 * 136 * @param bool $retval Whether or not the current user has the capability. 137 * @param int $user_id 138 * @param string $capability The capability being checked for. 139 * @param int $site_id Site ID. Defaults to the BP root blog. 140 * @param array $args Array of extra arguments passed. 141 * 142 * @return bool 143 */ 144 function 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 } 172 add_filter( 'bp_user_can', 'bp_members_user_can_filter', 10, 5 ); 173 174 /** 175 * Do not allow the new user to change the email address 176 * if they are accepting a community invitation. 177 * 178 * @since 8.0.0 179 * 180 * @param array $attributes The field attributes. 181 * @param string $name The field name. 182 * 183 * @return array $attributes The field attributes. 184 */ 185 function bp_members_invitations_make_registration_email_input_readonly_if_invite( $attributes, $name ) { 186 if ( 'email' === $name && bp_get_members_invitations_allowed() ) { 187 $invite = bp_get_members_invitation_from_request(); 188 if ( $invite->id ) { 189 $attributes['readonly'] = 'readonly'; 190 } 191 } 192 return $attributes; 193 } 194 add_filter( 'bp_get_form_field_attributes', 'bp_members_invitations_make_registration_email_input_readonly_if_invite', 10, 2 ); 195 196 /** 197 * Provide a more-specific welcome message if the new user 198 * is accepting a network invitation. 199 * 200 * @since 8.0.0 201 * 202 * @return string $message The message text. 203 */ 204 function bp_members_invitations_get_registration_welcome_message() { 205 $message = ''; 206 if ( ! bp_get_members_invitations_allowed() ) { 207 return $message; 208 } 209 $invite = bp_get_members_invitation_from_request(); 210 if ( ! $invite->id ) { 211 return $message; 212 } 213 214 // Fetch the display names of all inviters to personalize the welcome message. 215 $all_invites = bp_members_invitations_get_invites( 216 array( 217 'invitee_email' => $invite->invitee_email, 218 'invite_sent' => 'sent', 219 ) 220 ); 221 $inviters = array(); 222 foreach ( $all_invites as $inv ) { 223 $inviters[] = bp_core_get_user_displayname( $inv->inviter_id ); 224 } 225 226 if ( ! empty( $inviters ) ) { 227 $message = sprintf( _n( 'Welcome! You’ve been invited to join the site by the following user: %s. ', 'Welcome! You’ve been invited to join the site by the following users: %s. ', count( $inviters ), 'buddypress' ), implode( ', ', $inviters ) ); 228 } else { 229 $message = __( 'Welcome! You’ve been invited to join the site. ', 'buddypress' ); 230 } 231 return $message; 232 } 233 234 /** 235 * Provide a more-specific "registration is disabled" message 236 * if registration is available by invitation only. 237 * Also provide failure note if new user is trying to accept 238 * a network invitation but there's a problem. 239 * 240 * @since 8.0.0 241 * 242 * @return string $message The message text. 243 */ 244 function bp_members_invitations_get_modified_registration_disabled_message() { 245 $message = ''; 246 if ( bp_get_members_invitations_allowed() ) { 247 $message = __( 'Member registration is allowed by invitation only.', 'buddypress' ); 248 // Is the user trying to accept an invitation but something is wrong? 249 if ( ! empty( $_GET['inv'] ) ) { 250 $message .= __( ' It looks like there is a problem with your invitation. Please try again.', 'buddypress' ); 251 } 252 } 253 return $message; 254 } -
src/bp-members/bp-members-functions.php
diff --git src/bp-members/bp-members-functions.php src/bp-members/bp-members-functions.php index 165bc97c3..4afad7a7a 100644
function bp_members_avatar_upload_dir( $directory = 'avatars', $user_id = 0 ) { 3306 3306 'error' => false 3307 3307 ) ); 3308 3308 } 3309 3310 /** 3311 * Get invitations to the BP community filtered by arguments. 3312 * 3313 * @since 8.0.0 3314 * 3315 * @param array $args Invitation arguments. 3316 * See BP_Invitation::get() for list. 3317 * 3318 * @return array $invites Matching BP_Invitation objects. 3319 */ 3320 function bp_members_invitations_get_invites( $args = array() ) { 3321 $invites_class = new BP_Members_Invitation_Manager(); 3322 return $invites_class->get_invitations( $args ); 3323 } 3324 3325 /** 3326 * Invite a user to a BP community. 3327 * 3328 * @since 8.0.0 3329 * 3330 * @param array|string $args { 3331 * Array of arguments. 3332 * @type int $invitee_email Email address of the user being invited. 3333 * @type int $network_id ID of the network to which the user is being invited. 3334 * @type int $inviter_id Optional. ID of the inviting user. Default: 3335 * ID of the logged-in user. 3336 * @type string $date_modified Optional. Modified date for the invitation. 3337 * Default: current date/time. 3338 * @type string $content Optional. Message to invitee. 3339 * @type bool $send_invite Optional. Whether the invitation should be 3340 * sent now. Default: false. 3341 * } 3342 * @return bool True on success, false on failure. 3343 */ 3344 function bp_members_invitations_invite_user( $args ) { 3345 $r = bp_parse_args( $args, array( 3346 'invitee_email' => '', 3347 'network_id' => get_current_network_id(), 3348 'inviter_id' => bp_loggedin_user_id(), 3349 'date_modified' => bp_core_current_time(), 3350 'content' => '', 3351 'send_invite' => 0 3352 ), 'community_invite_user' ); 3353 3354 $inv_args = array( 3355 'invitee_email' => $r['invitee_email'], 3356 'item_id' => $r['network_id'], 3357 'inviter_id' => $r['inviter_id'], 3358 'date_modified' => $r['date_modified'], 3359 'content' => $r['content'], 3360 'send_invite' => $r['send_invite'] 3361 ); 3362 3363 // Create the invitataion. 3364 $invites_class = new BP_Members_Invitation_Manager(); 3365 $created = $invites_class->add_invitation( $inv_args ); 3366 3367 /** 3368 * Fires after the creation of a new network invite. 3369 * 3370 * @since 8.0.0 3371 * 3372 * @param array $r Array of parsed arguments for the network invite. 3373 * @param int|bool $created The ID of the invitation or false if it couldn't be created. 3374 */ 3375 do_action( 'bp_members_invitations_invite_user', $r, $created ); 3376 3377 return $created; 3378 } 3379 3380 /** 3381 * Resend a membership invitation email by id. 3382 * 3383 * @since 8.0.0 3384 * 3385 * @param int $id ID of the invitation to resend. 3386 * @return bool True on success, false on failure. 3387 */ 3388 function bp_members_invitation_resend_by_id( $id = 0 ) { 3389 3390 // Find the invitation before deleting it. 3391 $existing_invite = new BP_Invitation( $id ); 3392 $invites_class = new BP_Members_Invitation_Manager(); 3393 $success = $invites_class->send_invitation_by_id( $id ); 3394 3395 if ( ! $success ) { 3396 return $success; 3397 } 3398 3399 /** 3400 * Fires after the re-sending of a network invite. 3401 * 3402 * @since 8.0.0 3403 * 3404 * @param BP_Invitation $existing_invite The invitation that was resent. 3405 */ 3406 do_action( 'bp_members_invitations_resend_invitation', $existing_invite ); 3407 3408 return $success; 3409 } 3410 3411 /** 3412 * Delete a membership invitation by id. 3413 * 3414 * @since 8.0.0 3415 * 3416 * @param int $id ID of the invitation to delete. 3417 * @return int|bool Number of rows deleted on success, false on failure. 3418 */ 3419 function bp_members_invitations_delete_by_id( $id = 0 ) { 3420 3421 // Find the invitation before deleting it. 3422 $existing_invite = new BP_Invitation( $id ); 3423 $invites_class = new BP_Members_Invitation_Manager(); 3424 $success = $invites_class->delete_by_id( $id ); 3425 3426 if ( ! $success ) { 3427 return $success; 3428 } 3429 3430 // Run a different action depending on the status of the invite. 3431 if ( ! $existing_invite->invite_sent ) { 3432 /** 3433 * Fires after the deletion of an unsent community invite. 3434 * 3435 * @since 8.0.0 3436 * 3437 * @param BP_Invitation $existing_invite The invitation to be deleted. 3438 */ 3439 do_action( 'bp_members_invitations_canceled_invitation', $existing_invite ); 3440 } else if ( ! $existing_invite->accepted ) { 3441 /** 3442 * Fires after the deletion of a sent, but not yet accepted, community invite. 3443 * 3444 * @since 8.0.0 3445 * 3446 * @param BP_Invitation $existing_invite The invitation to be deleted. 3447 */ 3448 do_action( 'bp_members_invitations_revoked_invitation', $existing_invite ); 3449 } else { 3450 /** 3451 * Fires after the deletion of a sent and accepted community invite. 3452 * 3453 * @since 8.0.0 3454 * 3455 * @param BP_Invitation $existing_invite The invitation to be deleted. 3456 */ 3457 do_action( 'bp_members_invitations_deleted_invitation', $existing_invite ); 3458 } 3459 3460 return $success; 3461 } 3462 3463 /** 3464 * Delete a membership invitation. 3465 * 3466 * @since 8.0.0 3467 * 3468 * @param intring $args { 3469 * Array of arguments. 3470 * @type int|array $id Id(s) of the invitation(s) to remove. 3471 * @type int $invitee_email Email address of the user being invited. 3472 * @type int $network_id ID of the network to which the user is being invited. 3473 * @type int $inviter_id ID of the inviting user. 3474 * @type int $accepted Whether the invitation has been accepted yet. 3475 * @type int $invite_sent Whether the invitation has been sent yet. 3476 * } 3477 * @return bool True if all were deleted. 3478 */ 3479 function bp_members_invitations_delete_invites( $args ) { 3480 $r = bp_parse_args( $args, array( 3481 'id' => 0, 3482 'invitee_email' => '', 3483 'network_id' => get_current_network_id(), 3484 'inviter_id' => null, 3485 'accepted' => null, 3486 'invite_sent' => null 3487 ), 'community_invitation_delete_invites' ); 3488 3489 $inv_args = array( 3490 'id' => $r['id'], 3491 'invitee_email' => $r['invitee_email'], 3492 'item_id' => $r['network_id'], 3493 'inviter_id' => $r['inviter_id'], 3494 ); 3495 3496 // Find the invitation(s). 3497 $invites = bp_members_invitations_get_invites( $inv_args ); 3498 $total_count = count( $invites ); 3499 3500 // Loop through, deleting each invitation. 3501 $deleted = 0; 3502 foreach ( $invites as $invite ) { 3503 $success = bp_members_invitations_delete_by_id( $invite->id ); 3504 if ( $success ) { 3505 $deleted++; 3506 } 3507 } 3508 3509 return $deleted === $total_count; 3510 } 3511 3512 /** 3513 * Get hash based on details of a membership invitation and the inviter. 3514 * 3515 * @since 8.0.0 3516 * 3517 * @param BP_Invitation object $invitation Invitation to create hash from. 3518 * 3519 * @return string $hash Calculated sha1 hash. 3520 */ 3521 function bp_members_invitations_get_hash( BP_Invitation $invitation ) { 3522 $hash = false; 3523 3524 if ( ! empty( $invitation->id ) ) { 3525 $inviter_ud = get_userdata( $invitation->inviter_id ); 3526 if ( $inviter_ud ) { 3527 /* 3528 * Use some inviter details as part of the hash so that invitations from 3529 * users who are subsequently marked as spam will be invalidated. 3530 */ 3531 $hash = wp_hash( "{$invitation->inviter_id}:{$invitation->invitee_email}:{$inviter_ud->user_status}:{$inviter_ud->user_registered}" ); 3532 } 3533 } 3534 3535 // If there's a problem, return a string that will change and thus fail. 3536 if ( ! $hash ) { 3537 $hash = wp_generate_password( 32, false ); 3538 } 3539 3540 /** 3541 * Filters the hash calculated by the invitation details. 3542 * 3543 * @since 8.0.0 3544 * 3545 * @param string $hash Calculated sha1 hash. 3546 * @param BP_Invitation object $invitation Invitation hash was created from. 3547 */ 3548 return apply_filters( 'bp_members_invitations_get_hash', $hash, $invitation ); 3549 } 3550 3551 /** 3552 * Get the current invitation specified by the $_GET parameters. 3553 * 3554 * @since 8.0.0 3555 * 3556 * @return BP_Invitation $invite Invitation specified by the $_GET parameters. 3557 */ 3558 function bp_get_members_invitation_from_request() { 3559 $invites_class = new BP_Members_Invitation_Manager(); 3560 $invite = $invites_class->get_by_id( 0 ); 3561 3562 if ( bp_get_members_invitations_allowed() && ! empty( $_GET['inv'] ) ) { 3563 // Check to make sure the passed hash matches a calculated hash. 3564 $maybe_invite = $invites_class->get_by_id( absint( $_GET['inv'] ) ); 3565 $hash = bp_members_invitations_get_hash( $maybe_invite ); 3566 if ( $_GET['ih'] === $hash ) { 3567 $invite = $maybe_invite; 3568 } 3569 } 3570 3571 /** 3572 * Filters the invitation specified by the $_GET parameters. 3573 * 3574 * @since 8.0.0 3575 * 3576 * @param BP_Invitation $invite Invitation specified by the $_GET parameters. 3577 */ 3578 return apply_filters( 'bp_get_members_invitation_from_request', $invite ); 3579 } -
new file src/bp-members/bp-members-invitations.php
diff --git src/bp-members/bp-members-invitations.php src/bp-members/bp-members-invitations.php new file mode 100644 index 000000000..30dc91949
- + 1 <?php 2 /** 3 * BuddyPress Membersip Invitations 4 * 5 * @package BuddyPress 6 * @subpackage MembersInvitations 7 * @since 8.0.0 8 */ 9 10 // Exit if accessed directly. 11 defined( 'ABSPATH' ) || exit; 12 13 function 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 } 59 add_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 */ 71 function 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 } 86 add_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 */ 99 function 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 } 148 add_action( 'bp_core_signup_user', 'bp_members_invitations_complete_signup', 10, 4 ); 149 No newline at end of file -
src/bp-members/bp-members-template.php
diff --git src/bp-members/bp-members-template.php src/bp-members/bp-members-template.php index 5ceda3078..5b4021329 100644
function bp_activate_slug() { 274 274 return apply_filters( 'bp_get_activate_slug', $slug ); 275 275 } 276 276 277 /** 278 * Output the members invitation pane slug. 279 * 280 * @since 8.0.0 281 * 282 */ 283 function bp_members_invitations_slug() { 284 echo bp_get_members_invitations_slug(); 285 } 286 /** 287 * Return the members invitations root slug. 288 * 289 * @since 8.0.0 290 * 291 * @return string 292 */ 293 function bp_get_members_invitations_slug() { 294 295 /** 296 * Filters the Members invitations pane root slug. 297 * 298 * @since 8.0.0 299 * 300 * @param string $slug Members invitations pane root slug. 301 */ 302 return apply_filters( 'bp_get_members_invitations_slug', _x( 'invitations', 'Member profile invitations pane URL base', 'buddypress' ) ); 303 } 304 277 305 /** 278 306 * Initialize the members loop. 279 307 * … … function bp_signup_email_value() { 2381 2409 */ 2382 2410 function bp_get_signup_email_value() { 2383 2411 $value = ''; 2384 if ( isset( $_POST['signup_email'] ) ) 2412 if ( isset( $_POST['signup_email'] ) ) { 2385 2413 $value = $_POST['signup_email']; 2414 } else if ( bp_get_members_invitations_allowed() ) { 2415 $invite = bp_get_members_invitation_from_request(); 2416 if ( $invite ) { 2417 $value = $invite->invitee_email; 2418 } 2419 } 2386 2420 2387 2421 /** 2388 2422 * Filters the email address submitted during signup. … … function bp_signup_allowed() { 2755 2789 return apply_filters( 'bp_get_signup_allowed', (bool) bp_get_option( 'users_can_register' ) ); 2756 2790 } 2757 2791 2792 /** 2793 * Are users allowed to invite users to join this site? 2794 * 2795 * @since 8.0.0 2796 * 2797 * @return bool 2798 */ 2799 function bp_get_members_invitations_allowed() { 2800 /** 2801 * Filters whether or not community invitations are allowed. 2802 * 2803 * @since 8.0.0 2804 * 2805 * @param bool $allowed Whether or not community invitations are allowed. 2806 */ 2807 return apply_filters( 'bp_get_members_invitations_allowed', bp_is_active( 'members', 'invitations' ) && (bool) bp_get_option( 'bp-enable-members-invitations' ) ); 2808 } 2809 2758 2810 /** 2759 2811 * Hook member activity feed to <head>. 2760 2812 * … … function bp_avatar_delete_link() { 2861 2913 */ 2862 2914 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' ) ); 2863 2915 } 2916 2917 2918 /** The Members Invitations Loop ******************************************************************/ 2919 2920 /** 2921 * Initialize the community invitations loop. 2922 * 2923 * Based on the $args passed, bp_has_invitations() populates 2924 * buddypress()->invitations->query_loop global, enabling the use of BP 2925 * templates and template functions to display a list of invitations. 2926 * 2927 * @since 8.0.0 2928 * 2929 * @param array|string $args { 2930 * Arguments for limiting the contents of the invitations loop. Can be 2931 * passed as an associative array, or as a URL query string. 2932 * 2933 * See {@link BP_Invitations_Invitation::get()} for detailed 2934 * information on the arguments. In addition, also supports: 2935 * 2936 * @type int $max Optional. Max items to display. Default: false. 2937 * @type string $page_arg URL argument to use for pagination. 2938 * Default: 'ipage'. 2939 * } 2940 * @return bool 2941 */ 2942 function bp_has_members_invitations( $args = '' ) { 2943 2944 // Get the user ID. 2945 if ( bp_displayed_user_id() ) { 2946 $user_id = bp_displayed_user_id(); 2947 } else { 2948 $user_id = bp_loggedin_user_id(); 2949 } 2950 2951 // Set the search terms (by default an empty string to get all notifications) 2952 $search_terms = ''; 2953 2954 if ( isset( $_REQUEST['s'] ) ) { 2955 $search_terms = stripslashes( $_REQUEST['s'] ); 2956 } 2957 2958 // Parse the args. 2959 $r = bp_parse_args( $args, array( 2960 'id' => false, 2961 'inviter_id' => $user_id, 2962 'invitee_email' => false, 2963 'item_id' => false, 2964 'type' => 'invite', 2965 'invite_sent' => 'all', 2966 'accepted' => 'pending', 2967 'search_terms' => $search_terms, 2968 'order_by' => 'date_modified', 2969 'sort_order' => 'DESC', 2970 'page' => 1, 2971 'per_page' => 25, 2972 'fields' => 'all', 2973 2974 // These are additional arguments that are not available in 2975 // BP_Invitations_Invitation::get(). 2976 'page_arg' => 'ipage', 2977 ), 'has_community_invitations' ); 2978 2979 // Get the notifications. 2980 $query_loop = new BP_Members_Invitations_Template( $r ); 2981 2982 // Setup the global query loop. 2983 buddypress()->members->invitations->query_loop = $query_loop; 2984 2985 /** 2986 * Filters whether or not the user has network invitations to display. 2987 * 2988 * @since 8.0.0 2989 * 2990 * @param bool $value Whether or not there are network invitations to display. 2991 * @param BP_Notifications_Template $query_loop BP_Members_Invitations_Template object instance. 2992 * @param array $r Array of arguments passed into the BP_Members_Invitations_Template class. 2993 */ 2994 return apply_filters( 'bp_has_members_invitations', $query_loop->has_invitations(), $query_loop, $r ); 2995 } 2996 2997 /** 2998 * Get the network invitations returned by the template loop. 2999 * 3000 * @since 8.0.0 3001 * 3002 * @return array List of network invitations. 3003 */ 3004 function bp_the_members_invitations() { 3005 return buddypress()->members->invitations->query_loop->invitations(); 3006 } 3007 3008 /** 3009 * Get the current network invitation object in the loop. 3010 * 3011 * @since 8.0.0 3012 * 3013 * @return object The current network invitation within the loop. 3014 */ 3015 function bp_the_members_invitation() { 3016 return buddypress()->members->invitations->query_loop->the_invitation(); 3017 } 3018 3019 /** 3020 * Output the pagination count for the current network invitations loop. 3021 * 3022 * @since 8.0.0 3023 */ 3024 function bp_members_invitations_pagination_count() { 3025 echo bp_get_members_invitations_pagination_count(); 3026 } 3027 /** 3028 * Return the pagination count for the current network invitation loop. 3029 * 3030 * @since 8.0.0 3031 * 3032 * @return string HTML for the pagination count. 3033 */ 3034 function bp_get_members_invitations_pagination_count() { 3035 $query_loop = buddypress()->members->invitations->query_loop; 3036 $start_num = intval( ( $query_loop->pag_page - 1 ) * $query_loop->pag_num ) + 1; 3037 $from_num = bp_core_number_format( $start_num ); 3038 $to_num = bp_core_number_format( ( $start_num + ( $query_loop->pag_num - 1 ) > $query_loop->total_invitation_count ) ? $query_loop->total_invitation_count : $start_num + ( $query_loop->pag_num - 1 ) ); 3039 $total = bp_core_number_format( $query_loop->total_invitation_count ); 3040 3041 if ( 1 == $query_loop->total_invitation_count ) { 3042 $pag = __( 'Viewing 1 invitation', 'buddypress' ); 3043 } else { 3044 /* translators: 1: notification from number. 2: notification to number. 3: total notifications. */ 3045 $pag = sprintf( _n( 'Viewing %1$s - %2$s of %3$s invitation', 'Viewing %1$s - %2$s of %3$s invitations', $query_loop->total_invitation_count, 'buddypress' ), $from_num, $to_num, $total ); 3046 } 3047 3048 /** 3049 * Filters the pagination count for the current network invitation loop. 3050 * 3051 * @since 1.9.0 3052 * 3053 * @param string $pag HTML for the pagination count. 3054 */ 3055 return apply_filters( 'bp_get_members_invitations_pagination_count', $pag ); 3056 } 3057 3058 /** 3059 * Output the pagination links for the current network invitation loop. 3060 * 3061 * @since 8.0.0 3062 */ 3063 function bp_members_invitations_pagination_links() { 3064 echo bp_get_members_invitations_pagination_links(); 3065 } 3066 /** 3067 * Return the pagination links for the current network invitations loop. 3068 * 3069 * @since 8.0.0 3070 * 3071 * @return string HTML for the pagination links. 3072 */ 3073 function bp_get_members_invitations_pagination_links() { 3074 3075 /** 3076 * Filters the pagination links for the current network invitations loop. 3077 * 3078 * @since 8.0.0 3079 * 3080 * @param string $pag_links HTML for the pagination links. 3081 */ 3082 return apply_filters( 'bp_get_members_invitations_pagination_links', buddypress()->members->invitations->query_loop->pag_links ); 3083 } 3084 3085 /** 3086 * Output the ID of the invitation currently being iterated on. 3087 * 3088 * @since 8.0.0 3089 */ 3090 function bp_the_members_invitation_property( $property ) { 3091 echo bp_get_the_members_invitation_property( $property ); 3092 } 3093 /** 3094 * Return the value for a property of the network invitation currently being iterated on. 3095 * 3096 * @since 8.0.0 3097 * 3098 * @return int ID of the current network invitation. 3099 */ 3100 function bp_get_the_members_invitation_property( $property = 'id' ) { 3101 3102 switch ( $property ) { 3103 case 'id': 3104 case 'user_id': 3105 case 'item_id': 3106 case 'secondary_item_id': 3107 case 'invite_sent': 3108 case 'accepted': 3109 $value = 0; 3110 break; 3111 case 'invitee_email': 3112 case 'type': 3113 case 'content': 3114 case 'date_modified': 3115 $value = ''; 3116 break; 3117 default: 3118 // A known property has not been specified. 3119 $property = null; 3120 $value = ''; 3121 break; 3122 } 3123 3124 if ( isset( buddypress()->members->invitations->query_loop->invitation->{$property} ) ) { 3125 $value = buddypress()->members->invitations->query_loop->invitation->{$property}; 3126 } 3127 3128 /** 3129 * Filters the property of the network invitation currently being iterated on. 3130 * 3131 * @since 8.0.0 3132 * 3133 * @param int|string $value Property value of the network invitation being iterated on. 3134 */ 3135 return apply_filters( 'bp_get_the_members_invitation_property_' . $property, $value ); 3136 } 3137 3138 /** 3139 * Output the action links for the current invitation. 3140 * 3141 * @since 8.0.0 3142 * 3143 * @param array|string $args Array of arguments. 3144 */ 3145 function bp_the_members_invitation_action_links( $args = '' ) { 3146 echo bp_get_the_members_invitation_action_links( $args ); 3147 } 3148 /** 3149 * Return the action links for the current invitation. 3150 * 3151 * @since 8.0.0 3152 * 3153 * @param array|string $args { 3154 * @type string $before HTML before the links. 3155 * @type string $after HTML after the links. 3156 * @type string $sep HTML between the links. 3157 * @type array $links Array of links to implode by 'sep'. 3158 * @type int $user_id User ID to fetch action links for. Defaults to displayed user ID. 3159 * } 3160 * @return string HTML links for actions to take on single notifications. 3161 */ 3162 function bp_get_the_members_invitation_action_links( $args = '' ) { 3163 // Set default user ID to use. 3164 $inviter_id = isset( $args['inviter_id'] ) ? $args['inviter_id'] : bp_displayed_user_id(); 3165 3166 // Parse. 3167 $r = wp_parse_args( $args, array( 3168 'before' => '', 3169 'after' => '', 3170 'sep' => ' | ', 3171 'links' => array( 3172 bp_get_the_members_invitation_resend_link( $inviter_id ), 3173 bp_get_the_members_invitation_delete_link( $inviter_id ) 3174 ) 3175 ) ); 3176 3177 // Build the links. 3178 $retval = $r['before'] . implode( $r['sep'], $r['links'] ) . $r['after']; 3179 3180 /** 3181 * Filters the action links for the current notification. 3182 * 3183 * @since 1.9.0 3184 * @since 2.6.0 Added the `$r` parameter. 3185 * 3186 * @param string $retval HTML links for actions to take on single notifications. 3187 * @param array $r Array of parsed arguments. 3188 */ 3189 return apply_filters( 'bp_get_the_members_invitation_action_links', $retval, $r ); 3190 } 3191 3192 /** 3193 * Output the resend link for the current invitation. 3194 * 3195 * @since 8.0.0 3196 * 3197 * @param int $user_id The user ID. 3198 */ 3199 function bp_the_members_invitations_resend_link( $user_id = 0 ) { 3200 echo bp_get_the_members_invitation_delete_link( $user_id ); 3201 } 3202 /** 3203 * Return the resend link for the current notification. 3204 * 3205 * @since 78.0.0 3206 * 3207 * @param int $user_id The user ID. 3208 * @return string 3209 */ 3210 function bp_get_the_members_invitation_resend_link( $user_id = 0 ) { 3211 // Set default user ID to use. 3212 $user_id = 0 === $user_id ? bp_displayed_user_id() : $user_id; 3213 3214 // Don't allow resending of accepted invitations. 3215 if ( bp_get_the_members_invitation_property( 'accepted' ) ) { 3216 return; 3217 } 3218 3219 $retval = sprintf( '<a href="%1$s" class="resend secondary confirm bp-tooltip">%2$s</a>', esc_url( bp_get_the_members_invitations_resend_url( $user_id ) ), __( 'Resend', 'buddypress' ) ); 3220 3221 /** 3222 * Filters the resend link for the current invitation. 3223 * 3224 * @since 8.0.0 3225 * 3226 * @param string $retval HTML for the delete link for the current notification. 3227 * @param int $user_id The user ID. 3228 */ 3229 return apply_filters( 'bp_get_the_members_invitation_resend_link', $retval, $user_id ); 3230 } 3231 3232 /** 3233 * Output the URL used for resending a single invitation. 3234 * 3235 * Since this function directly outputs a URL, it is escaped. 3236 * 3237 * @since 8.0.0 3238 * 3239 * @param int $user_id The user ID. 3240 */ 3241 function bp_the_members_invitations_resend_url( $user_id = 0 ) { 3242 echo esc_url( bp_get_the_members_invitations_resend_url( $user_id ) ); 3243 } 3244 /** 3245 * Return the URL used for resending a single invitation. 3246 * 3247 * @since 8.0.0 3248 * 3249 * @param int $user_id The user ID. 3250 * @return string 3251 */ 3252 function bp_get_the_members_invitations_resend_url( $user_id = 0 ) { 3253 // Set default user ID to use. 3254 $user_id = 0 === $user_id ? bp_displayed_user_id() : $user_id; 3255 $link = bp_get_members_invitations_list_invites_permalink( $user_id ); 3256 3257 // Get the ID. 3258 $id = bp_get_the_members_invitation_property( 'id' ); 3259 3260 // Get the args to add to the URL. 3261 $args = array( 3262 'action' => 'resend', 3263 'invitation_id' => $id 3264 ); 3265 3266 // Add the args. 3267 $url = add_query_arg( $args, $link ); 3268 3269 // Add the nonce. 3270 $url = wp_nonce_url( $url, 'bp_network_invitation_resend_' . $id ); 3271 3272 /** 3273 * Filters the URL used for resending a single invitation. 3274 * 3275 * @since 8.0.0 3276 * 3277 * @param string $url URL used for deleting a single invitation. 3278 * @param int $user_id The user ID. 3279 */ 3280 return apply_filters( 'bp_get_the_members_invitations_resend_url', $url, $user_id ); 3281 } 3282 3283 /** 3284 * Output the delete link for the current invitation. 3285 * 3286 * @since 8.0.0 3287 * 3288 * @param int $user_id The user ID. 3289 */ 3290 function bp_the_members_invitations_delete_link( $user_id = 0 ) { 3291 echo bp_get_the_members_invitation_delete_link( $user_id ); 3292 } 3293 /** 3294 * Return the delete link for the current invitation. 3295 * 3296 * @since 8.0.0 3297 * 3298 * @param int $user_id The user ID. 3299 * @return string 3300 */ 3301 function bp_get_the_members_invitation_delete_link( $user_id = 0 ) { 3302 // Set default user ID to use. 3303 $user_id = 0 === $user_id ? bp_displayed_user_id() : $user_id; 3304 3305 // Modify the message for accepted/not accepted invitatons. 3306 if ( bp_get_the_members_invitation_property( 'accepted' ) ) { 3307 $message = __( 'Delete', 'buddypress' ); 3308 } else { 3309 $message = __( 'Cancel', 'buddypress' ); 3310 } 3311 3312 $retval = sprintf( '<a href="%1$s" class="delete secondary confirm bp-tooltip">%2$s</a>', esc_url( bp_get_the_members_invitations_delete_url( $user_id ) ), $message ); 3313 3314 /** 3315 * Filters the delete link for the current invitation. 3316 * 3317 * @since 8.0.0 3318 * 3319 * @param string $retval HTML for the delete link for the current notification. 3320 * @param int $user_id The user ID. 3321 */ 3322 return apply_filters( 'bp_get_the_members_invitation_delete_link', $retval, $user_id ); 3323 } 3324 3325 /** 3326 * Output the URL used for deleting a single invitation. 3327 * 3328 * Since this function directly outputs a URL, it is escaped. 3329 * 3330 * @since 8.0.0 3331 * 3332 * @param int $user_id The user ID. 3333 */ 3334 function bp_the_members_invitations_delete_url( $user_id = 0 ) { 3335 echo esc_url( bp_get_the_members_invitations_delete_url( $user_id ) ); 3336 } 3337 /** 3338 * Return the URL used for deleting a single invitation. 3339 * 3340 * @since 8.0.0 3341 * 3342 * @param int $user_id The user ID. 3343 * @return string 3344 */ 3345 function bp_get_the_members_invitations_delete_url( $user_id = 0 ) { 3346 // Set default user ID to use. 3347 $user_id = 0 === $user_id ? bp_displayed_user_id() : $user_id; 3348 $link = bp_get_members_invitations_list_invites_permalink( $user_id ); 3349 3350 // Get the ID. 3351 $id = bp_get_the_members_invitation_property( 'id' ); 3352 3353 // Get the args to add to the URL. 3354 $args = array( 3355 'action' => 'cancel', 3356 'invitation_id' => $id 3357 ); 3358 3359 // Add the args. 3360 $url = add_query_arg( $args, $link ); 3361 3362 // Add the nonce. 3363 $url = wp_nonce_url( $url, 'bp_members_invitations_cancel_' . $id ); 3364 3365 /** 3366 * Filters the URL used for deleting a single invitation. 3367 * 3368 * @since 8.0.0 3369 * 3370 * @param string $url URL used for deleting a single invitation. 3371 * @param int $user_id The user ID. 3372 */ 3373 return apply_filters( 'bp_get_the_members_invitations_delete_url', $url, $user_id ); 3374 } 3375 3376 /** 3377 * Output the members invitations list permalink for a user. 3378 * 3379 * @since 8.0.0 3380 * 3381 * @param int $user_id The user ID. 3382 */ 3383 function bp_members_invitations_list_invites_permalink( $user_id = 0 ) { 3384 echo bp_get_members_invitations_list_invites_permalink( $user_id ); 3385 } 3386 /** 3387 * Return the members invitations list permalink for a user. 3388 * 3389 * @since 8.0.0 3390 * 3391 * @return string Members invitations list permalink for a user. 3392 */ 3393 function bp_get_members_invitations_list_invites_permalink( $user_id = 0 ) { 3394 if ( 0 === $user_id ) { 3395 $user_id = bp_loggedin_user_id(); 3396 $domain = bp_loggedin_user_domain(); 3397 } else { 3398 $domain = bp_core_get_user_domain( (int) $user_id ); 3399 } 3400 3401 $retval = trailingslashit( $domain . bp_get_members_invitations_slug() . '/list-invites' ); 3402 3403 /** 3404 * Filters the members invitations list permalink for a user. 3405 * 3406 * @since 8.0.0 3407 * 3408 * @param string $retval Permalink for the sent invitation list screen. 3409 * @param int $user_id The user ID. 3410 */ 3411 return apply_filters( 'bp_get_members_invitations_list_invites_permalink', $retval, $user_id ); 3412 } 3413 3414 /** 3415 * Output the send invitation permalink for a user. 3416 * 3417 * @since 8.0.0 3418 * 3419 * @param int $user_id The user ID. 3420 */ 3421 function bp_members_invitations_send_invites_permalink( $user_id = 0 ) { 3422 echo bp_get_members_invitations_send_invites_permalink( $user_id ); 3423 } 3424 /** 3425 * Return the send invitations permalink. 3426 * 3427 * @since 8.0.0 3428 * 3429 * @return string Read notifications permalink. 3430 */ 3431 function bp_get_members_invitations_send_invites_permalink( $user_id = 0 ) { 3432 if ( 0 === $user_id ) { 3433 $user_id = bp_loggedin_user_id(); 3434 $domain = bp_loggedin_user_domain(); 3435 } else { 3436 $domain = bp_core_get_user_domain( (int) $user_id ); 3437 } 3438 3439 $retval = trailingslashit( $domain . bp_get_members_invitations_slug() . '/send-invites' ); 3440 3441 /** 3442 * Filters the read notifications permalink. 3443 * 3444 * @since 8.0.0 3445 * 3446 * @param string $retval Permalink for the sent invitation list screen. 3447 * @param int $user_id The user ID. 3448 */ 3449 return apply_filters( 'bp_get_members_invitations_send_invites_permalink', $retval, $user_id ); 3450 } 3451 No newline at end of file -
src/bp-members/classes/class-bp-members-admin.php
diff --git src/bp-members/classes/class-bp-members-admin.php src/bp-members/classes/class-bp-members-admin.php index c999cb923..574952589 100644
class BP_Members_Admin { 140 140 $this->users_url = bp_get_admin_url( 'users.php' ); 141 141 $this->users_screen = bp_core_do_network_admin() ? 'users-network' : 'users'; 142 142 143 $this->members_invites_page = ''; 144 143 145 // Specific config: BuddyPress is not network activated. 144 146 $this->subsite_activated = (bool) is_multisite() && ! bp_is_network_activated(); 145 147 … … class BP_Members_Admin { 248 250 * @param string $value 249 251 */ 250 252 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() ) { 252 256 bp_core_add_page_mappings( array( 253 257 'register' => 1, 254 258 'activate' => 1 … … class BP_Members_Admin { 266 270 */ 267 271 public function single_site_registration_on( $old_value, $value ) { 268 272 // Single site. 269 if ( ! is_multisite() && ! empty( $value) ) {273 if ( ! is_multisite() && ( ! empty( $value ) || bp_get_members_invitations_allowed() ) ) { 270 274 bp_core_add_page_mappings( array( 271 275 'register' => 1, 272 276 'activate' => 1 … … class BP_Members_Admin { 488 492 'bp-signups', 489 493 array( $this, 'signups_admin' ) 490 494 ); 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 ); 491 504 } 492 505 493 506 $edit_page = 'user-edit'; … … class BP_Members_Admin { 509 522 $this->user_page .= '-network'; 510 523 $this->users_page .= '-network'; 511 524 $this->signups_page .= '-network'; 525 526 $this->members_invites_page .= '-network'; 512 527 } 513 528 514 529 // Setup the screen ID's. … … class BP_Members_Admin { 2564 2579 2565 2580 return $value; 2566 2581 } 2582 2583 /** 2584 * Set up the signups admin page. 2585 * 2586 * Loaded before the page is rendered, this function does all initial 2587 * setup, including: processing form requests, registering contextual 2588 * help, and setting up screen options. 2589 * 2590 * @since 8.0.0 2591 * 2592 * @global $bp_members_invitations_list_table 2593 */ 2594 public function members_invitations_admin_load() { 2595 global $bp_members_invitations_list_table; 2596 2597 // Build redirection URL. 2598 $redirect_to = remove_query_arg( array( 'action', 'error', 'updated', 'activated', 'notactivated', 'deleted', 'notdeleted', 'resent', 'notresent', 'do_delete', 'do_resend', 'do_activate', '_wpnonce', 'signup_ids' ), $_SERVER['REQUEST_URI'] ); 2599 $doaction = bp_admin_list_table_current_bulk_action(); 2600 2601 /** 2602 * Fires at the start of the member invitations admin load. 2603 * 2604 * @since 8.0.0 2605 * 2606 * @param string $doaction Current bulk action being processed. 2607 * @param array $_REQUEST Current $_REQUEST global. 2608 */ 2609 do_action( 'bp_members_invitations_admin_load', $doaction, $_REQUEST ); 2610 2611 /** 2612 * Filters the allowed actions for use in the user signups admin page. 2613 * 2614 * @since 8.0.0 2615 * 2616 * @param array $value Array of allowed actions to use. 2617 */ 2618 $allowed_actions = apply_filters( 'bp_members_invitations_admin_allowed_actions', array( 'do_delete', 'do_resend' ) ); 2619 2620 // Prepare the display of the Community Profile screen. 2621 if ( ! in_array( $doaction, $allowed_actions ) || ( -1 == $doaction ) ) { 2622 2623 $bp_members_invitations_list_table = self::get_list_table_class( 'BP_Members_Invitations_List_Table', 'users' ); 2624 2625 // The per_page screen option. 2626 add_screen_option( 'per_page', array( 'label' => _x( 'Members Invitations', 'Members Invitations per page (screen options)', 'buddypress' ) ) ); 2627 2628 get_current_screen()->add_help_tab( array( 2629 'id' => 'bp-members-invitations-overview', 2630 'title' => __( 'Overview', 'buddypress' ), 2631 'content' => 2632 '<p>' . __( 'This is the administration screen for member invitations on your site.', 'buddypress' ) . '</p>' . 2633 '<p>' . __( 'From the screen options, you can customize the displayed columns and the pagination of this screen.', 'buddypress' ) . '</p>' . 2634 '<p>' . __( 'You can reorder the list of invitations by clicking on the Invitee, Inviter, Date Modified, Email Sent or Accepted column headers.', 'buddypress' ) . '</p>' . 2635 '<p>' . __( 'Using the search form, you can find specific invitations more easily. The Invitee Email field will be included in the search.', 'buddypress' ) . '</p>' 2636 ) ); 2637 2638 get_current_screen()->add_help_tab( array( 2639 'id' => 'bp-members-invitations-actions', 2640 'title' => __( 'Actions', 'buddypress' ), 2641 'content' => 2642 '<p>' . __( 'Hovering over a row in the pending accounts list will display action links that allow you to manage pending accounts. You can perform the following actions:', 'buddypress' ) . '</p>' . 2643 '<ul><li>' . __( '"Send" or "Resend" takes you to the confirmation screen before being able to send or resend the invitation email to the desired pending invitee.', 'buddypress' ) . '</li>' . 2644 '<li>' . __( '"Delete" allows you to delete an unsent or accepted invitation from your site; "Cancel" allows you to cancel a sent, but not yet accepted, invitation. You will be asked to confirm this deletion.', 'buddypress' ) . '</li></ul>' . 2645 '<p>' . __( 'Bulk actions allow you to perform these actions for the selected rows.', 'buddypress' ) . '</p>' 2646 ) ); 2647 2648 // Help panel - sidebar links. 2649 get_current_screen()->set_help_sidebar( 2650 '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' . 2651 '<p>' . __( '<a href="https://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>' 2652 ); 2653 2654 // Add accessible hidden headings and text for the Pending Users screen. 2655 get_current_screen()->set_screen_reader_content( array( 2656 /* translators: accessibility text */ 2657 'heading_views' => __( 'Filter invitations list', 'buddypress' ), 2658 /* translators: accessibility text */ 2659 'heading_pagination' => __( 'Invitation list navigation', 'buddypress' ), 2660 /* translators: accessibility text */ 2661 'heading_list' => __( 'Invitations list', 'buddypress' ), 2662 ) ); 2663 2664 } else { 2665 if ( empty( $_REQUEST['invite_ids' ] ) ) { 2666 return; 2667 } 2668 $invite_ids = wp_parse_id_list( $_REQUEST['invite_ids' ] ); 2669 2670 // Handle resent invitations. 2671 if ( 'do_resend' == $doaction ) { 2672 2673 // Nonce check. 2674 check_admin_referer( 'invitations_resend' ); 2675 2676 $success = 0; 2677 foreach ( $invite_ids as $invite_id ) { 2678 if ( bp_members_invitation_resend_by_id( $invite_id ) ) { 2679 $success++; 2680 } 2681 } 2682 2683 $query_arg = array( 'updated' => 'resent' ); 2684 2685 if ( ! empty( $success ) ) { 2686 $query_arg['resent'] = $success; 2687 } 2688 2689 $not_sent = count( $invite_ids ) - $success; 2690 if ( $not_sent > 0 ) { 2691 $query_arg['notsent'] = $not_sent; 2692 } 2693 2694 $redirect_to = add_query_arg( $query_arg, $redirect_to ); 2695 2696 bp_core_redirect( $redirect_to ); 2697 2698 // Handle invitation deletion. 2699 } elseif ( 'do_delete' == $doaction ) { 2700 2701 // Nonce check. 2702 check_admin_referer( 'invitations_delete' ); 2703 2704 $success = 0; 2705 foreach ( $invite_ids as $invite_id ) { 2706 if ( bp_members_invitations_delete_by_id( $invite_id ) ) { 2707 $success++; 2708 } 2709 } 2710 2711 $query_arg = array( 'updated' => 'deleted' ); 2712 2713 if ( ! empty( $success ) ) { 2714 $query_arg['deleted'] = $success; 2715 } 2716 2717 $notdeleted = count( $invite_ids ) - $success; 2718 if ( $notdeleted > 0 ) { 2719 $query_arg['notdeleted'] = $notdeleted; 2720 } 2721 2722 $redirect_to = add_query_arg( $query_arg, $redirect_to ); 2723 2724 bp_core_redirect( $redirect_to ); 2725 2726 // Plugins can update other stuff from here. 2727 } else { 2728 $this->redirect = $redirect_to; 2729 2730 /** 2731 * Fires at end of member invitations admin load 2732 * if doaction does not match any actions. 2733 * 2734 * @since 2.0.0 2735 * 2736 * @param string $doaction Current bulk action being processed. 2737 * @param array $_REQUEST Current $_REQUEST global. 2738 * @param string $redirect Determined redirect url to send user to. 2739 */ 2740 do_action( 'bp_members_admin_update_invitations', $doaction, $_REQUEST, $this->redirect ); 2741 2742 bp_core_redirect( $this->redirect ); 2743 } 2744 } 2745 } 2746 2747 /** 2748 * Get admin notice when viewing the invitations management page. 2749 * 2750 * @since 8.0.0 2751 * 2752 * @return array 2753 */ 2754 private function get_members_invitations_notice() { 2755 2756 // Setup empty notice for return value. 2757 $notice = array(); 2758 2759 // Updates. 2760 if ( ! empty( $_REQUEST['updated'] ) ) { 2761 switch ( $_REQUEST['updated'] ) { 2762 case 'resent': 2763 $notice = array( 2764 'class' => 'updated', 2765 'message' => '' 2766 ); 2767 2768 if ( ! empty( $_REQUEST['resent'] ) ) { 2769 $notice['message'] .= sprintf( 2770 /* translators: %s: number of invitation emails sent */ 2771 _nx( '%s invtitation email successfully sent! ', '%s invitation emails successfully sent! ', 2772 absint( $_REQUEST['resent'] ), 2773 'members invitation resent', 2774 'buddypress' 2775 ), 2776 number_format_i18n( absint( $_REQUEST['resent'] ) ) 2777 ); 2778 } 2779 2780 if ( ! empty( $_REQUEST['notsent'] ) ) { 2781 $notice['message'] .= sprintf( 2782 /* translators: %s: number of unsent invitation emails */ 2783 _nx( '%s invitation email was not sent.', '%s invitation emails were not sent.', 2784 absint( $_REQUEST['notsent'] ), 2785 'members invitation notsent', 2786 'buddypress' 2787 ), 2788 number_format_i18n( absint( $_REQUEST['notsent'] ) ) 2789 ); 2790 2791 if ( empty( $_REQUEST['resent'] ) ) { 2792 $notice['class'] = 'error'; 2793 } 2794 } 2795 2796 break; 2797 2798 case 'deleted': 2799 $notice = array( 2800 'class' => 'updated', 2801 'message' => '' 2802 ); 2803 2804 if ( ! empty( $_REQUEST['deleted'] ) ) { 2805 $notice['message'] .= sprintf( 2806 /* translators: %s: number of deleted invitations */ 2807 _nx( '%s invitation successfully deleted!', '%s invitations successfully deleted!', 2808 absint( $_REQUEST['deleted'] ), 2809 'members invitation deleted', 2810 'buddypress' 2811 ), 2812 number_format_i18n( absint( $_REQUEST['deleted'] ) ) 2813 ); 2814 } 2815 2816 if ( ! empty( $_REQUEST['notdeleted'] ) ) { 2817 $notice['message'] .= sprintf( 2818 /* translators: %s: number of invitations that failed to be deleted */ 2819 _nx( '%s invitation was not deleted.', '%s invitations were not deleted.', 2820 absint( $_REQUEST['notdeleted'] ), 2821 'members invitation notdeleted', 2822 'buddypress' 2823 ), 2824 number_format_i18n( absint( $_REQUEST['notdeleted'] ) ) 2825 ); 2826 2827 if ( empty( $_REQUEST['deleted'] ) ) { 2828 $notice['class'] = 'error'; 2829 } 2830 } 2831 2832 break; 2833 } 2834 } 2835 2836 // Errors. 2837 if ( ! empty( $_REQUEST['error'] ) ) { 2838 switch ( $_REQUEST['error'] ) { 2839 case 'do_resend': 2840 $notice = array( 2841 'class' => 'error', 2842 'message' => esc_html__( 'There was a problem sending the invitation emails. Please try again.', 'buddypress' ), 2843 ); 2844 break; 2845 2846 case 'do_delete': 2847 $notice = array( 2848 'class' => 'error', 2849 'message' => esc_html__( 'There was a problem deleting invitations. Please try again.', 'buddypress' ), 2850 ); 2851 break; 2852 } 2853 } 2854 2855 return $notice; 2856 } 2857 2858 /** 2859 * Member invitations admin page router. 2860 * 2861 * Depending on the context, display 2862 * - the list of invitations, 2863 * - or the delete confirmation screen, 2864 * - or the "resend" email confirmation screen. 2865 * 2866 * Also prepare the admin notices. 2867 * 2868 * @since 8.0.0 2869 */ 2870 public function invitations_admin() { 2871 $doaction = bp_admin_list_table_current_bulk_action(); 2872 2873 // Prepare notices for admin. 2874 $notice = $this->get_members_invitations_notice(); 2875 2876 // Display notices. 2877 if ( ! empty( $notice ) ) : 2878 if ( 'updated' === $notice['class'] ) : ?> 2879 2880 <div id="message" class="<?php echo esc_attr( $notice['class'] ); ?> notice is-dismissible"> 2881 2882 <?php else: ?> 2883 2884 <div class="<?php echo esc_attr( $notice['class'] ); ?> notice is-dismissible"> 2885 2886 <?php endif; ?> 2887 2888 <p><?php echo $notice['message']; ?></p> 2889 </div> 2890 2891 <?php endif; 2892 2893 // Show the proper screen. 2894 switch ( $doaction ) { 2895 case 'delete' : 2896 case 'resend' : 2897 $this->invitations_admin_manage( $doaction ); 2898 break; 2899 2900 default: 2901 $this->invitations_admin_index(); 2902 break; 2903 } 2904 } 2905 2906 /** 2907 * This is the list of invitations. 2908 * 2909 * @since 8.0.0 2910 * 2911 * @global $plugin_page 2912 * @global $bp_members_invitations_list_table 2913 */ 2914 public function invitations_admin_index() { 2915 global $plugin_page, $bp_members_invitations_list_table; 2916 2917 $usersearch = ! empty( $_REQUEST['s'] ) ? stripslashes( $_REQUEST['s'] ) : ''; 2918 2919 // Prepare the group items for display. 2920 $bp_members_invitations_list_table->prepare_items(); 2921 2922 if ( is_network_admin() ) { 2923 $form_url = network_admin_url( 'users.php' ); 2924 } else { 2925 $form_url = bp_get_admin_url( 'users.php' ); 2926 } 2927 2928 $form_url = add_query_arg( 2929 array( 2930 'page' => 'bp-members-invitations', 2931 ), 2932 $form_url 2933 ); 2934 2935 $search_form_url = remove_query_arg( 2936 array( 2937 'action', 2938 'deleted', 2939 'notdeleted', 2940 'error', 2941 'updated', 2942 'delete', 2943 'activate', 2944 'activated', 2945 'notactivated', 2946 'resend', 2947 'resent', 2948 'notresent', 2949 'do_delete', 2950 'do_activate', 2951 'do_resend', 2952 'action2', 2953 '_wpnonce', 2954 'invite_ids' 2955 ), $_SERVER['REQUEST_URI'] 2956 ); 2957 2958 ?> 2959 2960 <div class="wrap"> 2961 <h1 class="wp-heading-inline"><?php _e( 'Invitations', 'buddypress' ); ?></h1> 2962 2963 <?php 2964 if ( $usersearch ) { 2965 printf( '<span class="subtitle">' . __( 'Search results for “%s”', 'buddypress' ) . '</span>', esc_html( $usersearch ) ); 2966 } 2967 ?> 2968 2969 <hr class="wp-header-end"> 2970 2971 <?php // Display each invitation on its own row. ?> 2972 <?php $bp_members_invitations_list_table->views(); ?> 2973 2974 <form id="bp-members-invitations-search-form" action="<?php echo esc_url( $search_form_url ) ;?>"> 2975 <input type="hidden" name="page" value="<?php echo esc_attr( $plugin_page ); ?>" /> 2976 <?php $bp_members_invitations_list_table->search_box( __( 'Search Invitations', 'buddypress' ), 'bp-members-invitations' ); ?> 2977 </form> 2978 2979 <form id="bp-members-invitations-form" action="<?php echo esc_url( $form_url );?>" method="post"> 2980 <?php $bp_members_invitations_list_table->display(); ?> 2981 </form> 2982 </div> 2983 <?php 2984 } 2985 2986 /** 2987 * This is the confirmation screen for actions. 2988 * 2989 * @since 2.0.0 2990 * 2991 * @param string $action Delete or resend invitation. 2992 * 2993 * @return null|false 2994 */ 2995 public function invitations_admin_manage( $action = '' ) { 2996 if ( ! current_user_can( $this->capability ) || empty( $action ) ) { 2997 die( '-1' ); 2998 } 2999 3000 // Get the IDs from the URL. 3001 $ids = false; 3002 if ( ! empty( $_POST['invite_ids'] ) ) { 3003 $ids = wp_parse_id_list( $_POST['invite_ids'] ); 3004 } elseif ( ! empty( $_GET['invite_id'] ) ) { 3005 $ids = absint( $_GET['invite_id'] ); 3006 } 3007 3008 3009 if ( empty( $ids ) ) { 3010 return false; 3011 } 3012 3013 // Check invite IDs and set up strings. 3014 switch ( $action ) { 3015 case 'delete' : 3016 // Query for matching invites, and filter out bad IDs. 3017 $args = array( 3018 'id' => $ids, 3019 'invite_sent' => 'all', 3020 'accepted' => 'all', 3021 'fields' => 'ids', 3022 ); 3023 $invite_ids = bp_members_invitations_get_invites( $args ); 3024 3025 $header_text = __( 'Delete Invitations', 'buddypress' ); 3026 if ( 1 == count( $invite_ids ) ) { 3027 $helper_text = __( 'You are about to delete the following invitation:', 'buddypress' ); 3028 } else { 3029 $helper_text = __( 'You are about to delete the following invitations:', 'buddypress' ); 3030 } 3031 break; 3032 3033 case 'resend' : 3034 /** 3035 * Query for matching invites, and filter out bad IDs 3036 * or those that have already been accepted. 3037 */ 3038 $args = array( 3039 'id' => $ids, 3040 'invite_sent' => 'all', 3041 'accepted' => 'pending', 3042 ); 3043 $invites = bp_members_invitations_get_invites( $args ); 3044 $invite_ids = wp_list_pluck( $invites, 'id' ); 3045 3046 $header_text = __( 'Resend Invitation Emails', 'buddypress' ); 3047 if ( 1 == count( $invite_ids ) ) { 3048 $helper_text = __( 'You are about to resend an invitation email to the following address:', 'buddypress' ); 3049 } else { 3050 $helper_text = __( 'You are about to resend an invitation email to the following addresses:', 'buddypress' ); 3051 } 3052 break; 3053 } 3054 3055 // These arguments are added to all URLs. 3056 $url_args = array( 'page' => 'bp-members-invitations' ); 3057 3058 // These arguments are only added when performing an action. 3059 $action_args = array( 3060 'action' => 'do_' . $action, 3061 'invite_ids' => implode( ',', $invite_ids ) 3062 ); 3063 3064 if ( is_network_admin() ) { 3065 $base_url = network_admin_url( 'users.php' ); 3066 } else { 3067 $base_url = bp_get_admin_url( 'users.php' ); 3068 } 3069 3070 $cancel_url = add_query_arg( $url_args, $base_url ); 3071 $action_url = wp_nonce_url( 3072 add_query_arg( 3073 array_merge( $url_args, $action_args ), 3074 $base_url 3075 ), 3076 'invitations_' . $action 3077 ); 3078 3079 ?> 3080 3081 <div class="wrap"> 3082 <h1 class="wp-heading-inline"><?php echo esc_html( $header_text ); ?></h1> 3083 <hr class="wp-header-end"> 3084 3085 <p><?php echo esc_html( $helper_text ); ?></p> 3086 3087 <ol class="bp-invitations-list"> 3088 <?php foreach ( $invites as $invite ) : 3089 if ( $invite->invite_sent ) { 3090 $last_notified = mysql2date( 'Y/m/d g:i:s a', $invite->date_modified ); 3091 } else { 3092 $last_notified = __( 'Not yet notified', 'buddypress'); 3093 } 3094 ?> 3095 3096 <li> 3097 <strong><?php echo esc_html( $invite->invitee_email ) ?></strong> 3098 3099 <?php if ( 'resend' == $action ) : ?> 3100 3101 <p class="description"> 3102 <?php 3103 /* translators: %s: notification date */ 3104 printf( esc_html__( 'Last notified: %s', 'buddypress'), $last_notified ); 3105 ?> 3106 </p> 3107 3108 <?php endif; ?> 3109 3110 </li> 3111 3112 <?php endforeach; ?> 3113 </ol> 3114 3115 <?php if ( 'delete' === $action ) : ?> 3116 3117 <p><strong><?php esc_html_e( 'This action cannot be undone.', 'buddypress' ) ?></strong></p> 3118 3119 <?php endif ; ?> 3120 3121 <a class="button-primary" href="<?php echo esc_url( $action_url ); ?>"><?php esc_html_e( 'Confirm', 'buddypress' ); ?></a> 3122 <a class="button" href="<?php echo esc_url( $cancel_url ); ?>"><?php esc_html_e( 'Cancel', 'buddypress' ) ?></a> 3123 </div> 3124 3125 <?php 3126 } 3127 2567 3128 } 2568 3129 endif; // End class_exists check. -
src/bp-members/classes/class-bp-members-component.php
diff --git src/bp-members/classes/class-bp-members-component.php src/bp-members/classes/class-bp-members-component.php index 77777d645..2b91ee1ff 100644
class BP_Members_Component extends BP_Component { 39 39 buddypress()->plugin_dir, 40 40 array( 41 41 'adminbar_myaccount_order' => 20, 42 'search_query_arg' => 'members_search', 42 'search_query_arg' => 'members_search', 43 'features' => array( 'invitations' ) 43 44 ) 44 45 ); 45 46 } … … class BP_Members_Component extends BP_Component { 64 65 'blocks', 65 66 'widgets', 66 67 'cache', 68 'invitations', 67 69 ); 68 70 69 71 if ( bp_is_active( 'activity' ) ) { … … class BP_Members_Component extends BP_Component { 137 139 // Theme compatibility. 138 140 new BP_Registration_Theme_Compat(); 139 141 } 142 143 // Invitations. 144 if ( is_user_logged_in() && bp_is_user_members_invitations() ) { 145 if ( bp_is_user_members_invitations_send_screen() ) { 146 require $this->path . 'bp-members/screens/send-invites.php'; 147 } else { 148 require $this->path . 'bp-members/screens/list-invites.php'; 149 } 150 } 140 151 } 141 152 142 153 /** … … class BP_Members_Component extends BP_Component { 232 243 $bp->profile->slug = 'profile'; 233 244 $bp->profile->id = 'profile'; 234 245 } 246 247 /** Network Invitations ************************************************** 248 */ 249 250 $bp->members->invitations = new stdClass; 235 251 } 236 252 237 253 /** … … class BP_Members_Component extends BP_Component { 467 483 } 468 484 } 469 485 470 471 486 parent::setup_nav( $main_nav, $sub_nav ); 472 487 } 473 488 -
new file src/bp-members/classes/class-bp-members-invitation-manager.php
diff --git src/bp-members/classes/class-bp-members-invitation-manager.php src/bp-members/classes/class-bp-members-invitation-manager.php new file mode 100644 index 000000000..139caf279
- + 1 <?php 2 /** 3 * Membership invitations class. 4 * 5 * @package BuddyPress 6 * @subpackage Core 7 * @since 8.0.0 8 */ 9 10 // Exit if accessed directly. 11 defined( 'ABSPATH' ) || exit; 12 13 /** 14 * Membership invitations class. 15 * 16 * An extension of the core Invitations class that adapts the 17 * core logic to accommodate site membership invitation behavior. 18 * 19 * @since 8.0.0 20 */ 21 class BP_Members_Invitation_Manager extends BP_Invitation_Manager { 22 /** 23 * Construct parameters. 24 * 25 * @since 8.0.0 26 * 27 * @param array|string $args. 28 */ 29 public function __construct( $args = '' ) { 30 parent::__construct(); 31 } 32 33 /** 34 * This is where custom actions are added to run when notifications of an 35 * invitation or request need to be generated & sent. 36 * 37 * @since 8.0.0 38 * 39 * @param obj BP_Invitation $invitation The invitation to send. 40 * @return bool True on success, false on failure. 41 */ 42 public function run_send_action( BP_Invitation $invitation ) { 43 // Notify site admins of the pending request 44 if ( 'request' === $invitation->type ) { 45 // @TODO 46 return true; 47 // Notify the invitee of the invitation. 48 } else { 49 // Stop if the invitation has already been accepted. 50 if ( $invitation->accepted ) { 51 return false; 52 } 53 54 $inviter_ud = bp_core_get_core_userdata( $invitation->inviter_id ); 55 56 $invite_url = esc_url( 57 add_query_arg( 58 array( 59 'inv' => $invitation->id, 60 'ih' => bp_members_invitations_get_hash( $invitation ), 61 ), bp_get_signup_page() 62 ) 63 ); 64 $unsubscribe_args = array( 65 'user_id' => 0, 66 'email_address' => $invitation->invitee_email, 67 'notification_type' => 'bp-members-invitation', 68 ); 69 70 $args = array( 71 'tokens' => array( 72 'inviter.name' => bp_core_get_userlink( $invitation->inviter_id, true, false, true ), 73 'inviter.url' => bp_core_get_user_domain( $invitation->inviter_id ), 74 'inviter.id' => $invitation->inviter_id, 75 'invite.accept_url' => esc_url( $invite_url ), 76 'usermessage' => $invitation->content, 77 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ), 78 ), 79 ); 80 81 return bp_send_email( 'bp-members-invitation', $invitation->invitee_email, $args ); 82 } 83 } 84 85 /** 86 * This is where custom actions are added to run when an invitation 87 * or request is accepted. 88 * 89 * @since 8.0.0 90 * 91 * @param string $type Are we accepting an invitation or request? 92 * @param array $r Parameters that describe the invitation being accepted. 93 * @return bool True on success, false on failure. 94 */ 95 public function run_acceptance_action( $type = 'invite', $r ) { 96 // If the user is already a member (because BP at one point allowed two invitations to 97 // slip through), return early. 98 99 if ( 'request' === $type ) { 100 /** 101 * Fires after a network membership request has been accepted. 102 * 103 * @since 8.0.0 104 * 105 * @param int $user_id ID of the user who accepted membership. 106 * @param int $network_id ID of the network that was accepted membership to. 107 */ 108 do_action( 'network_membership_request_accepted', $r['user_id'], $r['item_id'] ); 109 } else { 110 /** 111 * Fires after a user has accepted a site membership invite. 112 * 113 * @since 8.0.0 114 * 115 * @param int $user_id ID of the user who accepted the membership invite. 116 * @param int $inviter_id ID of the user who invited this user to the group. 117 */ 118 do_action( 'network_membership_invite_accepted', $r['user_id'], $inviter_id ); 119 } 120 121 122 return true; 123 } 124 125 /** 126 * Should this invitation be created? 127 * 128 * @since 8.0.0 129 * 130 * @param array $args. 131 * @return bool 132 */ 133 public function allow_invitation( $args ) { 134 // Does the inviter have this capability? 135 if ( ! bp_user_can( $args['inviter_id'], 'bp_members_send_invitation' ) ) { 136 return false; 137 } 138 139 // Is the invited user eligible to receive an invitation? Hasn't opted out? 140 if ( ! bp_user_can( 0, 'bp_members_receive_invitation', $args ) ) { 141 return false; 142 } 143 144 return true; 145 } 146 147 /** 148 * Should this request be created? 149 * 150 * @since 8.0.0 151 * 152 * @param array $args. 153 * @return bool. 154 */ 155 public function allow_request( $args ) { 156 // Does the requester have this capability? 157 if ( ! bp_user_can( 0, 'bp_network_request_membership', $args ) ) { 158 return false; 159 } 160 161 return true; 162 } 163 } -
new file src/bp-members/classes/class-bp-members-invitations-list-table.php
diff --git src/bp-members/classes/class-bp-members-invitations-list-table.php src/bp-members/classes/class-bp-members-invitations-list-table.php new file mode 100644 index 000000000..90f35d921
- + 1 <?php 2 /** 3 * BuddyPress Membership Invitation List Table class. 4 * 5 * @package BuddyPress 6 * @subpackage MembersAdminClasses 7 * @since 8.0.0 8 */ 9 10 // Exit if accessed directly. 11 defined( 'ABSPATH' ) || exit; 12 13 /** 14 * List table class for signups admin page. 15 * 16 * @since 8.0.0 17 */ 18 class BP_Members_Invitations_List_Table extends WP_Users_List_Table { 19 20 /** 21 * The type of view currently being displayed. 22 * 23 * E.g. "All", "Pending", "Sent", "Unsent"... 24 * 25 * @since 8.0.0 26 * @var string 27 */ 28 public $active_filters = array(); 29 30 /** 31 * Signup counts. 32 * 33 * @since 8.0.0 34 * 35 * @var int 36 */ 37 public $total_items = 0; 38 39 /** 40 * Constructor. 41 * 42 * @since 8.0.0 43 */ 44 public function __construct() { 45 // Define singular and plural labels, as well as whether we support AJAX. 46 parent::__construct( array( 47 'ajax' => false, 48 'plural' => 'invitations', 49 'singular' => 'invitation', 50 'screen' => get_current_screen()->id, 51 ) ); 52 } 53 54 /** 55 * Set up items for display in the list table. 56 * 57 * Handles filtering of data, sorting, pagination, and any other data 58 * manipulation required prior to rendering. 59 * 60 * @since 8.0.0 61 */ 62 public function prepare_items() { 63 global $usersearch; 64 65 $search = isset( $_REQUEST['s'] ) ? $_REQUEST['s'] : ''; 66 $per_page = $this->get_items_per_page( str_replace( '-', '_', "{$this->screen->id}_per_page" ) ); 67 $paged = $this->get_pagenum(); 68 69 $args = array( 70 'invite_sent' => 'all', 71 'accepted' => 'all', 72 'search_terms' => $search, 73 'order_by' => 'date_modified', 74 'sort_order' => 'DESC', 75 'page' => $paged, 76 'per_page' => $per_page, 77 ); 78 79 if ( isset( $_REQUEST['accepted'] ) && in_array( $_REQUEST['accepted'], array( 'pending', 'accepted' ), true ) ) { 80 $args['accepted'] = $_REQUEST['accepted']; 81 $this->active_filters[] = $_REQUEST['accepted']; 82 } 83 if ( isset( $_REQUEST['sent'] ) && in_array( $_REQUEST['sent'], array( 'draft', 'sent' ), true ) ) { 84 $args['invite_sent'] = $_REQUEST['sent']; 85 $this->active_filters[] = $_REQUEST['sent']; 86 } 87 88 if ( isset( $_REQUEST['orderby'] ) ) { 89 $args['order_by'] = $_REQUEST['orderby']; 90 } 91 92 if ( isset( $_REQUEST['order'] ) ) { 93 $args['sort_order'] = $_REQUEST['order']; 94 } 95 96 $invites_class = new BP_Members_Invitation_Manager(); 97 $this->items = $invites_class->get_invitations( $args ); 98 $this->total_items = $invites_class->get_invitations_total_count( $args ); 99 100 $this->set_pagination_args( array( 101 'total_items' => $this->total_items, 102 'per_page' => $per_page, 103 ) ); 104 } 105 106 /** 107 * Get the list of views available on this table (e.g. "all", "public"). 108 * 109 * @since 8.0.0 110 */ 111 public function views() { 112 $url_base = add_query_arg( 113 array( 114 'page' => 'bp-members-invitations', 115 ), 116 bp_get_admin_url( 'users.php' ) 117 ); 118 119 ?> 120 121 <h2 class="screen-reader-text"><?php 122 /* translators: accessibility text */ 123 _e( 'Filter invitations list', 'buddypress' ); 124 ?></h2> 125 <ul class="subsubsub"> 126 <li class="all"> 127 <a href="<?php echo esc_url( $url_base ); ?>" class="<?php if ( empty( $this->active_filters ) ) echo 'current'; ?>"> 128 <?php esc_html_e( 'All', 'buddypress' ); ?> 129 </a> | 130 </li> 131 <li class="pending"> 132 <a href="<?php echo esc_url( add_query_arg( 'accepted', 'pending', $url_base ) ); ?>" class="<?php if ( in_array( 'pending', $this->active_filters, true ) ) echo 'current'; ?>"> 133 <?php esc_html_e( 'Pending', 'buddypress' ); ?> 134 </a> | 135 </li> 136 <li class="accepted"> 137 <a href="<?php echo esc_url( add_query_arg( 'accepted', 'accepted', $url_base ) ); ?>" class="<?php if ( in_array( 'accepted', $this->active_filters, true ) ) echo 'current'; ?>"> 138 <?php esc_html_e( 'Accepted', 'buddypress' ); ?> 139 </a> | 140 </li> 141 <li class="draft"> 142 <a href="<?php echo esc_url( add_query_arg( 'sent', 'draft', $url_base ) ); ?>" class="<?php if ( in_array( 'draft', $this->active_filters, true ) ) echo 'current'; ?>"> 143 <?php esc_html_e( 'Draft (Unsent)', 'buddypress' ); ?> 144 </a> | 145 </li> 146 <li class="sent"> 147 <a href="<?php echo esc_url( add_query_arg( 'sent', 'sent', $url_base ) ); ?>" class="<?php if ( in_array( 'sent', $this->active_filters, true ) ) echo 'current'; ?>"> 148 <?php esc_html_e( 'Sent', 'buddypress' ); ?> 149 </a> | 150 </li> 151 152 <?php 153 154 /** 155 * Fires inside listing of views so plugins can add their own. 156 * 157 * @since 8.0.0 158 * 159 * @param string $url_base Current URL base for view. 160 * @param array $active_filters Current filters being requested. 161 */ 162 do_action( 'bp_members_invitations_list_table_get_views', $url_base, $this->active_filters ); ?> 163 </ul> 164 <?php 165 } 166 167 /** 168 * Get rid of the extra nav. 169 * 170 * WP_Users_List_Table will add an extra nav to change user's role. 171 * As we're dealing with invitations, we don't need this. 172 * 173 * @since 8.0.0 174 * 175 * @param array $which Current table nav item. 176 */ 177 public function extra_tablenav( $which ) { 178 return; 179 } 180 181 /** 182 * Specific signups columns. 183 * 184 * @since 8.0.0 185 * 186 * @return array 187 */ 188 public function get_columns() { 189 190 /** 191 * Filters the single site Members signup columns. 192 * 193 * @since 8.0.0 194 * 195 * @param array $value Array of columns to display. 196 */ 197 return apply_filters( 'bp_members_invitations_list_columns', array( 198 'cb' => '<input type="checkbox" />', 199 'invitee_email' => __( 'Invitee', 'buddypress' ), 200 'username' => __( 'Inviter', 'buddypress' ), 201 'inviter_registered_date' => __( 'Inviter Registered', 'buddypress' ), 202 'invitation_date_modified' => __( 'Date Modified', 'buddypress' ), 203 'invitation_sent' => __( 'Email Sent', 'buddypress' ), 204 'invitation_accepted' => __( 'Accepted', 'buddypress' ) 205 ) ); 206 } 207 208 /** 209 * Specific bulk actions for signups. 210 * 211 * @since 8.0.0 212 */ 213 public function get_bulk_actions() { 214 $actions = array( 215 'resend' => _x( 'Resend Email', 'Pending invitation action', 'buddypress' ), 216 ); 217 218 if ( current_user_can( 'delete_users' ) ) { 219 $actions['delete'] = _x( 'Delete', 'Pending invitation action', 'buddypress' ); 220 } 221 222 return $actions; 223 } 224 225 /** 226 * The text shown when no items are found. 227 * 228 * Nice job, clean sheet! 229 * 230 * @since 8.0.0 231 */ 232 public function no_items() { 233 234 if ( bp_get_members_invitations_allowed() ) { 235 esc_html_e( 'No pending invitations found.', 'buddypress' ); 236 } else { 237 $link = sprintf( '<a href="%1$s">%2$s</a>', esc_url( bp_get_admin_url( add_query_arg( array( 'page' => 'bp-settings' ), 'admin.php' ) ) ), esc_html__( 'Edit settings', 'buddypress' ) ); 238 239 /* translators: %s: url to site settings */ 240 printf( __( 'Invitations are not allowed. %s', 'buddypress' ), $link ); 241 } 242 243 } 244 245 /** 246 * The columns invitations can be reordered by. 247 * 248 * @since 8.0.0 249 */ 250 public function get_sortable_columns() { 251 return array( 252 'invitee_email' => 'invitee_email', 253 'username' => 'inviter_id', 254 'invitation_date_modified' => 'date_modified', 255 'invitation_sent' => 'invite_sent', 256 'invitation_accepted' => 'accepted', 257 ); 258 } 259 260 /** 261 * Display invitation rows. 262 * 263 * @since 8.0.0 264 */ 265 public function display_rows() { 266 $style = ''; 267 foreach ( $this->items as $invite ) { 268 $style = ( ' class="alternate"' == $style ) ? '' : ' class="alternate"'; 269 echo "\n\t" . $this->single_row( $invite, $style ); 270 } 271 } 272 273 /** 274 * Display an invitation row. 275 * 276 * @since 8.0.0 277 * 278 * @see WP_List_Table::single_row() for explanation of params. 279 * 280 * @param BP_Invitation $invite BP_Invitation object. 281 * @param string $style Styles for the row. 282 * @param string $role Role to be assigned to user. 283 * @param int $numposts Number of posts. 284 * @return void 285 */ 286 public function single_row( $invite = null, $style = '', $role = '', $numposts = 0 ) { 287 echo '<tr' . $style . ' id="invitation-' . esc_attr( $invite->id ) . '">'; 288 echo $this->single_row_columns( $invite ); 289 echo '</tr>'; 290 } 291 292 /** 293 * Markup for the checkbox used to select items for bulk actions. 294 * 295 * @since 8.0.0 296 * 297 * @param BP_Invitation $invite BP_Invitation object. 298 */ 299 public function column_cb( $invite = null ) { 300 ?> 301 <label class="screen-reader-text" for="invitation_<?php echo intval( $invite->id ); ?>"><?php 302 /* translators: accessibility text */ 303 printf( esc_html__( 'Select invitation: %s', 'buddypress' ), $invite->id ); 304 ?></label> 305 <input type="checkbox" id="invitation_<?php echo intval( $invite->id ) ?>" name="invite_ids[]" value="<?php echo esc_attr( $invite->id ) ?>" /> 306 <?php 307 } 308 309 /** 310 * Markup for the checkbox used to select items for bulk actions. 311 * 312 * @since 8.0.0 313 * 314 * @param BP_Invitation $invite BP_Invitation object. 315 */ 316 public function column_invitee_email( $invite = null ) { 317 echo esc_html( $invite->invitee_email ); 318 319 $actions = array(); 320 321 // Resend action only if pending 322 if ( ! $invite->accepted ) { 323 // Resend invitation email link. 324 $email_link = add_query_arg( 325 array( 326 'page' => 'bp-members-invitations', 327 'invite_id' => $invite->id, 328 'action' => 'resend', 329 ), 330 bp_get_admin_url( 'users.php' ) 331 ); 332 if ( ! $invite->invite_sent ) { 333 $resend_label = __( 'Send', 'buddypress' ); 334 } else { 335 $resend_label = __( 'Resend', 'buddypress' ); 336 } 337 $actions['resend'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $email_link ), $resend_label ); 338 } 339 340 // Delete link. Could be cleanup or revoking the invitation. 341 $delete_link = add_query_arg( 342 array( 343 'page' => 'bp-members-invitations', 344 'invite_id' => $invite->id, 345 'action' => 'delete', 346 ), 347 bp_get_admin_url( 'users.php' ) 348 ); 349 // Two cases: unsent and accepted (cleanup), and pending (cancels invite). 350 if ( ! $invite->invite_sent || $invite->accepted ) { 351 $actions['delete'] = sprintf( '<a href="%1$s" class="delete">%2$s</a>', esc_url( $delete_link ), __( 'Delete', 'buddypress' ) ); 352 } else { 353 $actions['delete'] = sprintf( '<a href="%1$s" class="delete">%2$s</a>', esc_url( $delete_link ), __( 'Cancel', 'buddypress' ) ); 354 } 355 356 /** 357 * Filters the row actions for each invitation in list. 358 * 359 * @since 8.0.0 360 * 361 * @param array $actions Array of actions and corresponding links. 362 * @param object $invite The BP_Invitation. 363 */ 364 $actions = apply_filters( 'bp_members_invitations_management_row_actions', $actions, $invite ); 365 366 echo $this->row_actions( $actions ); 367 } 368 369 /** 370 * Display invited user's email address. 371 * 372 * @since 8.0.0 373 * 374 * @param BP_Invitation $invite BP_Invitation object. 375 */ 376 public function column_email( $invite = null ) { 377 printf( '<a href="mailto:%1$s">%2$s</a>', esc_attr( $invite->user_email ), esc_html( $invite->user_email ) ); 378 } 379 380 /** 381 * The inviter. 382 * 383 * @since 8.0.0 384 * 385 * @param BP_Invitation $invite BP_Invitation object. 386 */ 387 public function column_username( $invite = null ) { 388 $avatar = get_avatar( $invite->inviter_id, 32 ); 389 $inviter = get_user_by( 'id', $invite->inviter_id ); 390 if ( ! $inviter ) { 391 return; 392 } 393 $user_link = bp_core_get_user_domain( $invite->inviter_id ); 394 echo $avatar . sprintf( '<strong><a href="%1$s" class="edit">%2$s</a></strong><br/>', esc_url( $user_link ), $inviter->user_login ); 395 } 396 397 /** 398 * Display invitation date. 399 * 400 * @since 8.0.0 401 * 402 * @param BP_Invitation $invite BP_Invitation object. 403 */ 404 public function column_inviter_registered_date( $invite = null ) { 405 $inviter = get_user_by( 'id', $invite->inviter_id ); 406 if ( ! $inviter ) { 407 return; 408 } 409 echo esc_html( $inviter->user_registered ); 410 } 411 412 /** 413 * Display invitation date. 414 * 415 * @since 8.0.0 416 * 417 * @param BP_Invitation $invite BP_Invitation object. 418 */ 419 public function column_invitation_date_modified( $invite = null ) { 420 echo esc_html( $invite->date_modified ); 421 } 422 423 /** 424 * Display invitation date. 425 * 426 * @since 8.0.0 427 * 428 * @param BP_Invitation $invite BP_Invitation object. 429 */ 430 public function column_invitation_sent( $invite = null ) { 431 if ( $invite->invite_sent) { 432 esc_html_e( 'Yes', 'buddypress' ); 433 } else { 434 esc_html_e( 'No', 'buddypress' ); 435 } 436 } 437 438 /** 439 * Display invitation acceptance status. 440 * 441 * @since 8.0.0 442 * 443 * @param BP_Invitation $invite BP_Invitation object. 444 */ 445 public function column_invitation_accepted( $invite = null ) { 446 if ( $invite->accepted ) { 447 esc_html_e( 'Yes', 'buddypress' ); 448 } else { 449 esc_html_e( 'No', 'buddypress' ); 450 } 451 } 452 453 /** 454 * Allow plugins to add their custom column. 455 * 456 * @since 8.0.0 457 * 458 * @param BP_Invitation $invite BP_Invitation object. 459 * @param string $column_name The column name. 460 * @return string 461 */ 462 function column_default( $invite = null, $column_name = '' ) { 463 464 /** 465 * Filters the single site custom columns for plugins. 466 * 467 * @since 8.0.0 468 * 469 * @param string $column_name The column name. 470 * @param object $invite The BP_Invitation object.. 471 */ 472 return apply_filters( 'bp_members_invitations_management_custom_column', '', $column_name, $invite ); 473 } 474 } -
new file src/bp-members/classes/class-bp-members-invitations-template.php
diff --git src/bp-members/classes/class-bp-members-invitations-template.php src/bp-members/classes/class-bp-members-invitations-template.php new file mode 100644 index 000000000..3ac8e17fb
- + 1 <?php 2 /** 3 * BuddyPress Members Invitation Template Loop Class. 4 * 5 * @package BuddyPress 6 * @subpackage TonificationsTemplate 7 * @since 8.0.0 8 */ 9 10 // Exit if accessed directly. 11 defined( 'ABSPATH' ) || exit; 12 13 /** 14 * The main membership invitations template loop class. 15 * 16 * Responsible for loading a group of membership invitations into a loop for display. 17 * 18 * @since 8.0.0 19 */ 20 class BP_Members_Invitations_Template { 21 22 /** 23 * The loop iterator. 24 * 25 * @since 8.0.0 26 * @var int 27 */ 28 public $current_invitation = -1; 29 30 /** 31 * The number of invitations returned by the paged query. 32 * 33 * @since 8.0.0 34 * @var int 35 */ 36 public $current_invitation_count; 37 38 /** 39 * Total number of invitations matching the query. 40 * 41 * @since 8.0.0 42 * @var int 43 */ 44 public $total_invitation_count; 45 46 /** 47 * Array of network invitations located by the query. 48 * 49 * @since 8.0.0 50 * @var array 51 */ 52 public $invitations; 53 54 /** 55 * The invitation object currently being iterated on. 56 * 57 * @since 8.0.0 58 * @var object 59 */ 60 public $invitation; 61 62 /** 63 * A flag for whether the loop is currently being iterated. 64 * 65 * @since 8.0.0 66 * @var bool 67 */ 68 public $in_the_loop; 69 70 /** 71 * The ID of the user to whom the displayed invitations were sent. 72 * 73 * @since 8.0.0 74 * @var int 75 */ 76 public $user_id; 77 78 /** 79 * The ID of the user to whom the displayed invitations belong. 80 * 81 * @since 8.0.0 82 * @var int 83 */ 84 public $inviter_id; 85 86 /** 87 * The page number being requested. 88 * 89 * @since 8.0.0 90 * @var int 91 */ 92 public $pag_page; 93 94 /** 95 * The $_GET argument used in URLs for determining pagination. 96 * 97 * @since 8.0.0 98 * @var int 99 */ 100 public $pag_arg; 101 102 /** 103 * The number of items to display per page of results. 104 * 105 * @since 8.0.0 106 * @var int 107 */ 108 public $pag_num; 109 110 /** 111 * An HTML string containing pagination links. 112 * 113 * @since 8.0.0 114 * @var string 115 */ 116 public $pag_links; 117 118 /** 119 * A string to match against. 120 * 121 * @since 8.0.0 122 * @var string 123 */ 124 public $search_terms; 125 126 /** 127 * A database column to order the results by. 128 * 129 * @since 8.0.0 130 * @var string 131 */ 132 public $order_by; 133 134 /** 135 * The direction to sort the results (ASC or DESC). 136 * 137 * @since 8.0.0 138 * @var string 139 */ 140 public $sort_order; 141 142 /** 143 * Array of variables used in this invitation query. 144 * 145 * @since 2.2.2 146 * @var array 147 */ 148 public $query_vars; 149 150 /** 151 * Constructor method. 152 * 153 * @see bp_has_members_invitations() For information on the array format. 154 * 155 * @since 8.0.0 156 * 157 * @param array $args { 158 * An array of arguments. See {@link bp_has_members_invitations()} 159 * for more details. 160 * } 161 */ 162 public function __construct( $args = array() ) { 163 164 // Parse arguments. 165 $r = wp_parse_args( $args, array( 166 'id' => false, 167 'user_id' => false, 168 'inviter_id' => false, 169 'invitee_email' => false, 170 'item_id' => false, 171 'type' => 'invite', 172 'invite_sent' => 'all', 173 'accepted' => 'all', 174 'search_terms' => '', 175 'order_by' => 'date_modified', 176 'sort_order' => 'DESC', 177 'page' => 1, 178 'per_page' => 25, 179 'fields' => 'all', 180 'page_arg' => 'ipage', 181 ) ); 182 183 // Sort order direction. 184 $orders = array( 'ASC', 'DESC' ); 185 if ( ! empty( $_GET['sort_order'] ) && in_array( $_GET['sort_order'], $orders ) ) { 186 $r['sort_order'] = $_GET['sort_order']; 187 } else { 188 $r['sort_order'] = in_array( $r['sort_order'], $orders ) ? $r['sort_order'] : 'DESC'; 189 } 190 191 // Setup variables. 192 $this->pag_arg = sanitize_key( $r['page_arg'] ); 193 $this->pag_page = bp_sanitize_pagination_arg( $this->pag_arg, $r['page'] ); 194 $this->pag_num = bp_sanitize_pagination_arg( 'num', $r['per_page'] ); 195 $this->user_id = $r['user_id']; 196 $this->search_terms = $r['search_terms']; 197 $this->order_by = $r['order_by']; 198 $this->sort_order = $r['sort_order']; 199 $this->query_vars = array( 200 'id' => $r['id'], 201 'user_id' => $r['user_id'], 202 'inviter_id' => $r['inviter_id'], 203 'invitee_email' => $r['invitee_email'], 204 'item_id' => $r['item_id'], 205 'type' => $r['type'], 206 'invite_sent' => $r['invite_sent'], 207 'accepted' => $r['accepted'], 208 'search_terms' => $this->search_terms, 209 'order_by' => $this->order_by, 210 'sort_order' => $this->sort_order, 211 'page' => $this->pag_page, 212 'per_page' => $this->pag_num, 213 ); 214 215 // Setup the invitations to loop through. 216 $invites_class = new BP_Members_Invitation_Manager(); 217 218 $this->invitations = $invites_class->get_invitations( $this->query_vars ); 219 $this->current_invitation_count = count( $this->invitations ); 220 $this->total_invitation_count = $invites_class->get_invitations_total_count( $this->query_vars ); 221 222 if ( (int) $this->total_invitation_count && (int) $this->pag_num ) { 223 $add_args = array( 224 'sort_order' => $this->sort_order, 225 ); 226 227 $this->pag_links = paginate_links( array( 228 'base' => add_query_arg( $this->pag_arg, '%#%' ), 229 'format' => '', 230 'total' => ceil( (int) $this->total_invitation_count / (int) $this->pag_num ), 231 'current' => $this->pag_page, 232 'prev_text' => _x( '←', 'Network invitation pagination previous text', 'buddypress' ), 233 'next_text' => _x( '→', 'Network invitation pagination next text', 'buddypress' ), 234 'mid_size' => 1, 235 'add_args' => $add_args, 236 ) ); 237 } 238 } 239 240 /** 241 * Whether there are invitations available in the loop. 242 * 243 * @since 8.0.0 244 * 245 * @see bp_has_members_invitations() 246 * 247 * @return bool True if there are items in the loop, otherwise false. 248 */ 249 public function has_invitations() { 250 if ( $this->current_invitation_count ) { 251 return true; 252 } 253 254 return false; 255 } 256 257 /** 258 * Set up the next invitation and iterate index. 259 * 260 * @since 8.0.0 261 * 262 * @return object The next invitation to iterate over. 263 */ 264 public function next_invitation() { 265 266 $this->current_invitation++; 267 268 $this->invitation = $this->invitations[ $this->current_invitation ]; 269 270 return $this->invitation; 271 } 272 273 /** 274 * Rewind the blogs and reset blog index. 275 * 276 * @since 8.0.0 277 */ 278 public function rewind_invitations() { 279 280 $this->current_invitation = -1; 281 282 if ( $this->current_invitation_count > 0 ) { 283 $this->invitation = $this->invitations[0]; 284 } 285 } 286 287 /** 288 * Whether there are invitations left in the loop to iterate over. 289 * 290 * This method is used by {@link bp_members_invitations()} as part of the 291 * while loop that controls iteration inside the invitations loop, eg: 292 * while ( bp_members_invitations() ) { ... 293 * 294 * @since 8.0.0 295 * 296 * @see bp_members_invitations() 297 * 298 * @return bool True if there are more invitations to show, 299 * otherwise false. 300 */ 301 public function invitations() { 302 303 if ( $this->current_invitation + 1 < $this->current_invitation_count ) { 304 return true; 305 306 } elseif ( $this->current_invitation + 1 == $this->current_invitation_count ) { 307 308 /** 309 * Fires right before the rewinding of invitation posts. 310 * 311 * @since 8.0.0 312 */ 313 do_action( 'members_invitations_loop_end'); 314 315 $this->rewind_invitations(); 316 } 317 318 $this->in_the_loop = false; 319 return false; 320 } 321 322 /** 323 * Set up the current invitation inside the loop. 324 * 325 * Used by {@link bp_the_invitation()} to set up the current 326 * invitation data while looping, so that template tags used during 327 * that iteration make reference to the current invitation. 328 * 329 * @since 8.0.0 330 * 331 * @see bp_the_invitation() 332 */ 333 public function the_invitation() { 334 $this->in_the_loop = true; 335 $this->invitation = $this->next_invitation(); 336 337 // Loop has just started. 338 if ( 0 === $this->current_invitation ) { 339 340 /** 341 * Fires if the current invitation item is the first in the invitation loop. 342 * 343 * @since 8.0.0 344 */ 345 do_action( 'members_invitations_loop_start' ); 346 } 347 } 348 } -
new file src/bp-members/screens/list-invites.php
diff --git src/bp-members/screens/list-invites.php src/bp-members/screens/list-invites.php new file mode 100644 index 000000000..8242dd279
- + 1 <?php 2 /** 3 * Members: Sent Invitations Status 4 * 5 * @package BuddyPress 6 * @subpackage MembersScreens 7 * @since 8.0.0 8 */ 9 10 /** 11 * Catch and process the Send Invites page. 12 * 13 * @since 8.0.0 14 */ 15 function members_screen_list_sent_invites() { 16 17 /** 18 * Fires before the loading of template for the send membership invitations page. 19 * 20 * @since 8.0.0 21 */ 22 do_action( 'members_screen_list_sent_invites' ); 23 24 /** 25 * Filters the template used to display the send membership invitations page. 26 * 27 * @since 8.0.0 28 * 29 * @param string $template Path to the send membership invitations template to load. 30 */ 31 bp_core_load_template( apply_filters( 'members_template_list_sent_invites', 'members/single/invitations' ) ); 32 } 33 34 /** 35 * Handle canceling or resending single invitations. 36 * 37 * @since 8.0.0 38 * 39 * @return bool 40 */ 41 function bp_members_invitations_action_handling() { 42 43 // Bail if not the read screen. 44 if ( ! bp_is_user_members_invitations_list() ) { 45 return false; 46 } 47 48 // Get the action. 49 $action = ! empty( $_GET['action'] ) ? $_GET['action'] : ''; 50 $nonce = ! empty( $_GET['_wpnonce'] ) ? $_GET['_wpnonce'] : ''; 51 $id = ! empty( $_GET['invitation_id'] ) ? $_GET['invitation_id'] : ''; 52 53 // Bail if no action or no ID. 54 if ( empty( $action ) || empty( $id ) ) { 55 return false; 56 } 57 58 if ( 'cancel' === $action ) { 59 // Check the nonce and delete the invitation. 60 if ( bp_verify_nonce_request( 'bp_members_invitations_cancel_' . $id ) && bp_members_invitations_delete_by_id( $id ) ) { 61 bp_core_add_message( __( 'Invitation successfully canceled.', 'buddypress' ) ); 62 } else { 63 bp_core_add_message( __( 'There was a problem canceling that invitation.', 'buddypress' ), 'error' ); 64 } 65 } else if ( 'resend' === $action ) { 66 // Check the nonce and resend the invitation. 67 if ( bp_verify_nonce_request( 'bp_network_invitation_resend_' . $id ) && bp_members_invitation_resend_by_id( $id ) ) { 68 bp_core_add_message( __( 'Invitation successfully resent.', 'buddypress' ) ); 69 } else { 70 bp_core_add_message( __( 'There was a problem resending that invitation.', 'buddypress' ), 'error' ); 71 } 72 } else { 73 return false; 74 } 75 76 // Redirect. 77 $user_id = bp_displayed_user_id(); 78 bp_core_redirect( bp_get_members_invitations_list_invites_permalink( $user_id ) ); 79 } 80 add_action( 'bp_actions', 'bp_members_invitations_action_handling' ); -
src/bp-members/screens/register.php
diff --git src/bp-members/screens/register.php src/bp-members/screens/register.php index 54b6facd5..b08f6ece8 100644
function bp_core_screen_signup() { 42 42 43 43 $bp->signup->step = 'request-details'; 44 44 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 } 47 54 55 if ( ! bp_get_signup_allowed() && ! $active_invite ) { 56 $bp->signup->step = 'registration-disabled'; 48 57 // If the signup page is submitted, validate and save. 49 58 } elseif ( isset( $_POST['signup_submit'] ) && bp_verify_nonce_request( 'bp_new_signup' ) ) { 50 59 -
new file src/bp-members/screens/send-invites.php
diff --git src/bp-members/screens/send-invites.php src/bp-members/screens/send-invites.php new file mode 100644 index 000000000..cc78d33c3
- + 1 <?php 2 /** 3 * Members: Send Invitations 4 * 5 * @package BuddyPress 6 * @subpackage MembersScreens 7 * @since 8.0.0 8 */ 9 10 /** 11 * Catch and process the Send Invites page. 12 * 13 * @since 8.0.0 14 */ 15 function members_screen_send_invites() { 16 17 /** 18 * Fires before the loading of template for the send membership invitations page. 19 * 20 * @since 8.0.0 21 */ 22 do_action( 'members_screen_send_invites' ); 23 24 /** 25 * Filters the template used to display the send membership invitations page. 26 * 27 * @since 8.0.0 28 * 29 * @param string $template Path to the send membership invitations template to load. 30 */ 31 bp_core_load_template( apply_filters( 'members_template_send_invites', 'members/single/invitations' ) ); 32 } 33 34 /** 35 * Handle sending invitations. 36 * 37 * @since 8.0.0 38 * 39 * @return bool 40 */ 41 function 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 } 77 add_action( 'bp_actions', 'bp_network_invitations_catch_send_action' ); 78 No newline at end of file -
src/bp-templates/bp-legacy/buddypress-functions.php
diff --git src/bp-templates/bp-legacy/buddypress-functions.php src/bp-templates/bp-legacy/buddypress-functions.php index f4a3e1016..03c09ac00 100644
function bp_legacy_theme_group_manage_members_add_search() { 2014 2014 <?php 2015 2015 endif; 2016 2016 } 2017 2018 /** 2019 * Modify welcome message in Legacy template pack when 2020 * community invitations are enabled. 2021 * 2022 * @since 8.0.0 2023 * 2024 * @return string $message The message text. 2025 */ 2026 function 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 } 2032 add_action( 'bp_before_register_page', 'bp_members_invitations_add_legacy_welcome_message' ); 2033 2034 2035 /** 2036 * Modify "registration disabled" message in Legacy template pack when 2037 * community invitations are enabled. 2038 * 2039 * @since 8.0.0 2040 * 2041 * @return string $message The message text. 2042 */ 2043 function 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 } 2049 add_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
89 89 elseif ( bp_is_user_notifications() ) : 90 90 bp_get_template_part( 'members/single/notifications' ); 91 91 92 elseif ( bp_is_user_members_invitations() ) : 93 bp_get_template_part( 'members/single/invitations' ); 94 92 95 elseif ( bp_is_user_settings() ) : 93 96 bp_get_template_part( 'members/single/settings' ); 94 97 -
new file src/bp-templates/bp-legacy/buddypress/members/single/invitations.php
diff --git src/bp-templates/bp-legacy/buddypress/members/single/invitations.php src/bp-templates/bp-legacy/buddypress/members/single/invitations.php new file mode 100644 index 000000000..876a2e314
- + 1 <?php 2 /** 3 * BuddyPress - membership invitations 4 * 5 * @package BuddyPress 6 * @subpackage bp-legacy 7 * @version 8.0.0 8 */ 9 10 ?> 11 12 <div class="item-list-tabs no-ajax" id="subnav" aria-label="<?php esc_attr_e( 'Member secondary navigation', 'buddypress' ); ?>" role="navigation"> 13 <ul> 14 <?php bp_get_options_nav(); ?> 15 </ul> 16 </div> 17 18 <?php 19 switch ( 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 30 endswitch; 31 -
new file src/bp-templates/bp-legacy/buddypress/members/single/invitations/invitations-loop.php
diff --git src/bp-templates/bp-legacy/buddypress/members/single/invitations/invitations-loop.php src/bp-templates/bp-legacy/buddypress/members/single/invitations/invitations-loop.php new file mode 100644 index 000000000..c02b7c56a
- + 1 <?php 2 /** 3 * BuddyPress - Membership Invitations Loop 4 * 5 * @package BuddyPress 6 * @subpackage bp-legacy 7 * @version 8.0.0 8 */ 9 10 ?> 11 <form action="" method="post" id="invitations-bulk-management"> 12 <table class="invitations"> 13 <thead> 14 <tr> 15 <th class="icon"></th> 16 <th class="bulk-select-all"><input id="select-all-invitations" type="checkbox"><label class="bp-screen-reader-text" for="select-all-invitations"><?php 17 /* translators: accessibility text */ 18 _e( 'Select all', 'buddypress' ); 19 ?></label></th> 20 <th class="title"><?php _e( 'Invitee', 'buddypress' ); ?></th> 21 <th class="content"><?php _e( 'Message', 'buddypress' ); ?></th> 22 <th class="sent"><?php _e( 'Sent', 'buddypress' ); ?></th> 23 <th class="accepted"><?php _e( 'Accepted', 'buddypress' ); ?></th> 24 <th class="date"><?php _e( 'Date Modified', 'buddypress' ); ?></th> 25 <th class="actions"><?php _e( 'Actions', 'buddypress' ); ?></th> 26 </tr> 27 </thead> 28 29 <tbody> 30 31 <?php while ( bp_the_members_invitations() ) : bp_the_members_invitation(); ?> 32 33 <tr> 34 <td></td> 35 <td class="bulk-select-check"><label for="<?php bp_the_members_invitation_property( 'id' ); ?>"><input id="<?php bp_the_members_invitation_property( 'id' ); ?>" type="checkbox" name="network_invitations[]" value="<?php bp_the_members_invitation_property( 'id' ); ?>" class="invitation-check"><span class="bp-screen-reader-text"><?php 36 /* translators: accessibility text */ 37 _e( 'Select this invitation', 'buddypress' ); 38 ?></span></label></td> 39 <td class="invitation-invitee"><?php bp_the_members_invitation_property( 'invitee_email' ); ?></td> 40 <td class="invitation-content"><?php wptexturize( bp_the_members_invitation_property( 'content' ) ); ?></td> 41 <td class="invitation-sent"><?php bp_the_members_invitation_property( 'invite_sent' ); ?></td> 42 <td class="invitation-accepted"><?php bp_the_members_invitation_property( 'accepted' ); ?></td> 43 <td class="invitation-date-modified"><?php bp_the_members_invitation_property( 'date_modified' ); ?></td> 44 <td class="invitation-actions"><?php bp_the_members_invitation_action_links(); ?></td> 45 </tr> 46 47 <?php endwhile; ?> 48 49 </tbody> 50 </table> 51 52 <div class="invitations-options-nav"> 53 <?php // @TODO //bp_invitations_bulk_management_dropdown(); ?> 54 </div><!-- .invitations-options-nav --> 55 56 <?php wp_nonce_field( 'invitations_bulk_nonce', 'invitations_bulk_nonce' ); ?> 57 </form> -
new file src/bp-templates/bp-legacy/buddypress/members/single/invitations/list-invites.php
diff --git src/bp-templates/bp-legacy/buddypress/members/single/invitations/list-invites.php src/bp-templates/bp-legacy/buddypress/members/single/invitations/list-invites.php new file mode 100644 index 000000000..f5a4ba80f
- + 1 <?php 2 /** 3 * BuddyPress - Sent Membership Invitations 4 * 5 * @package BuddyPress 6 * @subpackage bp-legacy 7 * @version 8.0.0 8 */ 9 ?> 10 11 <?php if ( bp_has_members_invitations() ) : ?> 12 13 <h2 class="bp-screen-reader-text"><?php 14 /* translators: accessibility text */ 15 _e( 'Invitations', 'buddypress' ); 16 ?></h2> 17 18 <div id="pag-top" class="pagination no-ajax"> 19 <div class="pag-count" id="invitations-count-top"> 20 <?php bp_members_invitations_pagination_count(); ?> 21 </div> 22 23 <div class="pagination-links" id="invitations-pag-top"> 24 <?php bp_members_invitations_pagination_links(); ?> 25 </div> 26 </div> 27 28 <?php bp_get_template_part( 'members/single/invitations/invitations-loop' ); ?> 29 30 <div id="pag-bottom" class="pagination no-ajax"> 31 <div class="pag-count" id="invitations-count-bottom"> 32 <?php bp_members_invitations_pagination_count(); ?> 33 </div> 34 35 <div class="pagination-links" id="invitations-pag-bottom"> 36 <?php bp_members_invitations_pagination_links(); ?> 37 </div> 38 </div> 39 40 <?php else : ?> 41 42 <p><?php _e( 'There are no invitations to display.', 'buddypress' ); ?></p> 43 44 <?php endif; -
new file src/bp-templates/bp-legacy/buddypress/members/single/invitations/send-invites.php
diff --git src/bp-templates/bp-legacy/buddypress/members/single/invitations/send-invites.php src/bp-templates/bp-legacy/buddypress/members/single/invitations/send-invites.php new file mode 100644 index 000000000..c27f4abc6
- + 1 <?php 2 /** 3 * BuddyPress - Sent Membership Invitations 4 * 5 * @package BuddyPress 6 * @subpackage bp-legacy 7 * @version 8.0.0 8 */ 9 ?> 10 <h2 class="bp-screen-reader-text"><?php 11 /* translators: accessibility text */ 12 _e( 'Send Invitations', 'buddypress' ); 13 ?></h2> 14 15 <form class="standard-form network-invitation-form" id="network-invitation-form" method="post"> 16 <label for="bp_network_invitation_invitee_email"><?php _e( 'Email address of new user', 'buddypress' ); ?></label> 17 <input id="bp_network_invitation_invitee_email" type="email" name="invitee_email" required="required"> 18 19 <label for="bp_network_invitation_message"><?php _e( 'Add a personalized message to the invitation (optional)', 'buddypress' ); ?></label> 20 <textarea id="bp_network_invitation_message" name="invite_message"></textarea> 21 22 <input type="hidden" name="action" value="send-invite"> 23 24 <?php wp_nonce_field( 'bp_network_invitation_send_' . bp_displayed_user_id() ) ?> 25 <p> 26 <input id="submit" type="submit" name="submit" class="submit" value="<?php esc_attr_e( 'Send Invitation', 'buddypress' ) ?>" /> 27 </p> 28 </form> -
src/bp-templates/bp-nouveau/buddypress-functions.php
diff --git src/bp-templates/bp-nouveau/buddypress-functions.php src/bp-templates/bp-nouveau/buddypress-functions.php index 892bf2e33..f93134f74 100644
class BP_Nouveau extends BP_Theme_Compat { 195 195 // Set the BP Uri for the Ajax customizer preview. 196 196 add_filter( 'bp_uri', array( $this, 'customizer_set_uri' ), 10, 1 ); 197 197 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 198 201 /** Override **********************************************************/ 199 202 200 203 /** … … class BP_Nouveau extends BP_Theme_Compat { 676 679 677 680 return $path; 678 681 } 682 /** 683 * Modify "registration disabled" message in Nouveau template pack. 684 * Modify welcome message in Nouveau template pack. 685 * 686 * @since 8.0.0 687 * 688 * @param array $messages The list of feedback messages. 689 * 690 * @return array $messages 691 */ 692 function filter_registration_messages( $messages ) { 693 // Change the "registration is disabled" message. 694 $disallowed_message = bp_members_invitations_get_modified_registration_disabled_message(); 695 if ( $disallowed_message ) { 696 $messages['registration-disabled']['message'] = $disallowed_message; 697 } 698 // Add information about invitations to the welcome block. 699 $welcome_message = bp_members_invitations_get_registration_welcome_message(); 700 if ( $welcome_message ) { 701 $messages['request-details']['message'] = $welcome_message . $messages['request-details']['message']; 702 } 703 return $messages; 704 } 679 705 } 680 706 681 707 /** -
new file src/bp-templates/bp-nouveau/buddypress/members/single/invitations.php
diff --git src/bp-templates/bp-nouveau/buddypress/members/single/invitations.php src/bp-templates/bp-nouveau/buddypress/members/single/invitations.php new file mode 100644 index 000000000..90211f0e2
- + 1 <?php 2 /** 3 * BuddyPress - Membership invitations 4 * 5 * @since 8.0.0 6 * @version 8.0.0 7 */ 8 // @TODO 9 ?> 10 11 <nav class="<?php bp_nouveau_single_item_subnav_classes(); ?>" id="subnav" role="navigation" aria-label="<?php esc_attr_e( 'Groups menu', 'buddypress' ); ?>"> 12 <ul class="subnav"> 13 14 <?php if ( bp_is_my_profile() ) : ?> 15 16 <?php bp_get_template_part( 'members/single/parts/item-subnav' ); ?> 17 18 <?php endif; ?> 19 20 </ul> 21 </nav><!-- .bp-navs --> 22 23 <?php bp_get_template_part( 'common/search-and-filters-bar' ); ?> 24 eh? 25 <?php 26 if ( 'sent-invites' === bp_current_action() ) { 27 echo "send invites"; 28 } else { 29 echo "default"; 30 } 31 -
src/class-buddypress.php
diff --git src/class-buddypress.php src/class-buddypress.php index 3dd1d483c..d3801b8e0 100644
class BuddyPress { 620 620 'BP_REST_Attachments_Member_Avatar_Endpoint' => 'members', 621 621 'BP_REST_Attachments_Member_Cover_Endpoint' => 'members', 622 622 'BP_REST_Signup_Endpoint' => 'members', 623 'BP_Members_Invitation_Manager' => 'members', 624 'BP_Members_Invitations_Template' => 'members', 623 625 624 626 'BP_REST_Messages_Endpoint' => 'messages', 625 627