[ Index ] |
PHP Cross Reference of BuddyPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * BuddyPress Members Admin 4 * 5 * @package BuddyPress 6 * @subpackage MembersAdmin 7 * @since 2.0.0 8 */ 9 10 // Exit if accessed directly. 11 defined( 'ABSPATH' ) || exit; 12 13 if ( !class_exists( 'BP_Members_Admin' ) ) : 14 15 /** 16 * Load Members admin area. 17 * 18 * @since 2.0.0 19 */ 20 class BP_Members_Admin { 21 22 /** Directory *************************************************************/ 23 24 /** 25 * Path to the BP Members Admin directory. 26 * 27 * @var string $admin_dir 28 */ 29 public $admin_dir = ''; 30 31 /** URLs ******************************************************************/ 32 33 /** 34 * URL to the BP Members Admin directory. 35 * 36 * @var string $admin_url 37 */ 38 public $admin_url = ''; 39 40 /** 41 * URL to the BP Members Admin CSS directory. 42 * 43 * @var string $css_url 44 */ 45 public $css_url = ''; 46 47 /** 48 * URL to the BP Members Admin JS directory. 49 * 50 * @var string 51 */ 52 public $js_url = ''; 53 54 /** Other *****************************************************************/ 55 56 /** 57 * Screen id for edit user's profile page. 58 * 59 * @var string 60 */ 61 public $user_page = ''; 62 63 /** 64 * Setup BP Members Admin. 65 * 66 * @since 2.0.0 67 * 68 * @return BP_Members_Admin 69 */ 70 public static function register_members_admin() { 71 if ( ! is_admin() ) { 72 return; 73 } 74 75 $bp = buddypress(); 76 77 if ( empty( $bp->members->admin ) ) { 78 $bp->members->admin = new self; 79 } 80 81 return $bp->members->admin; 82 } 83 84 /** 85 * Constructor method. 86 * 87 * @since 2.0.0 88 */ 89 public function __construct() { 90 $this->setup_globals(); 91 $this->setup_actions(); 92 } 93 94 /** 95 * Set admin-related globals. 96 * 97 * @since 2.0.0 98 */ 99 private function setup_globals() { 100 $bp = buddypress(); 101 102 // Paths and URLs 103 $this->admin_dir = trailingslashit( $bp->plugin_dir . 'bp-members/admin' ); // Admin path. 104 $this->admin_url = trailingslashit( $bp->plugin_url . 'bp-members/admin' ); // Admin URL. 105 $this->css_url = trailingslashit( $this->admin_url . 'css' ); // Admin CSS URL. 106 $this->js_url = trailingslashit( $this->admin_url . 'js' ); // Admin CSS URL. 107 108 // Capability depends on config. 109 $this->capability = bp_core_do_network_admin() ? 'manage_network_users' : 'edit_users'; 110 111 // The Edit Profile Screen id. 112 $this->user_page = ''; 113 114 // The Show Profile Screen id. 115 $this->user_profile = is_network_admin() ? 'users' : 'profile'; 116 117 // The current user id. 118 $this->current_user_id = get_current_user_id(); 119 120 // The user id being edited. 121 $this->user_id = 0; 122 123 // Is a member editing their own profile. 124 $this->is_self_profile = false; 125 126 // The screen ids to load specific css for. 127 $this->screen_id = array(); 128 129 // The stats metabox default position. 130 $this->stats_metabox = new StdClass(); 131 132 // BuddyPress edit user's profile args. 133 $this->edit_profile_args = array( 'page' => 'bp-profile-edit' ); 134 $this->edit_profile_url = ''; 135 $this->edit_url = ''; 136 137 // Data specific to signups. 138 $this->users_page = ''; 139 $this->signups_page = ''; 140 $this->users_url = bp_get_admin_url( 'users.php' ); 141 $this->users_screen = bp_core_do_network_admin() ? 'users-network' : 'users'; 142 143 $this->members_invites_page = ''; 144 145 // Specific config: BuddyPress is not network activated. 146 $this->subsite_activated = (bool) is_multisite() && ! bp_is_network_activated(); 147 148 // When BuddyPress is not network activated, only Super Admin can moderate signups. 149 if ( ! empty( $this->subsite_activated ) ) { 150 $this->capability = 'manage_network_users'; 151 } 152 153 /* 154 * For consistency with non-Multisite, we add a Tools menu in 155 * the Network Admin as a home for our Tools panel. 156 */ 157 if ( is_multisite() && bp_core_do_network_admin() ) { 158 $this->tools_parent = 'network-tools'; 159 } else { 160 $this->tools_parent = 'tools.php'; 161 } 162 } 163 164 /** 165 * Set admin-related actions and filters. 166 * 167 * @since 2.0.0 168 */ 169 private function setup_actions() { 170 171 /** Extended Profile ************************************************* 172 */ 173 174 // Enqueue all admin JS and CSS. 175 add_action( 'bp_admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); 176 177 // Add some page specific output to the <head>. 178 add_action( 'bp_admin_head', array( $this, 'admin_head' ), 999 ); 179 180 // Add menu item to all users menu. 181 add_action( 'admin_menu', array( $this, 'admin_menus' ), 5 ); 182 add_action( 'network_admin_menu', array( $this, 'admin_menus' ), 5 ); 183 184 if ( bp_members_is_community_profile_enabled() ) { 185 add_action( 'user_admin_menu', array( $this, 'user_profile_menu' ), 5 ); 186 187 // Create the Profile Navigation (Profile/Extended Profile). 188 add_action( 'edit_user_profile', array( $this, 'profile_nav' ), 99, 1 ); 189 add_action( 'show_user_profile', array( $this, 'profile_nav' ), 99, 1 ); 190 191 // Editing users of a specific site. 192 add_action( "admin_head-site-users.php", array( $this, 'profile_admin_head' ) ); 193 } 194 195 // Add a row action to users listing. 196 if ( bp_core_do_network_admin() ) { 197 if ( bp_members_is_community_profile_enabled() ) { 198 add_filter( 'ms_user_row_actions', array( $this, 'row_actions' ), 10, 2 ); 199 } 200 201 add_action( 'admin_init', array( $this, 'add_edit_profile_url_filter' ) ); 202 add_action( 'wp_after_admin_bar_render', array( $this, 'remove_edit_profile_url_filter' ) ); 203 } 204 205 // Add user row actions for single site. 206 if ( bp_members_is_community_profile_enabled() ) { 207 add_filter( 'user_row_actions', array( $this, 'row_actions' ), 10, 2 ); 208 } 209 210 // Process changes to member type. 211 add_action( 'bp_members_admin_load', array( $this, 'process_member_type_update' ) ); 212 213 /** Signups ********************************************************** 214 */ 215 216 if ( is_admin() ) { 217 218 // Filter non multisite user query to remove sign-up users. 219 if ( ! is_multisite() ) { 220 add_action( 'pre_user_query', array( $this, 'remove_signups_from_user_query' ), 10, 1 ); 221 } 222 223 // Reorganise the views navigation in users.php and signups page. 224 if ( current_user_can( $this->capability ) ) { 225 $user_screen = $this->users_screen; 226 227 /** 228 * Users screen on multiblog is users, but signups 229 * need to be managed in the network for this case 230 */ 231 if ( bp_is_network_activated() && bp_is_multiblog_mode() && false === strpos( $user_screen, '-network' ) ) { 232 $user_screen .= '-network'; 233 } 234 235 add_filter( "views_{$user_screen}", array( $this, 'signup_filter_view' ), 10, 1 ); 236 add_filter( 'set-screen-option', array( $this, 'signup_screen_options' ), 10, 3 ); 237 } 238 239 // Registration is turned on. 240 add_action( 'update_site_option_registration', array( $this, 'multisite_registration_on' ), 10, 2 ); 241 add_action( 'update_option_users_can_register', array( $this, 'single_site_registration_on' ), 10, 2 ); 242 243 // Member invitations are enabled. 244 if ( bp_is_network_activated() ) { 245 add_action( 'update_site_option_bp-enable-members-invitations', array( $this, 'multisite_registration_on' ), 10, 2 ); 246 } else { 247 add_action( 'update_option_bp-enable-members-invitations', array( $this, 'single_site_registration_on' ), 10, 2 ); 248 } 249 } 250 251 /** Users List - Members Types *************************************** 252 */ 253 254 if ( is_admin() && bp_get_member_types() ) { 255 256 // Add "Change type" <select> to WP admin users list table and process bulk members type changes. 257 add_action( 'restrict_manage_users', array( $this, 'users_table_output_type_change_select' ) ); 258 add_action( 'load-users.php', array( $this, 'users_table_process_bulk_type_change' ) ); 259 260 // Add the member type column to the WP admin users list table. 261 add_filter( 'manage_users_columns', array( $this, 'users_table_add_type_column' ) ); 262 add_filter( 'manage_users_custom_column', array( $this, 'users_table_populate_type_cell' ), 10, 3 ); 263 264 // Filter WP admin users list table to include users of the specified type. 265 add_filter( 'pre_get_users', array( $this, 'users_table_filter_by_type' ) ); 266 } 267 268 // Add the Members invitations submenu page to the tools submenu pages. 269 add_action( 'bp_admin_submenu_pages', array( $this, 'set_submenu_page' ), 10, 1 ); 270 } 271 272 /** 273 * Create registration pages when multisite user registration is turned on. 274 * 275 * @since 2.7.0 276 * 277 * @param string $option_name Current option name; value is always 'registration'. 278 * @param string $value 279 */ 280 public function multisite_registration_on( $option_name, $value ) { 281 // Is registration enabled or are network invitations enabled? 282 if ( ( 'user' === $value || 'all' === $value ) 283 || bp_get_members_invitations_allowed() ) { 284 bp_core_add_page_mappings( array( 285 'register' => 1, 286 'activate' => 1 287 ) ); 288 } 289 } 290 291 /** 292 * Create registration pages when single site registration is turned on. 293 * 294 * @since 2.7.0 295 * 296 * @param string $old_value 297 * @param string $value 298 */ 299 public function single_site_registration_on( $old_value, $value ) { 300 // Single site. 301 if ( ! is_multisite() && ( ! empty( $value ) || bp_get_members_invitations_allowed() ) ) { 302 bp_core_add_page_mappings( array( 303 'register' => 1, 304 'activate' => 1 305 ) ); 306 } 307 } 308 309 /** 310 * Get the user ID. 311 * 312 * Look for $_GET['user_id']. If anything else, force the user ID to the 313 * current user's ID so they aren't left without a user to edit. 314 * 315 * @since 2.1.0 316 * 317 * @return int 318 */ 319 private function get_user_id() { 320 if ( ! empty( $this->user_id ) ) { 321 return $this->user_id; 322 } 323 324 $this->user_id = (int) get_current_user_id(); 325 326 // We'll need a user ID when not on self profile. 327 if ( ! empty( $_GET['user_id'] ) ) { 328 $this->user_id = (int) $_GET['user_id']; 329 } 330 331 return $this->user_id; 332 } 333 334 /** 335 * Can the current user edit the one displayed. 336 * 337 * Self profile editing / or bp_moderate check. 338 * This might be replaced by more granular capabilities 339 * in the future. 340 * 341 * @since 2.1.0 342 * 343 * @param int $user_id ID of the user being checked for edit ability. 344 * 345 * @return bool 346 */ 347 private function member_can_edit( $user_id = 0 ) { 348 $retval = false; 349 350 // Bail if no user ID was passed. 351 if ( empty( $user_id ) ) { 352 return $retval; 353 } 354 355 // Member can edit if they are viewing their own profile. 356 if ( $this->current_user_id === $user_id ) { 357 $retval = true; 358 359 // Trust the 'bp_moderate' capability. 360 } else { 361 $retval = ( bp_current_user_can( 'edit_users' ) || bp_current_user_can( 'bp_moderate' ) ); 362 } 363 364 return $retval; 365 } 366 367 /** 368 * Get admin notice when saving a user or member profile. 369 * 370 * @since 2.1.0 371 * 372 * @return array 373 */ 374 private function get_user_notice() { 375 376 // Setup empty notice for return value. 377 $notice = array(); 378 379 // Updates. 380 if ( ! empty( $_REQUEST['updated'] ) ) { 381 switch ( $_REQUEST['updated'] ) { 382 case 'avatar': 383 $notice = array( 384 'class' => 'updated', 385 'message' => __( 'Profile photo was deleted.', 'buddypress' ) 386 ); 387 break; 388 case 'ham' : 389 $notice = array( 390 'class' => 'updated', 391 'message' => __( 'User removed as spammer.', 'buddypress' ) 392 ); 393 break; 394 case 'spam' : 395 $notice = array( 396 'class' => 'updated', 397 'message' => __( 'User marked as spammer. Spam users are visible only to site admins.', 'buddypress' ) 398 ); 399 break; 400 case 1 : 401 $notice = array( 402 'class' => 'updated', 403 'message' => __( 'Profile updated.', 'buddypress' ) 404 ); 405 break; 406 } 407 } 408 409 // Errors. 410 if ( ! empty( $_REQUEST['error'] ) ) { 411 switch ( $_REQUEST['error'] ) { 412 case 'avatar': 413 $notice = array( 414 'class' => 'error', 415 'message' => __( 'There was a problem deleting that profile photo. Please try again.', 'buddypress' ) 416 ); 417 break; 418 case 'ham' : 419 $notice = array( 420 'class' => 'error', 421 'message' => __( 'User could not be removed as spammer.', 'buddypress' ) 422 ); 423 break; 424 case 'spam' : 425 $notice = array( 426 'class' => 'error', 427 'message' => __( 'User could not be marked as spammer.', 'buddypress' ) 428 ); 429 break; 430 case 1 : 431 $notice = array( 432 'class' => 'error', 433 'message' => __( 'An error occurred while trying to update the profile.', 'buddypress' ) 434 ); 435 break; 436 case 2: 437 $notice = array( 438 'class' => 'error', 439 'message' => __( 'Your changes have not been saved. Please fill in all required fields, and save your changes again.', 'buddypress' ) 440 ); 441 break; 442 case 3: 443 $notice = array( 444 'class' => 'error', 445 'message' => __( 'There was a problem updating some of your profile information. Please try again.', 'buddypress' ) 446 ); 447 break; 448 } 449 } 450 451 return $notice; 452 } 453 454 /** 455 * Create the /user/ admin Profile submenus for all members. 456 * 457 * @since 2.1.0 458 * 459 */ 460 public function user_profile_menu() { 461 462 // Setup the hooks array. 463 $hooks = array(); 464 465 // Add the faux "Edit Profile" submenu page. 466 $hooks['user'] = $this->user_page = add_submenu_page( 467 'profile.php', 468 __( 'Edit Profile', 'buddypress' ), 469 __( 'Edit Profile', 'buddypress' ), 470 'exist', 471 'bp-profile-edit', 472 array( $this, 'user_admin' ) 473 ); 474 475 // Setup the screen ID's. 476 $this->screen_id = array( 477 $this->user_page . '-user', 478 $this->user_profile . '-user' 479 ); 480 481 // Loop through new hooks and add method actions. 482 foreach ( $hooks as $key => $hook ) { 483 add_action( "load-{$hook}", array( $this, $key . '_admin_load' ) ); 484 } 485 486 // Add the profile_admin_head method to proper admin_head actions. 487 add_action( "admin_head-{$this->user_page}", array( $this, 'profile_admin_head' ) ); 488 add_action( "admin_head-profile.php", array( $this, 'profile_admin_head' ) ); 489 } 490 491 /** 492 * Create the All Users / Profile > Edit Profile and All Users Signups submenus. 493 * 494 * @since 2.0.0 495 * 496 */ 497 public function admin_menus() { 498 499 // Setup the hooks array. 500 $hooks = array(); 501 502 if ( bp_members_is_community_profile_enabled() ) { 503 // Manage user's profile. 504 $hooks['user'] = $this->user_page = add_submenu_page( 505 $this->user_profile . '.php', 506 __( 'Edit Profile', 'buddypress' ), 507 __( 'Edit Profile', 'buddypress' ), 508 'read', 509 'bp-profile-edit', 510 array( $this, 'user_admin' ) 511 ); 512 } 513 514 // Only show sign-ups where they belong. 515 if ( ( ! bp_is_network_activated() && ! is_network_admin() ) || ( is_network_admin() && bp_is_network_activated() ) ) { 516 517 $signups_menu_label = __( 'Manage Signups', 'buddypress' ); 518 519 if ( bp_get_membership_requests_required() ) { 520 $signups_menu_label = __( 'Manage Pending Memberships', 'buddypress' ); 521 } 522 523 // Manage signups. 524 $hooks['signups'] = $this->signups_page = add_users_page( 525 $signups_menu_label, 526 $signups_menu_label, 527 $this->capability, 528 'bp-signups', 529 array( $this, 'signups_admin' ) 530 ); 531 } 532 533 $hooks['members_invitations'] = $this->members_invites_page = add_submenu_page( 534 $this->tools_parent, 535 __( 'Manage Invitations', 'buddypress' ), 536 __( 'Manage Invitations', 'buddypress' ), 537 $this->capability, 538 'bp-members-invitations', 539 array( $this, 'invitations_admin' ) 540 ); 541 542 $edit_page = 'user-edit'; 543 $profile_page = 'profile'; 544 $this->users_page = 'users'; 545 546 // Self profile check is needed for this pages. 547 $page_head = array( 548 $edit_page . '.php', 549 $profile_page . '.php', 550 $this->user_page, 551 $this->users_page . '.php', 552 ); 553 554 // Append '-network' to each array item if in network admin. 555 if ( is_network_admin() ) { 556 $edit_page .= '-network'; 557 $profile_page .= '-network'; 558 $this->user_page .= '-network'; 559 $this->users_page .= '-network'; 560 $this->signups_page .= '-network'; 561 562 $this->members_invites_page .= '-network'; 563 } 564 565 // Setup the screen ID's. 566 $this->screen_id = array( 567 $edit_page, 568 $this->user_page, 569 $profile_page 570 ); 571 572 // Loop through new hooks and add method actions. 573 foreach ( $hooks as $key => $hook ) { 574 add_action( "load-{$hook}", array( $this, $key . '_admin_load' ) ); 575 } 576 577 // Add the profile_admin_head method to proper admin_head actions. 578 foreach ( $page_head as $head ) { 579 add_action( "admin_head-{$head}", array( $this, 'profile_admin_head' ) ); 580 } 581 582 // Highlight the BuddyPress tools submenu when managing invitations. 583 add_action( "admin_head-{$this->members_invites_page}", 'bp_core_modify_admin_menu_highlight' ); 584 } 585 586 /** 587 * Include the Members Invitations tab to the Admin tabs needing specific inline styles. 588 * 589 * @since 10.0.0 590 * 591 * @param array $submenu_pages The BP_Admin submenu pages passed by reference. 592 */ 593 public function set_submenu_page( &$submenu_pages ) { 594 if ( isset( $submenu_pages['tools'] ) ) { 595 $submenu_pages['tools']['bp-members-invitations'] = get_plugin_page_hookname( 'bp-members-invitations', $this->tools_parent ); 596 } 597 } 598 599 /** 600 * Highlight the Users menu if on Edit Profile and check if on the user's admin profile. 601 * 602 * @since 2.1.0 603 */ 604 public function profile_admin_head() { 605 global $submenu_file, $parent_file; 606 607 // Is the user editing their own profile? 608 if ( is_user_admin() || ( defined( 'IS_PROFILE_PAGE' ) && IS_PROFILE_PAGE ) ) { 609 $this->is_self_profile = true; 610 611 // Is the user attempting to edit their own profile. 612 } elseif ( isset( $_GET['user_id' ] ) || ( isset( $_GET['page'] ) && ( 'bp-profile-edit' === $_GET['page'] ) ) ) { 613 $this->is_self_profile = (bool) ( $this->get_user_id() === $this->current_user_id ); 614 } 615 616 // Force the parent file to users.php to open the correct top level menu 617 // but only if not editing a site via the network site editing page. 618 if ( 'sites.php' !== $parent_file ) { 619 $parent_file = 'users.php'; 620 $submenu_file = 'users.php'; 621 } 622 623 // Editing your own profile, so recheck some vars. 624 if ( true === $this->is_self_profile ) { 625 626 // Use profile.php as the edit page. 627 $edit_page = 'profile.php'; 628 629 // Set profile.php as the parent & sub files to correct the menu nav. 630 if ( is_blog_admin() || is_user_admin() ) { 631 $parent_file = 'profile.php'; 632 $submenu_file = 'profile.php'; 633 } 634 635 // Not editing yourself, so use user-edit.php. 636 } else { 637 $edit_page = 'user-edit.php'; 638 } 639 640 if ( is_user_admin() ) { 641 $this->edit_profile_url = add_query_arg( $this->edit_profile_args, user_admin_url( 'profile.php' ) ); 642 $this->edit_url = user_admin_url( 'profile.php' ); 643 644 } elseif ( is_blog_admin() ) { 645 $this->edit_profile_url = add_query_arg( $this->edit_profile_args, admin_url( 'users.php' ) ); 646 $this->edit_url = admin_url( $edit_page ); 647 648 } elseif ( is_network_admin() ) { 649 $this->edit_profile_url = add_query_arg( $this->edit_profile_args, network_admin_url( 'users.php' ) ); 650 $this->edit_url = network_admin_url( $edit_page ); 651 } 652 } 653 654 /** 655 * Remove the Edit Profile page. 656 * 657 * We add these pages in order to integrate with WP's Users panel, but 658 * we want them to show up as a row action of the WP panel, not as separate 659 * subnav items under the Users menu. 660 * 661 * @since 2.0.0 662 */ 663 public function admin_head() { 664 remove_submenu_page( 'users.php', 'bp-profile-edit' ); 665 remove_submenu_page( 'profile.php', 'bp-profile-edit' ); 666 667 // Manage Invitations Tool screen is a tab of BP Tools. 668 if ( is_network_admin() ) { 669 remove_submenu_page( 'network-tools', 'bp-members-invitations' ); 670 } else { 671 remove_submenu_page( 'tools.php', 'bp-members-invitations' ); 672 } 673 } 674 675 /** Community Profile *****************************************************/ 676 677 /** 678 * Add some specific styling to the Edit User and Edit User's Profile page. 679 * 680 * @since 2.0.0 681 */ 682 public function enqueue_scripts() { 683 if ( ! in_array( get_current_screen()->id, $this->screen_id ) ) { 684 return; 685 } 686 687 if ( bp_members_is_community_profile_enabled() ) { 688 $min = bp_core_get_minified_asset_suffix(); 689 $css = $this->css_url . "admin{$min}.css"; 690 691 /** 692 * Filters the CSS URL to enqueue in the Members admin area. 693 * 694 * @since 2.0.0 695 * 696 * @param string $css URL to the CSS admin file to load. 697 */ 698 $css = apply_filters( 'bp_members_admin_css', $css ); 699 700 wp_enqueue_style( 'bp-members-css', $css, array(), bp_get_version() ); 701 702 wp_style_add_data( 'bp-members-css', 'rtl', 'replace' ); 703 if ( $min ) { 704 wp_style_add_data( 'bp-members-css', 'suffix', $min ); 705 } 706 707 // Only load JavaScript for BuddyPress profile. 708 if ( get_current_screen()->id == $this->user_page ) { 709 $js = $this->js_url . "admin{$min}.js"; 710 711 /** 712 * Filters the JS URL to enqueue in the Members admin area. 713 * 714 * @since 2.0.0 715 * 716 * @param string $js URL to the JavaScript admin file to load. 717 */ 718 $js = apply_filters( 'bp_members_admin_js', $js ); 719 wp_enqueue_script( 'bp-members-js', $js, array(), bp_get_version(), true ); 720 721 if ( ! bp_core_get_root_option( 'bp-disable-avatar-uploads' ) && buddypress()->avatar->show_avatars ) { 722 /** 723 * Get Thickbox. 724 * 725 * We cannot simply use add_thickbox() here as WordPress is not playing 726 * nice with Thickbox width/height see https://core.trac.wordpress.org/ticket/17249 727 * Using media-upload might be interesting in the future for the send to editor stuff 728 * and we make sure the tb_window is wide enough 729 */ 730 wp_enqueue_style ( 'thickbox' ); 731 wp_enqueue_script( 'media-upload' ); 732 733 // Get Avatar Uploader. 734 bp_attachments_enqueue_scripts( 'BP_Attachment_Avatar' ); 735 } 736 } 737 } 738 739 /** 740 * Fires after all of the members JavaScript and CSS are enqueued. 741 * 742 * @since 2.0.0 743 * 744 * @param string $id ID of the current screen. 745 * @param array $screen_id Array of allowed screens to add scripts and styles to. 746 */ 747 do_action( 'bp_members_admin_enqueue_scripts', get_current_screen()->id, $this->screen_id ); 748 } 749 750 /** 751 * Create the Profile navigation in Edit User & Edit Profile pages. 752 * 753 * @since 2.0.0 754 * 755 * @param object|null $user User to create profile navigation for. 756 * @param string $active Which profile to highlight. 757 * @return string|null 758 */ 759 public function profile_nav( $user = null, $active = 'WordPress' ) { 760 761 // Bail if no user ID exists here. 762 if ( empty( $user->ID ) ) { 763 return; 764 } 765 766 // Add the user ID to query arguments when not editing yourself. 767 if ( false === $this->is_self_profile ) { 768 $query_args = array( 'user_id' => $user->ID ); 769 } else { 770 $query_args = array(); 771 } 772 773 // Conditionally add a referer if it exists in the existing request. 774 if ( ! empty( $_REQUEST['wp_http_referer'] ) ) { 775 $wp_http_referer = wp_unslash( $_REQUEST['wp_http_referer'] ); 776 $wp_http_referer = wp_validate_redirect( esc_url_raw( $wp_http_referer ) ); 777 $query_args['wp_http_referer'] = urlencode( $wp_http_referer ); 778 } 779 780 // Setup the two distinct "edit" URL's. 781 $community_url = add_query_arg( $query_args, $this->edit_profile_url ); 782 $wordpress_url = add_query_arg( $query_args, $this->edit_url ); 783 784 $bp_active = false; 785 $wp_active = ' nav-tab-active'; 786 if ( 'BuddyPress' === $active ) { 787 $bp_active = ' nav-tab-active'; 788 $wp_active = false; 789 } ?> 790 791 <h2 id="profile-nav" class="nav-tab-wrapper"> 792 <?php 793 /** 794 * In configs where BuddyPress is not network activated, as regular 795 * admins do not have the capacity to edit other users, we must add 796 * this check. 797 */ 798 if ( current_user_can( 'edit_user', $user->ID ) ) : ?> 799 800 <a class="nav-tab<?php echo esc_attr( $wp_active ); ?>" href="<?php echo esc_url( $wordpress_url );?>"><?php _e( 'Profile', 'buddypress' ); ?></a> 801 802 <?php endif; ?> 803 804 <a class="nav-tab<?php echo esc_attr( $bp_active ); ?>" href="<?php echo esc_url( $community_url );?>"><?php _e( 'Extended Profile', 'buddypress' ); ?></a> 805 </h2> 806 807 <?php 808 } 809 810 /** 811 * Set up the user's profile admin page. 812 * 813 * Loaded before the page is rendered, this function does all initial 814 * setup, including: processing form requests, registering contextual 815 * help, and setting up screen options. 816 * 817 * @since 2.0.0 818 * @since 6.0.0 The `delete_avatar` action is now managed into this method. 819 */ 820 public function user_admin_load() { 821 822 // Get the user ID. 823 $user_id = $this->get_user_id(); 824 825 // Can current user edit this profile? 826 if ( ! $this->member_can_edit( $user_id ) ) { 827 wp_die( __( 'You cannot edit the requested user.', 'buddypress' ) ); 828 } 829 830 // Build redirection URL. 831 $redirect_to = remove_query_arg( array( 'action', 'error', 'updated', 'spam', 'ham', 'delete_avatar' ), $_SERVER['REQUEST_URI'] ); 832 $doaction = ! empty( $_REQUEST['action'] ) ? $_REQUEST['action'] : false; 833 834 if ( ! empty( $_REQUEST['user_status'] ) ) { 835 $spam = (bool) ( 'spam' === $_REQUEST['user_status'] ); 836 837 if ( $spam !== bp_is_user_spammer( $user_id ) ) { 838 $doaction = $_REQUEST['user_status']; 839 } 840 } 841 842 /** 843 * Fires at the start of the signups admin load. 844 * 845 * @since 2.0.0 846 * 847 * @param string $doaction Current bulk action being processed. 848 * @param array $_REQUEST Current $_REQUEST global. 849 */ 850 do_action_ref_array( 'bp_members_admin_load', array( $doaction, $_REQUEST ) ); 851 852 /** 853 * Filters the allowed actions for use in the user admin page. 854 * 855 * @since 2.0.0 856 * 857 * @param array $value Array of allowed actions to use. 858 */ 859 $allowed_actions = apply_filters( 'bp_members_admin_allowed_actions', array( 'update', 'delete_avatar', 'spam', 'ham' ) ); 860 861 // Prepare the display of the Community Profile screen. 862 if ( ! in_array( $doaction, $allowed_actions ) ) { 863 add_screen_option( 'layout_columns', array( 'default' => 2, 'max' => 2, ) ); 864 865 get_current_screen()->add_help_tab( array( 866 'id' => 'bp-profile-edit-overview', 867 'title' => __( 'Overview', 'buddypress' ), 868 'content' => 869 '<p>' . __( 'This is the admin view of a user's profile.', 'buddypress' ) . '</p>' . 870 '<p>' . __( 'In the main column, you can edit the fields of the user's extended profile.', 'buddypress' ) . '</p>' . 871 '<p>' . __( 'In the right-hand column, you can update the user's status, delete the user's avatar, and view recent statistics.', 'buddypress' ) . '</p>' 872 ) ); 873 874 // Help panel - sidebar links. 875 get_current_screen()->set_help_sidebar( 876 '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' . 877 '<p>' . __( '<a href="https://codex.buddypress.org/administrator-guide/extended-profiles/">Managing Profiles</a>', 'buddypress' ) . '</p>' . 878 '<p>' . __( '<a href="https://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>' 879 ); 880 881 // Register metaboxes for the edit screen. 882 add_meta_box( 883 'submitdiv', 884 _x( 'Status', 'members user-admin edit screen', 'buddypress' ), 885 array( $this, 'user_admin_status_metabox' ), 886 get_current_screen()->id, 887 'side', 888 'core' 889 ); 890 891 // In case xprofile is not active. 892 $this->stats_metabox->context = 'normal'; 893 $this->stats_metabox->priority = 'core'; 894 895 /** 896 * Fires before loading the profile fields if component is active. 897 * 898 * Plugins should not use this hook, please use 'bp_members_admin_user_metaboxes' instead. 899 * 900 * @since 2.0.0 901 * 902 * @param int $user_id Current user ID for the screen. 903 * @param string $id Current screen ID. 904 * @param object $stats_metabox Object holding position data for use with the stats metabox. 905 */ 906 do_action_ref_array( 'bp_members_admin_xprofile_metabox', array( $user_id, get_current_screen()->id, $this->stats_metabox ) ); 907 908 // If xProfile is inactive, difficult to know what's profile we're on. 909 if ( 'normal' === $this->stats_metabox->context ) { 910 $display_name = bp_core_get_user_displayname( $user_id ); 911 } else { 912 $display_name = __( 'Member', 'buddypress' ); 913 } 914 915 // Set the screen id. 916 $screen_id = get_current_screen()->id; 917 918 // User Stat metabox. 919 add_meta_box( 920 'bp_members_admin_user_stats', 921 sprintf( 922 /* translators: %s: member name */ 923 _x( "%s's Stats", 'members user-admin edit screen', 'buddypress' ), 924 $display_name 925 ), 926 array( $this, 'user_admin_stats_metabox' ), 927 $screen_id, 928 sanitize_key( $this->stats_metabox->context ), 929 sanitize_key( $this->stats_metabox->priority ) 930 ); 931 932 if ( buddypress()->avatar->show_avatars ) { 933 // Avatar Metabox. 934 add_meta_box( 935 'bp_members_user_admin_avatar', 936 _x( 'Profile Photo', 'members user-admin edit screen', 'buddypress' ), 937 array( $this, 'user_admin_avatar_metabox' ), 938 $screen_id, 939 'side', 940 'low' 941 ); 942 } 943 944 // Member Type metabox. Only added if member types have been registered. 945 $member_types = bp_get_member_types(); 946 if ( ! empty( $member_types ) ) { 947 add_meta_box( 948 'bp_members_admin_member_type', 949 _x( 'Member Type', 'members user-admin edit screen', 'buddypress' ), 950 array( $this, 'user_admin_member_type_metabox' ), 951 $screen_id, 952 'side', 953 'core' 954 ); 955 } 956 957 /** 958 * Fires at the end of the Community Profile screen. 959 * 960 * Plugins can restrict metabox to "bp_moderate" admins by checking if 961 * the first argument ($this->is_self_profile) is false in their callback. 962 * They can also restrict their metabox to self profile editing 963 * by setting it to true. 964 * 965 * @since 2.0.0 966 * 967 * @param bool $is_self_profile Whether or not it is the current user's profile. 968 * @param int $user_id Current user ID. 969 */ 970 do_action( 'bp_members_admin_user_metaboxes', $this->is_self_profile, $user_id ); 971 972 // Enqueue JavaScript files. 973 wp_enqueue_script( 'postbox' ); 974 wp_enqueue_script( 'dashboard' ); 975 976 // Spam or Ham user. 977 } elseif ( in_array( $doaction, array( 'spam', 'ham' ) ) && empty( $this->is_self_profile ) ) { 978 979 check_admin_referer( 'edit-bp-profile_' . $user_id ); 980 981 if ( bp_core_process_spammer_status( $user_id, $doaction ) ) { 982 $redirect_to = add_query_arg( 'updated', $doaction, $redirect_to ); 983 } else { 984 $redirect_to = add_query_arg( 'error', $doaction, $redirect_to ); 985 } 986 987 bp_core_redirect( $redirect_to ); 988 989 // Eventually delete avatar. 990 } elseif ( 'delete_avatar' === $doaction ) { 991 992 // Check the nonce. 993 check_admin_referer( 'delete_avatar' ); 994 995 $redirect_to = remove_query_arg( '_wpnonce', $redirect_to ); 996 997 if ( bp_core_delete_existing_avatar( array( 'item_id' => $user_id ) ) ) { 998 $redirect_to = add_query_arg( 'updated', 'avatar', $redirect_to ); 999 } else { 1000 $redirect_to = add_query_arg( 'error', 'avatar', $redirect_to ); 1001 } 1002 1003 bp_core_redirect( $redirect_to ); 1004 1005 // Update other stuff once above ones are done. 1006 } else { 1007 $this->redirect = $redirect_to; 1008 1009 /** 1010 * Fires at end of user profile admin load if doaction does not match any available actions. 1011 * 1012 * @since 2.0.0 1013 * 1014 * @param string $doaction Current bulk action being processed. 1015 * @param int $user_id Current user ID. 1016 * @param array $_REQUEST Current $_REQUEST global. 1017 * @param string $redirect Determined redirect url to send user to. 1018 */ 1019 do_action_ref_array( 'bp_members_admin_update_user', array( $doaction, $user_id, $_REQUEST, $this->redirect ) ); 1020 1021 bp_core_redirect( $this->redirect ); 1022 } 1023 } 1024 1025 /** 1026 * Display the user's profile. 1027 * 1028 * @since 2.0.0 1029 */ 1030 public function user_admin() { 1031 1032 if ( ! bp_current_user_can( 'edit_users' ) && ! bp_current_user_can( 'bp_moderate' ) && empty( $this->is_self_profile ) ) { 1033 die( '-1' ); 1034 } 1035 1036 // Get the user ID. 1037 $user_id = $this->get_user_id(); 1038 $user = get_user_to_edit( $user_id ); 1039 1040 // Construct title. 1041 if ( true === $this->is_self_profile ) { 1042 $title = __( 'Profile', 'buddypress' ); 1043 } else { 1044 /* translators: %s: User's display name. */ 1045 $title = sprintf( __( 'Edit User %s', 'buddypress' ), $user->display_name ); 1046 } 1047 1048 // Construct URL for form. 1049 $request_url = remove_query_arg( array( 'action', 'error', 'updated', 'spam', 'ham' ), $_SERVER['REQUEST_URI'] ); 1050 $form_action_url = add_query_arg( 'action', 'update', $request_url ); 1051 $wp_http_referer = false; 1052 if ( ! empty( $_REQUEST['wp_http_referer'] ) ) { 1053 $wp_http_referer = wp_unslash( $_REQUEST['wp_http_referer'] ); 1054 $wp_http_referer = remove_query_arg( array( 'action', 'updated' ), $wp_http_referer ); 1055 $wp_http_referer = wp_validate_redirect( esc_url_raw( $wp_http_referer ) ); 1056 } 1057 1058 // Prepare notice for admin. 1059 $notice = $this->get_user_notice(); 1060 1061 if ( ! empty( $notice ) ) : ?> 1062 1063 <div <?php if ( 'updated' === $notice['class'] ) : ?>id="message" <?php endif; ?>class="<?php echo esc_attr( $notice['class'] ); ?> notice is-dismissible"> 1064 1065 <p><?php echo esc_html( $notice['message'] ); ?></p> 1066 1067 <?php if ( !empty( $wp_http_referer ) && ( 'updated' === $notice['class'] ) ) : ?> 1068 1069 <p><a href="<?php echo esc_url( $wp_http_referer ); ?>"><?php esc_html_e( '← Back to Users', 'buddypress' ); ?></a></p> 1070 1071 <?php endif; ?> 1072 1073 </div> 1074 1075 <?php endif; ?> 1076 1077 <div class="wrap" id="community-profile-page"> 1078 <h1 class="wp-heading-inline"><?php echo esc_html( $title ); ?></h1> 1079 1080 <?php if ( empty( $this->is_self_profile ) ) : ?> 1081 1082 <?php if ( current_user_can( 'create_users' ) ) : ?> 1083 1084 <a href="user-new.php" class="page-title-action"><?php echo esc_html_x( 'Add New', 'user', 'buddypress' ); ?></a> 1085 1086 <?php elseif ( is_multisite() && current_user_can( 'promote_users' ) ) : ?> 1087 1088 <a href="user-new.php" class="page-title-action"><?php echo esc_html_x( 'Add Existing', 'user', 'buddypress' ); ?></a> 1089 1090 <?php endif; ?> 1091 1092 <?php endif; ?> 1093 1094 <hr class="wp-header-end"> 1095 1096 <?php if ( ! empty( $user ) ) : 1097 1098 $this->profile_nav( $user, 'BuddyPress' ); ?> 1099 1100 <form action="<?php echo esc_url( $form_action_url ); ?>" id="your-profile" method="post"> 1101 <div id="poststuff"> 1102 1103 <div id="post-body" class="metabox-holder columns-<?php echo 1 == get_current_screen()->get_columns() ? '1' : '2'; ?>"> 1104 1105 <div id="postbox-container-1" class="postbox-container"> 1106 <?php do_meta_boxes( get_current_screen()->id, 'side', $user ); ?> 1107 </div> 1108 1109 <div id="postbox-container-2" class="postbox-container"> 1110 <?php do_meta_boxes( get_current_screen()->id, 'normal', $user ); ?> 1111 <?php do_meta_boxes( get_current_screen()->id, 'advanced', $user ); ?> 1112 </div> 1113 </div><!-- #post-body --> 1114 1115 </div><!-- #poststuff --> 1116 1117 <?php wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false ); ?> 1118 <?php wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false ); ?> 1119 <?php wp_nonce_field( 'edit-bp-profile_' . $user->ID ); ?> 1120 1121 </form> 1122 1123 <?php else : ?> 1124 1125 <p><?php 1126 printf( 1127 '%1$s <a href="%2$s">%3$s</a>', 1128 __( 'No user found with this ID.', 'buddypress' ), 1129 esc_url( bp_get_admin_url( 'users.php' ) ), 1130 __( 'Go back and try again.', 'buddypress' ) 1131 ); 1132 ?></p> 1133 1134 <?php endif; ?> 1135 1136 </div><!-- .wrap --> 1137 <?php 1138 } 1139 1140 /** 1141 * Render the Status metabox for user's profile screen. 1142 * 1143 * Actions are: 1144 * - Update profile fields if xProfile component is active 1145 * - Spam/Unspam user 1146 * 1147 * @since 2.0.0 1148 * 1149 * @param WP_User|null $user The WP_User object to be edited. 1150 */ 1151 public function user_admin_status_metabox( $user = null ) { 1152 1153 // Bail if no user id or if the user has not activated their account yet. 1154 if ( empty( $user->ID ) ) { 1155 return; 1156 } 1157 1158 // Bail if user has not been activated yet (how did you get here?). 1159 if ( isset( $user->user_status ) && ( 2 == $user->user_status ) ) : ?> 1160 1161 <p class="not-activated"><?php esc_html_e( 'User account has not yet been activated', 'buddypress' ); ?></p><br/> 1162 1163 <?php return; 1164 1165 endif; ?> 1166 1167 <div class="submitbox" id="submitcomment"> 1168 <div id="minor-publishing"> 1169 <div id="misc-publishing-actions"> 1170 <?php 1171 1172 // Get the spam status once here to compare against below. 1173 $is_spammer = bp_is_user_spammer( $user->ID ); 1174 1175 /** 1176 * In configs where BuddyPress is not network activated, 1177 * regular admins cannot mark a user as a spammer on front 1178 * end. This prevent them to do it in the back end. 1179 * 1180 * Also prevent admins from marking themselves or other 1181 * admins as spammers. 1182 */ 1183 if ( ( empty( $this->is_self_profile ) && ( ! in_array( $user->user_login, get_super_admins() ) ) && empty( $this->subsite_activated ) ) || ( ! empty( $this->subsite_activated ) && current_user_can( 'manage_network_users' ) ) ) : ?> 1184 1185 <div class="misc-pub-section" id="comment-status-radio"> 1186 <label class="approved"><input type="radio" name="user_status" value="ham" <?php checked( $is_spammer, false ); ?>><?php esc_html_e( 'Active', 'buddypress' ); ?></label><br /> 1187 <label class="spam"><input type="radio" name="user_status" value="spam" <?php checked( $is_spammer, true ); ?>><?php esc_html_e( 'Spammer', 'buddypress' ); ?></label> 1188 </div> 1189 1190 <?php endif ;?> 1191 1192 <div class="misc-pub-section curtime misc-pub-section-last"> 1193 <?php 1194 1195 // Translators: Publish box date format, see http://php.net/date. 1196 $datef = __( 'M j, Y @ G:i', 'buddypress' ); 1197 $date = date_i18n( $datef, strtotime( $user->user_registered ) ); 1198 ?> 1199 <span id="timestamp"> 1200 <?php 1201 /* translators: %s: registration date */ 1202 printf( __( 'Registered on: %s', 'buddypress' ), '<strong>' . $date . '</strong>' ); 1203 ?> 1204 </span> 1205 </div> 1206 </div> <!-- #misc-publishing-actions --> 1207 1208 <div class="clear"></div> 1209 </div><!-- #minor-publishing --> 1210 1211 <div id="major-publishing-actions"> 1212 1213 <div id="publishing-action"> 1214 <a class="button bp-view-profile" href="<?php echo esc_url( bp_core_get_user_domain( $user->ID ) ); ?>" target="_blank"><?php esc_html_e( 'View Profile', 'buddypress' ); ?></a> 1215 <?php submit_button( esc_html__( 'Update Profile', 'buddypress' ), 'primary', 'save', false ); ?> 1216 </div> 1217 <div class="clear"></div> 1218 </div><!-- #major-publishing-actions --> 1219 1220 </div><!-- #submitcomment --> 1221 1222 <?php 1223 } 1224 1225 /** 1226 * Render the fallback metabox in case a user has been marked as a spammer. 1227 * 1228 * @since 2.0.0 1229 * 1230 * @param WP_User|null $user The WP_User object to be edited. 1231 */ 1232 public function user_admin_spammer_metabox( $user = null ) { 1233 ?> 1234 <p> 1235 <?php 1236 /* translators: %s: member name */ 1237 printf( __( '%s has been marked as a spammer. All BuddyPress data associated with the user has been removed', 'buddypress' ), esc_html( bp_core_get_user_displayname( $user->ID ) ) ); 1238 ?> 1239 </p> 1240 <?php 1241 } 1242 1243 /** 1244 * Render the Stats metabox to moderate inappropriate images. 1245 * 1246 * @since 2.0.0 1247 * 1248 * @param WP_User|null $user The WP_User object to be edited. 1249 */ 1250 public function user_admin_stats_metabox( $user = null ) { 1251 1252 // Bail if no user ID. 1253 if ( empty( $user->ID ) ) { 1254 return; 1255 } 1256 1257 // If account is not activated last activity is the time user registered. 1258 if ( isset( $user->user_status ) && 2 == $user->user_status ) { 1259 $last_active = $user->user_registered; 1260 1261 // Account is activated, getting user's last activity. 1262 } else { 1263 $last_active = bp_get_user_last_activity( $user->ID ); 1264 } 1265 1266 $datef = __( 'M j, Y @ G:i', 'buddypress' ); 1267 $date = date_i18n( $datef, strtotime( $last_active ) ); ?> 1268 1269 <ul> 1270 <li class="bp-members-profile-stats"> 1271 <?php 1272 /* translators: %s: date */ 1273 printf( __( 'Last active: %1$s', 'buddypress' ), '<strong>' . $date . '</strong>' ); 1274 ?> 1275 </li> 1276 1277 <?php 1278 // Loading other stats only if user has activated their account. 1279 if ( empty( $user->user_status ) ) { 1280 1281 /** 1282 * Fires in the user stats metabox if the user has activated their account. 1283 * 1284 * @since 2.0.0 1285 * 1286 * @param array $value Array holding the user ID. 1287 * @param object $user Current displayed user object. 1288 */ 1289 do_action( 'bp_members_admin_user_stats', array( 'user_id' => $user->ID ), $user ); 1290 } 1291 ?> 1292 </ul> 1293 1294 <?php 1295 } 1296 1297 /** 1298 * Render the Avatar metabox to moderate inappropriate images. 1299 * 1300 * @since 6.0.0 1301 * 1302 * @param WP_User|null $user The WP_User object for the user being edited. 1303 */ 1304 public function user_admin_avatar_metabox( $user = null ) { 1305 1306 if ( empty( $user->ID ) ) { 1307 return; 1308 } ?> 1309 1310 <div class="avatar"> 1311 1312 <?php echo bp_core_fetch_avatar( array( 1313 'item_id' => $user->ID, 1314 'object' => 'user', 1315 'type' => 'full', 1316 'title' => $user->display_name 1317 ) ); ?> 1318 1319 <?php if ( bp_get_user_has_avatar( $user->ID ) ) : 1320 1321 $query_args = array( 1322 'user_id' => $user->ID, 1323 'action' => 'delete_avatar' 1324 ); 1325 1326 if ( ! empty( $_REQUEST['wp_http_referer'] ) ) { 1327 $wp_http_referer = wp_unslash( $_REQUEST['wp_http_referer'] ); 1328 $wp_http_referer = remove_query_arg( array( 'action', 'updated' ), $wp_http_referer ); 1329 $wp_http_referer = wp_validate_redirect( esc_url_raw( $wp_http_referer ) ); 1330 $query_args['wp_http_referer'] = urlencode( $wp_http_referer ); 1331 } 1332 1333 $community_url = add_query_arg( $query_args, $this->edit_profile_url ); 1334 $delete_link = wp_nonce_url( $community_url, 'delete_avatar' ); ?> 1335 1336 <a href="<?php echo esc_url( $delete_link ); ?>" class="bp-members-avatar-user-admin"><?php esc_html_e( 'Delete Profile Photo', 'buddypress' ); ?></a> 1337 1338 <?php endif; 1339 1340 // Load the Avatar UI templates if user avatar uploads are enabled. 1341 if ( ! bp_core_get_root_option( 'bp-disable-avatar-uploads' ) ) : ?> 1342 <a href="#TB_inline?width=800px&height=400px&inlineId=bp-members-avatar-editor" class="thickbox bp-members-avatar-user-edit"><?php esc_html_e( 'Edit Profile Photo', 'buddypress' ); ?></a> 1343 <div id="bp-members-avatar-editor" style="display:none;"> 1344 <?php bp_attachments_get_template_part( 'avatars/index' ); ?> 1345 </div> 1346 <?php endif; ?> 1347 1348 </div> 1349 <?php 1350 } 1351 1352 /** 1353 * Render the Member Type metabox. 1354 * 1355 * @since 2.2.0 1356 * 1357 * @param WP_User|null $user The WP_User object to be edited. 1358 */ 1359 public function user_admin_member_type_metabox( $user = null ) { 1360 1361 // Bail if no user ID. 1362 if ( empty( $user->ID ) ) { 1363 return; 1364 } 1365 1366 $types = bp_get_member_types( array(), 'objects' ); 1367 $current_type = (array) bp_get_member_type( $user->ID, false ); 1368 $types_count = count( array_filter( $current_type ) ); 1369 ?> 1370 1371 <label for="bp-members-profile-member-type" class="screen-reader-text"> 1372 <?php 1373 /* translators: accessibility text */ 1374 esc_html_e( 'Select member type', 'buddypress' ); 1375 ?> 1376 </label> 1377 <ul class="categorychecklist form-no-clear"> 1378 <?php foreach ( $types as $type ) : ?> 1379 <li> 1380 <label class="selectit"> 1381 <input value="<?php echo esc_attr( $type->name ) ?>" name="bp-members-profile-member-type[]" type="checkbox" <?php checked( true, in_array( $type->name, $current_type ) ); ?>> 1382 <?php echo esc_html( $type->labels['singular_name'] ); ?> 1383 </label> 1384 </li> 1385 <?php endforeach; ?> 1386 <input type="hidden" value="<?php echo intval( $types_count ); ?>" name="bp-members-profile-member-types-count" /> 1387 </ul> 1388 1389 <?php 1390 wp_nonce_field( 'bp-member-type-change-' . $user->ID, 'bp-member-type-nonce' ); 1391 } 1392 1393 /** 1394 * Process changes from the Member Type metabox. 1395 * 1396 * @since 2.2.0 1397 */ 1398 public function process_member_type_update() { 1399 if ( ! isset( $_POST['bp-member-type-nonce'] ) || ! isset( $_POST['bp-members-profile-member-types-count'] ) ) { 1400 return; 1401 } 1402 1403 $user_id = $this->get_user_id(); 1404 1405 check_admin_referer( 'bp-member-type-change-' . $user_id, 'bp-member-type-nonce' ); 1406 1407 // Permission check. 1408 if ( ! bp_current_user_can( 'edit_users' ) && ! bp_current_user_can( 'bp_moderate' ) && $user_id != bp_loggedin_user_id() ) { 1409 return; 1410 } 1411 1412 if ( isset( $_POST['bp-members-profile-member-type'] ) ) { 1413 // Member type [string] must either reference a valid member type, or be empty. 1414 $member_type = wp_parse_slug_list( wp_unslash( $_POST['bp-members-profile-member-type'] ) ); 1415 $member_type = array_filter( $member_type ); 1416 } elseif ( 0 !== intval( $_POST['bp-members-profile-member-types-count'] ) ) { 1417 $member_type = false; 1418 } 1419 1420 // Nothing to do there. 1421 if ( ! isset( $member_type ) ) { 1422 return; 1423 } 1424 1425 /* 1426 * If an invalid member type is passed, someone's doing something 1427 * fishy with the POST request, so we can fail silently. 1428 */ 1429 if ( bp_set_member_type( $user_id, $member_type ) ) { 1430 // @todo Success messages can't be posted because other stuff happens on the page load. 1431 } 1432 } 1433 1434 /** 1435 * Add a link to Profile in Users listing row actions. 1436 * 1437 * @since 2.0.0 1438 * 1439 * @param array|string $actions WordPress row actions (edit, delete). 1440 * @param object|null $user The object for the user row. 1441 * @return null|string|array Merged actions. 1442 */ 1443 public function row_actions( $actions = '', $user = null ) { 1444 1445 // Bail if no user ID. 1446 if ( empty( $user->ID ) ) { 1447 return; 1448 } 1449 1450 // Setup args array. 1451 $args = array(); 1452 1453 // Add the user ID if it's not for the current user. 1454 if ( $user->ID !== $this->current_user_id ) { 1455 $args['user_id'] = $user->ID; 1456 } 1457 1458 // Add the referer. 1459 $wp_http_referer = wp_unslash( $_SERVER['REQUEST_URI'] ); 1460 $wp_http_referer = wp_validate_redirect( esc_url_raw( $wp_http_referer ) ); 1461 $args['wp_http_referer'] = urlencode( $wp_http_referer ); 1462 1463 // Add the "Extended" link if the current user can edit this user. 1464 if ( current_user_can( 'edit_user', $user->ID ) || bp_current_user_can( 'bp_moderate' ) ) { 1465 1466 // Add query args and setup the Extended link. 1467 $edit_profile = add_query_arg( $args, $this->edit_profile_url ); 1468 $edit_profile_link = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $edit_profile ), esc_html__( 'Extended', 'buddypress' ) ); 1469 1470 /** 1471 * Check the edit action is available 1472 * and preserve the order edit | profile | remove/delete. 1473 */ 1474 if ( ! empty( $actions['edit'] ) ) { 1475 $edit_action = $actions['edit']; 1476 unset( $actions['edit'] ); 1477 1478 $new_edit_actions = array( 1479 'edit' => $edit_action, 1480 'edit-profile' => $edit_profile_link, 1481 ); 1482 1483 // If not available simply add the edit profile action. 1484 } else { 1485 $new_edit_actions = array( 'edit-profile' => $edit_profile_link ); 1486 } 1487 1488 $actions = array_merge( $new_edit_actions, $actions ); 1489 } 1490 1491 return $actions; 1492 } 1493 1494 /** 1495 * Add a filter to edit profile url in WP Admin Bar. 1496 * 1497 * @since 2.1.0 1498 */ 1499 public function add_edit_profile_url_filter() { 1500 add_filter( 'bp_members_edit_profile_url', array( $this, 'filter_adminbar_profile_link' ), 10, 3 ); 1501 } 1502 1503 /** 1504 * Filter the profile url. 1505 * 1506 * @since 2.1.0 1507 * 1508 * 1509 * @param string $profile_link Profile Link for admin bar. 1510 * @param string $url Profile URL. 1511 * @param int $user_id User ID. 1512 * @return string 1513 */ 1514 public function filter_adminbar_profile_link( $profile_link = '', $url = '', $user_id = 0 ) { 1515 if ( ! is_super_admin( $user_id ) && is_admin() ) { 1516 $profile_link = user_admin_url( 'profile.php' ); 1517 } 1518 return $profile_link; 1519 } 1520 1521 /** 1522 * Remove the filter to edit profile url in WP Admin Bar. 1523 * 1524 * @since 2.1.0 1525 */ 1526 public function remove_edit_profile_url_filter() { 1527 remove_filter( 'bp_members_edit_profile_url', array( $this, 'filter_adminbar_profile_link' ), 10 ); 1528 } 1529 1530 /** Signups Management ****************************************************/ 1531 1532 /** 1533 * Display the admin preferences about signups pagination. 1534 * 1535 * @since 2.0.0 1536 * 1537 * @param int $value Value for signup option. 1538 * @param string $option Value for the option key. 1539 * @param int $new_value Value for the saved option. 1540 * @return int The pagination preferences. 1541 */ 1542 public function signup_screen_options( $value = 0, $option = '', $new_value = 0 ) { 1543 if ( 'users_page_bp_signups_network_per_page' != $option && 'users_page_bp_signups_per_page' != $option ) { 1544 return $value; 1545 } 1546 1547 // Per page. 1548 $new_value = (int) $new_value; 1549 if ( $new_value < 1 || $new_value > 999 ) { 1550 return $value; 1551 } 1552 1553 return $new_value; 1554 } 1555 1556 /** 1557 * Make sure no signups will show in users list. 1558 * 1559 * This is needed to handle signups that may have not been activated 1560 * before the 2.0.0 upgrade. 1561 * 1562 * @since 2.0.0 1563 * 1564 * @param WP_User_Query|null $query The users query. 1565 * @return WP_User_Query|null The users query without the signups. 1566 */ 1567 public function remove_signups_from_user_query( $query = null ) { 1568 global $wpdb; 1569 1570 // Bail if this is an ajax request. 1571 if ( defined( 'DOING_AJAX' ) ) { 1572 return; 1573 } 1574 1575 // Bail if updating BuddyPress. 1576 if ( bp_is_update() ) { 1577 return; 1578 } 1579 1580 // Bail if there is no current admin screen. 1581 if ( ! function_exists( 'get_current_screen' ) || ! get_current_screen() ) { 1582 return; 1583 } 1584 1585 // Get current screen. 1586 $current_screen = get_current_screen(); 1587 1588 // Bail if not on a users page. 1589 if ( ! isset( $current_screen->id ) || $this->users_page !== $current_screen->id ) { 1590 return; 1591 } 1592 1593 // Bail if already querying by an existing role. 1594 if ( ! empty( $query->query_vars['role'] ) ) { 1595 return; 1596 } 1597 1598 $query->query_where .= " AND {$wpdb->users}.user_status != 2"; 1599 } 1600 1601 /** 1602 * Filter the WP Users List Table views to include 'bp-signups'. 1603 * 1604 * @since 2.0.0 1605 * 1606 * @param array $views WP List Table views. 1607 * @return array The views with the signup view added. 1608 */ 1609 public function signup_filter_view( $views = array() ) { 1610 global $role; 1611 1612 // Remove the 'current' class from All if we're on the signups view. 1613 if ( 'registered' === $role ) { 1614 $views['all'] = str_replace( 'class="current"', '', $views['all'] ); 1615 $class = 'current'; 1616 } else { 1617 $class = ''; 1618 } 1619 1620 $signups = BP_Signup::count_signups(); 1621 1622 if ( is_network_admin() ) { 1623 $base_url = network_admin_url( 'users.php' ); 1624 } else { 1625 $base_url = bp_get_admin_url( 'users.php' ); 1626 } 1627 1628 $url = add_query_arg( 'page', 'bp-signups', $base_url ); 1629 1630 /* translators: %s: number of pending accounts */ 1631 $text = sprintf( _x( 'Pending %s', 'signup users', 'buddypress' ), '<span class="count">(' . number_format_i18n( $signups ) . ')</span>' ); 1632 1633 $views['registered'] = sprintf( '<a href="%1$s" class="%2$s">%3$s</a>', esc_url( $url ), $class, $text ); 1634 1635 return $views; 1636 } 1637 1638 /** 1639 * Load the Signup WP Users List table. 1640 * 1641 * @since 2.0.0 1642 * 1643 * @param string $class The name of the class to use. 1644 * @param string $required The parent class. 1645 * @return WP_List_Table|null The List table. 1646 */ 1647 public static function get_list_table_class( $class = '', $required = '' ) { 1648 if ( empty( $class ) ) { 1649 return; 1650 } 1651 1652 if ( ! empty( $required ) ) { 1653 require_once( ABSPATH . 'wp-admin/includes/class-wp-' . $required . '-list-table.php' ); 1654 } 1655 1656 return new $class(); 1657 } 1658 1659 /** 1660 * Set up the signups admin page. 1661 * 1662 * Loaded before the page is rendered, this function does all initial 1663 * setup, including: processing form requests, registering contextual 1664 * help, and setting up screen options. 1665 * 1666 * @since 2.0.0 1667 * 1668 * @global $bp_members_signup_list_table 1669 */ 1670 public function signups_admin_load() { 1671 global $bp_members_signup_list_table; 1672 1673 // Build redirection URL. 1674 $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'] ); 1675 $doaction = bp_admin_list_table_current_bulk_action(); 1676 1677 /** 1678 * Fires at the start of the signups admin load. 1679 * 1680 * @since 2.0.0 1681 * 1682 * @param string $doaction Current bulk action being processed. 1683 * @param array $_REQUEST Current $_REQUEST global. 1684 */ 1685 do_action( 'bp_signups_admin_load', $doaction, $_REQUEST ); 1686 1687 /** 1688 * Filters the allowed actions for use in the user signups admin page. 1689 * 1690 * @since 2.0.0 1691 * 1692 * @param array $value Array of allowed actions to use. 1693 */ 1694 $allowed_actions = apply_filters( 'bp_signups_admin_allowed_actions', array( 'do_delete', 'do_activate', 'do_resend' ) ); 1695 1696 // Prepare the display of the Signups screen. 1697 if ( ! in_array( $doaction, $allowed_actions ) || ( -1 == $doaction ) ) { 1698 1699 if ( is_network_admin() ) { 1700 $bp_members_signup_list_table = self::get_list_table_class( 'BP_Members_MS_List_Table', 'ms-users' ); 1701 } else { 1702 $bp_members_signup_list_table = self::get_list_table_class( 'BP_Members_List_Table', 'users' ); 1703 } 1704 1705 // The per_page screen option. 1706 add_screen_option( 'per_page', array( 'label' => _x( 'Pending Accounts', 'Pending Accounts per page (screen options)', 'buddypress' ) ) ); 1707 1708 get_current_screen()->add_help_tab( array( 1709 'id' => 'bp-signups-overview', 1710 'title' => __( 'Overview', 'buddypress' ), 1711 'content' => 1712 '<p>' . __( 'This is the administration screen for pending accounts on your site.', 'buddypress' ) . '</p>' . 1713 '<p>' . __( 'From the screen options, you can customize the displayed columns and the pagination of this screen.', 'buddypress' ) . '</p>' . 1714 '<p>' . __( 'You can reorder the list of your pending accounts by clicking on the Username, Email or Registered column headers.', 'buddypress' ) . '</p>' . 1715 '<p>' . __( 'Using the search form, you can find pending accounts more easily. The Username and Email fields will be included in the search.', 'buddypress' ) . '</p>' 1716 ) ); 1717 1718 $signup_help_content = '<p>' . esc_html__( '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>'; 1719 1720 if ( bp_get_membership_requests_required() ) { 1721 $signup_help_content .= '<ul><li>' . esc_html__( '"Activate" will activate the user immediately without requiring that they validate their email.', 'buddypress' ) .'</li>' . 1722 '<li>' . esc_html__( '"Approve Request" or "Resend Approval" takes you to the confirmation screen before being able to send the activation link to the desired pending request. You can only send the activation email once per day.', 'buddypress' ) . '</li>'; 1723 1724 if ( bp_is_active( 'xprofile' ) ) { 1725 $signup_help_content .= '<li>' . esc_html__( '"Profile Info" will display extended profile information for the request.', 'buddypress' ) . '</li>'; 1726 } 1727 1728 $signup_help_content .= '<li>' . esc_html__( '"Delete" allows you to delete a pending account from your site. You will be asked to confirm this deletion.', 'buddypress' ) . '</li></ul>'; 1729 } else { 1730 $signup_help_content .= '<ul><li>' . esc_html__( '"Email" takes you to the confirmation screen before being able to send the activation link to the desired pending account. You can only send the activation email once per day.', 'buddypress' ) . '</li>' . 1731 '<li>' . __( '"Delete" allows you to delete a pending account from your site. You will be asked to confirm this deletion.', 'buddypress' ) . '</li></ul>'; 1732 } 1733 1734 $signup_help_content .= '<p>' . esc_html__( 'By clicking on a Username you will be able to activate a pending account from the confirmation screen.', 'buddypress' ) . '</p>' . 1735 '<p>' . __( 'Bulk actions allow you to perform these 3 actions for the selected rows.', 'buddypress' ) . '</p>'; 1736 1737 get_current_screen()->add_help_tab( array( 1738 'id' => 'bp-signups-actions', 1739 'title' => __( 'Actions', 'buddypress' ), 1740 'content' => $signup_help_content 1741 ) ); 1742 1743 // Help panel - sidebar links. 1744 get_current_screen()->set_help_sidebar( 1745 '<p><strong>' . esc_html__( 'For more information:', 'buddypress' ) . '</strong></p>' . 1746 '<p>' . __( '<a href="https://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>' 1747 ); 1748 1749 // Add accessible hidden headings and text for the Pending Users screen. 1750 get_current_screen()->set_screen_reader_content( array( 1751 /* translators: accessibility text */ 1752 'heading_views' => __( 'Filter users list', 'buddypress' ), 1753 /* translators: accessibility text */ 1754 'heading_pagination' => __( 'Pending users list navigation', 'buddypress' ), 1755 /* translators: accessibility text */ 1756 'heading_list' => __( 'Pending users list', 'buddypress' ), 1757 ) ); 1758 1759 // Use thickbox to display the extended profile information. 1760 if ( bp_is_active( 'xprofile' ) || bp_members_site_requests_enabled() ) { 1761 wp_enqueue_style( 'thickbox' ); 1762 wp_enqueue_script( 1763 'bp-signup-preview', 1764 $this->js_url . 'signup-preview' . bp_core_get_minified_asset_suffix() . '.js', 1765 array( 'bp-thickbox', 'jquery' ), 1766 bp_get_version(), 1767 true 1768 ); 1769 wp_localize_script( 1770 'bp-signup-preview', 1771 'bpSignupPreview', 1772 array( 1773 'modalLabel' => __( 'Profile info preview', 'buddypress' ), 1774 ) 1775 ); 1776 } 1777 1778 } else { 1779 if ( ! empty( $_REQUEST['signup_ids' ] ) ) { 1780 $signups = wp_parse_id_list( $_REQUEST['signup_ids' ] ); 1781 } 1782 1783 // Handle resent activation links. 1784 if ( 'do_resend' == $doaction ) { 1785 1786 // Nonce check. 1787 check_admin_referer( 'signups_resend' ); 1788 1789 $resent = BP_Signup::resend( $signups ); 1790 1791 if ( empty( $resent ) ) { 1792 $redirect_to = add_query_arg( 'error', $doaction, $redirect_to ); 1793 } else { 1794 $query_arg = array( 'updated' => 'resent' ); 1795 1796 if ( ! empty( $resent['resent'] ) ) { 1797 $query_arg['resent'] = count( $resent['resent'] ); 1798 } 1799 1800 if ( ! empty( $resent['errors'] ) ) { 1801 $query_arg['notsent'] = count( $resent['errors'] ); 1802 set_transient( '_bp_admin_signups_errors', $resent['errors'], 30 ); 1803 } 1804 1805 $redirect_to = add_query_arg( $query_arg, $redirect_to ); 1806 } 1807 1808 bp_core_redirect( $redirect_to ); 1809 1810 // Handle activated accounts. 1811 } elseif ( 'do_activate' == $doaction ) { 1812 1813 // Nonce check. 1814 check_admin_referer( 'signups_activate' ); 1815 1816 $activated = BP_Signup::activate( $signups ); 1817 1818 if ( empty( $activated ) ) { 1819 $redirect_to = add_query_arg( 'error', $doaction, $redirect_to ); 1820 } else { 1821 $query_arg = array( 'updated' => 'activated' ); 1822 1823 if ( ! empty( $activated['activated'] ) ) { 1824 $query_arg['activated'] = count( $activated['activated'] ); 1825 } 1826 1827 if ( ! empty( $activated['errors'] ) ) { 1828 $query_arg['notactivated'] = count( $activated['errors'] ); 1829 set_transient( '_bp_admin_signups_errors', $activated['errors'], 30 ); 1830 } 1831 1832 $redirect_to = add_query_arg( $query_arg, $redirect_to ); 1833 } 1834 1835 bp_core_redirect( $redirect_to ); 1836 1837 // Handle sign-ups delete. 1838 } elseif ( 'do_delete' == $doaction ) { 1839 1840 // Nonce check. 1841 check_admin_referer( 'signups_delete' ); 1842 1843 $deleted = BP_Signup::delete( $signups ); 1844 1845 if ( empty( $deleted ) ) { 1846 $redirect_to = add_query_arg( 'error', $doaction, $redirect_to ); 1847 } else { 1848 $query_arg = array( 'updated' => 'deleted' ); 1849 1850 if ( ! empty( $deleted['deleted'] ) ) { 1851 $query_arg['deleted'] = count( $deleted['deleted'] ); 1852 } 1853 1854 if ( ! empty( $deleted['errors'] ) ) { 1855 $query_arg['notdeleted'] = count( $deleted['errors'] ); 1856 set_transient( '_bp_admin_signups_errors', $deleted['errors'], 30 ); 1857 } 1858 1859 $redirect_to = add_query_arg( $query_arg, $redirect_to ); 1860 } 1861 1862 bp_core_redirect( $redirect_to ); 1863 1864 // Plugins can update other stuff from here. 1865 } else { 1866 $this->redirect = $redirect_to; 1867 1868 /** 1869 * Fires at end of signups admin load if doaction does not match any actions. 1870 * 1871 * @since 2.0.0 1872 * 1873 * @param string $doaction Current bulk action being processed. 1874 * @param array $_REQUEST Current $_REQUEST global. 1875 * @param string $redirect Determined redirect url to send user to. 1876 */ 1877 do_action( 'bp_members_admin_update_signups', $doaction, $_REQUEST, $this->redirect ); 1878 1879 bp_core_redirect( $this->redirect ); 1880 } 1881 } 1882 } 1883 1884 /** 1885 * Display any activation errors. 1886 * 1887 * @since 2.0.0 1888 */ 1889 public function signups_display_errors() { 1890 1891 // Look for sign-up errors. 1892 $errors = get_transient( '_bp_admin_signups_errors' ); 1893 1894 // Bail if no activation errors. 1895 if ( empty( $errors ) ) { 1896 return; 1897 } 1898 1899 // Loop through errors and display them. 1900 foreach ( $errors as $error ) : ?> 1901 1902 <li><?php echo esc_html( $error[0] );?>: <?php echo esc_html( $error[1] );?></li> 1903 1904 <?php endforeach; 1905 1906 // Delete the redirect transient. 1907 delete_transient( '_bp_admin_signups_errors' ); 1908 } 1909 1910 /** 1911 * Get admin notice when viewing the sign-up page. 1912 * 1913 * @since 2.1.0 1914 * 1915 * @return array 1916 */ 1917 private function get_signup_notice() { 1918 1919 // Setup empty notice for return value. 1920 $notice = array(); 1921 1922 // Updates. 1923 if ( ! empty( $_REQUEST['updated'] ) ) { 1924 switch ( $_REQUEST['updated'] ) { 1925 case 'resent': 1926 $notice = array( 1927 'class' => 'updated', 1928 'message' => '' 1929 ); 1930 1931 if ( ! empty( $_REQUEST['resent'] ) ) { 1932 $notice['message'] .= sprintf( 1933 /* translators: %s: number of activation emails sent */ 1934 _nx( '%s activation email successfully sent! ', '%s activation emails successfully sent! ', 1935 absint( $_REQUEST['resent'] ), 1936 'signup resent', 1937 'buddypress' 1938 ), 1939 number_format_i18n( absint( $_REQUEST['resent'] ) ) 1940 ); 1941 } 1942 1943 if ( ! empty( $_REQUEST['notsent'] ) ) { 1944 $notice['message'] .= sprintf( 1945 /* translators: %s: number of unsent activation emails */ 1946 _nx( '%s activation email was not sent.', '%s activation emails were not sent.', 1947 absint( $_REQUEST['notsent'] ), 1948 'signup notsent', 1949 'buddypress' 1950 ), 1951 number_format_i18n( absint( $_REQUEST['notsent'] ) ) 1952 ); 1953 1954 if ( empty( $_REQUEST['resent'] ) ) { 1955 $notice['class'] = 'error'; 1956 } 1957 } 1958 1959 break; 1960 1961 case 'activated': 1962 $notice = array( 1963 'class' => 'updated', 1964 'message' => '' 1965 ); 1966 1967 if ( ! empty( $_REQUEST['activated'] ) ) { 1968 $notice['message'] .= sprintf( 1969 /* translators: %s: number of activated accounts */ 1970 _nx( '%s account successfully activated! ', '%s accounts successfully activated! ', 1971 absint( $_REQUEST['activated'] ), 1972 'signup resent', 1973 'buddypress' 1974 ), 1975 number_format_i18n( absint( $_REQUEST['activated'] ) ) 1976 ); 1977 } 1978 1979 if ( ! empty( $_REQUEST['notactivated'] ) ) { 1980 $notice['message'] .= sprintf( 1981 /* translators: %s: number of accounts not activated */ 1982 _nx( '%s account was not activated.', '%s accounts were not activated.', 1983 absint( $_REQUEST['notactivated'] ), 1984 'signup notsent', 1985 'buddypress' 1986 ), 1987 number_format_i18n( absint( $_REQUEST['notactivated'] ) ) 1988 ); 1989 1990 if ( empty( $_REQUEST['activated'] ) ) { 1991 $notice['class'] = 'error'; 1992 } 1993 } 1994 1995 break; 1996 1997 case 'deleted': 1998 $notice = array( 1999 'class' => 'updated', 2000 'message' => '' 2001 ); 2002 2003 if ( ! empty( $_REQUEST['deleted'] ) ) { 2004 $notice['message'] .= sprintf( 2005 /* translators: %s: number of deleted signups */ 2006 _nx( '%s sign-up successfully deleted!', '%s sign-ups successfully deleted!', 2007 absint( $_REQUEST['deleted'] ), 2008 'signup deleted', 2009 'buddypress' 2010 ), 2011 number_format_i18n( absint( $_REQUEST['deleted'] ) ) 2012 ); 2013 } 2014 2015 if ( ! empty( $_REQUEST['notdeleted'] ) ) { 2016 $notdeleted = absint( $_REQUEST['notdeleted'] ); 2017 $notice['message'] .= sprintf( 2018 _nx( 2019 /* translators: %s: number of deleted signups not deleted */ 2020 '%s sign-up was not deleted.', '%s sign-ups were not deleted.', 2021 $notdeleted, 2022 'signup notdeleted', 2023 'buddypress' 2024 ), 2025 number_format_i18n( $notdeleted ) 2026 ); 2027 2028 if ( empty( $_REQUEST['deleted'] ) ) { 2029 $notice['class'] = 'error'; 2030 } 2031 } 2032 2033 break; 2034 } 2035 } 2036 2037 // Errors. 2038 if ( ! empty( $_REQUEST['error'] ) ) { 2039 switch ( $_REQUEST['error'] ) { 2040 case 'do_resend': 2041 $notice = array( 2042 'class' => 'error', 2043 'message' => esc_html__( 'There was a problem sending the activation emails. Please try again.', 'buddypress' ), 2044 ); 2045 break; 2046 2047 case 'do_activate': 2048 $notice = array( 2049 'class' => 'error', 2050 'message' => esc_html__( 'There was a problem activating accounts. Please try again.', 'buddypress' ), 2051 ); 2052 break; 2053 2054 case 'do_delete': 2055 $notice = array( 2056 'class' => 'error', 2057 'message' => esc_html__( 'There was a problem deleting sign-ups. Please try again.', 'buddypress' ), 2058 ); 2059 break; 2060 } 2061 } 2062 2063 return $notice; 2064 } 2065 2066 /** 2067 * Signups admin page router. 2068 * 2069 * Depending on the context, display 2070 * - the list of signups, 2071 * - or the delete confirmation screen, 2072 * - or the activate confirmation screen, 2073 * - or the "resend" email confirmation screen. 2074 * 2075 * Also prepare the admin notices. 2076 * 2077 * @since 2.0.0 2078 */ 2079 public function signups_admin() { 2080 $doaction = bp_admin_list_table_current_bulk_action(); 2081 2082 // Prepare notices for admin. 2083 $notice = $this->get_signup_notice(); 2084 2085 // Display notices. 2086 if ( ! empty( $notice ) ) : 2087 if ( 'updated' === $notice['class'] ) : ?> 2088 2089 <div id="message" class="<?php echo esc_attr( $notice['class'] ); ?> notice is-dismissible"> 2090 2091 <?php else: ?> 2092 2093 <div class="<?php echo esc_attr( $notice['class'] ); ?> notice is-dismissible"> 2094 2095 <?php endif; ?> 2096 2097 <p><?php echo $notice['message']; ?></p> 2098 2099 <?php if ( ! empty( $_REQUEST['notactivated'] ) || ! empty( $_REQUEST['notdeleted'] ) || ! empty( $_REQUEST['notsent'] ) ) :?> 2100 2101 <ul><?php $this->signups_display_errors();?></ul> 2102 2103 <?php endif ;?> 2104 2105 </div> 2106 2107 <?php endif; 2108 2109 // Show the proper screen. 2110 switch ( $doaction ) { 2111 case 'activate' : 2112 case 'delete' : 2113 case 'resend' : 2114 $this->signups_admin_manage( $doaction ); 2115 break; 2116 2117 default: 2118 $this->signups_admin_index(); 2119 break; 2120 2121 } 2122 } 2123 2124 /** 2125 * This is the list of the Pending accounts (signups). 2126 * 2127 * @since 2.0.0 2128 * 2129 * @global $plugin_page 2130 * @global $bp_members_signup_list_table 2131 */ 2132 public function signups_admin_index() { 2133 global $plugin_page, $bp_members_signup_list_table; 2134 2135 $usersearch = ! empty( $_REQUEST['s'] ) ? stripslashes( $_REQUEST['s'] ) : ''; 2136 2137 // Prepare the group items for display. 2138 $bp_members_signup_list_table->prepare_items(); 2139 2140 if ( is_network_admin() ) { 2141 $form_url = network_admin_url( 'users.php' ); 2142 } else { 2143 $form_url = bp_get_admin_url( 'users.php' ); 2144 } 2145 2146 $form_url = add_query_arg( 2147 array( 2148 'page' => 'bp-signups', 2149 ), 2150 $form_url 2151 ); 2152 2153 $search_form_url = remove_query_arg( 2154 array( 2155 'action', 2156 'deleted', 2157 'notdeleted', 2158 'error', 2159 'updated', 2160 'delete', 2161 'activate', 2162 'activated', 2163 'notactivated', 2164 'resend', 2165 'resent', 2166 'notresent', 2167 'do_delete', 2168 'do_activate', 2169 'do_resend', 2170 'action2', 2171 '_wpnonce', 2172 'signup_ids' 2173 ), $_SERVER['REQUEST_URI'] 2174 ); 2175 2176 ?> 2177 2178 <div class="wrap"> 2179 <h1 class="wp-heading-inline"><?php _e( 'Users', 'buddypress' ); ?></h1> 2180 2181 <?php if ( current_user_can( 'create_users' ) ) : ?> 2182 2183 <a href="user-new.php" class="page-title-action"><?php echo esc_html_x( 'Add New', 'user', 'buddypress' ); ?></a> 2184 2185 <?php elseif ( is_multisite() && current_user_can( 'promote_users' ) ) : ?> 2186 2187 <a href="user-new.php" class="page-title-action"><?php echo esc_html_x( 'Add Existing', 'user', 'buddypress' ); ?></a> 2188 2189 <?php endif; 2190 2191 if ( $usersearch ) { 2192 printf( '<span class="subtitle">' . __( 'Search results for “%s”', 'buddypress' ) . '</span>', esc_html( $usersearch ) ); 2193 } 2194 ?> 2195 2196 <hr class="wp-header-end"> 2197 2198 <?php // Display each signups on its own row. ?> 2199 <?php $bp_members_signup_list_table->views(); ?> 2200 2201 <form id="bp-signups-search-form" action="<?php echo esc_url( $search_form_url ) ;?>"> 2202 <input type="hidden" name="page" value="<?php echo esc_attr( $plugin_page ); ?>" /> 2203 <?php $bp_members_signup_list_table->search_box( __( 'Search Pending Users', 'buddypress' ), 'bp-signups' ); ?> 2204 </form> 2205 2206 <form id="bp-signups-form" action="<?php echo esc_url( $form_url );?>" method="post"> 2207 <?php $bp_members_signup_list_table->display(); ?> 2208 </form> 2209 </div> 2210 <?php 2211 } 2212 2213 /** 2214 * This is the confirmation screen for actions. 2215 * 2216 * @since 2.0.0 2217 * 2218 * @param string $action Delete, activate, or resend activation link. 2219 * 2220 * @return null|false 2221 */ 2222 public function signups_admin_manage( $action = '' ) { 2223 if ( ! current_user_can( $this->capability ) || empty( $action ) ) { 2224 die( '-1' ); 2225 } 2226 2227 // Get the user IDs from the URL. 2228 $ids = false; 2229 if ( ! empty( $_POST['allsignups'] ) ) { 2230 $ids = wp_parse_id_list( $_POST['allsignups'] ); 2231 } elseif ( ! empty( $_GET['signup_id'] ) ) { 2232 $ids = absint( $_GET['signup_id'] ); 2233 } 2234 2235 if ( empty( $ids ) ) { 2236 return false; 2237 } 2238 2239 // Query for signups, and filter out those IDs that don't 2240 // correspond to an actual signup. 2241 $signups_query = BP_Signup::get( array( 2242 'include' => $ids, 2243 ) ); 2244 2245 $signups = $signups_query['signups']; 2246 $signup_ids = wp_list_pluck( $signups, 'id' ); 2247 2248 // Set up strings. 2249 switch ( $action ) { 2250 case 'delete' : 2251 $header_text = __( 'Delete Pending Accounts', 'buddypress' ); 2252 if ( 1 == count( $signup_ids ) ) { 2253 $helper_text = __( 'You are about to delete the following account:', 'buddypress' ); 2254 } else { 2255 $helper_text = __( 'You are about to delete the following accounts:', 'buddypress' ); 2256 } 2257 break; 2258 2259 case 'activate' : 2260 $header_text = __( 'Activate Pending Accounts', 'buddypress' ); 2261 if ( 1 == count( $signup_ids ) ) { 2262 $helper_text = __( 'You are about to activate the following account:', 'buddypress' ); 2263 } else { 2264 $helper_text = __( 'You are about to activate the following accounts:', 'buddypress' ); 2265 } 2266 break; 2267 2268 case 'resend' : 2269 2270 if ( bp_get_membership_requests_required() ) { 2271 $header_text = __( 'Approve Membership Requests', 'buddypress' ); 2272 if ( 1 === count( $signup_ids ) ) { 2273 $helper_text = __( 'You are about to send an approval email to the following user:', 'buddypress' ); 2274 } else { 2275 $helper_text = __( 'You are about to send approval emails to the following users:', 'buddypress' ); 2276 } 2277 } else { 2278 $header_text = __( 'Resend Activation Emails', 'buddypress' ); 2279 if ( 1 === count( $signup_ids ) ) { 2280 $helper_text = __( 'You are about to resend an activation email to the following account:', 'buddypress' ); 2281 } else { 2282 $helper_text = __( 'You are about to resend an activation email to the following accounts:', 'buddypress' ); 2283 } 2284 } 2285 break; 2286 2287 } 2288 2289 // These arguments are added to all URLs. 2290 $url_args = array( 'page' => 'bp-signups' ); 2291 2292 // These arguments are only added when performing an action. 2293 $action_args = array( 2294 'action' => 'do_' . $action, 2295 'signup_ids' => implode( ',', $signup_ids ) 2296 ); 2297 2298 if ( is_network_admin() ) { 2299 $base_url = network_admin_url( 'users.php' ); 2300 } else { 2301 $base_url = bp_get_admin_url( 'users.php' ); 2302 } 2303 2304 $cancel_url = add_query_arg( $url_args, $base_url ); 2305 $action_url = wp_nonce_url( 2306 add_query_arg( 2307 array_merge( $url_args, $action_args ), 2308 $base_url 2309 ), 2310 'signups_' . $action 2311 ); 2312 2313 // Prefetch registration field data. 2314 $fdata = array(); 2315 if ( bp_is_active( 'xprofile' ) && ( 'activate' == $action || ( 'resend' == $action && bp_get_membership_requests_required() ) ) ) { 2316 $field_groups = bp_xprofile_get_groups( array( 2317 'exclude_fields' => 1, 2318 'update_meta_cache' => false, 2319 'fetch_fields' => true, 2320 ) ); 2321 2322 foreach( $field_groups as $fg ) { 2323 foreach( $fg->fields as $f ) { 2324 $fdata[ $f->id ] = $f->name; 2325 } 2326 } 2327 } 2328 2329 ?> 2330 2331 <div class="wrap"> 2332 <h1 class="wp-heading-inline"><?php echo esc_html( $header_text ); ?></h1> 2333 <hr class="wp-header-end"> 2334 2335 <p><?php echo esc_html( $helper_text ); ?></p> 2336 2337 <ol class="bp-signups-list"> 2338 <?php foreach ( $signups as $signup ) : 2339 if ( $signup->count_sent > 0 ) { 2340 $last_notified = mysql2date( 'Y/m/d g:i:s a', $signup->date_sent ); 2341 } else { 2342 $last_notified = __( 'Not yet notified', 'buddypress' ); 2343 } 2344 $profile_field_ids = array(); 2345 2346 // Get all xprofile field IDs except field 1. 2347 if ( ! empty( $signup->meta['profile_field_ids'] ) ) { 2348 $profile_field_ids = array_flip( explode( ',', $signup->meta['profile_field_ids'] ) ); 2349 unset( $profile_field_ids[1] ); 2350 } ?> 2351 2352 <li> 2353 <strong><?php echo esc_html( $signup->user_login ) ?></strong> 2354 2355 <?php if ( 'activate' == $action || ( 'resend' == $action && bp_get_membership_requests_required() ) ) : ?> 2356 <table class="wp-list-table widefat fixed striped"> 2357 <tbody> 2358 <tr> 2359 <td class="column-fields"><?php esc_html_e( 'Display Name', 'buddypress' ); ?></td> 2360 <td><?php echo esc_html( $signup->user_name ); ?></td> 2361 </tr> 2362 2363 <tr> 2364 <td class="column-fields"><?php esc_html_e( 'Email', 'buddypress' ); ?></td> 2365 <td><?php echo sanitize_email( $signup->user_email ); ?></td> 2366 </tr> 2367 2368 <?php if ( bp_is_active( 'xprofile' ) && ! empty( $profile_field_ids ) ) : ?> 2369 <?php foreach ( $profile_field_ids as $pid => $noop ) : 2370 $field_value = isset( $signup->meta[ "field_{$pid}" ] ) ? $signup->meta[ "field_{$pid}" ] : ''; ?> 2371 <tr> 2372 <td class="column-fields"><?php echo esc_html( $fdata[ $pid ] ); ?></td> 2373 <td><?php echo bp_members_admin_format_xprofile_field_for_display( $field_value ); ?></td> 2374 </tr> 2375 2376 <?php endforeach; ?> 2377 2378 <?php endif; ?> 2379 2380 <?php 2381 /** 2382 * Fires inside the table listing the activate action confirmation details. 2383 * 2384 * @since 6.0.0 2385 * 2386 * @param object $signup The Sign-up Object. 2387 */ 2388 do_action( 'bp_activate_signup_confirmation_details', $signup ); 2389 ?> 2390 2391 </tbody> 2392 </table> 2393 2394 <?php 2395 /** 2396 * Fires outside the table listing the activate action confirmation details. 2397 * 2398 * @since 6.0.0 2399 * 2400 * @param object $signup The Sign-up Object. 2401 */ 2402 do_action( 'bp_activate_signup_confirmation_after_details', $signup ); 2403 ?> 2404 2405 <?php endif; ?> 2406 2407 <?php if ( 'resend' == $action ) : ?> 2408 2409 <p class="description"> 2410 <?php 2411 /* translators: %s: notification date */ 2412 printf( esc_html__( 'Last notified: %s', 'buddypress'), $last_notified ); 2413 ?> 2414 2415 <?php if ( ! empty( $signup->recently_sent ) ) : ?> 2416 2417 <span class="attention wp-ui-text-notification"> <?php esc_html_e( '(less than 24 hours ago)', 'buddypress' ); ?></span> 2418 2419 <?php endif; ?> 2420 </p> 2421 2422 <?php endif; ?> 2423 2424 </li> 2425 2426 <?php endforeach; ?> 2427 </ol> 2428 2429 <?php if ( 'delete' === $action ) : ?> 2430 2431 <p><strong><?php esc_html_e( 'This action cannot be undone.', 'buddypress' ) ?></strong></p> 2432 2433 <?php endif ; ?> 2434 2435 <a class="button-primary" href="<?php echo esc_url( $action_url ); ?>"><?php esc_html_e( 'Confirm', 'buddypress' ); ?></a> 2436 <a class="button" href="<?php echo esc_url( $cancel_url ); ?>"><?php esc_html_e( 'Cancel', 'buddypress' ) ?></a> 2437 </div> 2438 2439 <?php 2440 } 2441 2442 /** Users List Management ****************************************************/ 2443 2444 /** 2445 * Display a dropdown to bulk change the member type of selected user(s). 2446 * 2447 * @since 2.7.0 2448 * 2449 * @param string $which Where this dropdown is displayed - top or bottom. 2450 */ 2451 public function users_table_output_type_change_select( $which = 'top' ) { 2452 2453 // Bail if current user cannot promote users. 2454 if ( ! bp_current_user_can( 'promote_users' ) ) { 2455 return; 2456 } 2457 2458 // `$which` is only passed in WordPress 4.6+. Avoid duplicating controls in earlier versions. 2459 static $displayed = false; 2460 if ( version_compare( bp_get_major_wp_version(), '4.6', '<' ) && $displayed ) { 2461 return; 2462 } 2463 $displayed = true; 2464 2465 $id_name = 'bottom' === $which ? 'bp_change_type2' : 'bp_change_type'; 2466 2467 $types = bp_get_member_types( array(), 'objects' ); ?> 2468 2469 <label class="screen-reader-text" for="<?php echo $id_name; ?>"><?php _e( 'Change member type to…', 'buddypress' ) ?></label> 2470 <select name="<?php echo $id_name; ?>" id="<?php echo $id_name; ?>" style="display:inline-block;float:none;"> 2471 <option value=""><?php _e( 'Change member type to…', 'buddypress' ) ?></option> 2472 2473 <?php foreach( $types as $type ) : ?> 2474 2475 <option value="<?php echo esc_attr( $type->name ); ?>"><?php echo esc_html( $type->labels['singular_name'] ); ?></option> 2476 2477 <?php endforeach; ?> 2478 2479 <option value="remove_member_type"><?php _e( 'No Member Type', 'buddypress' ) ?></option> 2480 2481 </select> 2482 <?php 2483 wp_nonce_field( 'bp-bulk-users-change-type-' . bp_loggedin_user_id(), 'bp-bulk-users-change-type-nonce' ); 2484 submit_button( __( 'Change', 'buddypress' ), 'button', 'bp_change_member_type', false ); 2485 } 2486 2487 /** 2488 * Process bulk member type change submission from the WP admin users list table. 2489 * 2490 * @since 2.7.0 2491 */ 2492 public function users_table_process_bulk_type_change() { 2493 // Output the admin notice. 2494 $this->users_type_change_notice(); 2495 2496 // Bail if no users are specified or if this isn't a BuddyPress action. 2497 if ( empty( $_REQUEST['users'] ) 2498 || ( empty( $_REQUEST['bp_change_type'] ) && empty( $_REQUEST['bp_change_type2'] ) ) 2499 || empty( $_REQUEST['bp_change_member_type'] ) 2500 ) { 2501 return; 2502 } 2503 2504 // Bail if nonce check fails. 2505 check_admin_referer( 'bp-bulk-users-change-type-' . bp_loggedin_user_id(), 'bp-bulk-users-change-type-nonce' ); 2506 2507 // Bail if current user cannot promote users. 2508 if ( ! bp_current_user_can( 'promote_users' ) ) { 2509 return; 2510 } 2511 2512 $new_type = ''; 2513 if ( ! empty( $_REQUEST['bp_change_type2'] ) ) { 2514 $new_type = sanitize_text_field( $_REQUEST['bp_change_type2'] ); 2515 } elseif ( ! empty( $_REQUEST['bp_change_type'] ) ) { 2516 $new_type = sanitize_text_field( $_REQUEST['bp_change_type'] ); 2517 } 2518 2519 // Check that the selected type actually exists. 2520 if ( 'remove_member_type' != $new_type && null === bp_get_member_type_object( $new_type ) ) { 2521 $error = true; 2522 } else { 2523 // Run through user ids. 2524 $error = false; 2525 foreach ( (array) $_REQUEST['users'] as $user_id ) { 2526 $user_id = (int) $user_id; 2527 2528 // Get the old member types to check against. 2529 $current_types = bp_get_member_type( $user_id, false ); 2530 2531 if ( $current_types && 'remove_member_type' === $new_type ) { 2532 $member_types = array(); 2533 } elseif ( ! $current_types || 1 !== count( $current_types ) || $new_type !== $current_types[0] ) { 2534 // Set the new member type. 2535 $member_types = array( $new_type ); 2536 } 2537 2538 if ( isset( $member_types ) ) { 2539 $set = bp_set_member_type( $user_id, $member_types ); 2540 if ( false === $set || is_wp_error( $set ) ) { 2541 $error = true; 2542 } 2543 unset( $member_types ); 2544 } 2545 } 2546 } 2547 2548 // If there were any errors, show the error message. 2549 if ( $error ) { 2550 $redirect = add_query_arg( array( 'updated' => 'member-type-change-error' ), wp_get_referer() ); 2551 } else { 2552 $redirect = add_query_arg( array( 'updated' => 'member-type-change-success' ), wp_get_referer() ); 2553 } 2554 2555 wp_redirect( $redirect ); 2556 exit(); 2557 } 2558 2559 /** 2560 * Display an admin notice upon member type bulk update. 2561 * 2562 * @since 2.7.0 2563 */ 2564 public function users_type_change_notice() { 2565 $updated = isset( $_REQUEST['updated'] ) ? $_REQUEST['updated'] : false; 2566 2567 // Display feedback. 2568 if ( $updated && in_array( $updated, array( 'member-type-change-error', 'member-type-change-success' ), true ) ) { 2569 2570 if ( 'member-type-change-error' === $updated ) { 2571 $notice = __( 'There was an error while changing member type. Please try again.', 'buddypress' ); 2572 $type = 'error'; 2573 } else { 2574 $notice = __( 'Member type was changed successfully.', 'buddypress' ); 2575 $type = 'updated'; 2576 } 2577 2578 bp_core_add_admin_notice( $notice, $type ); 2579 } 2580 } 2581 2582 /** 2583 * Add member type column to the WordPress admin users list table. 2584 * 2585 * @since 2.7.0 2586 * 2587 * @param array $columns Users table columns. 2588 * 2589 * @return array $columns 2590 */ 2591 public function users_table_add_type_column( $columns = array() ) { 2592 $columns[ bp_get_member_type_tax_name() ] = _x( 'Member Type', 'Label for the WP users table member type column', 'buddypress' ); 2593 2594 return $columns; 2595 } 2596 2597 /** 2598 * Return member's type for display in the WP admin users list table. 2599 * 2600 * @since 2.7.0 2601 * 2602 * @param string $retval 2603 * @param string $column_name 2604 * @param int $user_id 2605 * 2606 * @return string Member type as a link to filter all users. 2607 */ 2608 public function users_table_populate_type_cell( $retval = '', $column_name = '', $user_id = 0 ) { 2609 // Only looking for member type column. 2610 if ( bp_get_member_type_tax_name() !== $column_name ) { 2611 return $retval; 2612 } 2613 2614 // Get the member type. 2615 $member_type = bp_get_member_type( $user_id, false ); 2616 2617 // Build the Output. 2618 if ( $member_type ) { 2619 $member_types = array_filter( array_map( 'bp_get_member_type_object', $member_type ) ); 2620 if ( ! $member_types ) { 2621 return $retval; 2622 } 2623 2624 $type_links = array(); 2625 foreach ( $member_types as $type ) { 2626 $url = add_query_arg( array( 'bp-member-type' => urlencode( $type->name ) ) ); 2627 $type_links[] = sprintf( 2628 '<a href="%1$s">%2$s</a>', 2629 esc_url( $url ), 2630 esc_html( $type->labels['singular_name'] ) 2631 ); 2632 } 2633 2634 $retval = implode( ', ', $type_links ); 2635 } 2636 2637 return $retval; 2638 } 2639 2640 /** 2641 * Filter WP Admin users list table to include users of the specified type. 2642 * 2643 * @param WP_Query $query 2644 * 2645 * @since 2.7.0 2646 */ 2647 public function users_table_filter_by_type( $query ) { 2648 global $pagenow; 2649 2650 if ( is_admin() && 'users.php' === $pagenow && ! empty( $_REQUEST['bp-member-type'] ) ) { 2651 $type_slug = sanitize_text_field( $_REQUEST['bp-member-type'] ); 2652 2653 // Check that the type is registered. 2654 if ( null == bp_get_member_type_object( $type_slug ) ) { 2655 return; 2656 } 2657 2658 // Get the list of users that are assigned to this member type. 2659 $type = bp_get_term_by( 'slug', $type_slug, bp_get_member_type_tax_name() ); 2660 2661 if ( empty( $type->term_id ) ) { 2662 return; 2663 } 2664 2665 $user_ids = bp_get_objects_in_term( $type->term_id, bp_get_member_type_tax_name() ); 2666 2667 if ( $user_ids && ! is_wp_error( $user_ids ) ) { 2668 $query->set( 'include', (array) $user_ids ); 2669 } 2670 } 2671 } 2672 2673 /** 2674 * Formats a signup's xprofile field data for display. 2675 * 2676 * Operates recursively on arrays, which are then imploded with commas. 2677 * 2678 * @since 2.8.0 2679 * @deprecated 10.0.0 2680 * 2681 * @param string|array $value Field value. 2682 * @return string 2683 */ 2684 protected function format_xprofile_field_for_display( $value ) { 2685 _deprecated_function( __METHOD__, '10.0.0', 'bp_members_admin_format_xprofile_field_for_display' ); 2686 2687 return bp_members_admin_format_xprofile_field_for_display( $value ); 2688 } 2689 2690 /** 2691 * Set up the signups admin page. 2692 * 2693 * Loaded before the page is rendered, this function does all initial 2694 * setup, including: processing form requests, registering contextual 2695 * help, and setting up screen options. 2696 * 2697 * @since 8.0.0 2698 * 2699 * @global $bp_members_invitations_list_table 2700 */ 2701 public function members_invitations_admin_load() { 2702 global $bp_members_invitations_list_table; 2703 2704 // Build redirection URL. 2705 $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'] ); 2706 $doaction = bp_admin_list_table_current_bulk_action(); 2707 2708 /** 2709 * Fires at the start of the member invitations admin load. 2710 * 2711 * @since 8.0.0 2712 * 2713 * @param string $doaction Current bulk action being processed. 2714 * @param array $_REQUEST Current $_REQUEST global. 2715 */ 2716 do_action( 'bp_members_invitations_admin_load', $doaction, $_REQUEST ); 2717 2718 /** 2719 * Filters the allowed actions for use in the user signups admin page. 2720 * 2721 * @since 8.0.0 2722 * 2723 * @param array $value Array of allowed actions to use. 2724 */ 2725 $allowed_actions = apply_filters( 'bp_members_invitations_admin_allowed_actions', array( 'do_delete', 'do_resend' ) ); 2726 2727 // Prepare the display of the bulk invitation action screen. 2728 if ( ! in_array( $doaction, $allowed_actions ) ) { 2729 2730 $bp_members_invitations_list_table = self::get_list_table_class( 'BP_Members_Invitations_List_Table', 'users' ); 2731 2732 // The per_page screen option. 2733 add_screen_option( 'per_page', array( 'label' => _x( 'Members Invitations', 'Members Invitations per page (screen options)', 'buddypress' ) ) ); 2734 2735 get_current_screen()->add_help_tab( array( 2736 'id' => 'bp-members-invitations-overview', 2737 'title' => __( 'Overview', 'buddypress' ), 2738 'content' => 2739 '<p>' . __( 'This is the administration screen for member invitations on your site.', 'buddypress' ) . '</p>' . 2740 '<p>' . __( 'From the screen options, you can customize the displayed columns and the pagination of this screen.', 'buddypress' ) . '</p>' . 2741 '<p>' . __( 'You can reorder the list of invitations by clicking on the Invitee, Inviter, Date Modified, Email Sent, or Accepted column headers.', 'buddypress' ) . '</p>' . 2742 '<p>' . __( 'Using the search form, you can find specific invitations more easily. The Invitee Email field will be included in the search.', 'buddypress' ) . '</p>' 2743 ) ); 2744 2745 get_current_screen()->add_help_tab( array( 2746 'id' => 'bp-members-invitations-actions', 2747 'title' => __( 'Actions', 'buddypress' ), 2748 'content' => 2749 '<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>' . 2750 '<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>' . 2751 '<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>' . 2752 '<p>' . __( 'Bulk actions allow you to perform these actions for the selected rows.', 'buddypress' ) . '</p>' 2753 ) ); 2754 2755 // Help panel - sidebar links. 2756 get_current_screen()->set_help_sidebar( 2757 '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' . 2758 '<p>' . __( '<a href="https://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>' 2759 ); 2760 2761 // Add accessible hidden headings and text for the Pending Users screen. 2762 get_current_screen()->set_screen_reader_content( array( 2763 /* translators: accessibility text */ 2764 'heading_views' => __( 'Filter invitations list', 'buddypress' ), 2765 /* translators: accessibility text */ 2766 'heading_pagination' => __( 'Invitation list navigation', 'buddypress' ), 2767 /* translators: accessibility text */ 2768 'heading_list' => __( 'Invitations list', 'buddypress' ), 2769 ) ); 2770 2771 } else { 2772 if ( empty( $_REQUEST['invite_ids' ] ) ) { 2773 return; 2774 } 2775 $invite_ids = wp_parse_id_list( $_REQUEST['invite_ids' ] ); 2776 2777 // Handle resent invitations. 2778 if ( 'do_resend' == $doaction ) { 2779 2780 // Nonce check. 2781 check_admin_referer( 'invitations_resend' ); 2782 2783 $success = 0; 2784 foreach ( $invite_ids as $invite_id ) { 2785 if ( bp_members_invitation_resend_by_id( $invite_id ) ) { 2786 $success++; 2787 } 2788 } 2789 2790 $query_arg = array( 'updated' => 'resent' ); 2791 2792 if ( ! empty( $success ) ) { 2793 $query_arg['resent'] = $success; 2794 } 2795 2796 $not_sent = count( $invite_ids ) - $success; 2797 if ( $not_sent > 0 ) { 2798 $query_arg['notsent'] = $not_sent; 2799 } 2800 2801 $redirect_to = add_query_arg( $query_arg, $redirect_to ); 2802 2803 bp_core_redirect( $redirect_to ); 2804 2805 // Handle invitation deletion. 2806 } elseif ( 'do_delete' == $doaction ) { 2807 2808 // Nonce check. 2809 check_admin_referer( 'invitations_delete' ); 2810 2811 $success = 0; 2812 foreach ( $invite_ids as $invite_id ) { 2813 if ( bp_members_invitations_delete_by_id( $invite_id ) ) { 2814 $success++; 2815 } 2816 } 2817 2818 $query_arg = array( 'updated' => 'deleted' ); 2819 2820 if ( ! empty( $success ) ) { 2821 $query_arg['deleted'] = $success; 2822 } 2823 2824 $notdeleted = count( $invite_ids ) - $success; 2825 if ( $notdeleted > 0 ) { 2826 $query_arg['notdeleted'] = $notdeleted; 2827 } 2828 2829 $redirect_to = add_query_arg( $query_arg, $redirect_to ); 2830 2831 bp_core_redirect( $redirect_to ); 2832 2833 // Plugins can update other stuff from here. 2834 } else { 2835 $this->redirect = $redirect_to; 2836 2837 /** 2838 * Fires at end of member invitations admin load 2839 * if doaction does not match any actions. 2840 * 2841 * @since 8.0.0 2842 * 2843 * @param string $doaction Current bulk action being processed. 2844 * @param array $_REQUEST Current $_REQUEST global. 2845 * @param string $redirect Determined redirect url to send user to. 2846 */ 2847 do_action( 'bp_members_admin_update_invitations', $doaction, $_REQUEST, $this->redirect ); 2848 2849 bp_core_redirect( $this->redirect ); 2850 } 2851 } 2852 } 2853 2854 /** 2855 * Get admin notice when viewing the invitations management page. 2856 * 2857 * @since 8.0.0 2858 * 2859 * @return array 2860 */ 2861 private function get_members_invitations_notice() { 2862 2863 // Setup empty notice for return value. 2864 $notice = array(); 2865 2866 // Updates. 2867 if ( ! empty( $_REQUEST['updated'] ) ) { 2868 switch ( $_REQUEST['updated'] ) { 2869 case 'resent': 2870 $notice = array( 2871 'class' => 'updated', 2872 'message' => '' 2873 ); 2874 2875 if ( ! empty( $_REQUEST['resent'] ) ) { 2876 $resent = absint( $_REQUEST['resent'] ); 2877 $notice['message'] .= sprintf( 2878 _nx( 2879 /* translators: %s: number of invitation emails sent */ 2880 '%s invtitation email successfully sent! ', '%s invitation emails successfully sent! ', 2881 $resent, 2882 'members invitation resent', 2883 'buddypress' 2884 ), 2885 number_format_i18n( $resent ) 2886 ); 2887 } 2888 2889 if ( ! empty( $_REQUEST['notsent'] ) ) { 2890 $notsent = absint( $_REQUEST['notsent'] ); 2891 $notice['message'] .= sprintf( 2892 _nx( 2893 /* translators: %s: number of unsent invitation emails */ 2894 '%s invitation email was not sent.', '%s invitation emails were not sent.', 2895 $notsent, 2896 'members invitation notsent', 2897 'buddypress' 2898 ), 2899 number_format_i18n( $notsent ) 2900 ); 2901 2902 if ( empty( $_REQUEST['resent'] ) ) { 2903 $notice['class'] = 'error'; 2904 } 2905 } 2906 2907 break; 2908 2909 case 'deleted': 2910 $notice = array( 2911 'class' => 'updated', 2912 'message' => '' 2913 ); 2914 2915 if ( ! empty( $_REQUEST['deleted'] ) ) { 2916 $deleted = absint( $_REQUEST['deleted'] ); 2917 $notice['message'] .= sprintf( 2918 _nx( 2919 /* translators: %s: number of deleted invitations */ 2920 '%s invitation successfully deleted!', '%s invitations successfully deleted!', 2921 $deleted, 2922 'members invitation deleted', 2923 'buddypress' 2924 ), 2925 number_format_i18n( $deleted ) 2926 ); 2927 } 2928 2929 if ( ! empty( $_REQUEST['notdeleted'] ) ) { 2930 $notdeleted = absint( $_REQUEST['notdeleted'] ); 2931 $notice['message'] .= sprintf( 2932 _nx( 2933 /* translators: %s: number of invitations that failed to be deleted */ 2934 '%s invitation was not deleted.', '%s invitations were not deleted.', 2935 $notdeleted, 2936 'members invitation notdeleted', 2937 'buddypress' 2938 ), 2939 number_format_i18n( $notdeleted ) 2940 ); 2941 2942 if ( empty( $_REQUEST['deleted'] ) ) { 2943 $notice['class'] = 'error'; 2944 } 2945 } 2946 2947 break; 2948 } 2949 } 2950 2951 // Errors. 2952 if ( ! empty( $_REQUEST['error'] ) ) { 2953 switch ( $_REQUEST['error'] ) { 2954 case 'do_resend': 2955 $notice = array( 2956 'class' => 'error', 2957 'message' => esc_html__( 'There was a problem sending the invitation emails. Please try again.', 'buddypress' ), 2958 ); 2959 break; 2960 2961 case 'do_delete': 2962 $notice = array( 2963 'class' => 'error', 2964 'message' => esc_html__( 'There was a problem deleting invitations. Please try again.', 'buddypress' ), 2965 ); 2966 break; 2967 } 2968 } 2969 2970 return $notice; 2971 } 2972 2973 /** 2974 * Member invitations admin page router. 2975 * 2976 * Depending on the context, display 2977 * - the list of invitations, 2978 * - or the delete confirmation screen, 2979 * - or the "resend" email confirmation screen. 2980 * 2981 * Also prepare the admin notices. 2982 * 2983 * @since 8.0.0 2984 */ 2985 public function invitations_admin() { 2986 $doaction = bp_admin_list_table_current_bulk_action(); 2987 2988 // Prepare notices for admin. 2989 $notice = $this->get_members_invitations_notice(); 2990 2991 // Display notices. 2992 if ( ! empty( $notice ) ) : 2993 if ( 'updated' === $notice['class'] ) : ?> 2994 2995 <div id="message" class="<?php echo esc_attr( $notice['class'] ); ?> notice is-dismissible"> 2996 2997 <?php else: ?> 2998 2999 <div class="<?php echo esc_attr( $notice['class'] ); ?> notice is-dismissible"> 3000 3001 <?php endif; ?> 3002 3003 <p><?php echo $notice['message']; ?></p> 3004 </div> 3005 3006 <?php endif; 3007 3008 // Show the proper screen. 3009 switch ( $doaction ) { 3010 case 'delete' : 3011 case 'resend' : 3012 $this->invitations_admin_manage( $doaction ); 3013 break; 3014 3015 default: 3016 $this->invitations_admin_index(); 3017 break; 3018 } 3019 } 3020 3021 /** 3022 * This is the list of invitations. 3023 * 3024 * @since 8.0.0 3025 * 3026 * @global $plugin_page 3027 * @global $bp_members_invitations_list_table 3028 */ 3029 public function invitations_admin_index() { 3030 global $plugin_page, $bp_members_invitations_list_table; 3031 3032 $usersearch = ! empty( $_REQUEST['s'] ) ? stripslashes( $_REQUEST['s'] ) : ''; 3033 3034 // Prepare the group items for display. 3035 $bp_members_invitations_list_table->prepare_items(); 3036 3037 if ( is_network_admin() ) { 3038 $form_url = network_admin_url( 'admin.php' ); 3039 } else { 3040 $form_url = bp_get_admin_url( 'tools.php' ); 3041 } 3042 3043 $form_url = add_query_arg( 3044 array( 3045 'page' => 'bp-members-invitations', 3046 ), 3047 $form_url 3048 ); 3049 3050 $search_form_url = remove_query_arg( 3051 array( 3052 'action', 3053 'deleted', 3054 'notdeleted', 3055 'error', 3056 'updated', 3057 'delete', 3058 'activate', 3059 'activated', 3060 'notactivated', 3061 'resend', 3062 'resent', 3063 'notresent', 3064 'do_delete', 3065 'do_activate', 3066 'do_resend', 3067 'action2', 3068 '_wpnonce', 3069 'invite_ids' 3070 ), $_SERVER['REQUEST_URI'] 3071 ); 3072 3073 bp_core_admin_tabbed_screen_header( __( 'BuddyPress tools', 'buddypress' ), __( 'Manage Invitations', 'buddypress' ), 'tools' ); 3074 ?> 3075 3076 <div class="buddypress-body"> 3077 <?php 3078 if ( $usersearch ) { 3079 printf( '<span class="subtitle">' . __( 'Search results for “%s”', 'buddypress' ) . '</span>', esc_html( $usersearch ) ); 3080 } 3081 ?> 3082 3083 <?php // Display each invitation on its own row. ?> 3084 <?php $bp_members_invitations_list_table->views(); ?> 3085 3086 <form id="bp-members-invitations-search-form" action="<?php echo esc_url( $search_form_url ) ;?>"> 3087 <input type="hidden" name="page" value="<?php echo esc_attr( $plugin_page ); ?>" /> 3088 <?php $bp_members_invitations_list_table->search_box( __( 'Search Invitations', 'buddypress' ), 'bp-members-invitations' ); ?> 3089 </form> 3090 3091 <form id="bp-members-invitations-form" action="<?php echo esc_url( $form_url );?>" method="post"> 3092 <?php $bp_members_invitations_list_table->display(); ?> 3093 </form> 3094 </div> 3095 <?php 3096 } 3097 3098 /** 3099 * This is the confirmation screen for actions. 3100 * 3101 * @since 8.0.0 3102 * 3103 * @param string $action Delete or resend invitation. 3104 * @return null|false 3105 */ 3106 public function invitations_admin_manage( $action = '' ) { 3107 if ( ! current_user_can( $this->capability ) || empty( $action ) ) { 3108 die( '-1' ); 3109 } 3110 3111 // Get the IDs from the URL. 3112 $ids = false; 3113 if ( ! empty( $_POST['invite_ids'] ) ) { 3114 $ids = wp_parse_id_list( $_POST['invite_ids'] ); 3115 } elseif ( ! empty( $_GET['invite_id'] ) ) { 3116 $ids = absint( $_GET['invite_id'] ); 3117 } 3118 3119 3120 if ( empty( $ids ) ) { 3121 return false; 3122 } 3123 3124 // Check invite IDs and set up strings. 3125 switch ( $action ) { 3126 case 'delete' : 3127 // Query for matching invites, and filter out bad IDs. 3128 $args = array( 3129 'id' => $ids, 3130 'invite_sent' => 'all', 3131 'accepted' => 'all', 3132 ); 3133 $invites = bp_members_invitations_get_invites( $args ); 3134 $invite_ids = wp_list_pluck( $invites, 'id' ); 3135 3136 $header_text = __( 'Delete Invitations', 'buddypress' ); 3137 if ( 0 === count( $invite_ids ) ) { 3138 $helper_text = __( 'No invites were found, nothing to delete!', 'buddypress' ); 3139 } else { 3140 $helper_text = _n( 'You are about to delete the following invitation:', 'You are about to delete the following invitations:', count( $invite_ids ), 'buddypress' ); 3141 } 3142 break; 3143 3144 case 'resend' : 3145 /** 3146 * Query for matching invites, and filter out bad IDs 3147 * or those that have already been accepted. 3148 */ 3149 $args = array( 3150 'id' => $ids, 3151 'invite_sent' => 'all', 3152 'accepted' => 'pending', 3153 ); 3154 $invites = bp_members_invitations_get_invites( $args ); 3155 $invite_ids = wp_list_pluck( $invites, 'id' ); 3156 3157 $header_text = __( 'Resend Invitation Emails', 'buddypress' ); 3158 if ( 0 === count( $invite_ids ) ) { 3159 $helper_text = __( 'No pending invites were found, nothing to resend!', 'buddypress' ); 3160 } else { 3161 $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' ); 3162 } 3163 break; 3164 } 3165 3166 // These arguments are added to all URLs. 3167 $url_args = array( 'page' => 'bp-members-invitations' ); 3168 3169 // These arguments are only added when performing an action. 3170 $action_args = array( 3171 'action' => 'do_' . $action, 3172 'invite_ids' => implode( ',', $invite_ids ) 3173 ); 3174 3175 if ( is_network_admin() ) { 3176 $base_url = network_admin_url( 'admin.php' ); 3177 } else { 3178 $base_url = bp_get_admin_url( 'tools.php' ); 3179 } 3180 3181 $cancel_url = add_query_arg( $url_args, $base_url ); 3182 $action_url = wp_nonce_url( 3183 add_query_arg( 3184 array_merge( $url_args, $action_args ), 3185 $base_url 3186 ), 3187 'invitations_' . $action 3188 ); 3189 3190 bp_core_admin_tabbed_screen_header( __( 'BuddyPress tools', 'buddypress' ), __( 'Manage Invitations', 'buddypress' ), 'tools' ); 3191 ?> 3192 3193 <div class="buddypress-body"> 3194 <h2><?php echo esc_html( $header_text ); ?></h2> 3195 3196 <p><?php echo esc_html( $helper_text ); ?></p> 3197 3198 <?php if ( $invites ) : ?> 3199 3200 <ol class="bp-invitations-list"> 3201 <?php foreach ( $invites as $invite ) : 3202 if ( $invite->invite_sent ) { 3203 $last_notified = mysql2date( 'Y/m/d g:i:s a', $invite->date_modified ); 3204 } else { 3205 $last_notified = __( 'Not yet notified', 'buddypress'); 3206 } 3207 ?> 3208 3209 <li> 3210 <strong><?php echo esc_html( $invite->invitee_email ) ?></strong> 3211 3212 <?php if ( 'resend' === $action ) : ?> 3213 3214 <p class="description"> 3215 <?php 3216 /* translators: %s: notification date */ 3217 printf( esc_html__( 'Last notified: %s', 'buddypress'), $last_notified ); 3218 ?> 3219 </p> 3220 3221 <?php endif; ?> 3222 3223 </li> 3224 3225 <?php endforeach; ?> 3226 </ol> 3227 3228 <?php endif ; ?> 3229 3230 <?php if ( 'delete' === $action ) : ?> 3231 3232 <p><strong><?php esc_html_e( 'This action cannot be undone.', 'buddypress' ) ?></strong></p> 3233 3234 <?php endif; ?> 3235 3236 <?php if ( $invites ) : ?> 3237 3238 <a class="button-primary" href="<?php echo esc_url( $action_url ); ?>" <?php disabled( ! $invites ); ?>><?php esc_html_e( 'Confirm', 'buddypress' ); ?></a> 3239 3240 <?php endif; ?> 3241 3242 <a class="button" href="<?php echo esc_url( $cancel_url ); ?>"><?php esc_html_e( 'Cancel', 'buddypress' ) ?></a> 3243 </div> 3244 3245 <?php 3246 } 3247 3248 } 3249 endif; // End class_exists check.
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Nov 21 01:00:57 2024 | Cross-referenced by PHPXref 0.7.1 |