Ticket #8139: 8139.07.patch
File 8139.07.patch, 197.7 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 7749dd449..1b2642448 100644
function bp_core_modify_admin_menu_highlight() { 85 85 $submenu_file = $plugin_page; 86 86 } 87 87 88 // Keep the BuddyPress tools menu highlighted .89 if ( 'bp-optouts' === $plugin_page ) {88 // Keep the BuddyPress tools menu highlighted when using a tools tab. 89 if ( 'bp-optouts' === $plugin_page || 'bp-members-invitations' === $plugin_page ) { 90 90 $submenu_file = 'bp-tools'; 91 91 } 92 92 } … … function bp_core_activation_notice() { 284 284 285 285 // Activate and Register are special cases. They are not components but they need WP pages. 286 286 // If user registration is disabled, we can skip this step. 287 if ( bp_get_signup_allowed() ) {287 if ( bp_get_signup_allowed() || bp_get_members_invitations_allowed() ) { 288 288 $wp_page_components[] = array( 289 289 'id' => 'activate', 290 290 'name' => __( 'Activate', 'buddypress' ), … … function bp_core_get_admin_tabs( $active_tab = '', $context = 'settings' ) { 479 479 'name' => __( 'Repair', 'buddypress' ), 480 480 ), 481 481 '1' => array( 482 'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-members-invitations' ), $tools_page ) ), 483 'name' => __( 'Manage Invitations', 'buddypress' ), 484 ), 485 '2' => array( 482 486 'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-optouts' ), $tools_page ) ), 483 487 'name' => __( 'Manage Opt-outs', 'buddypress' ), 484 488 ), -
src/bp-core/admin/bp-core-admin-optouts.php
diff --git src/bp-core/admin/bp-core-admin-optouts.php src/bp-core/admin/bp-core-admin-optouts.php index d47cf79de..95d789a08 100644
function bp_core_get_optouts_notice() { 174 174 ); 175 175 176 176 if ( ! empty( $_REQUEST['deleted'] ) ) { 177 $deleted = absint( $_REQUEST['deleted'] ); 177 178 $notice['message'] .= sprintf( 178 /* translators: %s: number of deleted optouts */ 179 _nx( '%s opt-out successfully deleted!', '%s opt-outs successfully deleted!', 180 absint( $_REQUEST['deleted'] ), 181 'nonmembers opt-out deleted', 182 'buddypress' 179 _nx( 180 /* translators: %s: number of deleted optouts */ 181 '%s opt-out successfully deleted!', '%s opt-outs successfully deleted!', 182 $deleted, 183 'nonmembers opt-out deleted', 184 'buddypress' 183 185 ), 184 186 number_format_i18n( absint( $_REQUEST['deleted'] ) ) 185 187 ); 186 188 } 187 189 188 190 if ( ! empty( $_REQUEST['notdeleted'] ) ) { 191 $notdeleted = absint( $_REQUEST['notdeleted'] ); 189 192 $notice['message'] .= sprintf( 190 /* translators: %s: number of optouts that failed to be deleted */ 191 _nx( '%s opt-out was not deleted.', '%s opt-outs were not deleted.', 192 absint( $_REQUEST['notdeleted'] ), 193 'nonmembers opt-out not deleted', 194 'buddypress' 193 _nx( 194 /* translators: %s: number of optouts that failed to be deleted */ 195 '%s opt-out was not deleted.', '%s opt-outs were not deleted.', 196 $notdeleted, 197 'nonmembers opt-out not deleted', 198 'buddypress' 195 199 ), 196 number_format_i18n( absint( $_REQUEST['notdeleted'] ))200 number_format_i18n( $notdeleted ) 197 201 ); 198 202 199 203 if ( empty( $_REQUEST['deleted'] ) ) { -
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/admin/bp-core-admin-tools.php
diff --git src/bp-core/admin/bp-core-admin-tools.php src/bp-core/admin/bp-core-admin-tools.php index f93549295..bd2a2d3f8 100644
function bp_core_admin_available_tools_intro() { 557 557 ); 558 558 ?> 559 559 </dd> 560 561 <dt><?php esc_html_e( 'Manage Invitations', 'buddypress' ) ?></dt> 562 <dd> 563 <?php esc_html_e( 'When enabled, BuddyPress allows your users to invite nonmembers to join your site.', 'buddypress' ); ?> 564 <?php 565 $url = add_query_arg( 'page', 'bp-members-invitations', bp_get_admin_url( $page ) ); 566 printf( 567 /* translators: %s: the link to the BuddyPress Invitations management tool screen */ 568 esc_html_x( 'Visit %s to manage your site’s invitations.', 'buddypress invitations tool intro', 'buddypress' ), 569 '<a href="' . esc_url( $url ) . '">' . esc_html__( 'Invitations', 'buddypress' ) . '</a>' 570 ); 571 ?> 572 </dd> 573 560 574 <dt><?php esc_html_e( 'Manage Opt-outs', 'buddypress' ) ?></dt> 561 575 <dd> 562 576 <?php esc_html_e( 'BuddyPress stores opt-out requests from people who are not members of this site, but have been contacted via communication from this site, and wish to opt-out from future communication.', 'buddypress' ); ?> 563 577 <?php 564 578 $url = add_query_arg( 'page', 'bp-optouts', bp_get_admin_url( $page ) ); 565 579 printf( 566 /* translators: %s: the link to the BuddyPress Nonmember Opt-outs */580 /* translators: %s: the link to the BuddyPress Nonmember Opt-outs management tool screen */ 567 581 esc_html_x( 'Visit %s to manage your site’s opt-out requests.', 'buddypress opt-outs intro', 'buddypress' ), 568 582 '<a href="' . esc_url( $url ) . '">' . esc_html__( 'Nonmember Opt-outs', 'buddypress' ) . '</a>' 569 583 ); -
src/bp-core/admin/css/common-rtl.css
diff --git src/bp-core/admin/css/common-rtl.css src/bp-core/admin/css/common-rtl.css index d460dc8d2..1bbd8508a 100644
body.tools-php .bp-tools dd { 317 317 margin: 0; 318 318 } 319 319 320 body.tools_page_bp-members-invitations .nav-tab-wrapper, 321 body.tools_page_bp-optouts .nav-tab-wrapper { 322 margin-bottom: 1em; 323 } 324 320 325 /* 321 326 * 2.4 Tooltips 322 327 */ -
src/bp-core/admin/css/common.css
diff --git src/bp-core/admin/css/common.css src/bp-core/admin/css/common.css index 0272626bb..d2730f9a9 100644
body.tools-php .bp-tools dd { 317 317 margin: 0; 318 318 } 319 319 320 body.tools_page_bp-members-invitations .nav-tab-wrapper, 321 body.tools_page_bp-optouts .nav-tab-wrapper { 322 margin-bottom: 1em; 323 } 324 320 325 /* 321 326 * 2.4 Tooltips 322 327 */ -
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..85a8978d2 100644
function bp_email_set_default_headers( $headers, $property, $transform, $email ) 1067 1067 1068 1068 // Add 'List-Unsubscribe' header if applicable. 1069 1069 if ( ! empty( $tokens['unsubscribe'] ) && $tokens['unsubscribe'] !== wp_login_url() ) { 1070 $user = get_user_by( 'email', $tokens['recipient.email'] ); 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 1078 // If this email is not to a current member, include the nonmember's email address and the Inviter ID. 1079 if ( ! $user_id ) { 1080 $args['email_address'] = $tokens['recipient.email']; 1081 $args['member_id'] = bp_loggedin_user_id(); 1082 } 1083 1084 $link = bp_email_get_unsubscribe_link( $args ); 1076 1085 1077 1086 if ( ! empty( $link ) ) { 1078 1087 $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 1535afed4..9464d61ad 100644
function bp_core_add_page_mappings( $components, $existing = 'keep' ) { 702 702 703 703 // Register and Activate are not components, but need pages when 704 704 // registration is enabled. 705 if ( bp_get_signup_allowed() ) {705 if ( bp_get_signup_allowed() || bp_get_members_invitations_allowed() ) { 706 706 foreach ( array( 'register', 'activate' ) as $slug ) { 707 707 if ( ! isset( $pages[ $slug ] ) ) { 708 708 $pages_to_create[ $slug ] = $page_titles[ $slug ]; … … function bp_send_email( $email_type, $to, $args = array() ) { 3472 3472 // From, subject, content are set automatically. 3473 3473 if ( 'settings-verify-email-change' === $email_type && isset( $args['tokens']['displayname'] ) ) { 3474 3474 $email->set_to( $to, $args['tokens']['displayname'] ); 3475 // Emails sent to nonmembers will have no recipient.name populated. 3476 } else if ( 'bp-members-invitation' === $email_type ) { 3477 $email->set_to( $to, $to ); 3475 3478 } else { 3476 3479 $email->set_to( $to ); 3477 3480 } … … function bp_email_get_schema() { 3815 3818 /* translators: do not remove {} brackets or translate its contents. */ 3816 3819 'post_title' => __( '[{{{site.name}}}] You have an invitation to the group: "{{group.name}}"', 'buddypress' ), 3817 3820 /* translators: do not remove {} brackets or translate its contents. */ 3818 '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' ),3821 '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' ), 3819 3822 /* translators: do not remove {} brackets or translate its contents. */ 3820 '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' ),3823 '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' ), 3821 3824 ), 3822 3825 'groups-member-promoted' => array( 3823 3826 /* translators: do not remove {} brackets or translate its contents. */ … … function bp_email_get_schema() { 3867 3870 /* translators: do not remove {} brackets or translate its contents. */ 3868 3871 'post_excerpt' => __( "Your membership request for the group \"{{group.name}}\" has been rejected.\n\nTo request membership again, visit: {{{group.url}}}", 'buddypress' ), 3869 3872 ), 3873 'bp-members-invitation' => array( 3874 /* translators: do not remove {} brackets or translate its contents. */ 3875 'post_title' => __( '{{inviter.name}} has invited you to join {{site.name}}', 'buddypress' ), 3876 /* translators: do not remove {} brackets or translate its contents. */ 3877 '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' ), 3878 /* translators: do not remove {} brackets or translate its contents. */ 3879 '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' ), 3880 ), 3870 3881 ) ); 3871 3882 } 3872 3883 … … function bp_email_get_type_schema( $field = 'description' ) { 4012 4023 'description' => __( 'Recipient has successfully activated an account.', 'buddypress' ), 4013 4024 ); 4014 4025 4026 $members_invitation = array( 4027 'description' => __( 'A site member has sent a site invitation to the recipient.', 'buddypress' ), 4028 'unsubscribe' => array( 4029 'meta_key' => 'notification_bp_members_invite', 4030 'message' => __( 'You will no longer receive emails when you are invited to join this site.', 'buddypress' ), 4031 ), 4032 ); 4033 4015 4034 $types = array( 4016 4035 'activity-comment' => $activity_comment, 4017 4036 'activity-comment-author' => $activity_comment_author, … … function bp_email_get_type_schema( $field = 'description' ) { 4030 4049 'groups-membership-request-accepted' => $groups_membership_request_accepted, 4031 4050 'groups-membership-request-rejected' => $groups_membership_request_rejected, 4032 4051 'core-user-activation' => $core_user_activation, 4052 'bp-members-invitation' => $members_invitation, 4033 4053 ); 4034 4054 4035 4055 if ( $field !== 'all' ) { … … function bp_email_unsubscribe_handler() { 4049 4069 $raw_email_type = ! empty( $_GET['nt'] ) ? $_GET['nt'] : ''; 4050 4070 $raw_hash = ! empty( $_GET['nh'] ) ? $_GET['nh'] : ''; 4051 4071 $raw_user_id = ! empty( $_GET['uid'] ) ? absint( $_GET['uid'] ) : 0; 4052 $new_hash = hash_hmac( 'sha1', "{$raw_email_type}:{$raw_user_id}", bp_email_get_salt() ); 4072 $raw_user_email = ! empty( $_GET['uem'] ) ? $_GET['uem'] : ''; 4073 $raw_member_id = ! empty( $_GET['mid'] ) ? absint( $_GET['mid'] ) : 0; 4074 $redirect_to = ''; 4075 4076 $new_hash = ''; 4077 if ( ! empty( $raw_user_id ) ) { 4078 $new_hash = hash_hmac( 'sha1', "{$raw_email_type}:{$raw_user_id}", bp_email_get_salt() ); 4079 } else if ( ! empty( $raw_user_email ) ) { 4080 $new_hash = hash_hmac( 'sha1', "{$raw_email_type}:{$raw_user_email}", bp_email_get_salt() ); 4081 } 4053 4082 4054 4083 // Check required values. 4055 if ( ! $raw_user_id|| ! $raw_email_type || ! $raw_hash || ! array_key_exists( $raw_email_type, $emails ) ) {4084 if ( ( ! $raw_user_id && ! $raw_user_email ) || ! $raw_email_type || ! $raw_hash || ! array_key_exists( $raw_email_type, $emails ) ) { 4056 4085 $redirect_to = wp_login_url(); 4057 4086 $result_msg = __( 'Something has gone wrong.', 'buddypress' ); 4058 4087 $unsub_msg = __( 'Please log in and go to your settings to unsubscribe from notification emails.', 'buddypress' ); … … function bp_email_unsubscribe_handler() { 4078 4107 $redirect_to = bp_core_get_user_domain( get_current_user_id() ); 4079 4108 } 4080 4109 4110 // This is an unsubscribe request from a nonmember. 4111 } else if ( $raw_user_email ) { 4112 // Unsubscribe. 4113 if ( bp_user_has_opted_out() ) { 4114 $result_msg = $emails[ $raw_email_type ]['unsubscribe']['message']; 4115 $unsub_msg = __( 'You have already unsubscribed from all communication from this site.', 'buddypress' ); 4116 } else { 4117 $optout_args = array( 4118 'email_address' => $raw_user_email, 4119 'user_id' => $raw_member_id, 4120 'email_type' => $raw_email_type, 4121 'date_modified' => bp_core_current_time(), 4122 ); 4123 bp_add_optout( $optout_args ); 4124 $result_msg = $emails[ $raw_email_type ]['unsubscribe']['message']; 4125 $unsub_msg = __( 'You have been unsubscribed.', 'buddypress' ); 4126 } 4127 4128 // This is an unsubscribe request from a current member. 4081 4129 } else { 4082 4130 if ( bp_is_active( 'settings' ) ) { 4083 4131 $redirect_to = sprintf( … … function bp_email_unsubscribe_handler() { 4097 4145 $unsub_msg = __( 'You can change this or any other email notification preferences in your email settings.', 'buddypress' ); 4098 4146 } 4099 4147 4100 $message = sprintf( 4101 '%1$s <a href="%2$s">%3$s</a>', 4102 $result_msg, 4103 esc_url( $redirect_to ), 4104 esc_html( $unsub_msg ) 4105 ); 4148 if ( $raw_user_id && $redirect_to ) { 4149 $message = sprintf( 4150 '%1$s <a href="%2$s">%3$s</a>', 4151 $result_msg, 4152 esc_url( $redirect_to ), 4153 esc_html( $unsub_msg ) 4154 ); 4106 4155 4107 bp_core_add_message( $message ); 4108 bp_core_redirect( bp_core_get_user_domain( $raw_user_id ) ); 4156 // Template notices are only displayed on BP pages. 4157 bp_core_add_message( $message ); 4158 bp_core_redirect( bp_core_get_user_domain( $raw_user_id ) ); 4109 4159 4110 exit; 4160 exit; 4161 } else { 4162 wp_die( 4163 sprintf( '%1$s %2$s', esc_html( $unsub_msg ), esc_html( $result_msg ) ), 4164 esc_html( $unsub_msg ), 4165 array( 4166 'link_url' => home_url(), 4167 'link_text' => __( 'Go to website\'s home page.', 'buddypress' ), 4168 ) 4169 ); 4170 } 4111 4171 } 4112 4172 4113 4173 /** … … function bp_email_unsubscribe_handler() { 4122 4182 * @type string $notification_type Which notification type is being sent. 4123 4183 * @type string $user_id The ID of the user to whom the notification is sent. 4124 4184 * @type string $redirect_to Optional. The url to which the user will be redirected. Default is the activity directory. 4185 * @type string $email Optional. The email address of the user to whom the notification is sent. 4125 4186 * } 4126 4187 * @return string The unsubscribe link. 4127 4188 */ … … function bp_email_get_unsubscribe_link( $args ) { 4141 4202 return ''; 4142 4203 } 4143 4204 4144 $link = add_query_arg( 4145 array( 4146 'action' => 'unsubscribe', 4147 'nh' => hash_hmac( 'sha1', "{$email_type}:{$user_id}", bp_email_get_salt() ), 4148 'nt' => $args['notification_type'], 4149 'uid' => $user_id, 4150 ), 4151 $redirect_to 4152 ); 4205 $link = ''; 4206 // Case where the recipient is a member of the site. 4207 if ( ! empty( $user_id ) ) { 4208 $link = add_query_arg( 4209 array( 4210 'action' => 'unsubscribe', 4211 'nh' => hash_hmac( 'sha1', "{$email_type}:{$user_id}", bp_email_get_salt() ), 4212 'nt' => $args['notification_type'], 4213 'uid' => $user_id, 4214 ), 4215 $redirect_to 4216 ); 4217 4218 // Case where the recipient is not a member of the site. 4219 } else if ( ! empty( $args['email_address'] ) ) { 4220 $email_address = $args['email_address']; 4221 $member_id = (int) $args['member_id']; 4222 $link = add_query_arg( 4223 array( 4224 'action' => 'unsubscribe', 4225 'nh' => hash_hmac( 'sha1', "{$email_type}:{$email_address}", bp_email_get_salt() ), 4226 'nt' => $args['notification_type'], 4227 'mid' => $member_id, 4228 'uem' => $email_address, 4229 ), 4230 $redirect_to 4231 ); 4232 } 4153 4233 4154 4234 /** 4155 4235 * Filters the unsubscribe link. … … function bp_get_optouts( $args = array() ) { 4360 4440 return $optout_class::get( $args ); 4361 4441 } 4362 4442 4443 /** 4444 * Check an email address to see if that individual has opted out. 4445 * 4446 * @since 8.0.0 4447 * 4448 * @param string $email_address Email address to check. 4449 * @return bool True if the user has opted out, false otherwise. 4450 */ 4451 function bp_user_has_opted_out( $email_address = '' ) { 4452 $optout_class = new BP_Optout(); 4453 $optout_id = $optout_class->optout_exists( 4454 array( 4455 'email_address' => $email_address, 4456 ) 4457 ); 4458 return (bool) $optout_id; 4459 } 4460 4363 4461 /** 4364 4462 * Delete a BP_Optout by ID. 4365 4463 * -
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/bp-core-update.php
diff --git src/bp-core/bp-core-update.php src/bp-core/bp-core-update.php index 6747c3ac5..03710213c 100644
function bp_core_get_8_0_upgrade_email_schema( $emails ) { 697 697 $new_emails['core-user-activation'] = $emails['core-user-activation']; 698 698 } 699 699 700 if ( isset( $emails['bp-members-invitation'] ) ) { 701 $new_emails['bp-members-invitation'] = $emails['bp-members-invitation']; 702 } 703 700 704 return $new_emails; 701 705 } 702 706 -
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 1e10deab7..bbf945471 100644
class BP_Admin { 411 411 register_setting( 'buddypress', 'bp-disable-cover-image-uploads', 'intval' ); 412 412 } 413 413 414 // Community Invitations. 415 if ( bp_is_active( 'members', 'invitations' ) ) { 416 add_settings_field( 'bp-enable-members-invitations', __( 'Invitations', 'buddypress' ), 'bp_admin_setting_callback_members_invitations', 'buddypress', 'bp_members' ); 417 register_setting( 'buddypress', 'bp-enable-members-invitations', 'intval' ); 418 } 419 414 420 /* XProfile Section **************************************************/ 415 421 416 422 if ( bp_is_active( 'xprofile' ) ) { -
src/bp-core/classes/class-bp-email.php
diff --git src/bp-core/classes/class-bp-email.php src/bp-core/classes/class-bp-email.php index 78188fe4e..7c64102df 100644
class BP_Email { 999 999 $retval = new WP_Error( 'missing_parameter', __CLASS__, $this ); 1000 1000 } 1001 1001 1002 // Has the user opted out of receiving any email from this site? 1003 $recipient_address = array_shift( $this->get_to() )->get_address(); 1004 if ( bp_user_has_opted_out( $recipient_address ) ) { 1005 $retval = new WP_Error( 'user_has_opted_out', 'The email recipient has opted out from receiving communication from this site.', $this ); 1006 } 1007 1002 1008 /** 1003 1009 * Filters whether the email passes basic validation checks. 1004 1010 * -
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..a478c2c81 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 { 475 504 public function accept_invitation( $args = array() ) { 476 505 477 506 $r = bp_parse_args( $args, array( 507 'id' => false, 478 508 'user_id' => 0, 479 509 'invitee_email' => '', 480 510 'item_id' => null, … … abstract class BP_Invitation_Manager { 484 514 ), 'accept_invitation' ); 485 515 $r['class'] = $this->class_name; 486 516 487 if ( ! ( ( $r['user_id'] || $r['invitee_email'] ) && $r['class'] && $r['item_id'] ) ) {517 if ( ! $r['id'] && ! ( ( $r['user_id'] || $r['invitee_email'] ) && $r['class'] && $r['item_id'] ) ) { 488 518 return false; 489 519 } 490 520 … … abstract class BP_Invitation_Manager { 703 733 ) ); 704 734 } 705 735 736 /** 737 * Delete an invitation by id. 738 * 739 * @since 8.0.0 740 * 741 * @param int $id ID of the invitation to delete. 742 * @return int|bool Number of rows deleted on success, false on failure. 743 */ 744 public function delete_by_id( $id ) { 745 // Ensure that the invitation exists and was created by this class. 746 $invite = new BP_Invitation( $id ); 747 if ( ! $invite->id || sanitize_key( $this->class_name ) !== $invite->class ) { 748 return false; 749 } 750 751 return BP_Invitation::delete_by_id( $id ); 752 } 753 754 755 706 756 /** 707 757 * This is where custom actions are added (in child classes) 708 758 * to determine whether an invitation should be allowed. -
src/bp-core/classes/class-bp-invitation.php
diff --git src/bp-core/classes/class-bp-invitation.php src/bp-core/classes/class-bp-invitation.php index 2f5504df2..c1e941de2 100644
class BP_Invitation { 660 660 * Associative array of arguments. All arguments but $page and 661 661 * $per_page can be treated as filter values for get_where_sql() 662 662 * and get_query_clauses(). All items are optional. 663 * @type int|array $id ID of invitation being updated.663 * @type int|array $id ID of invitation being fetched. 664 664 * Can be an array of IDs. 665 665 * @type int|array $user_id ID of user being queried. Can be an 666 666 * Can be an array of IDs. -
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-activity.php
diff --git src/bp-members/bp-members-activity.php src/bp-members/bp-members-activity.php index 8907d0a7e..a110cd6e7 100644
add_action( 'bp_register_activity_actions', 'bp_members_register_activity_action 56 56 * @return string $action 57 57 */ 58 58 function bp_members_format_activity_action_new_member( $action, $activity ) { 59 $userlink = bp_core_get_userlink( $activity->user_id ); 59 $userlink = bp_core_get_userlink( $activity->user_id ); 60 $inviter_userlink = false; 61 $invite_id = bp_get_user_meta( $activity->user_id, 'accepted_members_invitation', true ); 60 62 61 /* translators: %s: user link */ 62 $action = sprintf( esc_html__( '%s became a registered member', 'buddypress' ), $userlink ); 63 if ( $invite_id ) { 64 $invite = new BP_Invitation( (int) $invite_id ); 65 66 if ( $invite->inviter_id ) { 67 $inviter_userlink = bp_core_get_userlink( $invite->inviter_id ); 68 } 69 } 70 71 if ( $inviter_userlink ) { 72 $action = sprintf( 73 /* translators: 1: new user link. 2: inviter user link. */ 74 esc_html__( '%1$s accepted an invitation from %2$s and became a registered member', 'buddypress' ), 75 $userlink, 76 $inviter_userlink 77 ); 78 } else { 79 /* translators: %s: user link */ 80 $action = sprintf( esc_html__( '%s became a registered member', 'buddypress' ), $userlink ); 81 } 63 82 64 83 // Legacy filter - pass $user_id instead of $activity. 65 84 if ( has_filter( 'bp_core_activity_registered_member_action' ) ) { … … function bp_members_format_activity_action_new_member( $action, $activity ) { 69 88 /** 70 89 * Filters the formatted 'new member' activity actions. 71 90 * 72 * @since 2.2.091 * @since 8.0.0 73 92 * 74 * @param string $action Static activity action. 75 * @param object $activity Activity object. 93 * @param string $action Static activity action. 94 * @param object $activity Activity object. 95 * @param int $invite_id The ID of the invite. 76 96 */ 77 return apply_filters( 'bp_members_format_activity_action_new_member', $action, $activity );97 return apply_filters( 'bp_members_format_activity_action_new_member', $action, $activity, $invite_id ); 78 98 } 79 99 80 100 /** -
src/bp-members/bp-members-adminbar.php
diff --git src/bp-members/bp-members-adminbar.php src/bp-members/bp-members-adminbar.php index 10f784d09..282be654c 100644
function bp_members_admin_bar_my_account_menu() { 23 23 global $wp_admin_bar; 24 24 25 25 // Bail if this is an ajax request. 26 if ( defined( 'DOING_AJAX' ) )26 if ( wp_doing_ajax() ) { 27 27 return; 28 } 28 29 29 30 // Logged in user. 30 31 if ( is_user_logged_in() ) { … … function bp_members_remove_edit_page_menu() { 178 179 } 179 180 } 180 181 add_action( 'add_admin_bar_menus', 'bp_members_remove_edit_page_menu' ); 182 183 /** 184 * Add the "Invitations" menu and submenus. 185 * 186 * @since 8.0.0 187 */ 188 function bp_members_admin_bar_add_invitations_menu() { 189 global $wp_admin_bar; 190 191 // Bail if this is an ajax request. 192 if ( wp_doing_ajax() ) { 193 return; 194 } 195 196 if ( is_user_logged_in() && bp_get_members_invitations_allowed() && ( bp_current_user_can( 'bp_members_send_invitation' ) || bp_members_invitations_user_has_sent_invites() ) ) { 197 $bp = buddypress(); 198 $invitations_link = trailingslashit( bp_loggedin_user_domain() . bp_get_members_invitations_slug() ); 199 200 $wp_admin_bar->add_node( 201 array( 202 'id' => $bp->my_account_menu_id . '-invitations', 203 'parent' => $bp->my_account_menu_id, 204 'title' => __( 'Invitations', 'buddypress' ), 205 'href' => $invitations_link, 206 'meta' => array( 207 'class' => 'ab-sub-secondary' 208 ) 209 ) 210 ); 211 212 if ( bp_current_user_can( 'bp_members_send_invitation' ) ) { 213 $wp_admin_bar->add_node( 214 array( 215 'id' => $bp->my_account_menu_id . '-invitations-send', 216 'parent' => $bp->my_account_menu_id . '-invitations', 217 'title' => __( 'Send Invites', 'buddypress' ), 218 'href' => $invitations_link, 219 'meta' => array( 220 'class' => 'ab-sub-secondary' 221 ) 222 ) 223 ); 224 } 225 226 $wp_admin_bar->add_node( 227 array( 228 'id' => $bp->my_account_menu_id . '-invitations-list', 229 'parent' => $bp->my_account_menu_id . '-invitations', 230 'title' => __( 'Pending Invites', 'buddypress' ), 231 'href' => $invitations_link . 'list-invites/', 232 'meta' => array( 233 'class' => 'ab-sub-secondary' 234 ) 235 ) 236 ); 237 } 238 } 239 add_action( 'bp_setup_admin_bar', 'bp_members_admin_bar_add_invitations_menu', 90 ); -
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..4c6eacead 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 = array() ) { 145 146 switch ( $capability ) { 147 case 'bp_members_manage_membership_requests': 148 $retval = bp_user_can( $user_id, 'bp_moderate' ); 149 break; 150 151 case 'bp_members_send_invitation': 152 if ( bp_get_members_invitations_allowed() ) { 153 $retval = true; 154 } 155 break; 156 157 case 'bp_members_receive_invitation': 158 if ( bp_get_members_invitations_allowed() ) { 159 $retval = true; 160 // The invited user must not already be a member of the network. 161 if ( empty( $args['invitee_email'] ) || false !== get_user_by( 'email', $args['invitee_email'] ) ) { 162 $retval = false; 163 } 164 // The invited user must not have opted out from being contacted from this site. 165 if ( bp_user_has_opted_out( $args['invitee_email'] ) ) { 166 $retval = false; 167 } 168 } 169 break; 170 } 171 172 return $retval; 173 } 174 add_filter( 'bp_user_can', 'bp_members_user_can_filter', 10, 5 ); 175 176 /** 177 * Do not allow the new user to change the email address 178 * if they are accepting a community invitation. 179 * 180 * @since 8.0.0 181 * 182 * @param array $attributes The field attributes. 183 * @param string $name The field name. 184 * 185 * @return array $attributes The field attributes. 186 */ 187 function bp_members_invitations_make_registration_email_input_readonly_if_invite( $attributes, $name ) { 188 if ( 'email' === $name && bp_get_members_invitations_allowed() ) { 189 $invite = bp_get_members_invitation_from_request(); 190 if ( $invite->id ) { 191 $attributes['readonly'] = 'readonly'; 192 } 193 } 194 return $attributes; 195 } 196 add_filter( 'bp_get_form_field_attributes', 'bp_members_invitations_make_registration_email_input_readonly_if_invite', 10, 2 ); 197 198 /** 199 * Provide a more-specific welcome message if the new user 200 * is accepting a network invitation. 201 * 202 * @since 8.0.0 203 * 204 * @return string $message The message text. 205 */ 206 function bp_members_invitations_get_registration_welcome_message() { 207 $message = ''; 208 if ( ! bp_get_members_invitations_allowed() ) { 209 return $message; 210 } 211 $invite = bp_get_members_invitation_from_request(); 212 if ( ! $invite->id || ! $invite->invitee_email ) { 213 return $message; 214 } 215 216 // Check if the user is already a site member. 217 $maybe_user = get_user_by( 'email', $invite->invitee_email ); 218 219 // This user is already a member 220 if ( $maybe_user ) { 221 $message = sprintf( __( 'Welcome! You are already a member of this site. Please <a href="%1s">log in</a> to continue. If you have forgotten your password, you can <a href="%2s">reset it</a>.', 'buddypress' ), wp_login_url( bp_get_root_domain() ), wp_lostpassword_url( bp_get_root_domain() ) ); 222 // This user can register! 223 } else { 224 225 // Fetch the display names of all inviters to personalize the welcome message. 226 $args = array( 227 'invitee_email' => $invite->invitee_email, 228 'invite_sent' => 'sent', 229 ); 230 $all_invites = bp_members_invitations_get_invites( $all_args ); 231 $inviters = array(); 232 foreach ( $all_invites as $inv ) { 233 $inviters[] = bp_core_get_user_displayname( $inv->inviter_id ); 234 } 235 236 if ( ! empty( $inviters ) ) { 237 $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 ) ); 238 } else { 239 $message = __( 'Welcome! You’ve been invited to join the site. ', 'buddypress' ); 240 } 241 } 242 243 return $message; 244 } 245 246 /** 247 * Provide a more-specific "registration is disabled" message 248 * if registration is available by invitation only. 249 * Also provide failure note if new user is trying to accept 250 * a network invitation but there's a problem. 251 * 252 * @since 8.0.0 253 * 254 * @return string $message The message text. 255 */ 256 function bp_members_invitations_get_modified_registration_disabled_message() { 257 $message = ''; 258 if ( bp_get_members_invitations_allowed() ) { 259 260 $invite = bp_get_members_invitation_from_request(); 261 if ( ! $invite->id || ! $invite->invitee_email ) { 262 return $message; 263 } 264 265 // Check if the user is already a site member. 266 $maybe_user = get_user_by( 'email', $invite->invitee_email ); 267 268 if ( ! $maybe_user ) { 269 $message = __( 'Member registration is allowed by invitation only.', 'buddypress' ); 270 // Is the user trying to accept an invitation but something is wrong? 271 if ( ! empty( $_GET['inv'] ) ) { 272 $message .= __( ' It looks like there is a problem with your invitation. Please try again.', 'buddypress' ); 273 } 274 } else if ( 'nouveau' === bp_get_theme_package_id() ) { 275 $message = sprintf( __( 'Welcome! You are already a member of this site. Please <a href="%1s">log in</a> to continue. If you have forgotten your password, you can <a href="%2s">reset it</a>.', 'buddypress' ), wp_login_url( bp_get_root_domain() ), wp_lostpassword_url( bp_get_root_domain() ) ); 276 } 277 } 278 return $message; 279 } 280 281 /** 282 * Sanitize the invitation property output. 283 * 284 * @since 8.0.0 285 * 286 * @param int|string $value The value for the requested property. 287 * @param string $property The name of the requested property. 288 * @param string $context The context of display. 289 * @return int|string The sanitized value. 290 */ 291 function bp_members_sanitize_invitation_property( $value = '', $property = '', $context = 'html' ) { 292 if ( ! $property ) { 293 return ''; 294 } 295 296 switch ( $property ) { 297 case 'id': 298 case 'user_id': 299 case 'item_id': 300 case 'secondary_item_id': 301 $value = absint( $value ); 302 break; 303 case 'invite_sent': 304 case 'accepted': 305 $value = absint( $value ) ? __( 'Yes', 'buddypress' ) : __( 'No', 'buddypress' ); 306 $value = 'attribute' === $context ? esc_attr( $value ) : esc_html( $value ); 307 break; 308 case 'invitee_email': 309 $value = sanitize_email( $value ); 310 break; 311 case 'content': 312 $value = wp_kses( $value, array() ); 313 $value = wptexturize( $value ); 314 break; 315 case 'date_modified': 316 $value = mysql2date( 'Y/m/d g:i:s a', $value ); 317 $value = 'attribute' === $context ? esc_attr( $value ) : esc_html( $value ); 318 break; 319 320 default: 321 $value = 'attribute' === $context ? esc_attr( $value ) : esc_html( $value ); 322 break; 323 } 324 325 return $value; 326 } 327 add_filter( 'bp_the_members_invitation_property', 'bp_members_sanitize_invitation_property', 10, 3 ); -
src/bp-members/bp-members-functions.php
diff --git src/bp-members/bp-members-functions.php src/bp-members/bp-members-functions.php index 347614fc8..b6fdc0122 100644
function bp_send_welcome_email( $user_id = 0 ) { 3342 3342 bp_send_email( 'core-user-activation', $user_id, array( 'tokens' => $welcome_tokens ) ); 3343 3343 } 3344 3344 add_action( 'bp_core_activated_user', 'bp_send_welcome_email', 10, 1 ); 3345 3346 /** 3347 * Get invitations to the BP community filtered by arguments. 3348 * 3349 * @since 8.0.0 3350 * 3351 * @param array $args Invitation arguments. 3352 * See BP_Invitation::get() for list. 3353 * 3354 * @return array $invites Matching BP_Invitation objects. 3355 */ 3356 function bp_members_invitations_get_invites( $args = array() ) { 3357 $invites_class = new BP_Members_Invitation_Manager(); 3358 return $invites_class->get_invitations( $args ); 3359 } 3360 3361 /** 3362 * Check whether a user has sent any community invitations. 3363 * 3364 * @since 8.0.0 3365 * 3366 * @param int $user_id ID of user to check for invitations sent by. 3367 * Defaults to the current user's ID. 3368 * 3369 * @return bool $invites True if user has sent invites. 3370 */ 3371 function bp_members_invitations_user_has_sent_invites( $user_id = 0 ) { 3372 if ( 0 === $user_id ) { 3373 $user_id = bp_loggedin_user_id(); 3374 if ( ! $user_id ) { 3375 return false; 3376 } 3377 } 3378 $invites_class = new BP_Members_Invitation_Manager(); 3379 $args = array( 3380 'inviter_id' => $user_id, 3381 ); 3382 return (bool) $invites_class->invitation_exists( $args ); 3383 } 3384 3385 /** 3386 * Invite a user to a BP community. 3387 * 3388 * @since 8.0.0 3389 * 3390 * @param array|string $args { 3391 * Array of arguments. 3392 * @type int $invitee_email Email address of the user being invited. 3393 * @type int $network_id ID of the network to which the user is being invited. 3394 * @type int $inviter_id Optional. ID of the inviting user. Default: 3395 * ID of the logged-in user. 3396 * @type string $date_modified Optional. Modified date for the invitation. 3397 * Default: current date/time. 3398 * @type string $content Optional. Message to invitee. 3399 * @type bool $send_invite Optional. Whether the invitation should be 3400 * sent now. Default: false. 3401 * } 3402 * @return bool True on success, false on failure. 3403 */ 3404 function bp_members_invitations_invite_user( $args ) { 3405 $r = bp_parse_args( $args, array( 3406 'invitee_email' => '', 3407 'network_id' => get_current_network_id(), 3408 'inviter_id' => bp_loggedin_user_id(), 3409 'date_modified' => bp_core_current_time(), 3410 'content' => '', 3411 'send_invite' => 0 3412 ), 'community_invite_user' ); 3413 3414 $inv_args = array( 3415 'invitee_email' => $r['invitee_email'], 3416 'item_id' => $r['network_id'], 3417 'inviter_id' => $r['inviter_id'], 3418 'date_modified' => $r['date_modified'], 3419 'content' => $r['content'], 3420 'send_invite' => $r['send_invite'] 3421 ); 3422 3423 // Create the invitataion. 3424 $invites_class = new BP_Members_Invitation_Manager(); 3425 $created = $invites_class->add_invitation( $inv_args ); 3426 3427 /** 3428 * Fires after the creation of a new network invite. 3429 * 3430 * @since 8.0.0 3431 * 3432 * @param array $r Array of parsed arguments for the network invite. 3433 * @param int|bool $created The ID of the invitation or false if it couldn't be created. 3434 */ 3435 do_action( 'bp_members_invitations_invite_user', $r, $created ); 3436 3437 return $created; 3438 } 3439 3440 /** 3441 * Resend a membership invitation email by id. 3442 * 3443 * @since 8.0.0 3444 * 3445 * @param int $id ID of the invitation to resend. 3446 * @return bool True on success, false on failure. 3447 */ 3448 function bp_members_invitation_resend_by_id( $id = 0 ) { 3449 3450 // Find the invitation before deleting it. 3451 $existing_invite = new BP_Invitation( $id ); 3452 $invites_class = new BP_Members_Invitation_Manager(); 3453 $success = $invites_class->send_invitation_by_id( $id ); 3454 3455 if ( ! $success ) { 3456 return $success; 3457 } 3458 3459 /** 3460 * Fires after the re-sending of a network invite. 3461 * 3462 * @since 8.0.0 3463 * 3464 * @param BP_Invitation $existing_invite The invitation that was resent. 3465 */ 3466 do_action( 'bp_members_invitations_resend_invitation', $existing_invite ); 3467 3468 return $success; 3469 } 3470 3471 /** 3472 * Delete a membership invitation by id. 3473 * 3474 * @since 8.0.0 3475 * 3476 * @param int $id ID of the invitation to delete. 3477 * @return int|bool Number of rows deleted on success, false on failure. 3478 */ 3479 function bp_members_invitations_delete_by_id( $id = 0 ) { 3480 3481 // Find the invitation before deleting it. 3482 $existing_invite = new BP_Invitation( $id ); 3483 $invites_class = new BP_Members_Invitation_Manager(); 3484 $success = $invites_class->delete_by_id( $id ); 3485 3486 if ( ! $success ) { 3487 return $success; 3488 } 3489 3490 // Run a different action depending on the status of the invite. 3491 if ( ! $existing_invite->invite_sent ) { 3492 /** 3493 * Fires after the deletion of an unsent community invite. 3494 * 3495 * @since 8.0.0 3496 * 3497 * @param BP_Invitation $existing_invite The invitation to be deleted. 3498 */ 3499 do_action( 'bp_members_invitations_canceled_invitation', $existing_invite ); 3500 } else if ( ! $existing_invite->accepted ) { 3501 /** 3502 * Fires after the deletion of a sent, but not yet accepted, community invite. 3503 * 3504 * @since 8.0.0 3505 * 3506 * @param BP_Invitation $existing_invite The invitation to be deleted. 3507 */ 3508 do_action( 'bp_members_invitations_revoked_invitation', $existing_invite ); 3509 } else { 3510 /** 3511 * Fires after the deletion of a sent and accepted community invite. 3512 * 3513 * @since 8.0.0 3514 * 3515 * @param BP_Invitation $existing_invite The invitation to be deleted. 3516 */ 3517 do_action( 'bp_members_invitations_deleted_invitation', $existing_invite ); 3518 } 3519 3520 return $success; 3521 } 3522 3523 /** 3524 * Delete a membership invitation. 3525 * 3526 * @since 8.0.0 3527 * 3528 * @param intring $args { 3529 * Array of arguments. 3530 * @type int|array $id Id(s) of the invitation(s) to remove. 3531 * @type int $invitee_email Email address of the user being invited. 3532 * @type int $network_id ID of the network to which the user is being invited. 3533 * @type int $inviter_id ID of the inviting user. 3534 * @type int $accepted Whether the invitation has been accepted yet. 3535 * @type int $invite_sent Whether the invitation has been sent yet. 3536 * } 3537 * @return bool True if all were deleted. 3538 */ 3539 function bp_members_invitations_delete_invites( $args ) { 3540 $r = bp_parse_args( $args, array( 3541 'id' => false, 3542 'invitee_email' => '', 3543 'network_id' => get_current_network_id(), 3544 'inviter_id' => null, 3545 'accepted' => null, 3546 'invite_sent' => null 3547 ), 'members_invitations_delete_invites' ); 3548 3549 $inv_args = array( 3550 'id' => $r['id'], 3551 'invitee_email' => $r['invitee_email'], 3552 'item_id' => $r['network_id'], 3553 'inviter_id' => $r['inviter_id'], 3554 'accepted' => $r['accepted'], 3555 'invite_sent' => $r['invite_sent'] 3556 ); 3557 3558 // Find the invitation(s). 3559 $invites = bp_members_invitations_get_invites( $inv_args ); 3560 $total_count = count( $invites ); 3561 3562 // Loop through, deleting each invitation. 3563 $deleted = 0; 3564 foreach ( $invites as $invite ) { 3565 $success = bp_members_invitations_delete_by_id( $invite->id ); 3566 if ( $success ) { 3567 $deleted++; 3568 } 3569 } 3570 3571 return $deleted === $total_count; 3572 } 3573 3574 /** 3575 * Get hash based on details of a membership invitation and the inviter. 3576 * 3577 * @since 8.0.0 3578 * 3579 * @param BP_Invitation object $invitation Invitation to create hash from. 3580 * 3581 * @return string $hash Calculated sha1 hash. 3582 */ 3583 function bp_members_invitations_get_hash( BP_Invitation $invitation ) { 3584 $hash = false; 3585 3586 if ( ! empty( $invitation->id ) ) { 3587 $inviter_ud = get_userdata( $invitation->inviter_id ); 3588 if ( $inviter_ud ) { 3589 /* 3590 * Use some inviter details as part of the hash so that invitations from 3591 * users who are subsequently marked as spam will be invalidated. 3592 */ 3593 $hash = wp_hash( "{$invitation->inviter_id}:{$invitation->invitee_email}:{$inviter_ud->user_status}:{$inviter_ud->user_registered}" ); 3594 } 3595 } 3596 3597 // If there's a problem, return a string that will change and thus fail. 3598 if ( ! $hash ) { 3599 $hash = wp_generate_password( 32, false ); 3600 } 3601 3602 /** 3603 * Filters the hash calculated by the invitation details. 3604 * 3605 * @since 8.0.0 3606 * 3607 * @param string $hash Calculated sha1 hash. 3608 * @param BP_Invitation object $invitation Invitation hash was created from. 3609 */ 3610 return apply_filters( 'bp_members_invitations_get_hash', $hash, $invitation ); 3611 } 3612 3613 /** 3614 * Get the current invitation specified by the $_GET parameters. 3615 * 3616 * @since 8.0.0 3617 * 3618 * @return BP_Invitation $invite Invitation specified by the $_GET parameters. 3619 */ 3620 function bp_get_members_invitation_from_request() { 3621 $invites_class = new BP_Members_Invitation_Manager(); 3622 $invite = $invites_class->get_by_id( 0 ); 3623 3624 if ( bp_get_members_invitations_allowed() && ! empty( $_GET['inv'] ) ) { 3625 // Check to make sure the passed hash matches a calculated hash. 3626 $maybe_invite = $invites_class->get_by_id( absint( $_GET['inv'] ) ); 3627 $hash = bp_members_invitations_get_hash( $maybe_invite ); 3628 if ( $_GET['ih'] === $hash ) { 3629 $invite = $maybe_invite; 3630 } 3631 } 3632 3633 /** 3634 * Filters the invitation specified by the $_GET parameters. 3635 * 3636 * @since 8.0.0 3637 * 3638 * @param BP_Invitation $invite Invitation specified by the $_GET parameters. 3639 */ 3640 return apply_filters( 'bp_get_members_invitation_from_request', $invite ); 3641 } -
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..2a04c3dbd
- + 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(); 19 $user_can_send = bp_user_can( bp_displayed_user_id(), 'bp_members_send_invitation' ); 20 $user_has_invites = bp_members_invitations_user_has_sent_invites( bp_displayed_user_id() ); 21 22 /* Add 'Invitations' to the main user profile navigation */ 23 bp_core_new_nav_item( 24 array( 25 'name' => __( 'Invitations', 'buddypress' ), 26 'slug' => bp_get_members_invitations_slug(), 27 'position' => 80, 28 'screen_function' => 'members_screen_send_invites', 29 'default_subnav_slug' => ( $user_can_send && bp_is_my_profile() ) ? 'send-invites' : 'list-invites', 30 'show_for_displayed_user' => $user_has_access && ( $user_can_send || $user_has_invites ) 31 ) 32 ); 33 34 $parent_link = trailingslashit( bp_displayed_user_domain() . bp_get_members_invitations_slug() ); 35 36 /* Create two subnav items for community invitations */ 37 bp_core_new_subnav_item( 38 array( 39 'name' => __( 'Send Invites', 'buddypress' ), 40 'slug' => 'send-invites', 41 'parent_slug' => bp_get_members_invitations_slug(), 42 'parent_url' => $parent_link, 43 'screen_function' => 'members_screen_send_invites', 44 'position' => 10, 45 'user_has_access' => $user_has_access && $user_can_send && bp_is_my_profile() 46 ) 47 ); 48 49 bp_core_new_subnav_item( 50 array( 51 'name' => __( 'Pending Invites', 'buddypress' ), 52 'slug' => 'list-invites', 53 'parent_slug' => bp_get_members_invitations_slug(), 54 'parent_url' => $parent_link, 55 'screen_function' => 'members_screen_list_sent_invites', 56 'position' => 20, 57 'user_has_access' => $user_has_access && ( $user_can_send || $user_has_invites ) 58 ) 59 ); 60 } 61 add_action( 'bp_setup_nav', 'bp_members_invitations_setup_nav' ); 62 63 /** 64 * When a user joins the network via an invitation, skip sending the activation email. 65 * 66 * @param bool $send Whether or not to send the activation key. 67 * @param int $user_id User ID to send activation key to. 68 * @param string $user_email User email to send activation key to. 69 * @param string $activation_key Activation key to be sent. 70 * @param array $usermeta Miscellaneous metadata about the user (blog-specific 71 * signup data, xprofile data, etc). 72 */ 73 function bp_members_invitations_cancel_activation_email( $send, $user_id, $user_email, $activation_key, $usermeta ) { 74 $invite = bp_members_invitations_get_invites( 75 array( 76 'invitee_email' => $user_email, 77 'invite_sent' => 'sent' 78 ) 79 ); 80 81 if ( $invite ) { 82 $send = false; 83 } 84 85 return $send; 86 } 87 add_filter( 'bp_core_signup_send_activation_key', 'bp_members_invitations_cancel_activation_email', 10, 5 ); 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 // Check to see if this signup is the result of a valid invitation. 105 $invite = bp_get_members_invitation_from_request(); 106 if ( ! $invite->id ) { 107 return; 108 } 109 110 // Accept the invitation. 111 $invites_class = new BP_Members_Invitation_Manager(); 112 $args = array( 113 'id' => $invite->id, 114 ); 115 $invites_class->accept_invitation( $args ); 116 117 // User has already verified their email by responding to the invitation, so we can activate. 118 $key = bp_get_user_meta( $user_id, 'activation_key', true ); 119 if ( $key ) { 120 /** 121 * Filters the activation signup. 122 * 123 * @since 1.1.0 124 * 125 * @param bool|int $value Value returned by activation. 126 * Integer on success, boolean on failure. 127 */ 128 $user = apply_filters( 'bp_core_activate_account', bp_core_activate_signup( $key ) ); 129 130 // If there were errors, add a message and redirect. 131 if ( ! empty( $user->errors ) ) { 132 bp_core_add_message( $user->get_error_message(), 'error' ); 133 bp_core_redirect( trailingslashit( bp_get_root_domain() . '/' . $bp->pages->activate->slug ) ); 134 } 135 136 bp_core_add_message( __( 'Your account is now active!', 'buddypress' ) ); 137 bp_core_redirect( add_query_arg( 'activated', '1', bp_get_activation_page() ) ); 138 } 139 } 140 add_action( 'bp_core_signup_user', 'bp_members_invitations_complete_signup', 10, 4 ); 141 142 /** 143 * Delete site membership invitations when an opt-out request is saved. 144 * 145 * @since 8.0.0 146 * 147 * @param BP_Optout $optout Characteristics of the opt-out just saved. 148 */ 149 function bp_members_invitations_delete_optedout_invites( $optout ) { 150 151 $args = array( 152 'invitee_email' => $optout->email_address, 153 ); 154 bp_members_invitations_delete_invites( $args ); 155 } 156 add_action( 'bp_optout_after_save', 'bp_members_invitations_delete_optedout_invites' ); -
new file src/bp-members/bp-members-notifications.php
diff --git src/bp-members/bp-members-notifications.php src/bp-members/bp-members-notifications.php new file mode 100644 index 000000000..6571eb1e5
- + 1 <?php 2 /** 3 * BuddyPress Members Activity Functions. 4 * 5 * These functions handle the recording, deleting and formatting of activity 6 * for the user and for this specific component. 7 * 8 * @package BuddyPress 9 * @subpackage MembersNotifications 10 * @since 8.0.0 11 */ 12 13 // Exit if accessed directly. 14 defined( 'ABSPATH' ) || exit; 15 16 /** 17 * Notification formatting callback for bp-members notifications. 18 * 19 * @since 8.0.0 20 * 21 * @param string $action The kind of notification being rendered. 22 * @param int $item_id The primary item ID. 23 * @param int $secondary_item_id The secondary item ID. 24 * @param int $total_items The total number of members-related notifications 25 * waiting for the user. 26 * @param string $format 'string' for BuddyBar-compatible notifications; 27 * 'array' for WP Toolbar. Default: 'string'. 28 * @return array|string 29 */ 30 function members_format_notifications( $action, $item_id, $secondary_item_id, $total_items, $format = 'string' ) { 31 32 switch ( $action ) { 33 case 'accepted_invitation': 34 35 // Set up the string and the filter. 36 if ( (int) $total_items > 1 ) { 37 $link = bp_get_notifications_permalink(); 38 $amount = 'multiple'; 39 40 // This is the inviter whose invitation was accepted. 41 if ( 0 !== (int) $secondary_item_id ) { 42 /* translators: %d: the number of new users */ 43 $text = sprintf( __( '%d members accepted your membership invitations', 'buddypress' ), (int) $total_items ); 44 // This is someone who also invited that user to join. 45 } else { 46 /* translators: %d: the number of new users */ 47 $text = sprintf( __( '%d members are now members of the site', 'buddypress' ), (int) $total_items ); 48 } 49 } else { 50 $link = add_query_arg( 'welcome', 1, bp_core_get_user_domain( $item_id ) ); 51 $amount = 'single'; 52 53 // This is the inviter whose invitation was accepted. 54 if ( 0 !== (int) $secondary_item_id ) { 55 /* translators: %s: new user name */ 56 $text = sprintf( __( '%s accepted your membership invitation', 'buddypress' ), bp_core_get_user_displayname( $item_id ) ); // This is someone who also invited that user to join. 57 } else { 58 /* translators: %s: new user name */ 59 $text = sprintf( __( '%s is now a member of the site', 'buddypress' ), bp_core_get_user_displayname( $item_id ) ); 60 } 61 } 62 break; 63 } 64 65 // Return either an HTML link or an array, depending on the requested format. 66 if ( 'string' == $format ) { 67 68 /** 69 * Filters the format of members notifications based on type and amount * of notifications pending. 70 * 71 * This is a variable filter that has four possible versions. 72 * The possible versions are: 73 * - bp_members_single_accepted_invitation_notification 74 * - bp_members_multiple_accepted_invitation_notification 75 * 76 * @since 8.0.0 77 * 78 * @param string|array $value Depending on format, an HTML link to new requests profile tab or array with link and text. 79 * @param int $total_items The total number of messaging-related notifications waiting for the user. 80 * @param int $item_id The primary item ID. 81 * @param int $secondary_item_id The secondary item ID. 82 */ 83 $return = apply_filters( 'bp_members_' . $amount . '_'. $action . '_notification', '<a href="' . esc_url( $link ) . '">' . esc_html( $text ) . '</a>', (int) $total_items, $item_id, $secondary_item_id ); 84 } else { 85 /** This filter is documented in bp-members/bp-members-notifications.php */ 86 $return = apply_filters( 'bp_members_' . $amount . '_'. $action . '_notification', array( 87 'link' => $link, 88 'text' => $text 89 ), (int) $total_items, $item_id, $secondary_item_id ); 90 } 91 92 /** 93 * Fires at the end of the bp-members notification format callback. 94 * 95 * @since 8.0.0 96 * 97 * @param string $action The kind of notification being rendered. 98 * @param int $item_id The primary item ID. 99 * @param int $secondary_item_id The secondary item ID. 100 * @param int $total_items The total number of members-related notifications 101 * waiting for the user. 102 * @param array|string $return Notification text string or array of link and text. 103 */ 104 do_action( 'members_format_notifications', $action, $item_id, $secondary_item_id, $total_items, $return ); 105 106 return $return; 107 } 108 109 /** 110 * Notify one use that another user has accepted their site membership invitation. 111 * 112 * @since 8.0.0 113 * 114 * @param BP_Invitation $invite Invitation that was accepted. 115 * @param WP_user $new_user User who accepted the membership invite. 116 * @param int $inviter_id ID of the user who invited this user to the site. 117 */ 118 function bp_members_invitations_accepted_invitation_notification( $invite, $new_user, $inviter_id ) { 119 120 // Add "user is a member of the site" notification for other inviters. 121 $args = array( 122 'invitee_email' => $new_user->user_email, 123 'accepted' => 'all', 124 ); 125 $invites = bp_members_invitations_get_invites( $args ); 126 127 if ( ! $invites ) { 128 return; 129 } 130 foreach ( $invites as $invite) { 131 // Include the id of the "accepted" invitation. 132 if ( $invite->inviter_id === $inviter_id ) { 133 $secondary_item_id = $invite->id; 134 } else { 135 // Else don't store the invite id, so we know this is not the primary. 136 $secondary_item_id = 0; 137 } 138 $res = bp_notifications_add_notification( array( 139 'user_id' => $invite->inviter_id, 140 'item_id' => $new_user->ID, 141 'secondary_item_id' => $secondary_item_id, 142 'component_name' => buddypress()->members->id, 143 'component_action' => 'accepted_invitation', 144 'date_notified' => bp_core_current_time(), 145 'is_new' => 1, 146 ) ); 147 } 148 } 149 add_action( 'community_membership_invite_accepted', 'bp_members_invitations_accepted_invitation_notification', 10, 3 ); 150 151 /** 152 * Mark accepted invitation notifications as read when user visits new user profile. 153 * 154 * 155 * @since 8.0.0 156 */ 157 function bp_members_mark_read_accepted_invitation_notification() { 158 if ( false === is_singular() || false === is_user_logged_in() || ! bp_is_user() || empty( $_GET['welcome'] ) ) { 159 return; 160 } 161 162 // Mark notification as read. 163 BP_Notifications_Notification::update( 164 array( 165 'is_new' => false 166 ), 167 array( 168 'user_id' => bp_loggedin_user_id(), 169 'item_id' => bp_displayed_user_id(), 170 ) 171 ); 172 } 173 add_action( 'bp_screens', 'bp_members_mark_read_accepted_invitation_notification' ); 174 175 /** 176 * Add Friends-related settings to the Settings > Notifications page. 177 * 178 * @since 8.0.0 179 */ 180 function members_screen_notification_settings() { 181 182 // Bail early if invitations are not allowed--they are the only members notification so far. 183 if ( ! bp_get_members_invitations_allowed () ) { 184 return; 185 } 186 187 if ( ! $allow_acceptance_emails = bp_get_user_meta( bp_displayed_user_id(), 'notification_members_invitation_accepted', true ) ) { 188 $allow_acceptance_emails = 'yes'; 189 } 190 ?> 191 192 <table class="notification-settings" id="members-notification-settings"> 193 <thead> 194 <tr> 195 <th class="icon"></th> 196 <th class="title"><?php _ex( 'Members', 'Member settings on notification settings page', 'buddypress' ) ?></th> 197 <th class="yes"><?php _e( 'Yes', 'buddypress' ) ?></th> 198 <th class="no"><?php _e( 'No', 'buddypress' )?></th> 199 </tr> 200 </thead> 201 202 <tbody> 203 <tr id="members-notification-settings-invitation_accepted"> 204 <td></td> 205 <td><?php _ex( 'Someone accepts your membership invitation', 'Member settings on notification settings page', 'buddypress' ) ?></td> 206 <td class="yes"><input type="radio" name="notifications[notification_members_invitation_accepted]" id="notification-members-invitation-accepted-yes" value="yes" <?php checked( $allow_acceptance_emails, 'yes', true ) ?>/><label for="notification-members-invitation-accepted-yes" class="bp-screen-reader-text"><?php 207 /* translators: accessibility text */ 208 _e( 'Yes, send email', 'buddypress' ); 209 ?></label></td> 210 <td class="no"><input type="radio" name="notifications[notification_members_invitation_accepted]" id="notification-members-invitation-accepted-no" value="no" <?php checked( $allow_acceptance_emails, 'no', true ) ?>/><label for="notification-members-invitation-accepted-no" class="bp-screen-reader-text"><?php 211 /* translators: accessibility text */ 212 _e( 'No, do not send email', 'buddypress' ); 213 ?></label></td> 214 </tr> 215 216 <?php 217 218 /** 219 * Fires after the last table row on the members notification screen. 220 * 221 * @since 1.0.0 222 */ 223 do_action( 'members_screen_notification_settings' ); ?> 224 225 </tbody> 226 </table> 227 228 <?php 229 } 230 add_action( 'bp_notification_settings', 'members_screen_notification_settings' ); -
src/bp-members/bp-members-template.php
diff --git src/bp-members/bp-members-template.php src/bp-members/bp-members-template.php index 541b27479..b7f9c9afb 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() { 2869 2921 */ 2870 2922 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' ) ); 2871 2923 } 2924 2925 2926 /** The Members Invitations Loop ******************************************************************/ 2927 2928 /** 2929 * Initialize the community invitations loop. 2930 * 2931 * Based on the $args passed, bp_has_invitations() populates 2932 * buddypress()->invitations->query_loop global, enabling the use of BP 2933 * templates and template functions to display a list of invitations. 2934 * 2935 * @since 8.0.0 2936 * 2937 * @param array|string $args { 2938 * Arguments for limiting the contents of the invitations loop. Can be 2939 * passed as an associative array, or as a URL query string. 2940 * 2941 * See {@link BP_Invitations_Invitation::get()} for detailed 2942 * information on the arguments. In addition, also supports: 2943 * 2944 * @type int $max Optional. Max items to display. Default: false. 2945 * @type string $page_arg URL argument to use for pagination. 2946 * Default: 'ipage'. 2947 * } 2948 * @return bool 2949 */ 2950 function bp_has_members_invitations( $args = '' ) { 2951 2952 // Get the user ID. 2953 if ( bp_displayed_user_id() ) { 2954 $user_id = bp_displayed_user_id(); 2955 } else { 2956 $user_id = bp_loggedin_user_id(); 2957 } 2958 2959 // Set the search terms (by default an empty string to get all notifications) 2960 $search_terms = ''; 2961 2962 if ( isset( $_REQUEST['s'] ) ) { 2963 $search_terms = stripslashes( $_REQUEST['s'] ); 2964 } 2965 2966 // Parse the args. 2967 $r = bp_parse_args( $args, array( 2968 'id' => false, 2969 'inviter_id' => $user_id, 2970 'invitee_email' => false, 2971 'item_id' => false, 2972 'type' => 'invite', 2973 'invite_sent' => 'all', 2974 'accepted' => 'pending', 2975 'search_terms' => $search_terms, 2976 'order_by' => 'date_modified', 2977 'sort_order' => 'DESC', 2978 'page' => 1, 2979 'per_page' => 25, 2980 'fields' => 'all', 2981 2982 // These are additional arguments that are not available in 2983 // BP_Invitations_Invitation::get(). 2984 'page_arg' => 'ipage', 2985 ), 'has_community_invitations' ); 2986 2987 // Get the notifications. 2988 $query_loop = new BP_Members_Invitations_Template( $r ); 2989 2990 // Setup the global query loop. 2991 buddypress()->members->invitations->query_loop = $query_loop; 2992 2993 /** 2994 * Filters whether or not the user has network invitations to display. 2995 * 2996 * @since 8.0.0 2997 * 2998 * @param bool $value Whether or not there are network invitations to display. 2999 * @param BP_Notifications_Template $query_loop BP_Members_Invitations_Template object instance. 3000 * @param array $r Array of arguments passed into the BP_Members_Invitations_Template class. 3001 */ 3002 return apply_filters( 'bp_has_members_invitations', $query_loop->has_invitations(), $query_loop, $r ); 3003 } 3004 3005 /** 3006 * Get the network invitations returned by the template loop. 3007 * 3008 * @since 8.0.0 3009 * 3010 * @return array List of network invitations. 3011 */ 3012 function bp_the_members_invitations() { 3013 return buddypress()->members->invitations->query_loop->invitations(); 3014 } 3015 3016 /** 3017 * Get the current network invitation object in the loop. 3018 * 3019 * @since 8.0.0 3020 * 3021 * @return object The current network invitation within the loop. 3022 */ 3023 function bp_the_members_invitation() { 3024 return buddypress()->members->invitations->query_loop->the_invitation(); 3025 } 3026 3027 /** 3028 * Output the pagination count for the current network invitations loop. 3029 * 3030 * @since 8.0.0 3031 */ 3032 function bp_members_invitations_pagination_count() { 3033 echo bp_get_members_invitations_pagination_count(); 3034 } 3035 /** 3036 * Return the pagination count for the current network invitation loop. 3037 * 3038 * @since 8.0.0 3039 * 3040 * @return string HTML for the pagination count. 3041 */ 3042 function bp_get_members_invitations_pagination_count() { 3043 $query_loop = buddypress()->members->invitations->query_loop; 3044 $start_num = intval( ( $query_loop->pag_page - 1 ) * $query_loop->pag_num ) + 1; 3045 $from_num = bp_core_number_format( $start_num ); 3046 $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 ) ); 3047 $total = bp_core_number_format( $query_loop->total_invitation_count ); 3048 3049 if ( 1 == $query_loop->total_invitation_count ) { 3050 $pag = __( 'Viewing 1 invitation', 'buddypress' ); 3051 } else { 3052 /* translators: 1: notification from number. 2: notification to number. 3: total notifications. */ 3053 $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 ); 3054 } 3055 3056 /** 3057 * Filters the pagination count for the current network invitation loop. 3058 * 3059 * @since 8.0.0 3060 * 3061 * @param string $pag HTML for the pagination count. 3062 */ 3063 return apply_filters( 'bp_get_members_invitations_pagination_count', $pag ); 3064 } 3065 3066 /** 3067 * Output the pagination links for the current network invitation loop. 3068 * 3069 * @since 8.0.0 3070 */ 3071 function bp_members_invitations_pagination_links() { 3072 echo bp_get_members_invitations_pagination_links(); 3073 } 3074 /** 3075 * Return the pagination links for the current network invitations loop. 3076 * 3077 * @since 8.0.0 3078 * 3079 * @return string HTML for the pagination links. 3080 */ 3081 function bp_get_members_invitations_pagination_links() { 3082 3083 /** 3084 * Filters the pagination links for the current network invitations loop. 3085 * 3086 * @since 8.0.0 3087 * 3088 * @param string $pag_links HTML for the pagination links. 3089 */ 3090 return apply_filters( 'bp_get_members_invitations_pagination_links', buddypress()->members->invitations->query_loop->pag_links ); 3091 } 3092 3093 /** 3094 * Output the requested property of the invitation currently being iterated on. 3095 * 3096 * @since 8.0.0 3097 * 3098 * @param string $property The name of the property to display. 3099 * @param string $context The context of display. 3100 * Possible values are 'attribute' and 'html'. 3101 */ 3102 function bp_the_members_invitation_property( $property = '', $context = 'html' ) { 3103 if ( ! $property ) { 3104 return; 3105 } 3106 3107 /** 3108 * Use this filter to sanitize the output. 3109 * 3110 * @since 8.0.0 3111 * 3112 * @param int|string $value The value for the requested property. 3113 * @param string $property The name of the requested property. 3114 * @param string $context The context of display. 3115 */ 3116 echo apply_filters( 'bp_the_members_invitation_property', bp_get_the_members_invitation_property( $property ), $property, $context ); 3117 } 3118 /** 3119 * Return the value for a property of the network invitation currently being iterated on. 3120 * 3121 * @since 8.0.0 3122 * 3123 * @return int ID of the current network invitation. 3124 */ 3125 function bp_get_the_members_invitation_property( $property = 'id' ) { 3126 3127 switch ( $property ) { 3128 case 'id': 3129 case 'user_id': 3130 case 'item_id': 3131 case 'secondary_item_id': 3132 case 'invite_sent': 3133 case 'accepted': 3134 $value = 0; 3135 break; 3136 case 'invitee_email': 3137 case 'type': 3138 case 'content': 3139 case 'date_modified': 3140 $value = ''; 3141 break; 3142 default: 3143 // A known property has not been specified. 3144 $property = null; 3145 $value = ''; 3146 break; 3147 } 3148 3149 if ( isset( buddypress()->members->invitations->query_loop->invitation->{$property} ) ) { 3150 $value = buddypress()->members->invitations->query_loop->invitation->{$property}; 3151 } 3152 3153 /** 3154 * Filters the property of the network invitation currently being iterated on. 3155 * 3156 * @since 8.0.0 3157 * 3158 * @param int|string $value Property value of the network invitation being iterated on. 3159 */ 3160 return apply_filters( 'bp_get_the_members_invitation_property_' . $property, $value ); 3161 } 3162 3163 /** 3164 * Output the action links for the current invitation. 3165 * 3166 * @since 8.0.0 3167 * 3168 * @param array|string $args Array of arguments. 3169 */ 3170 function bp_the_members_invitation_action_links( $args = '' ) { 3171 echo bp_get_the_members_invitation_action_links( $args ); 3172 } 3173 /** 3174 * Return the action links for the current invitation. 3175 * 3176 * @since 8.0.0 3177 * 3178 * @param array|string $args { 3179 * @type string $before HTML before the links. 3180 * @type string $after HTML after the links. 3181 * @type string $sep HTML between the links. 3182 * @type array $links Array of links to implode by 'sep'. 3183 * @type int $user_id User ID to fetch action links for. Defaults to displayed user ID. 3184 * } 3185 * @return string HTML links for actions to take on single notifications. 3186 */ 3187 function bp_get_the_members_invitation_action_links( $args = '' ) { 3188 // Set default user ID to use. 3189 $inviter_id = isset( $args['inviter_id'] ) ? $args['inviter_id'] : bp_displayed_user_id(); 3190 3191 // Parse. 3192 $r = wp_parse_args( $args, array( 3193 'before' => '', 3194 'after' => '', 3195 'sep' => ' | ', 3196 'links' => array( 3197 bp_get_the_members_invitation_resend_link( $inviter_id ), 3198 bp_get_the_members_invitation_delete_link( $inviter_id ) 3199 ) 3200 ) ); 3201 3202 // Build the links. 3203 $retval = $r['before'] . implode( $r['sep'], $r['links'] ) . $r['after']; 3204 3205 /** 3206 * Filters the action links for the current invitation. 3207 * 3208 * @since 8.0.0 3209 * 3210 * @param string $retval HTML links for actions to take on single invitation. 3211 * @param array $r Array of parsed arguments. 3212 */ 3213 return apply_filters( 'bp_get_the_members_invitation_action_links', $retval, $r ); 3214 } 3215 3216 /** 3217 * Output the resend link for the current invitation. 3218 * 3219 * @since 8.0.0 3220 * 3221 * @param int $user_id The user ID. 3222 */ 3223 function bp_the_members_invitations_resend_link( $user_id = 0 ) { 3224 echo bp_get_the_members_invitation_delete_link( $user_id ); 3225 } 3226 /** 3227 * Return the resend link for the current notification. 3228 * 3229 * @since 8.0.0 3230 * 3231 * @param int $user_id The user ID. 3232 * @return string 3233 */ 3234 function bp_get_the_members_invitation_resend_link( $user_id = 0 ) { 3235 // Set default user ID to use. 3236 $user_id = 0 === $user_id ? bp_displayed_user_id() : $user_id; 3237 3238 // Don't allow resending of accepted invitations. 3239 if ( bp_get_the_members_invitation_property( 'accepted' ) ) { 3240 return; 3241 } 3242 3243 $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' ) ); 3244 3245 /** 3246 * Filters the resend link for the current invitation. 3247 * 3248 * @since 8.0.0 3249 * 3250 * @param string $retval HTML for the delete link for the current notification. 3251 * @param int $user_id The user ID. 3252 */ 3253 return apply_filters( 'bp_get_the_members_invitation_resend_link', $retval, $user_id ); 3254 } 3255 3256 /** 3257 * Output the URL used for resending a single invitation. 3258 * 3259 * Since this function directly outputs a URL, it is escaped. 3260 * 3261 * @since 8.0.0 3262 * 3263 * @param int $user_id The user ID. 3264 */ 3265 function bp_the_members_invitations_resend_url( $user_id = 0 ) { 3266 echo esc_url( bp_get_the_members_invitations_resend_url( $user_id ) ); 3267 } 3268 /** 3269 * Return the URL used for resending a single invitation. 3270 * 3271 * @since 8.0.0 3272 * 3273 * @param int $user_id The user ID. 3274 * @return string 3275 */ 3276 function bp_get_the_members_invitations_resend_url( $user_id = 0 ) { 3277 // Set default user ID to use. 3278 $user_id = 0 === $user_id ? bp_displayed_user_id() : $user_id; 3279 $link = bp_get_members_invitations_list_invites_permalink( $user_id ); 3280 3281 // Get the ID. 3282 $id = bp_get_the_members_invitation_property( 'id' ); 3283 3284 // Get the args to add to the URL. 3285 $args = array( 3286 'action' => 'resend', 3287 'invitation_id' => $id 3288 ); 3289 3290 // Add the args. 3291 $url = add_query_arg( $args, $link ); 3292 3293 // Add the nonce. 3294 $url = wp_nonce_url( $url, 'bp_network_invitation_resend_' . $id ); 3295 3296 /** 3297 * Filters the URL used for resending a single invitation. 3298 * 3299 * @since 8.0.0 3300 * 3301 * @param string $url URL used for deleting a single invitation. 3302 * @param int $user_id The user ID. 3303 */ 3304 return apply_filters( 'bp_get_the_members_invitations_resend_url', $url, $user_id ); 3305 } 3306 3307 /** 3308 * Output the delete link for the current invitation. 3309 * 3310 * @since 8.0.0 3311 * 3312 * @param int $user_id The user ID. 3313 */ 3314 function bp_the_members_invitations_delete_link( $user_id = 0 ) { 3315 echo bp_get_the_members_invitation_delete_link( $user_id ); 3316 } 3317 /** 3318 * Return the delete link for the current invitation. 3319 * 3320 * @since 8.0.0 3321 * 3322 * @param int $user_id The user ID. 3323 * @return string 3324 */ 3325 function bp_get_the_members_invitation_delete_link( $user_id = 0 ) { 3326 // Set default user ID to use. 3327 $user_id = 0 === $user_id ? bp_displayed_user_id() : $user_id; 3328 3329 // Modify the message for accepted/not accepted invitatons. 3330 if ( bp_get_the_members_invitation_property( 'accepted' ) ) { 3331 $message = __( 'Delete', 'buddypress' ); 3332 } else { 3333 $message = __( 'Cancel', 'buddypress' ); 3334 } 3335 3336 $retval = sprintf( 3337 '<a href="%1$s" class="delete secondary confirm bp-tooltip">%2$s</a>', 3338 esc_url( bp_get_the_members_invitations_delete_url( $user_id ) ), 3339 esc_html( $message ) 3340 ); 3341 3342 /** 3343 * Filters the delete link for the current invitation. 3344 * 3345 * @since 8.0.0 3346 * 3347 * @param string $retval HTML for the delete link for the current notification. 3348 * @param int $user_id The user ID. 3349 */ 3350 return apply_filters( 'bp_get_the_members_invitation_delete_link', $retval, $user_id ); 3351 } 3352 3353 /** 3354 * Output the URL used for deleting a single invitation. 3355 * 3356 * Since this function directly outputs a URL, it is escaped. 3357 * 3358 * @since 8.0.0 3359 * 3360 * @param int $user_id The user ID. 3361 */ 3362 function bp_the_members_invitations_delete_url( $user_id = 0 ) { 3363 echo esc_url( bp_get_the_members_invitations_delete_url( $user_id ) ); 3364 } 3365 /** 3366 * Return the URL used for deleting a single invitation. 3367 * 3368 * @since 8.0.0 3369 * 3370 * @param int $user_id The user ID. 3371 * @return string 3372 */ 3373 function bp_get_the_members_invitations_delete_url( $user_id = 0 ) { 3374 // Set default user ID to use. 3375 $user_id = 0 === $user_id ? bp_displayed_user_id() : $user_id; 3376 $link = bp_get_members_invitations_list_invites_permalink( $user_id ); 3377 3378 // Get the ID. 3379 $id = bp_get_the_members_invitation_property( 'id' ); 3380 3381 // Get the args to add to the URL. 3382 $args = array( 3383 'action' => 'cancel', 3384 'invitation_id' => $id 3385 ); 3386 3387 // Add the args. 3388 $url = add_query_arg( $args, $link ); 3389 3390 // Add the nonce. 3391 $url = wp_nonce_url( $url, 'bp_members_invitations_cancel_' . $id ); 3392 3393 /** 3394 * Filters the URL used for deleting a single invitation. 3395 * 3396 * @since 8.0.0 3397 * 3398 * @param string $url URL used for deleting a single invitation. 3399 * @param int $user_id The user ID. 3400 */ 3401 return apply_filters( 'bp_get_the_members_invitations_delete_url', $url, $user_id ); 3402 } 3403 3404 /** 3405 * Output the members invitations list permalink for a user. 3406 * 3407 * @since 8.0.0 3408 * 3409 * @param int $user_id The user ID. 3410 */ 3411 function bp_members_invitations_list_invites_permalink( $user_id = 0 ) { 3412 echo bp_get_members_invitations_list_invites_permalink( $user_id ); 3413 } 3414 /** 3415 * Return the members invitations list permalink for a user. 3416 * 3417 * @since 8.0.0 3418 * 3419 * @return string Members invitations list permalink for a user. 3420 */ 3421 function bp_get_members_invitations_list_invites_permalink( $user_id = 0 ) { 3422 if ( 0 === $user_id ) { 3423 $user_id = bp_loggedin_user_id(); 3424 $domain = bp_loggedin_user_domain(); 3425 } else { 3426 $domain = bp_core_get_user_domain( (int) $user_id ); 3427 } 3428 3429 $retval = trailingslashit( $domain . bp_get_members_invitations_slug() . '/list-invites' ); 3430 3431 /** 3432 * Filters the members invitations list permalink for a user. 3433 * 3434 * @since 8.0.0 3435 * 3436 * @param string $retval Permalink for the sent invitation list screen. 3437 * @param int $user_id The user ID. 3438 */ 3439 return apply_filters( 'bp_get_members_invitations_list_invites_permalink', $retval, $user_id ); 3440 } 3441 3442 /** 3443 * Output the send invitation permalink for a user. 3444 * 3445 * @since 8.0.0 3446 * 3447 * @param int $user_id The user ID. 3448 */ 3449 function bp_members_invitations_send_invites_permalink( $user_id = 0 ) { 3450 echo bp_get_members_invitations_send_invites_permalink( $user_id ); 3451 } 3452 /** 3453 * Return the send invitations permalink. 3454 * 3455 * @since 8.0.0 3456 * 3457 * @param int $user_id The user ID. 3458 * @return string The send invitations permalink. 3459 */ 3460 function bp_get_members_invitations_send_invites_permalink( $user_id = 0 ) { 3461 if ( 0 === $user_id ) { 3462 $user_id = bp_loggedin_user_id(); 3463 $domain = bp_loggedin_user_domain(); 3464 } else { 3465 $domain = bp_core_get_user_domain( (int) $user_id ); 3466 } 3467 3468 $retval = trailingslashit( $domain . bp_get_members_invitations_slug() . '/send-invites' ); 3469 3470 /** 3471 * Filters the send invitations permalink. 3472 * 3473 * @since 8.0.0 3474 * 3475 * @param string $retval Permalink for the sent invitation list screen. 3476 * @param int $user_id The user ID. 3477 */ 3478 return apply_filters( 'bp_get_members_invitations_send_invites_permalink', $retval, $user_id ); 3479 } -
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 64903c107..8c1d68b46 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 { 219 221 // Registration is turned on. 220 222 add_action( 'update_site_option_registration', array( $this, 'multisite_registration_on' ), 10, 2 ); 221 223 add_action( 'update_option_users_can_register', array( $this, 'single_site_registration_on' ), 10, 2 ); 224 225 // Member invitations are enabled. 226 if ( bp_is_network_activated() ) { 227 add_action( 'update_site_option_bp-enable-members-invitations', array( $this, 'multisite_registration_on' ), 10, 2 ); 228 } else { 229 add_action( 'update_option_bp-enable-members-invitations', array( $this, 'single_site_registration_on' ), 10, 2 ); 230 } 222 231 } 223 232 224 233 /** Users List - Members Types *************************************** … … class BP_Members_Admin { 248 257 * @param string $value 249 258 */ 250 259 public function multisite_registration_on( $option_name, $value ) { 251 if ( 'user' === $value || 'all' === $value ) { 260 // Is registration enabled or are network invitations enabled? 261 if ( ( 'user' === $value || 'all' === $value ) 262 || bp_get_members_invitations_allowed() ) { 252 263 bp_core_add_page_mappings( array( 253 264 'register' => 1, 254 265 'activate' => 1 … … class BP_Members_Admin { 266 277 */ 267 278 public function single_site_registration_on( $old_value, $value ) { 268 279 // Single site. 269 if ( ! is_multisite() && ! empty( $value) ) {280 if ( ! is_multisite() && ( ! empty( $value ) || bp_get_members_invitations_allowed() ) ) { 270 281 bp_core_add_page_mappings( array( 271 282 'register' => 1, 272 283 'activate' => 1 … … class BP_Members_Admin { 490 501 ); 491 502 } 492 503 504 // For consistency with non-Multisite, we add a Tools menu in 505 // the Network Admin as a home for our Tools panel. 506 if ( is_multisite() && bp_core_do_network_admin() ) { 507 $tools_parent = 'network-tools'; 508 } else { 509 $tools_parent = 'tools.php'; 510 } 511 512 $hooks['members_invitations'] = $this->members_invites_page = add_submenu_page( 513 $tools_parent, 514 __( 'Manage Invitations', 'buddypress' ), 515 __( 'Manage Invitations', 'buddypress' ), 516 $this->capability, 517 'bp-members-invitations', 518 array( $this, 'invitations_admin' ) 519 ); 520 493 521 $edit_page = 'user-edit'; 494 522 $profile_page = 'profile'; 495 523 $this->users_page = 'users'; … … class BP_Members_Admin { 510 538 $this->users_page .= '-network'; 511 539 $this->signups_page .= '-network'; 512 540 513 $this->members_ optouts_page .= '-network';541 $this->members_invites_page .= '-network'; 514 542 } 515 543 516 544 // Setup the screen ID's. … … class BP_Members_Admin { 529 557 foreach ( $page_head as $head ) { 530 558 add_action( "admin_head-{$head}", array( $this, 'profile_admin_head' ) ); 531 559 } 560 561 // Highlight the BuddyPress tools submenu when managing invitations. 562 add_action( "admin_head-{$this->members_invites_page}", 'bp_core_modify_admin_menu_highlight' ); 532 563 } 533 564 534 565 /** … … class BP_Members_Admin { 598 629 public function admin_head() { 599 630 remove_submenu_page( 'users.php', 'bp-profile-edit' ); 600 631 remove_submenu_page( 'profile.php', 'bp-profile-edit' ); 632 633 // Manage Invitations Tool screen is a tab of BP Tools. 634 if ( is_network_admin() ) { 635 remove_submenu_page( 'network-tools', 'bp-members-invitations' ); 636 } else { 637 remove_submenu_page( 'tools.php', 'bp-members-invitations' ); 638 } 601 639 } 602 640 603 641 /** Community Profile *****************************************************/ … … class BP_Members_Admin { 1905 1943 } 1906 1944 1907 1945 if ( ! empty( $_REQUEST['notdeleted'] ) ) { 1946 $notdeleted = absint( $_REQUEST['notdeleted'] ); 1908 1947 $notice['message'] .= sprintf( 1909 /* translators: %s: number of deleted signups not deleted */ 1910 _nx( '%s sign-up was not deleted.', '%s sign-ups were not deleted.', 1911 absint( $_REQUEST['notdeleted'] ), 1912 'signup notdeleted', 1913 'buddypress' 1948 _nx( 1949 /* translators: %s: number of deleted signups not deleted */ 1950 '%s sign-up was not deleted.', '%s sign-ups were not deleted.', 1951 $notdeleted, 1952 'signup notdeleted', 1953 'buddypress' 1914 1954 ), 1915 number_format_i18n( absint( $_REQUEST['notdeleted'] ))1955 number_format_i18n( $notdeleted ) 1916 1956 ); 1917 1957 1918 1958 if ( empty( $_REQUEST['deleted'] ) ) { … … class BP_Members_Admin { 2566 2606 2567 2607 return $value; 2568 2608 } 2609 2610 /** 2611 * Set up the signups admin page. 2612 * 2613 * Loaded before the page is rendered, this function does all initial 2614 * setup, including: processing form requests, registering contextual 2615 * help, and setting up screen options. 2616 * 2617 * @since 8.0.0 2618 * 2619 * @global $bp_members_invitations_list_table 2620 */ 2621 public function members_invitations_admin_load() { 2622 global $bp_members_invitations_list_table; 2623 2624 // Build redirection URL. 2625 $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'] ); 2626 $doaction = bp_admin_list_table_current_bulk_action(); 2627 2628 /** 2629 * Fires at the start of the member invitations admin load. 2630 * 2631 * @since 8.0.0 2632 * 2633 * @param string $doaction Current bulk action being processed. 2634 * @param array $_REQUEST Current $_REQUEST global. 2635 */ 2636 do_action( 'bp_members_invitations_admin_load', $doaction, $_REQUEST ); 2637 2638 /** 2639 * Filters the allowed actions for use in the user signups admin page. 2640 * 2641 * @since 8.0.0 2642 * 2643 * @param array $value Array of allowed actions to use. 2644 */ 2645 $allowed_actions = apply_filters( 'bp_members_invitations_admin_allowed_actions', array( 'do_delete', 'do_resend' ) ); 2646 2647 // Prepare the display of the bulk invitation action screen. 2648 if ( ! in_array( $doaction, $allowed_actions ) ) { 2649 2650 $bp_members_invitations_list_table = self::get_list_table_class( 'BP_Members_Invitations_List_Table', 'users' ); 2651 2652 // The per_page screen option. 2653 add_screen_option( 'per_page', array( 'label' => _x( 'Members Invitations', 'Members Invitations per page (screen options)', 'buddypress' ) ) ); 2654 2655 get_current_screen()->add_help_tab( array( 2656 'id' => 'bp-members-invitations-overview', 2657 'title' => __( 'Overview', 'buddypress' ), 2658 'content' => 2659 '<p>' . __( 'This is the administration screen for member invitations on your site.', 'buddypress' ) . '</p>' . 2660 '<p>' . __( 'From the screen options, you can customize the displayed columns and the pagination of this screen.', 'buddypress' ) . '</p>' . 2661 '<p>' . __( 'You can reorder the list of invitations by clicking on the Invitee, Inviter, Date Modified, Email Sent, or Accepted column headers.', 'buddypress' ) . '</p>' . 2662 '<p>' . __( 'Using the search form, you can find specific invitations more easily. The Invitee Email field will be included in the search.', 'buddypress' ) . '</p>' 2663 ) ); 2664 2665 get_current_screen()->add_help_tab( array( 2666 'id' => 'bp-members-invitations-actions', 2667 'title' => __( 'Actions', 'buddypress' ), 2668 'content' => 2669 '<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>' . 2670 '<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>' . 2671 '<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>' . 2672 '<p>' . __( 'Bulk actions allow you to perform these actions for the selected rows.', 'buddypress' ) . '</p>' 2673 ) ); 2674 2675 // Help panel - sidebar links. 2676 get_current_screen()->set_help_sidebar( 2677 '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' . 2678 '<p>' . __( '<a href="https://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>' 2679 ); 2680 2681 // Add accessible hidden headings and text for the Pending Users screen. 2682 get_current_screen()->set_screen_reader_content( array( 2683 /* translators: accessibility text */ 2684 'heading_views' => __( 'Filter invitations list', 'buddypress' ), 2685 /* translators: accessibility text */ 2686 'heading_pagination' => __( 'Invitation list navigation', 'buddypress' ), 2687 /* translators: accessibility text */ 2688 'heading_list' => __( 'Invitations list', 'buddypress' ), 2689 ) ); 2690 2691 } else { 2692 if ( empty( $_REQUEST['invite_ids' ] ) ) { 2693 return; 2694 } 2695 $invite_ids = wp_parse_id_list( $_REQUEST['invite_ids' ] ); 2696 2697 // Handle resent invitations. 2698 if ( 'do_resend' == $doaction ) { 2699 2700 // Nonce check. 2701 check_admin_referer( 'invitations_resend' ); 2702 2703 $success = 0; 2704 foreach ( $invite_ids as $invite_id ) { 2705 if ( bp_members_invitation_resend_by_id( $invite_id ) ) { 2706 $success++; 2707 } 2708 } 2709 2710 $query_arg = array( 'updated' => 'resent' ); 2711 2712 if ( ! empty( $success ) ) { 2713 $query_arg['resent'] = $success; 2714 } 2715 2716 $not_sent = count( $invite_ids ) - $success; 2717 if ( $not_sent > 0 ) { 2718 $query_arg['notsent'] = $not_sent; 2719 } 2720 2721 $redirect_to = add_query_arg( $query_arg, $redirect_to ); 2722 2723 bp_core_redirect( $redirect_to ); 2724 2725 // Handle invitation deletion. 2726 } elseif ( 'do_delete' == $doaction ) { 2727 2728 // Nonce check. 2729 check_admin_referer( 'invitations_delete' ); 2730 2731 $success = 0; 2732 foreach ( $invite_ids as $invite_id ) { 2733 if ( bp_members_invitations_delete_by_id( $invite_id ) ) { 2734 $success++; 2735 } 2736 } 2737 2738 $query_arg = array( 'updated' => 'deleted' ); 2739 2740 if ( ! empty( $success ) ) { 2741 $query_arg['deleted'] = $success; 2742 } 2743 2744 $notdeleted = count( $invite_ids ) - $success; 2745 if ( $notdeleted > 0 ) { 2746 $query_arg['notdeleted'] = $notdeleted; 2747 } 2748 2749 $redirect_to = add_query_arg( $query_arg, $redirect_to ); 2750 2751 bp_core_redirect( $redirect_to ); 2752 2753 // Plugins can update other stuff from here. 2754 } else { 2755 $this->redirect = $redirect_to; 2756 2757 /** 2758 * Fires at end of member invitations admin load 2759 * if doaction does not match any actions. 2760 * 2761 * @since 8.0.0 2762 * 2763 * @param string $doaction Current bulk action being processed. 2764 * @param array $_REQUEST Current $_REQUEST global. 2765 * @param string $redirect Determined redirect url to send user to. 2766 */ 2767 do_action( 'bp_members_admin_update_invitations', $doaction, $_REQUEST, $this->redirect ); 2768 2769 bp_core_redirect( $this->redirect ); 2770 } 2771 } 2772 } 2773 2774 /** 2775 * Get admin notice when viewing the invitations management page. 2776 * 2777 * @since 8.0.0 2778 * 2779 * @return array 2780 */ 2781 private function get_members_invitations_notice() { 2782 2783 // Setup empty notice for return value. 2784 $notice = array(); 2785 2786 // Updates. 2787 if ( ! empty( $_REQUEST['updated'] ) ) { 2788 switch ( $_REQUEST['updated'] ) { 2789 case 'resent': 2790 $notice = array( 2791 'class' => 'updated', 2792 'message' => '' 2793 ); 2794 2795 if ( ! empty( $_REQUEST['resent'] ) ) { 2796 $resent = absint( $_REQUEST['resent'] ); 2797 $notice['message'] .= sprintf( 2798 _nx( 2799 /* translators: %s: number of invitation emails sent */ 2800 '%s invtitation email successfully sent! ', '%s invitation emails successfully sent! ', 2801 $resent, 2802 'members invitation resent', 2803 'buddypress' 2804 ), 2805 number_format_i18n( $resent ) 2806 ); 2807 } 2808 2809 if ( ! empty( $_REQUEST['notsent'] ) ) { 2810 $notsent = absint( $_REQUEST['notsent'] ); 2811 $notice['message'] .= sprintf( 2812 _nx( 2813 /* translators: %s: number of unsent invitation emails */ 2814 '%s invitation email was not sent.', '%s invitation emails were not sent.', 2815 $notsent, 2816 'members invitation notsent', 2817 'buddypress' 2818 ), 2819 number_format_i18n( $notsent ) 2820 ); 2821 2822 if ( empty( $_REQUEST['resent'] ) ) { 2823 $notice['class'] = 'error'; 2824 } 2825 } 2826 2827 break; 2828 2829 case 'deleted': 2830 $notice = array( 2831 'class' => 'updated', 2832 'message' => '' 2833 ); 2834 2835 if ( ! empty( $_REQUEST['deleted'] ) ) { 2836 $deleted = absint( $_REQUEST['deleted'] ); 2837 $notice['message'] .= sprintf( 2838 _nx( 2839 /* translators: %s: number of deleted invitations */ 2840 '%s invitation successfully deleted!', '%s invitations successfully deleted!', 2841 $deleted, 2842 'members invitation deleted', 2843 'buddypress' 2844 ), 2845 number_format_i18n( $deleted ) 2846 ); 2847 } 2848 2849 if ( ! empty( $_REQUEST['notdeleted'] ) ) { 2850 $notdeleted = absint( $_REQUEST['notdeleted'] ); 2851 $notice['message'] .= sprintf( 2852 _nx( 2853 /* translators: %s: number of invitations that failed to be deleted */ 2854 '%s invitation was not deleted.', '%s invitations were not deleted.', 2855 $notdeleted, 2856 'members invitation notdeleted', 2857 'buddypress' 2858 ), 2859 number_format_i18n( $notdeleted ) 2860 ); 2861 2862 if ( empty( $_REQUEST['deleted'] ) ) { 2863 $notice['class'] = 'error'; 2864 } 2865 } 2866 2867 break; 2868 } 2869 } 2870 2871 // Errors. 2872 if ( ! empty( $_REQUEST['error'] ) ) { 2873 switch ( $_REQUEST['error'] ) { 2874 case 'do_resend': 2875 $notice = array( 2876 'class' => 'error', 2877 'message' => esc_html__( 'There was a problem sending the invitation emails. Please try again.', 'buddypress' ), 2878 ); 2879 break; 2880 2881 case 'do_delete': 2882 $notice = array( 2883 'class' => 'error', 2884 'message' => esc_html__( 'There was a problem deleting invitations. Please try again.', 'buddypress' ), 2885 ); 2886 break; 2887 } 2888 } 2889 2890 return $notice; 2891 } 2892 2893 /** 2894 * Member invitations admin page router. 2895 * 2896 * Depending on the context, display 2897 * - the list of invitations, 2898 * - or the delete confirmation screen, 2899 * - or the "resend" email confirmation screen. 2900 * 2901 * Also prepare the admin notices. 2902 * 2903 * @since 8.0.0 2904 */ 2905 public function invitations_admin() { 2906 $doaction = bp_admin_list_table_current_bulk_action(); 2907 2908 // Prepare notices for admin. 2909 $notice = $this->get_members_invitations_notice(); 2910 2911 // Display notices. 2912 if ( ! empty( $notice ) ) : 2913 if ( 'updated' === $notice['class'] ) : ?> 2914 2915 <div id="message" class="<?php echo esc_attr( $notice['class'] ); ?> notice is-dismissible"> 2916 2917 <?php else: ?> 2918 2919 <div class="<?php echo esc_attr( $notice['class'] ); ?> notice is-dismissible"> 2920 2921 <?php endif; ?> 2922 2923 <p><?php echo $notice['message']; ?></p> 2924 </div> 2925 2926 <?php endif; 2927 2928 // Show the proper screen. 2929 switch ( $doaction ) { 2930 case 'delete' : 2931 case 'resend' : 2932 $this->invitations_admin_manage( $doaction ); 2933 break; 2934 2935 default: 2936 $this->invitations_admin_index(); 2937 break; 2938 } 2939 } 2940 2941 /** 2942 * This is the list of invitations. 2943 * 2944 * @since 8.0.0 2945 * 2946 * @global $plugin_page 2947 * @global $bp_members_invitations_list_table 2948 */ 2949 public function invitations_admin_index() { 2950 global $plugin_page, $bp_members_invitations_list_table; 2951 2952 $usersearch = ! empty( $_REQUEST['s'] ) ? stripslashes( $_REQUEST['s'] ) : ''; 2953 2954 // Prepare the group items for display. 2955 $bp_members_invitations_list_table->prepare_items(); 2956 2957 if ( is_network_admin() ) { 2958 $form_url = network_admin_url( 'admin.php' ); 2959 } else { 2960 $form_url = bp_get_admin_url( 'tools.php' ); 2961 } 2962 2963 $form_url = add_query_arg( 2964 array( 2965 'page' => 'bp-members-invitations', 2966 ), 2967 $form_url 2968 ); 2969 2970 $search_form_url = remove_query_arg( 2971 array( 2972 'action', 2973 'deleted', 2974 'notdeleted', 2975 'error', 2976 'updated', 2977 'delete', 2978 'activate', 2979 'activated', 2980 'notactivated', 2981 'resend', 2982 'resent', 2983 'notresent', 2984 'do_delete', 2985 'do_activate', 2986 'do_resend', 2987 'action2', 2988 '_wpnonce', 2989 'invite_ids' 2990 ), $_SERVER['REQUEST_URI'] 2991 ); 2992 2993 ?> 2994 2995 <div class="wrap"> 2996 <h1 class="wp-heading-inline"><?php esc_html_e( 'BuddyPress tools', 'buddypress' ); ?></h1> 2997 <hr class="wp-header-end"> 2998 2999 <h2 class="nav-tab-wrapper"><?php bp_core_admin_tabs( __( 'Manage Invitations', 'buddypress' ), 'tools' ); ?></h2> 3000 3001 <?php 3002 if ( $usersearch ) { 3003 printf( '<span class="subtitle">' . __( 'Search results for “%s”', 'buddypress' ) . '</span>', esc_html( $usersearch ) ); 3004 } 3005 ?> 3006 3007 <hr class="wp-header-end"> 3008 3009 <?php // Display each invitation on its own row. ?> 3010 <?php $bp_members_invitations_list_table->views(); ?> 3011 3012 <form id="bp-members-invitations-search-form" action="<?php echo esc_url( $search_form_url ) ;?>"> 3013 <input type="hidden" name="page" value="<?php echo esc_attr( $plugin_page ); ?>" /> 3014 <?php $bp_members_invitations_list_table->search_box( __( 'Search Invitations', 'buddypress' ), 'bp-members-invitations' ); ?> 3015 </form> 3016 3017 <form id="bp-members-invitations-form" action="<?php echo esc_url( $form_url );?>" method="post"> 3018 <?php $bp_members_invitations_list_table->display(); ?> 3019 </form> 3020 </div> 3021 <?php 3022 } 3023 3024 /** 3025 * This is the confirmation screen for actions. 3026 * 3027 * @since 8.0.0 3028 * 3029 * @param string $action Delete or resend invitation. 3030 * @return null|false 3031 */ 3032 public function invitations_admin_manage( $action = '' ) { 3033 if ( ! current_user_can( $this->capability ) || empty( $action ) ) { 3034 die( '-1' ); 3035 } 3036 3037 // Get the IDs from the URL. 3038 $ids = false; 3039 if ( ! empty( $_POST['invite_ids'] ) ) { 3040 $ids = wp_parse_id_list( $_POST['invite_ids'] ); 3041 } elseif ( ! empty( $_GET['invite_id'] ) ) { 3042 $ids = absint( $_GET['invite_id'] ); 3043 } 3044 3045 3046 if ( empty( $ids ) ) { 3047 return false; 3048 } 3049 3050 // Check invite IDs and set up strings. 3051 switch ( $action ) { 3052 case 'delete' : 3053 // Query for matching invites, and filter out bad IDs. 3054 $args = array( 3055 'id' => $ids, 3056 'invite_sent' => 'all', 3057 'accepted' => 'all', 3058 ); 3059 $invites = bp_members_invitations_get_invites( $args ); 3060 $invite_ids = wp_list_pluck( $invites, 'id' ); 3061 3062 $header_text = __( 'Delete Invitations', 'buddypress' ); 3063 if ( 0 === count( $invite_ids ) ) { 3064 $helper_text = __( 'No invites were found, nothing to delete!', 'buddypress' ); 3065 } else { 3066 $helper_text = _n( 'You are about to delete the following invitation:', 'You are about to delete the following invitations:', count( $invite_ids ), 'buddypress' ); 3067 } 3068 break; 3069 3070 case 'resend' : 3071 /** 3072 * Query for matching invites, and filter out bad IDs 3073 * or those that have already been accepted. 3074 */ 3075 $args = array( 3076 'id' => $ids, 3077 'invite_sent' => 'all', 3078 'accepted' => 'pending', 3079 ); 3080 $invites = bp_members_invitations_get_invites( $args ); 3081 $invite_ids = wp_list_pluck( $invites, 'id' ); 3082 3083 $header_text = __( 'Resend Invitation Emails', 'buddypress' ); 3084 if ( 0 === count( $invite_ids ) ) { 3085 $helper_text = __( 'No pending invites were found, nothing to resend!', 'buddypress' ); 3086 } else { 3087 $helper_text = _n( 'You are about to resend an invitation email to the following address:', 'You are about to resend invitation emails to the following addresses:', count( $invite_ids ), 'buddypress' ); 3088 } 3089 break; 3090 } 3091 3092 // These arguments are added to all URLs. 3093 $url_args = array( 'page' => 'bp-members-invitations' ); 3094 3095 // These arguments are only added when performing an action. 3096 $action_args = array( 3097 'action' => 'do_' . $action, 3098 'invite_ids' => implode( ',', $invite_ids ) 3099 ); 3100 3101 if ( is_network_admin() ) { 3102 $base_url = network_admin_url( 'admin.php' ); 3103 } else { 3104 $base_url = bp_get_admin_url( 'tools.php' ); 3105 } 3106 3107 $cancel_url = add_query_arg( $url_args, $base_url ); 3108 $action_url = wp_nonce_url( 3109 add_query_arg( 3110 array_merge( $url_args, $action_args ), 3111 $base_url 3112 ), 3113 'invitations_' . $action 3114 ); 3115 3116 ?> 3117 3118 <div class="wrap"> 3119 <h1 class="wp-heading-inline"><?php echo esc_html( $header_text ); ?></h1> 3120 <hr class="wp-header-end"> 3121 3122 <p><?php echo esc_html( $helper_text ); ?></p> 3123 3124 <?php if ( $invites ) : ?> 3125 3126 <ol class="bp-invitations-list"> 3127 <?php foreach ( $invites as $invite ) : 3128 if ( $invite->invite_sent ) { 3129 $last_notified = mysql2date( 'Y/m/d g:i:s a', $invite->date_modified ); 3130 } else { 3131 $last_notified = __( 'Not yet notified', 'buddypress'); 3132 } 3133 ?> 3134 3135 <li> 3136 <strong><?php echo esc_html( $invite->invitee_email ) ?></strong> 3137 3138 <?php if ( 'resend' === $action ) : ?> 3139 3140 <p class="description"> 3141 <?php 3142 /* translators: %s: notification date */ 3143 printf( esc_html__( 'Last notified: %s', 'buddypress'), $last_notified ); 3144 ?> 3145 </p> 3146 3147 <?php endif; ?> 3148 3149 </li> 3150 3151 <?php endforeach; ?> 3152 </ol> 3153 3154 <?php endif ; ?> 3155 3156 <?php if ( 'delete' === $action ) : ?> 3157 3158 <p><strong><?php esc_html_e( 'This action cannot be undone.', 'buddypress' ) ?></strong></p> 3159 3160 <?php endif; ?> 3161 3162 <?php if ( $invites ) : ?> 3163 3164 <a class="button-primary" href="<?php echo esc_url( $action_url ); ?>" <?php disabled( ! $invites ); ?>><?php esc_html_e( 'Confirm', 'buddypress' ); ?></a> 3165 3166 <?php endif; ?> 3167 3168 <a class="button" href="<?php echo esc_url( $cancel_url ); ?>"><?php esc_html_e( 'Cancel', 'buddypress' ) ?></a> 3169 </div> 3170 3171 <?php 3172 } 3173 2569 3174 } 2570 3175 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 4db47da8d..c819eb08b 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', 69 'notifications', 67 70 ); 68 71 69 72 if ( bp_is_active( 'activity' ) ) { … … class BP_Members_Component extends BP_Component { 137 140 // Theme compatibility. 138 141 new BP_Registration_Theme_Compat(); 139 142 } 143 144 // Invitations. 145 if ( is_user_logged_in() && bp_is_user_members_invitations() ) { 146 if ( bp_is_user_members_invitations_list() ) { 147 require $this->path . 'bp-members/screens/list-invites.php'; 148 } else { 149 require $this->path . 'bp-members/screens/send-invites.php'; 150 } 151 } 140 152 } 141 153 142 154 /** … … class BP_Members_Component extends BP_Component { 180 192 'table_name_last_activity' => bp_core_get_table_prefix() . 'bp_activity', 181 193 'table_name_optouts' => bp_core_get_table_prefix() . 'bp_optouts', 182 194 'table_name_signups' => $wpdb->base_prefix . 'signups', // Signups is a global WordPress table. 183 ) 195 ), 196 'notification_callback' => 'members_format_notifications', 184 197 ); 185 198 186 199 parent::setup_globals( $args ); … … class BP_Members_Component extends BP_Component { 233 246 $bp->profile->slug = 'profile'; 234 247 $bp->profile->id = 'profile'; 235 248 } 249 250 /** Network Invitations ************************************************** 251 */ 252 253 $bp->members->invitations = new stdClass; 236 254 } 237 255 238 256 /** … … class BP_Members_Component extends BP_Component { 468 486 } 469 487 } 470 488 471 472 489 parent::setup_nav( $main_nav, $sub_nav ); 473 490 } 474 491 … … class BP_Members_Component extends BP_Component { 549 566 return $wp_admin_nav; 550 567 } 551 568 569 /** 570 * Get the members invitations admin bar navs. 571 * 572 * @since 8.0.0 573 * 574 * @param string $admin_bar_menu_id The Admin bar menu ID to attach sub items to. 575 * @return array The members invitations admin navs. 576 */ 577 public function get_members_invitations_admin_navs( $admin_bar_menu_id = '' ) { 578 $wp_admin_nav = array(); 579 $invite_link = trailingslashit( bp_loggedin_user_domain() . bp_get_profile_slug() ); 580 581 if ( ! $admin_bar_menu_id ) { 582 $admin_bar_menu_id = $this->id; 583 } 584 585 return $wp_admin_nav; 586 } 587 552 588 /** 553 589 * Set up the Admin Bar. 554 590 * -
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..a708ee17b
- + 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 // Coming soon to a BuddyPress near you! 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 ), 62 bp_get_signup_page() 63 ) 64 ); 65 $unsubscribe_args = array( 66 'user_id' => 0, 67 'email_address' => $invitation->invitee_email, 68 'member_id' => $invitation->inviter_id, 69 'notification_type' => 'bp-members-invitation', 70 ); 71 72 $args = array( 73 'tokens' => array( 74 'inviter.name' => bp_core_get_userlink( $invitation->inviter_id, true, false, true ), 75 'inviter.url' => bp_core_get_user_domain( $invitation->inviter_id ), 76 'inviter.id' => $invitation->inviter_id, 77 'invite.accept_url' => esc_url( $invite_url ), 78 'usermessage' => wp_kses( $invitation->content, array() ), 79 'unsubscribe' => esc_url( bp_email_get_unsubscribe_link( $unsubscribe_args ) ), 80 ), 81 ); 82 83 return bp_send_email( 'bp-members-invitation', $invitation->invitee_email, $args ); 84 } 85 } 86 87 /** 88 * This is where custom actions are added to run when an invitation 89 * or request is accepted. 90 * 91 * @since 8.0.0 92 * 93 * @param string $type Are we accepting an invitation or request? 94 * @param array $r Parameters that describe the invitation being accepted. 95 * @return bool True on success, false on failure. 96 */ 97 public function run_acceptance_action( $type, $r ) { 98 if ( ! $type || ! in_array( $type, array( 'request', 'invite' ), true ) ) { 99 return false; 100 } 101 102 if ( 'invite' === $type ) { 103 104 $invites = $this->get_invitations( $r ); 105 if ( ! $invites ) { 106 return; 107 } 108 109 foreach ( $invites as $invite ) { 110 // Add the accepted invitation ID to the user's meta. 111 $new_user = get_user_by( 'email', $invite->invitee_email ); 112 bp_update_user_meta( $new_user->ID, 'accepted_members_invitation', $invite->id ); 113 114 // We will mark all invitations to this user as "accepted." 115 if ( ! empty( $invite->invitee_email ) ) { 116 $args = array( 117 'invitee_email' => $invite->invitee_email, 118 'item_id' => get_current_network_id(), 119 'type' => 'all' 120 ); 121 $this->mark_accepted( $args ); 122 } 123 124 /** 125 * Fires after a user has accepted a site membership invite. 126 * 127 * @since 8.0.0 128 * 129 * @param BP_Invitation $invite Invitation that was accepted. 130 * @param WP_user $new_user ID of the user who accepted the membership invite. 131 * @param int $inviter_id ID of the user who invited this user to the site. 132 */ 133 do_action( 'community_membership_invite_accepted', $invite, $new_user, $invite->inviter_id ); 134 } 135 } 136 137 return true; 138 } 139 140 /** 141 * Should this invitation be created? 142 * 143 * @since 8.0.0 144 * 145 * @param array $args. 146 * @return bool 147 */ 148 public function allow_invitation( $args ) { 149 // Does the inviter have this capability? 150 if ( ! bp_user_can( $args['inviter_id'], 'bp_members_send_invitation' ) ) { 151 return false; 152 } 153 154 // Is the invited user eligible to receive an invitation? Hasn't opted out? 155 if ( ! bp_user_can( 0, 'bp_members_receive_invitation', $args ) ) { 156 return false; 157 } 158 159 return true; 160 } 161 162 /** 163 * Should this request be created? 164 * 165 * @since 8.0.0 166 * 167 * @param array $args. 168 * @return bool. 169 */ 170 public function allow_request( $args ) { 171 // Does the requester have this capability? 172 if ( ! bp_user_can( 0, 'bp_network_request_membership', $args ) ) { 173 return false; 174 } 175 176 return true; 177 } 178 } -
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..db5468ee4
- + 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 Invitations 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 * Invitation counts. 32 * 33 * @since 8.0.0 34 * @var int 35 */ 36 public $total_items = 0; 37 38 /** 39 * Constructor. 40 * 41 * @since 8.0.0 42 */ 43 public function __construct() { 44 // Define singular and plural labels, as well as whether we support AJAX. 45 parent::__construct( array( 46 'ajax' => false, 47 'plural' => 'invitations', 48 'singular' => 'invitation', 49 'screen' => get_current_screen()->id, 50 ) ); 51 } 52 53 /** 54 * Set up items for display in the list table. 55 * 56 * Handles filtering of data, sorting, pagination, and any other data 57 * manipulation required prior to rendering. 58 * 59 * @since 8.0.0 60 */ 61 public function prepare_items() { 62 global $usersearch; 63 64 $search = isset( $_REQUEST['s'] ) ? $_REQUEST['s'] : ''; 65 $per_page = $this->get_items_per_page( str_replace( '-', '_', "{$this->screen->id}_per_page" ) ); 66 $paged = $this->get_pagenum(); 67 68 $args = array( 69 'invite_sent' => 'all', 70 'accepted' => 'all', 71 'search_terms' => $search, 72 'order_by' => 'date_modified', 73 'sort_order' => 'DESC', 74 'page' => $paged, 75 'per_page' => $per_page, 76 ); 77 78 if ( isset( $_REQUEST['accepted'] ) && in_array( $_REQUEST['accepted'], array( 'pending', 'accepted' ), true ) ) { 79 $args['accepted'] = $_REQUEST['accepted']; 80 $this->active_filters[] = $_REQUEST['accepted']; 81 } 82 if ( isset( $_REQUEST['sent'] ) && in_array( $_REQUEST['sent'], array( 'draft', 'sent' ), true ) ) { 83 $args['invite_sent'] = $_REQUEST['sent']; 84 $this->active_filters[] = $_REQUEST['sent']; 85 } 86 87 if ( isset( $_REQUEST['orderby'] ) ) { 88 $args['order_by'] = $_REQUEST['orderby']; 89 } 90 91 if ( isset( $_REQUEST['order'] ) ) { 92 $args['sort_order'] = $_REQUEST['order']; 93 } 94 95 $invites_class = new BP_Members_Invitation_Manager(); 96 $this->items = $invites_class->get_invitations( $args ); 97 $this->total_items = $invites_class->get_invitations_total_count( $args ); 98 99 $this->set_pagination_args( array( 100 'total_items' => $this->total_items, 101 'per_page' => $per_page, 102 ) ); 103 } 104 105 /** 106 * Get the list of views available on this table (e.g. "all", "public"). 107 * 108 * @since 8.0.0 109 */ 110 public function views() { 111 $tools_url = bp_get_admin_url( 'tools.php' ); 112 113 if ( is_network_admin() ) { 114 $tools_url = network_admin_url( 'admin.php' ); 115 } 116 117 $url_base = add_query_arg( 118 array( 119 'page' => 'bp-members-invitations', 120 ), 121 $tools_url 122 ); 123 ?> 124 125 <h2 class="screen-reader-text"><?php 126 /* translators: accessibility text */ 127 esc_html_e( 'Filter invitations list', 'buddypress' ); 128 ?></h2> 129 <ul class="subsubsub"> 130 <li class="all"> 131 <a href="<?php echo esc_url( $url_base ); ?>" class="<?php if ( empty( $this->active_filters ) ) echo 'current'; ?>"> 132 <?php esc_html_e( 'All', 'buddypress' ); ?> 133 </a> | 134 </li> 135 <li class="pending"> 136 <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'; ?>"> 137 <?php esc_html_e( 'Pending', 'buddypress' ); ?> 138 </a> | 139 </li> 140 <li class="accepted"> 141 <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'; ?>"> 142 <?php esc_html_e( 'Accepted', 'buddypress' ); ?> 143 </a> | 144 </li> 145 <li class="draft"> 146 <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'; ?>"> 147 <?php esc_html_e( 'Draft (Unsent)', 'buddypress' ); ?> 148 </a> | 149 </li> 150 <li class="sent"> 151 <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'; ?>"> 152 <?php esc_html_e( 'Sent', 'buddypress' ); ?> 153 </a> 154 </li> 155 156 <?php 157 158 /** 159 * Fires inside listing of views so plugins can add their own. 160 * 161 * @since 8.0.0 162 * 163 * @param string $url_base Current URL base for view. 164 * @param array $active_filters Current filters being requested. 165 */ 166 do_action( 'bp_members_invitations_list_table_get_views', $url_base, $this->active_filters ); ?> 167 </ul> 168 <?php 169 } 170 171 /** 172 * Get rid of the extra nav. 173 * 174 * WP_Users_List_Table will add an extra nav to change user's role. 175 * As we're dealing with invitations, we don't need this. 176 * 177 * @since 8.0.0 178 * 179 * @param array $which Current table nav item. 180 */ 181 public function extra_tablenav( $which ) { 182 return; 183 } 184 185 /** 186 * Specific signups columns. 187 * 188 * @since 8.0.0 189 * 190 * @return array 191 */ 192 public function get_columns() { 193 194 /** 195 * Filters the single site Members signup columns. 196 * 197 * @since 8.0.0 198 * 199 * @param array $value Array of columns to display. 200 */ 201 return apply_filters( 'bp_members_invitations_list_columns', array( 202 'cb' => '<input type="checkbox" />', 203 'invitee_email' => __( 'Invitee', 'buddypress' ), 204 'username' => __( 'Inviter', 'buddypress' ), 205 'inviter_registered_date' => __( 'Inviter Registered', 'buddypress' ), 206 'invitation_date_modified' => __( 'Date Modified', 'buddypress' ), 207 'invitation_sent' => __( 'Email Sent', 'buddypress' ), 208 'invitation_accepted' => __( 'Accepted', 'buddypress' ) 209 ) ); 210 } 211 212 /** 213 * Specific bulk actions for signups. 214 * 215 * @since 8.0.0 216 */ 217 public function get_bulk_actions() { 218 $actions = array( 219 'resend' => _x( 'Resend Email', 'Pending invitation action', 'buddypress' ), 220 ); 221 222 if ( current_user_can( 'delete_users' ) ) { 223 $actions['delete'] = _x( 'Delete', 'Pending invitation action', 'buddypress' ); 224 } 225 226 return $actions; 227 } 228 229 /** 230 * The text shown when no items are found. 231 * 232 * Nice job, clean sheet! 233 * 234 * @since 8.0.0 235 */ 236 public function no_items() { 237 238 if ( bp_get_members_invitations_allowed() ) { 239 esc_html_e( 'No invitations found.', 'buddypress' ); 240 } else { 241 $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' ) ); 242 243 /* translators: %s: url to site settings */ 244 printf( __( 'Invitations are not allowed. %s', 'buddypress' ), $link ); 245 } 246 247 } 248 249 /** 250 * The columns invitations can be reordered by. 251 * 252 * @since 8.0.0 253 */ 254 public function get_sortable_columns() { 255 return array( 256 'invitee_email' => 'invitee_email', 257 'username' => 'inviter_id', 258 'invitation_date_modified' => 'date_modified', 259 'invitation_sent' => 'invite_sent', 260 'invitation_accepted' => 'accepted', 261 ); 262 } 263 264 /** 265 * Display invitation rows. 266 * 267 * @since 8.0.0 268 */ 269 public function display_rows() { 270 $style = ''; 271 foreach ( $this->items as $invite ) { 272 $style = ( ' class="alternate"' == $style ) ? '' : ' class="alternate"'; 273 echo "\n\t" . $this->single_row( $invite, $style ); 274 } 275 } 276 277 /** 278 * Display an invitation row. 279 * 280 * @since 8.0.0 281 * 282 * @see WP_List_Table::single_row() for explanation of params. 283 * 284 * @param BP_Invitation $invite BP_Invitation object. 285 * @param string $style Styles for the row. 286 * @param string $role Role to be assigned to user. 287 * @param int $numposts Number of posts. 288 * @return void 289 */ 290 public function single_row( $invite = null, $style = '', $role = '', $numposts = 0 ) { 291 echo '<tr' . $style . ' id="invitation-' . esc_attr( $invite->id ) . '">'; 292 echo $this->single_row_columns( $invite ); 293 echo '</tr>'; 294 } 295 296 /** 297 * Markup for the checkbox used to select items for bulk actions. 298 * 299 * @since 8.0.0 300 * 301 * @param BP_Invitation $invite BP_Invitation object. 302 */ 303 public function column_cb( $invite = null ) { 304 ?> 305 <label class="screen-reader-text" for="invitation_<?php echo intval( $invite->id ); ?>"><?php 306 /* translators: accessibility text */ 307 printf( esc_html__( 'Select invitation: %s', 'buddypress' ), $invite->id ); 308 ?></label> 309 <input type="checkbox" id="invitation_<?php echo intval( $invite->id ) ?>" name="invite_ids[]" value="<?php echo esc_attr( $invite->id ) ?>" /> 310 <?php 311 } 312 313 /** 314 * Markup for the checkbox used to select items for bulk actions. 315 * 316 * @since 8.0.0 317 * 318 * @param BP_Invitation $invite BP_Invitation object. 319 */ 320 public function column_invitee_email( $invite = null ) { 321 echo esc_html( $invite->invitee_email ); 322 323 $actions = array(); 324 $tools_url = bp_get_admin_url( 'tools.php' ); 325 326 if ( is_network_admin() ) { 327 $tools_url = network_admin_url( 'admin.php' ); 328 } 329 330 // Resend action only if pending 331 if ( ! $invite->accepted ) { 332 // Resend invitation email link. 333 $email_link = add_query_arg( 334 array( 335 'page' => 'bp-members-invitations', 336 'invite_id' => $invite->id, 337 'action' => 'resend', 338 ), 339 $tools_url 340 ); 341 342 if ( ! $invite->invite_sent ) { 343 $resend_label = __( 'Send', 'buddypress' ); 344 } else { 345 $resend_label = __( 'Resend', 'buddypress' ); 346 } 347 348 $actions['resend'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $email_link ), esc_html( $resend_label ) ); 349 } 350 351 // Delete link. Could be cleanup or revoking the invitation. 352 $delete_link = add_query_arg( 353 array( 354 'page' => 'bp-members-invitations', 355 'invite_id' => $invite->id, 356 'action' => 'delete', 357 ), 358 $tools_url 359 ); 360 361 // Two cases: unsent and accepted (cleanup), and pending (cancels invite). 362 if ( ! $invite->invite_sent || $invite->accepted ) { 363 $actions['delete'] = sprintf( '<a href="%1$s" class="delete">%2$s</a>', esc_url( $delete_link ), esc_html__( 'Delete', 'buddypress' ) ); 364 } else { 365 $actions['delete'] = sprintf( '<a href="%1$s" class="delete">%2$s</a>', esc_url( $delete_link ), esc_html__( 'Cancel', 'buddypress' ) ); 366 } 367 368 /** 369 * Filters the row actions for each invitation in list. 370 * 371 * @since 8.0.0 372 * 373 * @param array $actions Array of actions and corresponding links. 374 * @param object $invite The BP_Invitation. 375 */ 376 $actions = apply_filters( 'bp_members_invitations_management_row_actions', $actions, $invite ); 377 378 echo $this->row_actions( $actions ); 379 } 380 381 /** 382 * Display invited user's email address. 383 * 384 * @since 8.0.0 385 * 386 * @param BP_Invitation $invite BP_Invitation object. 387 */ 388 public function column_email( $invite = null ) { 389 printf( '<a href="mailto:%1$s">%2$s</a>', esc_attr( $invite->user_email ), esc_html( $invite->user_email ) ); 390 } 391 392 /** 393 * The inviter. 394 * 395 * @since 8.0.0 396 * 397 * @param BP_Invitation $invite BP_Invitation object. 398 */ 399 public function column_username( $invite = null ) { 400 $avatar = get_avatar( $invite->inviter_id, 32 ); 401 $inviter = get_user_by( 'id', $invite->inviter_id ); 402 if ( ! $inviter ) { 403 return; 404 } 405 406 $user_link = bp_core_get_user_domain( $invite->inviter_id ); 407 408 printf( '%1$s <strong><a href="%2$s" class="edit">%3$s</a></strong><br/>', $avatar, esc_url( $user_link ), esc_html( $inviter->user_login ) ); 409 } 410 411 /** 412 * Display invitation date. 413 * 414 * @since 8.0.0 415 * 416 * @param BP_Invitation $invite BP_Invitation object. 417 */ 418 public function column_inviter_registered_date( $invite = null ) { 419 $inviter = get_user_by( 'id', $invite->inviter_id ); 420 if ( ! $inviter ) { 421 return; 422 } 423 echo esc_html( $inviter->user_registered ); 424 } 425 426 /** 427 * Display invitation date. 428 * 429 * @since 8.0.0 430 * 431 * @param BP_Invitation $invite BP_Invitation object. 432 */ 433 public function column_invitation_date_modified( $invite = null ) { 434 echo esc_html( $invite->date_modified ); 435 } 436 437 /** 438 * Display invitation date. 439 * 440 * @since 8.0.0 441 * 442 * @param BP_Invitation $invite BP_Invitation object. 443 */ 444 public function column_invitation_sent( $invite = null ) { 445 if ( $invite->invite_sent) { 446 esc_html_e( 'Yes', 'buddypress' ); 447 } else { 448 esc_html_e( 'No', 'buddypress' ); 449 } 450 } 451 452 /** 453 * Display invitation acceptance status. 454 * 455 * @since 8.0.0 456 * 457 * @param BP_Invitation $invite BP_Invitation object. 458 */ 459 public function column_invitation_accepted( $invite = null ) { 460 if ( $invite->accepted ) { 461 esc_html_e( 'Yes', 'buddypress' ); 462 } else { 463 esc_html_e( 'No', 'buddypress' ); 464 } 465 } 466 467 /** 468 * Allow plugins to add their custom column. 469 * 470 * @since 8.0.0 471 * 472 * @param BP_Invitation $invite BP_Invitation object. 473 * @param string $column_name The column name. 474 * @return string 475 */ 476 function column_default( $invite = null, $column_name = '' ) { 477 478 /** 479 * Filters the single site custom columns for plugins. 480 * 481 * @since 8.0.0 482 * 483 * @param string $column_name The column name. 484 * @param object $invite The BP_Invitation object.. 485 */ 486 return apply_filters( 'bp_members_invitations_management_custom_column', '', $column_name, $invite ); 487 } 488 } -
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..7f1bd91af
- + 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 8.0.0 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..600cee733
- + 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..77929c442 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 && $maybe_invite->invitee_email ) { 51 // Check if this user is already a member. 52 $args = array( 53 'invitee_email' => $maybe_invite->invitee_email, 54 'accepted' => 'accepted', 55 'fields' => 'ids', 56 ); 57 $accepted_invites = bp_members_invitations_get_invites( $args ); 58 if ( ! $accepted_invites ) { 59 $active_invite = true; 60 } 61 } 62 } 47 63 64 if ( ! bp_get_signup_allowed() && ! $active_invite ) { 65 $bp->signup->step = 'registration-disabled'; 48 66 // If the signup page is submitted, validate and save. 49 67 } elseif ( isset( $_POST['signup_submit'] ) && bp_verify_nonce_request( 'bp_new_signup' ) ) { 50 68 -
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..f2af326e2
- + 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_members_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. The user could already be a member of the site or have chosen not to receive invitations from this site.', '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' ); -
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..4da3d1ae9 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>' . $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..f73857cc8
- + 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"> 17 <label class="bp-screen-reader-text" for="select-all-invitations"> 18 <?php 19 /* translators: accessibility text */ 20 esc_html_e( 'Select all', 'buddypress' ); 21 ?> 22 </label> 23 </th> 24 <th class="title"><?php esc_html_e( 'Invitee', 'buddypress' ); ?></th> 25 <th class="content"><?php esc_html_e( 'Message', 'buddypress' ); ?></th> 26 <th class="sent"><?php esc_html_e( 'Sent', 'buddypress' ); ?></th> 27 <th class="accepted"><?php esc_html_e( 'Accepted', 'buddypress' ); ?></th> 28 <th class="date"><?php esc_html_e( 'Date Modified', 'buddypress' ); ?></th> 29 <th class="actions"><?php esc_html_e( 'Actions', 'buddypress' ); ?></th> 30 </tr> 31 </thead> 32 33 <tbody> 34 35 <?php while ( bp_the_members_invitations() ) : bp_the_members_invitation(); ?> 36 37 <tr> 38 <td></td> 39 <td class="bulk-select-check"> 40 <label for="<?php bp_the_members_invitation_property( 'id', 'attribute' ); ?>"> 41 <input id="<?php bp_the_members_invitation_property( 'id', 'attribute' ); ?>" type="checkbox" name="network_invitations[]" value="<?php bp_the_members_invitation_property( 'id', 'attribute' ); ?>" class="invitation-check"> 42 <span class="bp-screen-reader-text"> 43 <?php 44 /* translators: accessibility text */ 45 esc_html_e( 'Select this invitation', 'buddypress' ); 46 ?> 47 </span> 48 </label> 49 </td> 50 <td class="invitation-invitee"><?php bp_the_members_invitation_property( 'invitee_email' ); ?></td> 51 <td class="invitation-content"><?php bp_the_members_invitation_property( 'content' ); ?></td> 52 <td class="invitation-sent"><?php bp_the_members_invitation_property( 'invite_sent' ); ?></td> 53 <td class="invitation-accepted"><?php bp_the_members_invitation_property( 'accepted' ); ?></td> 54 <td class="invitation-date-modified"><?php bp_the_members_invitation_property( 'date_modified' ); ?></td> 55 <td class="invitation-actions"><?php bp_the_members_invitation_action_links(); ?></td> 56 </tr> 57 58 <?php endwhile; ?> 59 60 </tbody> 61 </table> 62 63 <div class="invitations-options-nav"> 64 <?php // @TODO //bp_invitations_bulk_management_dropdown(); ?> 65 </div><!-- .invitations-options-nav --> 66 67 <?php wp_nonce_field( 'invitations_bulk_nonce', 'invitations_bulk_nonce' ); ?> 68 </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..8e299f1d6
- + 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"> 14 <?php 15 /* translators: accessibility text */ 16 esc_html_e( 'Invitations', 'buddypress' ); 17 ?> 18 </h2> 19 20 <div id="pag-top" class="pagination no-ajax"> 21 <div class="pag-count" id="invitations-count-top"> 22 <?php bp_members_invitations_pagination_count(); ?> 23 </div> 24 25 <div class="pagination-links" id="invitations-pag-top"> 26 <?php bp_members_invitations_pagination_links(); ?> 27 </div> 28 </div> 29 30 <?php bp_get_template_part( 'members/single/invitations/invitations-loop' ); ?> 31 32 <div id="pag-bottom" class="pagination no-ajax"> 33 <div class="pag-count" id="invitations-count-bottom"> 34 <?php bp_members_invitations_pagination_count(); ?> 35 </div> 36 37 <div class="pagination-links" id="invitations-pag-bottom"> 38 <?php bp_members_invitations_pagination_links(); ?> 39 </div> 40 </div> 41 42 <?php else : ?> 43 44 <p><?php esc_html_e( 'There are no invitations to display.', 'buddypress' ); ?></p> 45 46 <?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..6eeb3b62f
- + 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"> 11 <?php 12 /* translators: accessibility text */ 13 esc_html_e( 'Send Invitations', 'buddypress' ); 14 ?> 15 </h2> 16 17 <form class="standard-form members-invitation-form" id="members-invitation-form" method="post"> 18 <p class="description"><?php esc_html_e( 'Fill out the form below to invite a new user to join this site. Upon submission of the form, an email will be sent to the invitee containing a link to accept your invitation. You may also add a custom message to the email.', 'buddypress' ); ?></p> 19 20 <label for="bp_members_invitation_invitee_email"><?php esc_html_e( 'Email address of new user', 'buddypress' ); ?></label> 21 <input id="bp_members_invitation_invitee_email" type="email" name="invitee_email" required="required"> 22 23 <label for="bp_members_invitation_message"><?php esc_html_e( 'Add a personalized message to the invitation (optional)', 'buddypress' ); ?></label> 24 <textarea id="bp_members_invitation_message" name="invite_message"></textarea> 25 26 <input type="hidden" name="action" value="send-invite"> 27 28 <?php wp_nonce_field( 'bp_members_invitation_send_' . bp_displayed_user_id() ) ?> 29 <p> 30 <input id="submit" type="submit" name="submit" class="submit" value="<?php esc_attr_e( 'Send Invitation', 'buddypress' ) ?>" /> 31 </p> 32 </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..1fd36bab1
- + 1 <?php 2 /** 3 * BuddyPress - Membership invitations 4 * 5 * @since 8.0.0 6 * @version 8.0.0 7 */ 8 ?> 9 10 <nav class="<?php bp_nouveau_single_item_subnav_classes(); ?>" id="subnav" role="navigation" aria-label="<?php esc_attr_e( 'Groups menu', 'buddypress' ); ?>"> 11 <ul class="subnav"> 12 <?php bp_get_template_part( 'members/single/parts/item-subnav' ); ?> 13 </ul> 14 </nav><!-- .bp-navs --> 15 16 <?php 17 switch ( bp_current_action() ) : 18 19 case 'send-invites' : 20 bp_get_template_part( 'members/single/invitations/send-invites' ); 21 break; 22 23 case 'list-invites' : 24 default : 25 bp_get_template_part( 'members/single/invitations/list-invites' ); 26 break; 27 28 endswitch; 29 -
new file src/bp-templates/bp-nouveau/buddypress/members/single/invitations/invitations-loop.php
diff --git src/bp-templates/bp-nouveau/buddypress/members/single/invitations/invitations-loop.php src/bp-templates/bp-nouveau/buddypress/members/single/invitations/invitations-loop.php new file mode 100644 index 000000000..f4aa643ee
- + 1 <?php 2 /** 3 * BuddyPress - Membership Invitations Loop 4 * 5 * @since 8.0.0 6 * @version 8.0.0 7 */ 8 ?> 9 <form action="" method="post" id="invitations-bulk-management" class="standard-form"> 10 <table class="invitations"> 11 <thead> 12 <tr> 13 <th class="bulk-select-all"><input id="select-all-invitations" type="checkbox"> 14 <label class="bp-screen-reader-text" for="select-all-invitations"> 15 <?php 16 /* translators: accessibility text */ 17 esc_html_e( 'Select all', 'buddypress' ); 18 ?> 19 </label> 20 </th> 21 <th class="title"><?php esc_html_e( 'Invitee', 'buddypress' ); ?></th> 22 <th class="content"><?php esc_html_e( 'Message', 'buddypress' ); ?></th> 23 <th class="sent"><?php esc_html_e( 'Sent', 'buddypress' ); ?></th> 24 <th class="accepted"><?php esc_html_e( 'Accepted', 'buddypress' ); ?></th> 25 <th class="date"><?php esc_html_e( 'Date Modified', 'buddypress' ); ?></th> 26 <th class="actions"><?php esc_html_e( 'Actions', 'buddypress' ); ?></th> 27 </tr> 28 </thead> 29 30 <tbody> 31 32 <?php while ( bp_the_members_invitations() ) : bp_the_members_invitation(); ?> 33 34 <tr> 35 <td class="bulk-select-check"> 36 <label for="<?php bp_the_members_invitation_property( 'id', 'attribute' ); ?>"> 37 <input id="<?php bp_the_members_invitation_property( 'id', 'attribute' ); ?>" type="checkbox" name="network_invitations[]" value="<?php bp_the_members_invitation_property( 'id', 'attribute' ); ?>" class="invitation-check"> 38 <span class="bp-screen-reader-text"> 39 <?php 40 /* translators: accessibility text */ 41 esc_html_e( 'Select this invitation', 'buddypress' ); 42 ?> 43 </span> 44 </label> 45 </td> 46 <td class="invitation-invitee"><?php bp_the_members_invitation_property( 'invitee_email' ); ?></td> 47 <td class="invitation-content"><?php bp_the_members_invitation_property( 'content' ); ?></td> 48 <td class="invitation-sent"><?php bp_the_members_invitation_property( 'invite_sent' ); ?></td> 49 <td class="invitation-accepted"><?php bp_the_members_invitation_property( 'accepted' ); ?></td> 50 <td class="invitation-date-modified"><?php bp_the_members_invitation_property( 'date_modified' ); ?></td> 51 <td class="invitation-actions"><?php bp_the_members_invitation_action_links(); ?></td> 52 </tr> 53 54 <?php endwhile; ?> 55 56 </tbody> 57 </table> 58 59 <div class="invitations-options-nav"> 60 <?php bp_nouveau_invitations_bulk_management_dropdown(); ?> 61 </div><!-- .invitations-options-nav --> 62 63 <?php wp_nonce_field( 'invitations_bulk_nonce', 'invitations_bulk_nonce' ); ?> 64 </form> -
new file src/bp-templates/bp-nouveau/buddypress/members/single/invitations/list-invites.php
diff --git src/bp-templates/bp-nouveau/buddypress/members/single/invitations/list-invites.php src/bp-templates/bp-nouveau/buddypress/members/single/invitations/list-invites.php new file mode 100644 index 000000000..a83054098
- + 1 <?php 2 /** 3 * BuddyPress - Pending Membership Invitations 4 * 5 * @since 8.0.0 6 * @version 8.0.0 7 */ 8 ?> 9 10 <?php if ( bp_has_members_invitations() ) : ?> 11 12 <h2 class="bp-screen-reader-text"> 13 <?php 14 /* translators: accessibility text */ 15 esc_html_e( 'Invitations', 'buddypress' ); 16 ?> 17 </h2> 18 19 <div id="pag-top" class="bp-pagination no-ajax"> 20 <div class="pag-count" id="invitations-count-top"> 21 <?php bp_members_invitations_pagination_count(); ?> 22 </div> 23 24 <div class="pagination-links" id="invitations-pag-top"> 25 <?php bp_members_invitations_pagination_links(); ?> 26 </div> 27 </div> 28 29 <?php bp_get_template_part( 'members/single/invitations/invitations-loop' ); ?> 30 31 <div id="pag-bottom" class="bp-pagination no-ajax"> 32 <div class="pag-count" id="invitations-count-bottom"> 33 <?php bp_members_invitations_pagination_count(); ?> 34 </div> 35 36 <div class="pagination-links" id="invitations-pag-bottom"> 37 <?php bp_members_invitations_pagination_links(); ?> 38 </div> 39 </div> 40 41 <?php else : ?> 42 43 <?php bp_nouveau_user_feedback( 'member-invites-none' ); ?> 44 45 <?php endif; -
new file src/bp-templates/bp-nouveau/buddypress/members/single/invitations/send-invites.php
diff --git src/bp-templates/bp-nouveau/buddypress/members/single/invitations/send-invites.php src/bp-templates/bp-nouveau/buddypress/members/single/invitations/send-invites.php new file mode 100644 index 000000000..077c1fa24
- + 1 <?php 2 /** 3 * BuddyPress - Send a Membership Invitation. 4 * 5 * @since 8.0.0 6 * @version 8.0.0 7 */ 8 ?> 9 <h2 class="bp-screen-reader-text"> 10 <?php 11 /* translators: accessibility text */ 12 esc_html_e( 'Send Invitation', 'buddypress' ); 13 ?> 14 </h2> 15 16 <p class="bp-feedback info"> 17 <span class="bp-icon" aria-hidden="true"></span> 18 <span class="bp-help-text"> 19 <?php esc_html_e( 'Fill out the form below to invite a new user to join this site. Upon submission of the form, an email will be sent to the invitee containing a link to accept your invitation. You may also add a custom message to the email.', 'buddypress' ); ?> 20 </span> 21 </p> 22 23 <form class="standard-form network-invitation-form" id="network-invitation-form" method="post"> 24 <label for="bp_members_invitation_invitee_email"> 25 <?php esc_html_e( 'Email', 'buddypress' ); ?> 26 <span class="bp-required-field-label"><?php esc_html_e( '(required)', 'buddypress' ); ?></span> 27 </label> 28 <input id="bp_members_invitation_invitee_email" type="email" name="invitee_email" required="required"> 29 30 <label for="bp_members_invitation_message"> 31 <?php esc_html_e( 'Add a personalized message to the invitation (optional)', 'buddypress' ); ?> 32 </label> 33 <textarea id="bp_members_invitation_message" name="invite_message"></textarea> 34 35 <input type="hidden" name="action" value="send-invite"> 36 37 <?php bp_nouveau_submit_button( 'member-send-invite' ); ?> 38 </form> -
src/bp-templates/bp-nouveau/common-styles/_bp_filters.scss
diff --git src/bp-templates/bp-nouveau/common-styles/_bp_filters.scss src/bp-templates/bp-nouveau/common-styles/_bp_filters.scss index 8ff5970f1..1317aee14 100644
181 181 182 182 } // close .subnav-filters 183 183 184 .notifications-options-nav { 185 186 input#notification-bulk-manage { 187 border: 0; 188 border-radius: 0; 189 line-height: 1.6; 190 } 184 .notifications-options-nav input#notification-bulk-manage, 185 .invitations-options-nav input#invitation-bulk-manage { 186 border: 0; 187 border-radius: 0; 188 line-height: 1.6; 191 189 } 192 190 193 191 .group-subnav-filters { -
src/bp-templates/bp-nouveau/common-styles/_bp_forms.scss
diff --git src/bp-templates/bp-nouveau/common-styles/_bp_forms.scss src/bp-templates/bp-nouveau/common-styles/_bp_forms.scss index b39d8a03c..9453a4452 100644
24 24 opacity: 0.4; 25 25 } 26 26 27 #notification-bulk-manage[disabled] { 27 #notification-bulk-manage[disabled], 28 #invitation-bulk-manage[disabled] { 28 29 display: none; 29 30 } 30 31 … … body.no-js { 399 400 400 401 @include medium-small-up() { 401 402 402 .notifications-options-nav { 403 404 .select-wrap { 405 float: left; 406 } 403 .notifications-options-nav .select-wrap, 404 .invitations-options-nav .select-wrap { 405 float: left; 407 406 } 408 407 } 409 408 } -
src/bp-templates/bp-nouveau/common-styles/_bp_generic_and_typography.scss
diff --git src/bp-templates/bp-nouveau/common-styles/_bp_generic_and_typography.scss src/bp-templates/bp-nouveau/common-styles/_bp_generic_and_typography.scss index 65cabf5e7..2d2799368 100644
body.buddypress { 255 255 } 256 256 } 257 257 258 #notification-select { 258 #notification-select, 259 #invitation-select { 259 260 260 261 @include responsive-font(14); 261 262 } -
src/bp-templates/bp-nouveau/css/buddypress-rtl.css
diff --git src/bp-templates/bp-nouveau/css/buddypress-rtl.css src/bp-templates/bp-nouveau/css/buddypress-rtl.css index 35b21b66d..20f7c1a32 100644
body.buddypress article.page > .entry-header:not(.alignwide):not(.alignfull) .en 255 255 } 256 256 } 257 257 258 .buddypress-wrap #notification-select { 258 .buddypress-wrap #notification-select, 259 .buddypress-wrap #invitation-select { 259 260 font-size: 12px; 260 261 } 261 262 262 263 @media screen and (min-width: 46.8em) { 263 .buddypress-wrap #notification-select { 264 .buddypress-wrap #notification-select, 265 .buddypress-wrap #invitation-select { 264 266 font-size: 14px; 265 267 } 266 268 } … … body.buddypress article.page > .entry-header:not(.alignwide):not(.alignfull) .en 794 796 } 795 797 } 796 798 797 .buddypress-wrap .notifications-options-nav input#notification-bulk-manage { 799 .buddypress-wrap .notifications-options-nav input#notification-bulk-manage, 800 .buddypress-wrap .invitations-options-nav input#invitation-bulk-manage { 798 801 border: 0; 799 802 border-radius: 0; 800 803 line-height: 1.6; … … body.buddypress.settings.data #buddypress.buddypress-wrap .item-body p a { 3430 3433 opacity: 0.4; 3431 3434 } 3432 3435 3433 .buddypress-wrap #notification-bulk-manage[disabled] { 3436 .buddypress-wrap #notification-bulk-manage[disabled], 3437 .buddypress-wrap #invitation-bulk-manage[disabled] { 3434 3438 display: none; 3435 3439 } 3436 3440 … … body.no-js .buddypress #messages-bulk-management #select-all-messages { 3727 3731 } 3728 3732 3729 3733 @media screen and (min-width: 32em) { 3730 .buddypress-wrap .notifications-options-nav .select-wrap { 3734 .buddypress-wrap .notifications-options-nav .select-wrap, 3735 .buddypress-wrap .invitations-options-nav .select-wrap { 3731 3736 float: right; 3732 3737 } 3733 3738 } -
src/bp-templates/bp-nouveau/css/buddypress.css
diff --git src/bp-templates/bp-nouveau/css/buddypress.css src/bp-templates/bp-nouveau/css/buddypress.css index 2196e878f..7cc80ca7f 100644
body.buddypress article.page > .entry-header:not(.alignwide):not(.alignfull) .en 255 255 } 256 256 } 257 257 258 .buddypress-wrap #notification-select { 258 .buddypress-wrap #notification-select, 259 .buddypress-wrap #invitation-select { 259 260 font-size: 12px; 260 261 } 261 262 262 263 @media screen and (min-width: 46.8em) { 263 .buddypress-wrap #notification-select { 264 .buddypress-wrap #notification-select, 265 .buddypress-wrap #invitation-select { 264 266 font-size: 14px; 265 267 } 266 268 } … … body.buddypress article.page > .entry-header:not(.alignwide):not(.alignfull) .en 794 796 } 795 797 } 796 798 797 .buddypress-wrap .notifications-options-nav input#notification-bulk-manage { 799 .buddypress-wrap .notifications-options-nav input#notification-bulk-manage, 800 .buddypress-wrap .invitations-options-nav input#invitation-bulk-manage { 798 801 border: 0; 799 802 border-radius: 0; 800 803 line-height: 1.6; … … body.buddypress.settings.data #buddypress.buddypress-wrap .item-body p a { 3430 3433 opacity: 0.4; 3431 3434 } 3432 3435 3433 .buddypress-wrap #notification-bulk-manage[disabled] { 3436 .buddypress-wrap #notification-bulk-manage[disabled], 3437 .buddypress-wrap #invitation-bulk-manage[disabled] { 3434 3438 display: none; 3435 3439 } 3436 3440 … … body.no-js .buddypress #messages-bulk-management #select-all-messages { 3727 3731 } 3728 3732 3729 3733 @media screen and (min-width: 32em) { 3730 .buddypress-wrap .notifications-options-nav .select-wrap { 3734 .buddypress-wrap .notifications-options-nav .select-wrap, 3735 .buddypress-wrap .invitations-options-nav .select-wrap { 3731 3736 float: left; 3732 3737 } 3733 3738 } -
src/bp-templates/bp-nouveau/css/twentytwentyone-rtl.css
diff --git src/bp-templates/bp-nouveau/css/twentytwentyone-rtl.css src/bp-templates/bp-nouveau/css/twentytwentyone-rtl.css index 453826cd5..d3d05a346 100644
Hello, this is the BP Nouveau's Twenty Twenty-One companion stylesheet. 154 154 padding-right: 0; 155 155 } 156 156 157 #buddypress.twentytwentyone .notifications-options-nav { 157 #buddypress.twentytwentyone .notifications-options-nav, 158 #buddypress.twentytwentyone .invitations-options-nav { 158 159 margin-top: 1em; 159 160 } 160 161 161 #buddypress.twentytwentyone .notifications-options-nav input#notification-bulk-manage { 162 #buddypress.twentytwentyone .notifications-options-nav input#notification-bulk-manage, 163 #buddypress.twentytwentyone .invitations-options-nav input#invitation-bulk-manage { 162 164 line-height: 1.2; 163 165 } 164 166 -
src/bp-templates/bp-nouveau/css/twentytwentyone.css
diff --git src/bp-templates/bp-nouveau/css/twentytwentyone.css src/bp-templates/bp-nouveau/css/twentytwentyone.css index ecfaf8d9e..a8837db02 100644
Hello, this is the BP Nouveau's Twenty Twenty-One companion stylesheet. 154 154 padding-left: 0; 155 155 } 156 156 157 #buddypress.twentytwentyone .notifications-options-nav { 157 #buddypress.twentytwentyone .notifications-options-nav, 158 #buddypress.twentytwentyone .invitations-options-nav { 158 159 margin-top: 1em; 159 160 } 160 161 161 #buddypress.twentytwentyone .notifications-options-nav input#notification-bulk-manage { 162 #buddypress.twentytwentyone .notifications-options-nav input#notification-bulk-manage, 163 #buddypress.twentytwentyone .invitations-options-nav input#invitation-bulk-manage { 162 164 line-height: 1.2; 163 165 } 164 166 -
src/bp-templates/bp-nouveau/includes/functions.php
diff --git src/bp-templates/bp-nouveau/includes/functions.php src/bp-templates/bp-nouveau/includes/functions.php index 9ee9b52c5..1b17c6294 100644
function bp_nouveau_theme_cover_image( $params = array() ) { 927 927 * All user feedback messages are available here 928 928 * 929 929 * @since 3.0.0 930 * @since 8.0.0 Adds the 'member-invites-none' feedback. 930 931 * 931 932 * @param string $feedback_id The ID of the message. 932 933 * … … function bp_nouveau_get_user_feedback( $feedback_id = '' ) { 939 940 * Use this filter to add your custom feedback messages. 940 941 * 941 942 * @since 3.0.0 943 * @since 8.0.0 Adds the 'member-invites-none' feedback. 942 944 * 943 945 * @param array $value The list of feedback messages. 944 946 */ 945 $feedback_messages = apply_filters( 'bp_nouveau_feedback_messages', array( 946 'registration-disabled' => array( 947 'type' => 'info', 948 'message' => __( 'Member registration is currently not allowed.', 'buddypress' ), 949 'before' => 'bp_before_registration_disabled', 950 'after' => 'bp_after_registration_disabled' 951 ), 952 'request-details' => array( 953 'type' => 'info', 954 'message' => __( 'Registering for this site is easy. Just fill in the fields below, and we\'ll get a new account set up for you in no time.', 'buddypress' ), 955 'before' => false, 956 'after' => false, 957 ), 958 'completed-confirmation' => array( 959 'type' => 'info', 960 'message' => __( 'You have successfully created your account! Please log in using the username and password you have just created.', 'buddypress' ), 961 'before' => 'bp_before_registration_confirmed', 962 'after' => 'bp_after_registration_confirmed', 963 ), 964 'directory-activity-loading' => array( 965 'type' => 'loading', 966 'message' => __( 'Loading the community updates. Please wait.', 'buddypress' ), 967 ), 968 'single-activity-loading' => array( 969 'type' => 'loading', 970 'message' => __( 'Loading the update. Please wait.', 'buddypress' ), 971 ), 972 'activity-loop-none' => array( 973 'type' => 'info', 974 'message' => __( 'Sorry, there was no activity found. Please try a different filter.', 'buddypress' ), 975 ), 976 'blogs-loop-none' => array( 977 'type' => 'info', 978 'message' => __( 'Sorry, there were no sites found.', 'buddypress' ), 979 ), 980 'blogs-no-signup' => array( 981 'type' => 'info', 982 'message' => __( 'Site registration is currently disabled.', 'buddypress' ), 983 ), 984 'directory-blogs-loading' => array( 985 'type' => 'loading', 986 'message' => __( 'Loading the sites of the network. Please wait.', 'buddypress' ), 987 ), 988 'directory-groups-loading' => array( 989 'type' => 'loading', 990 'message' => __( 'Loading the groups of the community. Please wait.', 'buddypress' ), 991 ), 992 'groups-loop-none' => array( 993 'type' => 'info', 994 'message' => __( 'Sorry, there were no groups found.', 'buddypress' ), 995 ), 996 'group-activity-loading' => array( 997 'type' => 'loading', 998 'message' => __( 'Loading the group updates. Please wait.', 'buddypress' ), 999 ), 1000 'group-members-loading' => array( 1001 'type' => 'loading', 1002 'message' => __( 'Requesting the group members. Please wait.', 'buddypress' ), 1003 ), 1004 'group-members-none' => array( 1005 'type' => 'info', 1006 'message' => __( 'Sorry, there were no group members found.', 'buddypress' ), 1007 ), 1008 'group-members-search-none' => array( 1009 'type' => 'info', 1010 'message' => __( 'Sorry, there was no member of that name found in this group.', 'buddypress' ), 1011 ), 1012 'group-manage-members-none' => array( 1013 'type' => 'info', 1014 'message' => __( 'This group has no members.', 'buddypress' ), 1015 ), 1016 'group-requests-none' => array( 1017 'type' => 'info', 1018 'message' => __( 'There are no pending membership requests.', 'buddypress' ), 1019 ), 1020 'group-requests-loading' => array( 1021 'type' => 'loading', 1022 'message' => __( 'Loading the members who requested to join the group. Please wait.', 'buddypress' ), 1023 ), 1024 'group-delete-warning' => array( 1025 'type' => 'warning', 1026 'message' => __( 'WARNING: Deleting this group will completely remove ALL content associated with it. There is no way back. Please be careful with this option.', 'buddypress' ), 1027 ), 1028 'group-avatar-delete-info' => array( 1029 'type' => 'info', 1030 'message' => __( 'If you\'d like to remove the existing group profile photo but not upload a new one, please use the delete group profile photo button.', 'buddypress' ), 1031 ), 1032 'directory-members-loading' => array( 1033 'type' => 'loading', 1034 'message' => __( 'Loading the members of your community. Please wait.', 'buddypress' ), 1035 ), 1036 'members-loop-none' => array( 1037 'type' => 'info', 1038 'message' => __( 'Sorry, no members were found.', 'buddypress' ), 1039 ), 1040 'member-requests-none' => array( 1041 'type' => 'info', 1042 'message' => __( 'You have no pending friendship requests.', 'buddypress' ), 1043 ), 1044 'member-invites-none' => array( 1045 'type' => 'info', 1046 'message' => __( 'You have no outstanding group invites.', 'buddypress' ), 1047 ), 1048 'member-notifications-none' => array( 1049 'type' => 'info', 1050 'message' => __( 'This member has no notifications.', 'buddypress' ), 1051 ), 1052 'member-wp-profile-none' => array( 1053 'type' => 'info', 1054 /* translators: %s: member name */ 1055 'message' => __( '%s did not save any profile information yet.', 'buddypress' ), 1056 ), 1057 'member-delete-account' => array( 1058 'type' => 'warning', 1059 'message' => __( 'Deleting this account will delete all of the content it has created. It will be completely unrecoverable.', 'buddypress' ), 1060 ), 1061 'member-activity-loading' => array( 1062 'type' => 'loading', 1063 'message' => __( 'Loading the member\'s updates. Please wait.', 'buddypress' ), 1064 ), 1065 'member-blogs-loading' => array( 1066 'type' => 'loading', 1067 'message' => __( 'Loading the member\'s blogs. Please wait.', 'buddypress' ), 1068 ), 1069 'member-friends-loading' => array( 1070 'type' => 'loading', 1071 'message' => __( 'Loading the member\'s friends. Please wait.', 'buddypress' ), 1072 ), 1073 'member-groups-loading' => array( 1074 'type' => 'loading', 1075 'message' => __( 'Loading the member\'s groups. Please wait.', 'buddypress' ), 1076 ), 1077 'member-notifications-loading' => array( 1078 'type' => 'loading', 1079 'message' => __( 'Loading notifications. Please wait.', 'buddypress' ), 1080 ), 1081 'member-group-invites-all' => array( 1082 'type' => 'info', 1083 'message' => __( 'Currently every member of the community can invite you to join their groups. If you are not comfortable with it, you can always restrict group invites to your friends only.', 'buddypress' ), 1084 ), 1085 'member-group-invites-friends-only' => array( 1086 'type' => 'info', 1087 'message' => __( 'Currently only your friends can invite you to groups. Uncheck the box to allow any member to send invites.', 'buddypress' ), 1088 ), 1089 ) ); 947 $feedback_messages = apply_filters( 948 'bp_nouveau_feedback_messages', 949 array( 950 'registration-disabled' => array( 951 'type' => 'info', 952 'message' => __( 'Member registration is currently not allowed.', 'buddypress' ), 953 'before' => 'bp_before_registration_disabled', 954 'after' => 'bp_after_registration_disabled' 955 ), 956 'request-details' => array( 957 'type' => 'info', 958 'message' => __( 'Registering for this site is easy. Just fill in the fields below, and we\'ll get a new account set up for you in no time.', 'buddypress' ), 959 'before' => false, 960 'after' => false, 961 ), 962 'completed-confirmation' => array( 963 'type' => 'info', 964 'message' => __( 'You have successfully created your account! Please log in using the username and password you have just created.', 'buddypress' ), 965 'before' => 'bp_before_registration_confirmed', 966 'after' => 'bp_after_registration_confirmed', 967 ), 968 'directory-activity-loading' => array( 969 'type' => 'loading', 970 'message' => __( 'Loading the community updates. Please wait.', 'buddypress' ), 971 ), 972 'single-activity-loading' => array( 973 'type' => 'loading', 974 'message' => __( 'Loading the update. Please wait.', 'buddypress' ), 975 ), 976 'activity-loop-none' => array( 977 'type' => 'info', 978 'message' => __( 'Sorry, there was no activity found. Please try a different filter.', 'buddypress' ), 979 ), 980 'blogs-loop-none' => array( 981 'type' => 'info', 982 'message' => __( 'Sorry, there were no sites found.', 'buddypress' ), 983 ), 984 'blogs-no-signup' => array( 985 'type' => 'info', 986 'message' => __( 'Site registration is currently disabled.', 'buddypress' ), 987 ), 988 'directory-blogs-loading' => array( 989 'type' => 'loading', 990 'message' => __( 'Loading the sites of the network. Please wait.', 'buddypress' ), 991 ), 992 'directory-groups-loading' => array( 993 'type' => 'loading', 994 'message' => __( 'Loading the groups of the community. Please wait.', 'buddypress' ), 995 ), 996 'groups-loop-none' => array( 997 'type' => 'info', 998 'message' => __( 'Sorry, there were no groups found.', 'buddypress' ), 999 ), 1000 'group-activity-loading' => array( 1001 'type' => 'loading', 1002 'message' => __( 'Loading the group updates. Please wait.', 'buddypress' ), 1003 ), 1004 'group-members-loading' => array( 1005 'type' => 'loading', 1006 'message' => __( 'Requesting the group members. Please wait.', 'buddypress' ), 1007 ), 1008 'group-members-none' => array( 1009 'type' => 'info', 1010 'message' => __( 'Sorry, there were no group members found.', 'buddypress' ), 1011 ), 1012 'group-members-search-none' => array( 1013 'type' => 'info', 1014 'message' => __( 'Sorry, there was no member of that name found in this group.', 'buddypress' ), 1015 ), 1016 'group-manage-members-none' => array(