[ 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 // Specific config: BuddyPress is not network activated. 144 $this->subsite_activated = (bool) is_multisite() && ! bp_is_network_activated(); 145 146 // When BuddyPress is not network activated, only Super Admin can moderate signups. 147 if ( ! empty( $this->subsite_activated ) ) { 148 $this->capability = 'manage_network_users'; 149 } 150 } 151 152 /** 153 * Set admin-related actions and filters. 154 * 155 * @since 2.0.0 156 */ 157 private function setup_actions() { 158 159 /** Extended Profile ************************************************* 160 */ 161 162 // Enqueue all admin JS and CSS. 163 add_action( 'bp_admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); 164 165 // Add some page specific output to the <head>. 166 add_action( 'bp_admin_head', array( $this, 'admin_head' ), 999 ); 167 168 // Add menu item to all users menu. 169 add_action( 'admin_menu', array( $this, 'admin_menus' ), 5 ); 170 add_action( 'network_admin_menu', array( $this, 'admin_menus' ), 5 ); 171 add_action( 'user_admin_menu', array( $this, 'user_profile_menu' ), 5 ); 172 173 // Create the Profile Navigation (Profile/Extended Profile). 174 add_action( 'edit_user_profile', array( $this, 'profile_nav' ), 99, 1 ); 175 add_action( 'show_user_profile', array( $this, 'profile_nav' ), 99, 1 ); 176 177 // Editing users of a specific site. 178 add_action( "admin_head-site-users.php", array( $this, 'profile_admin_head' ) ); 179 180 // Add a row action to users listing. 181 if ( bp_core_do_network_admin() ) { 182 add_filter( 'ms_user_row_actions', array( $this, 'row_actions' ), 10, 2 ); 183 add_action( 'admin_init', array( $this, 'add_edit_profile_url_filter' ) ); 184 add_action( 'wp_after_admin_bar_render', array( $this, 'remove_edit_profile_url_filter' ) ); 185 } 186 187 // Add user row actions for single site. 188 add_filter( 'user_row_actions', array( $this, 'row_actions' ), 10, 2 ); 189 190 // Process changes to member type. 191 add_action( 'bp_members_admin_load', array( $this, 'process_member_type_update' ) ); 192 193 /** Signups ********************************************************** 194 */ 195 196 if ( is_admin() ) { 197 198 // Filter non multisite user query to remove sign-up users. 199 if ( ! is_multisite() ) { 200 add_action( 'pre_user_query', array( $this, 'remove_signups_from_user_query' ), 10, 1 ); 201 } 202 203 // Reorganise the views navigation in users.php and signups page. 204 if ( current_user_can( $this->capability ) ) { 205 $user_screen = $this->users_screen; 206 207 /** 208 * Users screen on multiblog is users, but signups 209 * need to be managed in the network for this case 210 */ 211 if ( bp_is_network_activated() && bp_is_multiblog_mode() && false === strpos( $user_screen, '-network' ) ) { 212 $user_screen .= '-network'; 213 } 214 215 add_filter( "views_{$user_screen}", array( $this, 'signup_filter_view' ), 10, 1 ); 216 add_filter( 'set-screen-option', array( $this, 'signup_screen_options' ), 10, 3 ); 217 } 218 219 // Registration is turned on. 220 add_action( 'update_site_option_registration', array( $this, 'multisite_registration_on' ), 10, 2 ); 221 add_action( 'update_option_users_can_register', array( $this, 'single_site_registration_on' ), 10, 2 ); 222 } 223 224 /** Users List - Members Types *************************************** 225 */ 226 227 if ( is_admin() && bp_get_member_types() ) { 228 229 // Add "Change type" <select> to WP admin users list table and process bulk members type changes. 230 add_action( 'restrict_manage_users', array( $this, 'users_table_output_type_change_select' ) ); 231 add_action( 'load-users.php', array( $this, 'users_table_process_bulk_type_change' ) ); 232 233 // Add the member type column to the WP admin users list table. 234 add_filter( 'manage_users_columns', array( $this, 'users_table_add_type_column' ) ); 235 add_filter( 'manage_users_custom_column', array( $this, 'users_table_populate_type_cell' ), 10, 3 ); 236 237 // Filter WP admin users list table to include users of the specified type. 238 add_filter( 'pre_get_users', array( $this, 'users_table_filter_by_type' ) ); 239 } 240 } 241 242 /** 243 * Create registration pages when multisite user registration is turned on. 244 * 245 * @since 2.7.0 246 * 247 * @param string $option_name Current option name; value is always 'registration'. 248 * @param string $value 249 */ 250 public function multisite_registration_on( $option_name, $value ) { 251 if ( 'user' === $value || 'all' === $value ) { 252 bp_core_add_page_mappings( array( 253 'register' => 1, 254 'activate' => 1 255 ) ); 256 } 257 } 258 259 /** 260 * Create registration pages when single site registration is turned on. 261 * 262 * @since 2.7.0 263 * 264 * @param string $old_value 265 * @param string $value 266 */ 267 public function single_site_registration_on( $old_value, $value ) { 268 // Single site. 269 if ( ! is_multisite() && ! empty( $value ) ) { 270 bp_core_add_page_mappings( array( 271 'register' => 1, 272 'activate' => 1 273 ) ); 274 } 275 } 276 277 /** 278 * Get the user ID. 279 * 280 * Look for $_GET['user_id']. If anything else, force the user ID to the 281 * current user's ID so they aren't left without a user to edit. 282 * 283 * @since 2.1.0 284 * 285 * @return int 286 */ 287 private function get_user_id() { 288 if ( ! empty( $this->user_id ) ) { 289 return $this->user_id; 290 } 291 292 $this->user_id = (int) get_current_user_id(); 293 294 // We'll need a user ID when not on self profile. 295 if ( ! empty( $_GET['user_id'] ) ) { 296 $this->user_id = (int) $_GET['user_id']; 297 } 298 299 return $this->user_id; 300 } 301 302 /** 303 * Can the current user edit the one displayed. 304 * 305 * Self profile editing / or bp_moderate check. 306 * This might be replaced by more granular capabilities 307 * in the future. 308 * 309 * @since 2.1.0 310 * 311 * @param int $user_id ID of the user being checked for edit ability. 312 * 313 * @return bool 314 */ 315 private function member_can_edit( $user_id = 0 ) { 316 $retval = false; 317 318 // Bail if no user ID was passed. 319 if ( empty( $user_id ) ) { 320 return $retval; 321 } 322 323 // Member can edit if they are viewing their own profile. 324 if ( $this->current_user_id === $user_id ) { 325 $retval = true; 326 327 // Trust the 'bp_moderate' capability. 328 } else { 329 $retval = bp_current_user_can( 'bp_moderate' ); 330 } 331 332 return $retval; 333 } 334 335 /** 336 * Get admin notice when saving a user or member profile. 337 * 338 * @since 2.1.0 339 * 340 * @return array 341 */ 342 private function get_user_notice() { 343 344 // Setup empty notice for return value. 345 $notice = array(); 346 347 // Updates. 348 if ( ! empty( $_REQUEST['updated'] ) ) { 349 switch ( $_REQUEST['updated'] ) { 350 case 'avatar': 351 $notice = array( 352 'class' => 'updated', 353 'message' => __( 'Profile photo was deleted.', 'buddypress' ) 354 ); 355 break; 356 case 'ham' : 357 $notice = array( 358 'class' => 'updated', 359 'message' => __( 'User removed as spammer.', 'buddypress' ) 360 ); 361 break; 362 case 'spam' : 363 $notice = array( 364 'class' => 'updated', 365 'message' => __( 'User marked as spammer. Spam users are visible only to site admins.', 'buddypress' ) 366 ); 367 break; 368 case 1 : 369 $notice = array( 370 'class' => 'updated', 371 'message' => __( 'Profile updated.', 'buddypress' ) 372 ); 373 break; 374 } 375 } 376 377 // Errors. 378 if ( ! empty( $_REQUEST['error'] ) ) { 379 switch ( $_REQUEST['error'] ) { 380 case 'avatar': 381 $notice = array( 382 'class' => 'error', 383 'message' => __( 'There was a problem deleting that profile photo. Please try again.', 'buddypress' ) 384 ); 385 break; 386 case 'ham' : 387 $notice = array( 388 'class' => 'error', 389 'message' => __( 'User could not be removed as spammer.', 'buddypress' ) 390 ); 391 break; 392 case 'spam' : 393 $notice = array( 394 'class' => 'error', 395 'message' => __( 'User could not be marked as spammer.', 'buddypress' ) 396 ); 397 break; 398 case 1 : 399 $notice = array( 400 'class' => 'error', 401 'message' => __( 'An error occurred while trying to update the profile.', 'buddypress' ) 402 ); 403 break; 404 case 2: 405 $notice = array( 406 'class' => 'error', 407 'message' => __( 'Your changes have not been saved. Please fill in all required fields, and save your changes again.', 'buddypress' ) 408 ); 409 break; 410 case 3: 411 $notice = array( 412 'class' => 'error', 413 'message' => __( 'There was a problem updating some of your profile information. Please try again.', 'buddypress' ) 414 ); 415 break; 416 } 417 } 418 419 return $notice; 420 } 421 422 /** 423 * Create the /user/ admin Profile submenus for all members. 424 * 425 * @since 2.1.0 426 * 427 */ 428 public function user_profile_menu() { 429 430 // Setup the hooks array. 431 $hooks = array(); 432 433 // Add the faux "Edit Profile" submenu page. 434 $hooks['user'] = $this->user_page = add_submenu_page( 435 'profile.php', 436 __( 'Edit Profile', 'buddypress' ), 437 __( 'Edit Profile', 'buddypress' ), 438 'exist', 439 'bp-profile-edit', 440 array( $this, 'user_admin' ) 441 ); 442 443 // Setup the screen ID's. 444 $this->screen_id = array( 445 $this->user_page . '-user', 446 $this->user_profile . '-user' 447 ); 448 449 // Loop through new hooks and add method actions. 450 foreach ( $hooks as $key => $hook ) { 451 add_action( "load-{$hook}", array( $this, $key . '_admin_load' ) ); 452 } 453 454 // Add the profile_admin_head method to proper admin_head actions. 455 add_action( "admin_head-{$this->user_page}", array( $this, 'profile_admin_head' ) ); 456 add_action( "admin_head-profile.php", array( $this, 'profile_admin_head' ) ); 457 } 458 459 /** 460 * Create the All Users / Profile > Edit Profile and All Users Signups submenus. 461 * 462 * @since 2.0.0 463 * 464 */ 465 public function admin_menus() { 466 467 // Setup the hooks array. 468 $hooks = array(); 469 470 // Manage user's profile. 471 $hooks['user'] = $this->user_page = add_submenu_page( 472 $this->user_profile . '.php', 473 __( 'Edit Profile', 'buddypress' ), 474 __( 'Edit Profile', 'buddypress' ), 475 'read', 476 'bp-profile-edit', 477 array( $this, 'user_admin' ) 478 ); 479 480 // Only show sign-ups where they belong. 481 if ( ( ! bp_is_network_activated() && ! is_network_admin() ) || ( is_network_admin() && bp_is_network_activated() ) ) { 482 483 // Manage signups. 484 $hooks['signups'] = $this->signups_page = add_users_page( 485 __( 'Manage Signups', 'buddypress' ), 486 __( 'Manage Signups', 'buddypress' ), 487 $this->capability, 488 'bp-signups', 489 array( $this, 'signups_admin' ) 490 ); 491 } 492 493 $edit_page = 'user-edit'; 494 $profile_page = 'profile'; 495 $this->users_page = 'users'; 496 497 // Self profile check is needed for this pages. 498 $page_head = array( 499 $edit_page . '.php', 500 $profile_page . '.php', 501 $this->user_page, 502 $this->users_page . '.php', 503 ); 504 505 // Append '-network' to each array item if in network admin. 506 if ( is_network_admin() ) { 507 $edit_page .= '-network'; 508 $profile_page .= '-network'; 509 $this->user_page .= '-network'; 510 $this->users_page .= '-network'; 511 $this->signups_page .= '-network'; 512 } 513 514 // Setup the screen ID's. 515 $this->screen_id = array( 516 $edit_page, 517 $this->user_page, 518 $profile_page 519 ); 520 521 // Loop through new hooks and add method actions. 522 foreach ( $hooks as $key => $hook ) { 523 add_action( "load-{$hook}", array( $this, $key . '_admin_load' ) ); 524 } 525 526 // Add the profile_admin_head method to proper admin_head actions. 527 foreach ( $page_head as $head ) { 528 add_action( "admin_head-{$head}", array( $this, 'profile_admin_head' ) ); 529 } 530 } 531 532 /** 533 * Highlight the Users menu if on Edit Profile and check if on the user's admin profile. 534 * 535 * @since 2.1.0 536 */ 537 public function profile_admin_head() { 538 global $submenu_file, $parent_file; 539 540 // Is the user editing their own profile? 541 if ( is_user_admin() || ( defined( 'IS_PROFILE_PAGE' ) && IS_PROFILE_PAGE ) ) { 542 $this->is_self_profile = true; 543 544 // Is the user attempting to edit their own profile. 545 } elseif ( isset( $_GET['user_id' ] ) || ( isset( $_GET['page'] ) && ( 'bp-profile-edit' === $_GET['page'] ) ) ) { 546 $this->is_self_profile = (bool) ( $this->get_user_id() === $this->current_user_id ); 547 } 548 549 // Force the parent file to users.php to open the correct top level menu 550 // but only if not editing a site via the network site editing page. 551 if ( 'sites.php' !== $parent_file ) { 552 $parent_file = 'users.php'; 553 $submenu_file = 'users.php'; 554 } 555 556 // Editing your own profile, so recheck some vars. 557 if ( true === $this->is_self_profile ) { 558 559 // Use profile.php as the edit page. 560 $edit_page = 'profile.php'; 561 562 // Set profile.php as the parent & sub files to correct the menu nav. 563 if ( is_blog_admin() || is_user_admin() ) { 564 $parent_file = 'profile.php'; 565 $submenu_file = 'profile.php'; 566 } 567 568 // Not editing yourself, so use user-edit.php. 569 } else { 570 $edit_page = 'user-edit.php'; 571 } 572 573 if ( is_user_admin() ) { 574 $this->edit_profile_url = add_query_arg( $this->edit_profile_args, user_admin_url( 'profile.php' ) ); 575 $this->edit_url = user_admin_url( 'profile.php' ); 576 577 } elseif ( is_blog_admin() ) { 578 $this->edit_profile_url = add_query_arg( $this->edit_profile_args, admin_url( 'users.php' ) ); 579 $this->edit_url = admin_url( $edit_page ); 580 581 } elseif ( is_network_admin() ) { 582 $this->edit_profile_url = add_query_arg( $this->edit_profile_args, network_admin_url( 'users.php' ) ); 583 $this->edit_url = network_admin_url( $edit_page ); 584 } 585 } 586 587 /** 588 * Remove the Edit Profile page. 589 * 590 * We add these pages in order to integrate with WP's Users panel, but 591 * we want them to show up as a row action of the WP panel, not as separate 592 * subnav items under the Users menu. 593 * 594 * @since 2.0.0 595 */ 596 public function admin_head() { 597 remove_submenu_page( 'users.php', 'bp-profile-edit' ); 598 remove_submenu_page( 'profile.php', 'bp-profile-edit' ); 599 } 600 601 /** Community Profile *****************************************************/ 602 603 /** 604 * Add some specific styling to the Edit User and Edit User's Profile page. 605 * 606 * @since 2.0.0 607 */ 608 public function enqueue_scripts() { 609 if ( ! in_array( get_current_screen()->id, $this->screen_id ) ) { 610 return; 611 } 612 613 $min = bp_core_get_minified_asset_suffix(); 614 $css = $this->css_url . "admin{$min}.css"; 615 616 /** 617 * Filters the CSS URL to enqueue in the Members admin area. 618 * 619 * @since 2.0.0 620 * 621 * @param string $css URL to the CSS admin file to load. 622 */ 623 $css = apply_filters( 'bp_members_admin_css', $css ); 624 625 wp_enqueue_style( 'bp-members-css', $css, array(), bp_get_version() ); 626 627 wp_style_add_data( 'bp-members-css', 'rtl', 'replace' ); 628 if ( $min ) { 629 wp_style_add_data( 'bp-members-css', 'suffix', $min ); 630 } 631 632 // Only load JavaScript for BuddyPress profile. 633 if ( get_current_screen()->id == $this->user_page ) { 634 $js = $this->js_url . "admin{$min}.js"; 635 636 /** 637 * Filters the JS URL to enqueue in the Members admin area. 638 * 639 * @since 2.0.0 640 * 641 * @param string $js URL to the JavaScript admin file to load. 642 */ 643 $js = apply_filters( 'bp_members_admin_js', $js ); 644 wp_enqueue_script( 'bp-members-js', $js, array( 'jquery' ), bp_get_version(), true ); 645 646 if ( ! bp_core_get_root_option( 'bp-disable-avatar-uploads' ) && buddypress()->avatar->show_avatars ) { 647 /** 648 * Get Thickbox. 649 * 650 * We cannot simply use add_thickbox() here as WordPress is not playing 651 * nice with Thickbox width/height see https://core.trac.wordpress.org/ticket/17249 652 * Using media-upload might be interesting in the future for the send to editor stuff 653 * and we make sure the tb_window is wide enough 654 */ 655 wp_enqueue_style ( 'thickbox' ); 656 wp_enqueue_script( 'media-upload' ); 657 658 // Get Avatar Uploader. 659 bp_attachments_enqueue_scripts( 'BP_Attachment_Avatar' ); 660 } 661 } 662 663 /** 664 * Fires after all of the members JavaScript and CSS are enqueued. 665 * 666 * @since 2.0.0 667 * 668 * @param string $id ID of the current screen. 669 * @param array $screen_id Array of allowed screens to add scripts and styles to. 670 */ 671 do_action( 'bp_members_admin_enqueue_scripts', get_current_screen()->id, $this->screen_id ); 672 } 673 674 /** 675 * Create the Profile navigation in Edit User & Edit Profile pages. 676 * 677 * @since 2.0.0 678 * 679 * @param object|null $user User to create profile navigation for. 680 * @param string $active Which profile to highlight. 681 * @return string|null 682 */ 683 public function profile_nav( $user = null, $active = 'WordPress' ) { 684 685 // Bail if no user ID exists here. 686 if ( empty( $user->ID ) ) { 687 return; 688 } 689 690 // Add the user ID to query arguments when not editing yourself. 691 if ( false === $this->is_self_profile ) { 692 $query_args = array( 'user_id' => $user->ID ); 693 } else { 694 $query_args = array(); 695 } 696 697 // Conditionally add a referer if it exists in the existing request. 698 if ( ! empty( $_REQUEST['wp_http_referer'] ) ) { 699 $wp_http_referer = wp_unslash( $_REQUEST['wp_http_referer'] ); 700 $wp_http_referer = wp_validate_redirect( esc_url_raw( $wp_http_referer ) ); 701 $query_args['wp_http_referer'] = urlencode( $wp_http_referer ); 702 } 703 704 // Setup the two distinct "edit" URL's. 705 $community_url = add_query_arg( $query_args, $this->edit_profile_url ); 706 $wordpress_url = add_query_arg( $query_args, $this->edit_url ); 707 708 $bp_active = false; 709 $wp_active = ' nav-tab-active'; 710 if ( 'BuddyPress' === $active ) { 711 $bp_active = ' nav-tab-active'; 712 $wp_active = false; 713 } ?> 714 715 <h2 id="profile-nav" class="nav-tab-wrapper"> 716 <?php 717 /** 718 * In configs where BuddyPress is not network activated, as regular 719 * admins do not have the capacity to edit other users, we must add 720 * this check. 721 */ 722 if ( current_user_can( 'edit_user', $user->ID ) ) : ?> 723 724 <a class="nav-tab<?php echo esc_attr( $wp_active ); ?>" href="<?php echo esc_url( $wordpress_url );?>"><?php _e( 'Profile', 'buddypress' ); ?></a> 725 726 <?php endif; ?> 727 728 <a class="nav-tab<?php echo esc_attr( $bp_active ); ?>" href="<?php echo esc_url( $community_url );?>"><?php _e( 'Extended Profile', 'buddypress' ); ?></a> 729 </h2> 730 731 <?php 732 } 733 734 /** 735 * Set up the user's profile admin page. 736 * 737 * Loaded before the page is rendered, this function does all initial 738 * setup, including: processing form requests, registering contextual 739 * help, and setting up screen options. 740 * 741 * @since 2.0.0 742 * @since 6.0.0 The `delete_avatar` action is now managed into this method. 743 */ 744 public function user_admin_load() { 745 746 // Get the user ID. 747 $user_id = $this->get_user_id(); 748 749 // Can current user edit this profile? 750 if ( ! $this->member_can_edit( $user_id ) ) { 751 wp_die( __( 'You cannot edit the requested user.', 'buddypress' ) ); 752 } 753 754 // Build redirection URL. 755 $redirect_to = remove_query_arg( array( 'action', 'error', 'updated', 'spam', 'ham', 'delete_avatar' ), $_SERVER['REQUEST_URI'] ); 756 $doaction = ! empty( $_REQUEST['action'] ) ? $_REQUEST['action'] : false; 757 758 if ( ! empty( $_REQUEST['user_status'] ) ) { 759 $spam = (bool) ( 'spam' === $_REQUEST['user_status'] ); 760 761 if ( $spam !== bp_is_user_spammer( $user_id ) ) { 762 $doaction = $_REQUEST['user_status']; 763 } 764 } 765 766 /** 767 * Fires at the start of the signups admin load. 768 * 769 * @since 2.0.0 770 * 771 * @param string $doaction Current bulk action being processed. 772 * @param array $_REQUEST Current $_REQUEST global. 773 */ 774 do_action_ref_array( 'bp_members_admin_load', array( $doaction, $_REQUEST ) ); 775 776 /** 777 * Filters the allowed actions for use in the user admin page. 778 * 779 * @since 2.0.0 780 * 781 * @param array $value Array of allowed actions to use. 782 */ 783 $allowed_actions = apply_filters( 'bp_members_admin_allowed_actions', array( 'update', 'delete_avatar', 'spam', 'ham' ) ); 784 785 // Prepare the display of the Community Profile screen. 786 if ( ! in_array( $doaction, $allowed_actions ) ) { 787 add_screen_option( 'layout_columns', array( 'default' => 2, 'max' => 2, ) ); 788 789 get_current_screen()->add_help_tab( array( 790 'id' => 'bp-profile-edit-overview', 791 'title' => __( 'Overview', 'buddypress' ), 792 'content' => 793 '<p>' . __( 'This is the admin view of a user's profile.', 'buddypress' ) . '</p>' . 794 '<p>' . __( 'In the main column, you can edit the fields of the user's extended profile.', 'buddypress' ) . '</p>' . 795 '<p>' . __( 'In the right-hand column, you can update the user's status, delete the user's avatar, and view recent statistics.', 'buddypress' ) . '</p>' 796 ) ); 797 798 // Help panel - sidebar links. 799 get_current_screen()->set_help_sidebar( 800 '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' . 801 '<p>' . __( '<a href="https://codex.buddypress.org/administrator-guide/extended-profiles/">Managing Profiles</a>', 'buddypress' ) . '</p>' . 802 '<p>' . __( '<a href="https://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>' 803 ); 804 805 // Register metaboxes for the edit screen. 806 add_meta_box( 807 'submitdiv', 808 _x( 'Status', 'members user-admin edit screen', 'buddypress' ), 809 array( $this, 'user_admin_status_metabox' ), 810 get_current_screen()->id, 811 'side', 812 'core' 813 ); 814 815 // In case xprofile is not active. 816 $this->stats_metabox->context = 'normal'; 817 $this->stats_metabox->priority = 'core'; 818 819 /** 820 * Fires before loading the profile fields if component is active. 821 * 822 * Plugins should not use this hook, please use 'bp_members_admin_user_metaboxes' instead. 823 * 824 * @since 2.0.0 825 * 826 * @param int $user_id Current user ID for the screen. 827 * @param string $id Current screen ID. 828 * @param object $stats_metabox Object holding position data for use with the stats metabox. 829 */ 830 do_action_ref_array( 'bp_members_admin_xprofile_metabox', array( $user_id, get_current_screen()->id, $this->stats_metabox ) ); 831 832 // If xProfile is inactive, difficult to know what's profile we're on. 833 if ( 'normal' === $this->stats_metabox->context ) { 834 $display_name = bp_core_get_user_displayname( $user_id ); 835 } else { 836 $display_name = __( 'Member', 'buddypress' ); 837 } 838 839 // Set the screen id. 840 $screen_id = get_current_screen()->id; 841 842 // User Stat metabox. 843 add_meta_box( 844 'bp_members_admin_user_stats', 845 sprintf( 846 /* translators: %s: member name */ 847 _x( "%s's Stats", 'members user-admin edit screen', 'buddypress' ), 848 $display_name 849 ), 850 array( $this, 'user_admin_stats_metabox' ), 851 $screen_id, 852 sanitize_key( $this->stats_metabox->context ), 853 sanitize_key( $this->stats_metabox->priority ) 854 ); 855 856 if ( buddypress()->avatar->show_avatars ) { 857 // Avatar Metabox. 858 add_meta_box( 859 'bp_members_user_admin_avatar', 860 _x( 'Profile Photo', 'members user-admin edit screen', 'buddypress' ), 861 array( $this, 'user_admin_avatar_metabox' ), 862 $screen_id, 863 'side', 864 'low' 865 ); 866 } 867 868 // Member Type metabox. Only added if member types have been registered. 869 $member_types = bp_get_member_types(); 870 if ( ! empty( $member_types ) ) { 871 add_meta_box( 872 'bp_members_admin_member_type', 873 _x( 'Member Type', 'members user-admin edit screen', 'buddypress' ), 874 array( $this, 'user_admin_member_type_metabox' ), 875 $screen_id, 876 'side', 877 'core' 878 ); 879 } 880 881 /** 882 * Fires at the end of the Community Profile screen. 883 * 884 * Plugins can restrict metabox to "bp_moderate" admins by checking if 885 * the first argument ($this->is_self_profile) is false in their callback. 886 * They can also restrict their metabox to self profile editing 887 * by setting it to true. 888 * 889 * @since 2.0.0 890 * 891 * @param bool $is_self_profile Whether or not it is the current user's profile. 892 * @param int $user_id Current user ID. 893 */ 894 do_action( 'bp_members_admin_user_metaboxes', $this->is_self_profile, $user_id ); 895 896 // Enqueue JavaScript files. 897 wp_enqueue_script( 'postbox' ); 898 wp_enqueue_script( 'dashboard' ); 899 900 // Spam or Ham user. 901 } elseif ( in_array( $doaction, array( 'spam', 'ham' ) ) && empty( $this->is_self_profile ) ) { 902 903 check_admin_referer( 'edit-bp-profile_' . $user_id ); 904 905 if ( bp_core_process_spammer_status( $user_id, $doaction ) ) { 906 $redirect_to = add_query_arg( 'updated', $doaction, $redirect_to ); 907 } else { 908 $redirect_to = add_query_arg( 'error', $doaction, $redirect_to ); 909 } 910 911 bp_core_redirect( $redirect_to ); 912 913 // Eventually delete avatar. 914 } elseif ( 'delete_avatar' === $doaction ) { 915 916 // Check the nonce. 917 check_admin_referer( 'delete_avatar' ); 918 919 $redirect_to = remove_query_arg( '_wpnonce', $redirect_to ); 920 921 if ( bp_core_delete_existing_avatar( array( 'item_id' => $user_id ) ) ) { 922 $redirect_to = add_query_arg( 'updated', 'avatar', $redirect_to ); 923 } else { 924 $redirect_to = add_query_arg( 'error', 'avatar', $redirect_to ); 925 } 926 927 bp_core_redirect( $redirect_to ); 928 929 // Update other stuff once above ones are done. 930 } else { 931 $this->redirect = $redirect_to; 932 933 /** 934 * Fires at end of user profile admin load if doaction does not match any available actions. 935 * 936 * @since 2.0.0 937 * 938 * @param string $doaction Current bulk action being processed. 939 * @param int $user_id Current user ID. 940 * @param array $_REQUEST Current $_REQUEST global. 941 * @param string $redirect Determined redirect url to send user to. 942 */ 943 do_action_ref_array( 'bp_members_admin_update_user', array( $doaction, $user_id, $_REQUEST, $this->redirect ) ); 944 945 bp_core_redirect( $this->redirect ); 946 } 947 } 948 949 /** 950 * Display the user's profile. 951 * 952 * @since 2.0.0 953 */ 954 public function user_admin() { 955 956 if ( ! bp_current_user_can( 'bp_moderate' ) && empty( $this->is_self_profile ) ) { 957 die( '-1' ); 958 } 959 960 // Get the user ID. 961 $user_id = $this->get_user_id(); 962 $user = get_user_to_edit( $user_id ); 963 964 // Construct title. 965 if ( true === $this->is_self_profile ) { 966 $title = __( 'Profile', 'buddypress' ); 967 } else { 968 $title = __( 'Edit User', 'buddypress' ); 969 } 970 971 // Construct URL for form. 972 $request_url = remove_query_arg( array( 'action', 'error', 'updated', 'spam', 'ham' ), $_SERVER['REQUEST_URI'] ); 973 $form_action_url = add_query_arg( 'action', 'update', $request_url ); 974 $wp_http_referer = false; 975 if ( ! empty( $_REQUEST['wp_http_referer'] ) ) { 976 $wp_http_referer = wp_unslash( $_REQUEST['wp_http_referer'] ); 977 $wp_http_referer = remove_query_arg( array( 'action', 'updated' ), $wp_http_referer ); 978 $wp_http_referer = wp_validate_redirect( esc_url_raw( $wp_http_referer ) ); 979 } 980 981 // Prepare notice for admin. 982 $notice = $this->get_user_notice(); 983 984 if ( ! empty( $notice ) ) : ?> 985 986 <div <?php if ( 'updated' === $notice['class'] ) : ?>id="message" <?php endif; ?>class="<?php echo esc_attr( $notice['class'] ); ?> notice is-dismissible"> 987 988 <p><?php echo esc_html( $notice['message'] ); ?></p> 989 990 <?php if ( !empty( $wp_http_referer ) && ( 'updated' === $notice['class'] ) ) : ?> 991 992 <p><a href="<?php echo esc_url( $wp_http_referer ); ?>"><?php esc_html_e( '← Back to Users', 'buddypress' ); ?></a></p> 993 994 <?php endif; ?> 995 996 </div> 997 998 <?php endif; ?> 999 1000 <div class="wrap" id="community-profile-page"> 1001 <h1 class="wp-heading-inline"><?php echo esc_html( $title ); ?></h1> 1002 1003 <?php if ( empty( $this->is_self_profile ) ) : ?> 1004 1005 <?php if ( current_user_can( 'create_users' ) ) : ?> 1006 1007 <a href="user-new.php" class="page-title-action"><?php echo esc_html_x( 'Add New', 'user', 'buddypress' ); ?></a> 1008 1009 <?php elseif ( is_multisite() && current_user_can( 'promote_users' ) ) : ?> 1010 1011 <a href="user-new.php" class="page-title-action"><?php echo esc_html_x( 'Add Existing', 'user', 'buddypress' ); ?></a> 1012 1013 <?php endif; ?> 1014 1015 <?php endif; ?> 1016 1017 <hr class="wp-header-end"> 1018 1019 <?php if ( ! empty( $user ) ) : 1020 1021 $this->profile_nav( $user, 'BuddyPress' ); ?> 1022 1023 <form action="<?php echo esc_url( $form_action_url ); ?>" id="your-profile" method="post"> 1024 <div id="poststuff"> 1025 1026 <div id="post-body" class="metabox-holder columns-<?php echo 1 == get_current_screen()->get_columns() ? '1' : '2'; ?>"> 1027 1028 <div id="postbox-container-1" class="postbox-container"> 1029 <?php do_meta_boxes( get_current_screen()->id, 'side', $user ); ?> 1030 </div> 1031 1032 <div id="postbox-container-2" class="postbox-container"> 1033 <?php do_meta_boxes( get_current_screen()->id, 'normal', $user ); ?> 1034 <?php do_meta_boxes( get_current_screen()->id, 'advanced', $user ); ?> 1035 </div> 1036 </div><!-- #post-body --> 1037 1038 </div><!-- #poststuff --> 1039 1040 <?php wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false ); ?> 1041 <?php wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false ); ?> 1042 <?php wp_nonce_field( 'edit-bp-profile_' . $user->ID ); ?> 1043 1044 </form> 1045 1046 <?php else : ?> 1047 1048 <p><?php 1049 printf( 1050 '%1$s <a href="%2$s">%3$s</a>', 1051 __( 'No user found with this ID.', 'buddypress' ), 1052 esc_url( bp_get_admin_url( 'users.php' ) ), 1053 __( 'Go back and try again.', 'buddypress' ) 1054 ); 1055 ?></p> 1056 1057 <?php endif; ?> 1058 1059 </div><!-- .wrap --> 1060 <?php 1061 } 1062 1063 /** 1064 * Render the Status metabox for user's profile screen. 1065 * 1066 * Actions are: 1067 * - Update profile fields if xProfile component is active 1068 * - Spam/Unspam user 1069 * 1070 * @since 2.0.0 1071 * 1072 * @param WP_User|null $user The WP_User object to be edited. 1073 */ 1074 public function user_admin_status_metabox( $user = null ) { 1075 1076 // Bail if no user id or if the user has not activated their account yet. 1077 if ( empty( $user->ID ) ) { 1078 return; 1079 } 1080 1081 // Bail if user has not been activated yet (how did you get here?). 1082 if ( isset( $user->user_status ) && ( 2 == $user->user_status ) ) : ?> 1083 1084 <p class="not-activated"><?php esc_html_e( 'User account has not yet been activated', 'buddypress' ); ?></p><br/> 1085 1086 <?php return; 1087 1088 endif; ?> 1089 1090 <div class="submitbox" id="submitcomment"> 1091 <div id="minor-publishing"> 1092 <div id="misc-publishing-actions"> 1093 <?php 1094 1095 // Get the spam status once here to compare against below. 1096 $is_spammer = bp_is_user_spammer( $user->ID ); 1097 1098 /** 1099 * In configs where BuddyPress is not network activated, 1100 * regular admins cannot mark a user as a spammer on front 1101 * end. This prevent them to do it in the back end. 1102 * 1103 * Also prevent admins from marking themselves or other 1104 * admins as spammers. 1105 */ 1106 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' ) ) ) : ?> 1107 1108 <div class="misc-pub-section" id="comment-status-radio"> 1109 <label class="approved"><input type="radio" name="user_status" value="ham" <?php checked( $is_spammer, false ); ?>><?php esc_html_e( 'Active', 'buddypress' ); ?></label><br /> 1110 <label class="spam"><input type="radio" name="user_status" value="spam" <?php checked( $is_spammer, true ); ?>><?php esc_html_e( 'Spammer', 'buddypress' ); ?></label> 1111 </div> 1112 1113 <?php endif ;?> 1114 1115 <div class="misc-pub-section curtime misc-pub-section-last"> 1116 <?php 1117 1118 // Translators: Publish box date format, see http://php.net/date. 1119 $datef = __( 'M j, Y @ G:i', 'buddypress' ); 1120 $date = date_i18n( $datef, strtotime( $user->user_registered ) ); 1121 ?> 1122 <span id="timestamp"> 1123 <?php 1124 /* translators: %s: registration date */ 1125 printf( __( 'Registered on: %s', 'buddypress' ), '<strong>' . $date . '</strong>' ); 1126 ?> 1127 </span> 1128 </div> 1129 </div> <!-- #misc-publishing-actions --> 1130 1131 <div class="clear"></div> 1132 </div><!-- #minor-publishing --> 1133 1134 <div id="major-publishing-actions"> 1135 1136 <div id="publishing-action"> 1137 <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> 1138 <?php submit_button( esc_html__( 'Update Profile', 'buddypress' ), 'primary', 'save', false ); ?> 1139 </div> 1140 <div class="clear"></div> 1141 </div><!-- #major-publishing-actions --> 1142 1143 </div><!-- #submitcomment --> 1144 1145 <?php 1146 } 1147 1148 /** 1149 * Render the fallback metabox in case a user has been marked as a spammer. 1150 * 1151 * @since 2.0.0 1152 * 1153 * @param WP_User|null $user The WP_User object to be edited. 1154 */ 1155 public function user_admin_spammer_metabox( $user = null ) { 1156 ?> 1157 <p> 1158 <?php 1159 /* translators: %s: member name */ 1160 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 ) ) ); 1161 ?> 1162 </p> 1163 <?php 1164 } 1165 1166 /** 1167 * Render the Stats metabox to moderate inappropriate images. 1168 * 1169 * @since 2.0.0 1170 * 1171 * @param WP_User|null $user The WP_User object to be edited. 1172 */ 1173 public function user_admin_stats_metabox( $user = null ) { 1174 1175 // Bail if no user ID. 1176 if ( empty( $user->ID ) ) { 1177 return; 1178 } 1179 1180 // If account is not activated last activity is the time user registered. 1181 if ( isset( $user->user_status ) && 2 == $user->user_status ) { 1182 $last_active = $user->user_registered; 1183 1184 // Account is activated, getting user's last activity. 1185 } else { 1186 $last_active = bp_get_user_last_activity( $user->ID ); 1187 } 1188 1189 $datef = __( 'M j, Y @ G:i', 'buddypress' ); 1190 $date = date_i18n( $datef, strtotime( $last_active ) ); ?> 1191 1192 <ul> 1193 <li class="bp-members-profile-stats"> 1194 <?php 1195 /* translators: %s: date */ 1196 printf( __( 'Last active: %1$s', 'buddypress' ), '<strong>' . $date . '</strong>' ); 1197 ?> 1198 </li> 1199 1200 <?php 1201 // Loading other stats only if user has activated their account. 1202 if ( empty( $user->user_status ) ) { 1203 1204 /** 1205 * Fires in the user stats metabox if the user has activated their account. 1206 * 1207 * @since 2.0.0 1208 * 1209 * @param array $value Array holding the user ID. 1210 * @param object $user Current displayed user object. 1211 */ 1212 do_action( 'bp_members_admin_user_stats', array( 'user_id' => $user->ID ), $user ); 1213 } 1214 ?> 1215 </ul> 1216 1217 <?php 1218 } 1219 1220 /** 1221 * Render the Avatar metabox to moderate inappropriate images. 1222 * 1223 * @since 6.0.0 1224 * 1225 * @param WP_User|null $user The WP_User object for the user being edited. 1226 */ 1227 public function user_admin_avatar_metabox( $user = null ) { 1228 1229 if ( empty( $user->ID ) ) { 1230 return; 1231 } ?> 1232 1233 <div class="avatar"> 1234 1235 <?php echo bp_core_fetch_avatar( array( 1236 'item_id' => $user->ID, 1237 'object' => 'user', 1238 'type' => 'full', 1239 'title' => $user->display_name 1240 ) ); ?> 1241 1242 <?php if ( bp_get_user_has_avatar( $user->ID ) ) : 1243 1244 $query_args = array( 1245 'user_id' => $user->ID, 1246 'action' => 'delete_avatar' 1247 ); 1248 1249 if ( ! empty( $_REQUEST['wp_http_referer'] ) ) { 1250 $wp_http_referer = wp_unslash( $_REQUEST['wp_http_referer'] ); 1251 $wp_http_referer = remove_query_arg( array( 'action', 'updated' ), $wp_http_referer ); 1252 $wp_http_referer = wp_validate_redirect( esc_url_raw( $wp_http_referer ) ); 1253 $query_args['wp_http_referer'] = urlencode( $wp_http_referer ); 1254 } 1255 1256 $community_url = add_query_arg( $query_args, $this->edit_profile_url ); 1257 $delete_link = wp_nonce_url( $community_url, 'delete_avatar' ); ?> 1258 1259 <a href="<?php echo esc_url( $delete_link ); ?>" class="bp-members-avatar-user-admin"><?php esc_html_e( 'Delete Profile Photo', 'buddypress' ); ?></a> 1260 1261 <?php endif; 1262 1263 // Load the Avatar UI templates if user avatar uploads are enabled. 1264 if ( ! bp_core_get_root_option( 'bp-disable-avatar-uploads' ) ) : ?> 1265 <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> 1266 <div id="bp-members-avatar-editor" style="display:none;"> 1267 <?php bp_attachments_get_template_part( 'avatars/index' ); ?> 1268 </div> 1269 <?php endif; ?> 1270 1271 </div> 1272 <?php 1273 } 1274 1275 /** 1276 * Render the Member Type metabox. 1277 * 1278 * @since 2.2.0 1279 * 1280 * @param WP_User|null $user The WP_User object to be edited. 1281 */ 1282 public function user_admin_member_type_metabox( $user = null ) { 1283 1284 // Bail if no user ID. 1285 if ( empty( $user->ID ) ) { 1286 return; 1287 } 1288 1289 $types = bp_get_member_types( array(), 'objects' ); 1290 $current_type = (array) bp_get_member_type( $user->ID, false ); 1291 $types_count = count( array_filter( $current_type ) ); 1292 ?> 1293 1294 <label for="bp-members-profile-member-type" class="screen-reader-text"> 1295 <?php 1296 /* translators: accessibility text */ 1297 esc_html_e( 'Select member type', 'buddypress' ); 1298 ?> 1299 </label> 1300 <ul class="categorychecklist form-no-clear"> 1301 <?php foreach ( $types as $type ) : ?> 1302 <li> 1303 <label class="selectit"> 1304 <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 ) ); ?>> 1305 <?php echo esc_html( $type->labels['singular_name'] ); ?> 1306 </label> 1307 </li> 1308 <?php endforeach; ?> 1309 <input type="hidden" value="<?php echo intval( $types_count ); ?>" name="bp-members-profile-member-types-count" /> 1310 </ul> 1311 1312 <?php 1313 wp_nonce_field( 'bp-member-type-change-' . $user->ID, 'bp-member-type-nonce' ); 1314 } 1315 1316 /** 1317 * Process changes from the Member Type metabox. 1318 * 1319 * @since 2.2.0 1320 */ 1321 public function process_member_type_update() { 1322 if ( ! isset( $_POST['bp-member-type-nonce'] ) || ! isset( $_POST['bp-members-profile-member-types-count'] ) ) { 1323 return; 1324 } 1325 1326 $user_id = $this->get_user_id(); 1327 1328 check_admin_referer( 'bp-member-type-change-' . $user_id, 'bp-member-type-nonce' ); 1329 1330 // Permission check. 1331 if ( ! bp_current_user_can( 'bp_moderate' ) && $user_id != bp_loggedin_user_id() ) { 1332 return; 1333 } 1334 1335 if ( isset( $_POST['bp-members-profile-member-type'] ) ) { 1336 // Member type [string] must either reference a valid member type, or be empty. 1337 $member_type = wp_parse_slug_list( wp_unslash( $_POST['bp-members-profile-member-type'] ) ); 1338 $member_type = array_filter( $member_type ); 1339 } elseif ( 0 !== intval( $_POST['bp-members-profile-member-types-count'] ) ) { 1340 $member_type = false; 1341 } 1342 1343 // Nothing to do there. 1344 if ( ! isset( $member_type ) ) { 1345 return; 1346 } 1347 1348 /* 1349 * If an invalid member type is passed, someone's doing something 1350 * fishy with the POST request, so we can fail silently. 1351 */ 1352 if ( bp_set_member_type( $user_id, $member_type ) ) { 1353 // @todo Success messages can't be posted because other stuff happens on the page load. 1354 } 1355 } 1356 1357 /** 1358 * Add a link to Profile in Users listing row actions. 1359 * 1360 * @since 2.0.0 1361 * 1362 * @param array|string $actions WordPress row actions (edit, delete). 1363 * @param object|null $user The object for the user row. 1364 * @return null|string|array Merged actions. 1365 */ 1366 public function row_actions( $actions = '', $user = null ) { 1367 1368 // Bail if no user ID. 1369 if ( empty( $user->ID ) ) { 1370 return; 1371 } 1372 1373 // Setup args array. 1374 $args = array(); 1375 1376 // Add the user ID if it's not for the current user. 1377 if ( $user->ID !== $this->current_user_id ) { 1378 $args['user_id'] = $user->ID; 1379 } 1380 1381 // Add the referer. 1382 $wp_http_referer = wp_unslash( $_SERVER['REQUEST_URI'] ); 1383 $wp_http_referer = wp_validate_redirect( esc_url_raw( $wp_http_referer ) ); 1384 $args['wp_http_referer'] = urlencode( $wp_http_referer ); 1385 1386 // Add the "Extended" link if the current user can edit this user. 1387 if ( current_user_can( 'edit_user', $user->ID ) || bp_current_user_can( 'bp_moderate' ) ) { 1388 1389 // Add query args and setup the Extended link. 1390 $edit_profile = add_query_arg( $args, $this->edit_profile_url ); 1391 $edit_profile_link = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $edit_profile ), esc_html__( 'Extended', 'buddypress' ) ); 1392 1393 /** 1394 * Check the edit action is available 1395 * and preserve the order edit | profile | remove/delete. 1396 */ 1397 if ( ! empty( $actions['edit'] ) ) { 1398 $edit_action = $actions['edit']; 1399 unset( $actions['edit'] ); 1400 1401 $new_edit_actions = array( 1402 'edit' => $edit_action, 1403 'edit-profile' => $edit_profile_link, 1404 ); 1405 1406 // If not available simply add the edit profile action. 1407 } else { 1408 $new_edit_actions = array( 'edit-profile' => $edit_profile_link ); 1409 } 1410 1411 $actions = array_merge( $new_edit_actions, $actions ); 1412 } 1413 1414 return $actions; 1415 } 1416 1417 /** 1418 * Add a filter to edit profile url in WP Admin Bar. 1419 * 1420 * @since 2.1.0 1421 */ 1422 public function add_edit_profile_url_filter() { 1423 add_filter( 'bp_members_edit_profile_url', array( $this, 'filter_adminbar_profile_link' ), 10, 3 ); 1424 } 1425 1426 /** 1427 * Filter the profile url. 1428 * 1429 * @since 2.1.0 1430 * 1431 * 1432 * @param string $profile_link Profile Link for admin bar. 1433 * @param string $url Profile URL. 1434 * @param int $user_id User ID. 1435 * @return string 1436 */ 1437 public function filter_adminbar_profile_link( $profile_link = '', $url = '', $user_id = 0 ) { 1438 if ( ! is_super_admin( $user_id ) && is_admin() ) { 1439 $profile_link = user_admin_url( 'profile.php' ); 1440 } 1441 return $profile_link; 1442 } 1443 1444 /** 1445 * Remove the filter to edit profile url in WP Admin Bar. 1446 * 1447 * @since 2.1.0 1448 */ 1449 public function remove_edit_profile_url_filter() { 1450 remove_filter( 'bp_members_edit_profile_url', array( $this, 'filter_adminbar_profile_link' ), 10 ); 1451 } 1452 1453 /** Signups Management ****************************************************/ 1454 1455 /** 1456 * Display the admin preferences about signups pagination. 1457 * 1458 * @since 2.0.0 1459 * 1460 * @param int $value Value for signup option. 1461 * @param string $option Value for the option key. 1462 * @param int $new_value Value for the saved option. 1463 * @return int The pagination preferences. 1464 */ 1465 public function signup_screen_options( $value = 0, $option = '', $new_value = 0 ) { 1466 if ( 'users_page_bp_signups_network_per_page' != $option && 'users_page_bp_signups_per_page' != $option ) { 1467 return $value; 1468 } 1469 1470 // Per page. 1471 $new_value = (int) $new_value; 1472 if ( $new_value < 1 || $new_value > 999 ) { 1473 return $value; 1474 } 1475 1476 return $new_value; 1477 } 1478 1479 /** 1480 * Make sure no signups will show in users list. 1481 * 1482 * This is needed to handle signups that may have not been activated 1483 * before the 2.0.0 upgrade. 1484 * 1485 * @since 2.0.0 1486 * 1487 * @param WP_User_Query|null $query The users query. 1488 * @return WP_User_Query|null The users query without the signups. 1489 */ 1490 public function remove_signups_from_user_query( $query = null ) { 1491 global $wpdb; 1492 1493 // Bail if this is an ajax request. 1494 if ( defined( 'DOING_AJAX' ) ) { 1495 return; 1496 } 1497 1498 // Bail if updating BuddyPress. 1499 if ( bp_is_update() ) { 1500 return; 1501 } 1502 1503 // Bail if there is no current admin screen. 1504 if ( ! function_exists( 'get_current_screen' ) || ! get_current_screen() ) { 1505 return; 1506 } 1507 1508 // Get current screen. 1509 $current_screen = get_current_screen(); 1510 1511 // Bail if not on a users page. 1512 if ( ! isset( $current_screen->id ) || $this->users_page !== $current_screen->id ) { 1513 return; 1514 } 1515 1516 // Bail if already querying by an existing role. 1517 if ( ! empty( $query->query_vars['role'] ) ) { 1518 return; 1519 } 1520 1521 $query->query_where .= " AND {$wpdb->users}.user_status != 2"; 1522 } 1523 1524 /** 1525 * Filter the WP Users List Table views to include 'bp-signups'. 1526 * 1527 * @since 2.0.0 1528 * 1529 * @param array $views WP List Table views. 1530 * @return array The views with the signup view added. 1531 */ 1532 public function signup_filter_view( $views = array() ) { 1533 global $role; 1534 1535 // Remove the 'current' class from All if we're on the signups view. 1536 if ( 'registered' === $role ) { 1537 $views['all'] = str_replace( 'class="current"', '', $views['all'] ); 1538 $class = 'current'; 1539 } else { 1540 $class = ''; 1541 } 1542 1543 $signups = BP_Signup::count_signups(); 1544 1545 if ( is_network_admin() ) { 1546 $base_url = network_admin_url( 'users.php' ); 1547 } else { 1548 $base_url = bp_get_admin_url( 'users.php' ); 1549 } 1550 1551 $url = add_query_arg( 'page', 'bp-signups', $base_url ); 1552 1553 /* translators: %s: number of pending accounts */ 1554 $text = sprintf( _x( 'Pending %s', 'signup users', 'buddypress' ), '<span class="count">(' . number_format_i18n( $signups ) . ')</span>' ); 1555 1556 $views['registered'] = sprintf( '<a href="%1$s" class="%2$s">%3$s</a>', esc_url( $url ), $class, $text ); 1557 1558 return $views; 1559 } 1560 1561 /** 1562 * Load the Signup WP Users List table. 1563 * 1564 * @since 2.0.0 1565 * 1566 * @param string $class The name of the class to use. 1567 * @param string $required The parent class. 1568 * @return WP_List_Table|null The List table. 1569 */ 1570 public static function get_list_table_class( $class = '', $required = '' ) { 1571 if ( empty( $class ) ) { 1572 return; 1573 } 1574 1575 if ( ! empty( $required ) ) { 1576 require_once( ABSPATH . 'wp-admin/includes/class-wp-' . $required . '-list-table.php' ); 1577 } 1578 1579 return new $class(); 1580 } 1581 1582 /** 1583 * Set up the signups admin page. 1584 * 1585 * Loaded before the page is rendered, this function does all initial 1586 * setup, including: processing form requests, registering contextual 1587 * help, and setting up screen options. 1588 * 1589 * @since 2.0.0 1590 * 1591 * @global $bp_members_signup_list_table 1592 */ 1593 public function signups_admin_load() { 1594 global $bp_members_signup_list_table; 1595 1596 // Build redirection URL. 1597 $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'] ); 1598 $doaction = bp_admin_list_table_current_bulk_action(); 1599 1600 /** 1601 * Fires at the start of the signups admin load. 1602 * 1603 * @since 2.0.0 1604 * 1605 * @param string $doaction Current bulk action being processed. 1606 * @param array $_REQUEST Current $_REQUEST global. 1607 */ 1608 do_action( 'bp_signups_admin_load', $doaction, $_REQUEST ); 1609 1610 /** 1611 * Filters the allowed actions for use in the user signups admin page. 1612 * 1613 * @since 2.0.0 1614 * 1615 * @param array $value Array of allowed actions to use. 1616 */ 1617 $allowed_actions = apply_filters( 'bp_signups_admin_allowed_actions', array( 'do_delete', 'do_activate', 'do_resend' ) ); 1618 1619 // Prepare the display of the Community Profile screen. 1620 if ( ! in_array( $doaction, $allowed_actions ) || ( -1 == $doaction ) ) { 1621 1622 if ( is_network_admin() ) { 1623 $bp_members_signup_list_table = self::get_list_table_class( 'BP_Members_MS_List_Table', 'ms-users' ); 1624 } else { 1625 $bp_members_signup_list_table = self::get_list_table_class( 'BP_Members_List_Table', 'users' ); 1626 } 1627 1628 // The per_page screen option. 1629 add_screen_option( 'per_page', array( 'label' => _x( 'Pending Accounts', 'Pending Accounts per page (screen options)', 'buddypress' ) ) ); 1630 1631 get_current_screen()->add_help_tab( array( 1632 'id' => 'bp-signups-overview', 1633 'title' => __( 'Overview', 'buddypress' ), 1634 'content' => 1635 '<p>' . __( 'This is the administration screen for pending accounts on your site.', 'buddypress' ) . '</p>' . 1636 '<p>' . __( 'From the screen options, you can customize the displayed columns and the pagination of this screen.', 'buddypress' ) . '</p>' . 1637 '<p>' . __( 'You can reorder the list of your pending accounts by clicking on the Username, Email or Registered column headers.', 'buddypress' ) . '</p>' . 1638 '<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>' 1639 ) ); 1640 1641 get_current_screen()->add_help_tab( array( 1642 'id' => 'bp-signups-actions', 1643 'title' => __( 'Actions', 'buddypress' ), 1644 'content' => 1645 '<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>' . 1646 '<ul><li>' . __( '"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>' . 1647 '<li>' . __( '"Delete" allows you to delete a pending account from your site. You will be asked to confirm this deletion.', 'buddypress' ) . '</li></ul>' . 1648 '<p>' . __( 'By clicking on a Username you will be able to activate a pending account from the confirmation screen.', 'buddypress' ) . '</p>' . 1649 '<p>' . __( 'Bulk actions allow you to perform these 3 actions for the selected rows.', 'buddypress' ) . '</p>' 1650 ) ); 1651 1652 // Help panel - sidebar links. 1653 get_current_screen()->set_help_sidebar( 1654 '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' . 1655 '<p>' . __( '<a href="https://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>' 1656 ); 1657 1658 // Add accessible hidden headings and text for the Pending Users screen. 1659 get_current_screen()->set_screen_reader_content( array( 1660 /* translators: accessibility text */ 1661 'heading_views' => __( 'Filter users list', 'buddypress' ), 1662 /* translators: accessibility text */ 1663 'heading_pagination' => __( 'Pending users list navigation', 'buddypress' ), 1664 /* translators: accessibility text */ 1665 'heading_list' => __( 'Pending users list', 'buddypress' ), 1666 ) ); 1667 1668 } else { 1669 if ( ! empty( $_REQUEST['signup_ids' ] ) ) { 1670 $signups = wp_parse_id_list( $_REQUEST['signup_ids' ] ); 1671 } 1672 1673 // Handle resent activation links. 1674 if ( 'do_resend' == $doaction ) { 1675 1676 // Nonce check. 1677 check_admin_referer( 'signups_resend' ); 1678 1679 $resent = BP_Signup::resend( $signups ); 1680 1681 if ( empty( $resent ) ) { 1682 $redirect_to = add_query_arg( 'error', $doaction, $redirect_to ); 1683 } else { 1684 $query_arg = array( 'updated' => 'resent' ); 1685 1686 if ( ! empty( $resent['resent'] ) ) { 1687 $query_arg['resent'] = count( $resent['resent'] ); 1688 } 1689 1690 if ( ! empty( $resent['errors'] ) ) { 1691 $query_arg['notsent'] = count( $resent['errors'] ); 1692 set_transient( '_bp_admin_signups_errors', $resent['errors'], 30 ); 1693 } 1694 1695 $redirect_to = add_query_arg( $query_arg, $redirect_to ); 1696 } 1697 1698 bp_core_redirect( $redirect_to ); 1699 1700 // Handle activated accounts. 1701 } elseif ( 'do_activate' == $doaction ) { 1702 1703 // Nonce check. 1704 check_admin_referer( 'signups_activate' ); 1705 1706 $activated = BP_Signup::activate( $signups ); 1707 1708 if ( empty( $activated ) ) { 1709 $redirect_to = add_query_arg( 'error', $doaction, $redirect_to ); 1710 } else { 1711 $query_arg = array( 'updated' => 'activated' ); 1712 1713 if ( ! empty( $activated['activated'] ) ) { 1714 $query_arg['activated'] = count( $activated['activated'] ); 1715 } 1716 1717 if ( ! empty( $activated['errors'] ) ) { 1718 $query_arg['notactivated'] = count( $activated['errors'] ); 1719 set_transient( '_bp_admin_signups_errors', $activated['errors'], 30 ); 1720 } 1721 1722 $redirect_to = add_query_arg( $query_arg, $redirect_to ); 1723 } 1724 1725 bp_core_redirect( $redirect_to ); 1726 1727 // Handle sign-ups delete. 1728 } elseif ( 'do_delete' == $doaction ) { 1729 1730 // Nonce check. 1731 check_admin_referer( 'signups_delete' ); 1732 1733 $deleted = BP_Signup::delete( $signups ); 1734 1735 if ( empty( $deleted ) ) { 1736 $redirect_to = add_query_arg( 'error', $doaction, $redirect_to ); 1737 } else { 1738 $query_arg = array( 'updated' => 'deleted' ); 1739 1740 if ( ! empty( $deleted['deleted'] ) ) { 1741 $query_arg['deleted'] = count( $deleted['deleted'] ); 1742 } 1743 1744 if ( ! empty( $deleted['errors'] ) ) { 1745 $query_arg['notdeleted'] = count( $deleted['errors'] ); 1746 set_transient( '_bp_admin_signups_errors', $deleted['errors'], 30 ); 1747 } 1748 1749 $redirect_to = add_query_arg( $query_arg, $redirect_to ); 1750 } 1751 1752 bp_core_redirect( $redirect_to ); 1753 1754 // Plugins can update other stuff from here. 1755 } else { 1756 $this->redirect = $redirect_to; 1757 1758 /** 1759 * Fires at end of signups admin load if doaction does not match any actions. 1760 * 1761 * @since 2.0.0 1762 * 1763 * @param string $doaction Current bulk action being processed. 1764 * @param array $_REQUEST Current $_REQUEST global. 1765 * @param string $redirect Determined redirect url to send user to. 1766 */ 1767 do_action( 'bp_members_admin_update_signups', $doaction, $_REQUEST, $this->redirect ); 1768 1769 bp_core_redirect( $this->redirect ); 1770 } 1771 } 1772 } 1773 1774 /** 1775 * Display any activation errors. 1776 * 1777 * @since 2.0.0 1778 */ 1779 public function signups_display_errors() { 1780 1781 // Look for sign-up errors. 1782 $errors = get_transient( '_bp_admin_signups_errors' ); 1783 1784 // Bail if no activation errors. 1785 if ( empty( $errors ) ) { 1786 return; 1787 } 1788 1789 // Loop through errors and display them. 1790 foreach ( $errors as $error ) : ?> 1791 1792 <li><?php echo esc_html( $error[0] );?>: <?php echo esc_html( $error[1] );?></li> 1793 1794 <?php endforeach; 1795 1796 // Delete the redirect transient. 1797 delete_transient( '_bp_admin_signups_errors' ); 1798 } 1799 1800 /** 1801 * Get admin notice when viewing the sign-up page. 1802 * 1803 * @since 2.1.0 1804 * 1805 * @return array 1806 */ 1807 private function get_signup_notice() { 1808 1809 // Setup empty notice for return value. 1810 $notice = array(); 1811 1812 // Updates. 1813 if ( ! empty( $_REQUEST['updated'] ) ) { 1814 switch ( $_REQUEST['updated'] ) { 1815 case 'resent': 1816 $notice = array( 1817 'class' => 'updated', 1818 'message' => '' 1819 ); 1820 1821 if ( ! empty( $_REQUEST['resent'] ) ) { 1822 $notice['message'] .= sprintf( 1823 /* translators: %s: number of activation emails sent */ 1824 _nx( '%s activation email successfully sent! ', '%s activation emails successfully sent! ', 1825 absint( $_REQUEST['resent'] ), 1826 'signup resent', 1827 'buddypress' 1828 ), 1829 number_format_i18n( absint( $_REQUEST['resent'] ) ) 1830 ); 1831 } 1832 1833 if ( ! empty( $_REQUEST['notsent'] ) ) { 1834 $notice['message'] .= sprintf( 1835 /* translators: %s: number of unsent activation emails */ 1836 _nx( '%s activation email was not sent.', '%s activation emails were not sent.', 1837 absint( $_REQUEST['notsent'] ), 1838 'signup notsent', 1839 'buddypress' 1840 ), 1841 number_format_i18n( absint( $_REQUEST['notsent'] ) ) 1842 ); 1843 1844 if ( empty( $_REQUEST['resent'] ) ) { 1845 $notice['class'] = 'error'; 1846 } 1847 } 1848 1849 break; 1850 1851 case 'activated': 1852 $notice = array( 1853 'class' => 'updated', 1854 'message' => '' 1855 ); 1856 1857 if ( ! empty( $_REQUEST['activated'] ) ) { 1858 $notice['message'] .= sprintf( 1859 /* translators: %s: number of activated accounts */ 1860 _nx( '%s account successfully activated! ', '%s accounts successfully activated! ', 1861 absint( $_REQUEST['activated'] ), 1862 'signup resent', 1863 'buddypress' 1864 ), 1865 number_format_i18n( absint( $_REQUEST['activated'] ) ) 1866 ); 1867 } 1868 1869 if ( ! empty( $_REQUEST['notactivated'] ) ) { 1870 $notice['message'] .= sprintf( 1871 /* translators: %s: number of accounts not activated */ 1872 _nx( '%s account was not activated.', '%s accounts were not activated.', 1873 absint( $_REQUEST['notactivated'] ), 1874 'signup notsent', 1875 'buddypress' 1876 ), 1877 number_format_i18n( absint( $_REQUEST['notactivated'] ) ) 1878 ); 1879 1880 if ( empty( $_REQUEST['activated'] ) ) { 1881 $notice['class'] = 'error'; 1882 } 1883 } 1884 1885 break; 1886 1887 case 'deleted': 1888 $notice = array( 1889 'class' => 'updated', 1890 'message' => '' 1891 ); 1892 1893 if ( ! empty( $_REQUEST['deleted'] ) ) { 1894 $notice['message'] .= sprintf( 1895 /* translators: %s: number of deleted signups */ 1896 _nx( '%s sign-up successfully deleted!', '%s sign-ups successfully deleted!', 1897 absint( $_REQUEST['deleted'] ), 1898 'signup deleted', 1899 'buddypress' 1900 ), 1901 number_format_i18n( absint( $_REQUEST['deleted'] ) ) 1902 ); 1903 } 1904 1905 if ( ! empty( $_REQUEST['notdeleted'] ) ) { 1906 $notice['message'] .= sprintf( 1907 /* translators: %s: number of deleted signups not deleted */ 1908 _nx( '%s sign-up was not deleted.', '%s sign-ups were not deleted.', 1909 absint( $_REQUEST['notdeleted'] ), 1910 'signup notdeleted', 1911 'buddypress' 1912 ), 1913 number_format_i18n( absint( $_REQUEST['notdeleted'] ) ) 1914 ); 1915 1916 if ( empty( $_REQUEST['deleted'] ) ) { 1917 $notice['class'] = 'error'; 1918 } 1919 } 1920 1921 break; 1922 } 1923 } 1924 1925 // Errors. 1926 if ( ! empty( $_REQUEST['error'] ) ) { 1927 switch ( $_REQUEST['error'] ) { 1928 case 'do_resend': 1929 $notice = array( 1930 'class' => 'error', 1931 'message' => esc_html__( 'There was a problem sending the activation emails. Please try again.', 'buddypress' ), 1932 ); 1933 break; 1934 1935 case 'do_activate': 1936 $notice = array( 1937 'class' => 'error', 1938 'message' => esc_html__( 'There was a problem activating accounts. Please try again.', 'buddypress' ), 1939 ); 1940 break; 1941 1942 case 'do_delete': 1943 $notice = array( 1944 'class' => 'error', 1945 'message' => esc_html__( 'There was a problem deleting sign-ups. Please try again.', 'buddypress' ), 1946 ); 1947 break; 1948 } 1949 } 1950 1951 return $notice; 1952 } 1953 1954 /** 1955 * Signups admin page router. 1956 * 1957 * Depending on the context, display 1958 * - the list of signups, 1959 * - or the delete confirmation screen, 1960 * - or the activate confirmation screen, 1961 * - or the "resend" email confirmation screen. 1962 * 1963 * Also prepare the admin notices. 1964 * 1965 * @since 2.0.0 1966 */ 1967 public function signups_admin() { 1968 $doaction = bp_admin_list_table_current_bulk_action(); 1969 1970 // Prepare notices for admin. 1971 $notice = $this->get_signup_notice(); 1972 1973 // Display notices. 1974 if ( ! empty( $notice ) ) : 1975 if ( 'updated' === $notice['class'] ) : ?> 1976 1977 <div id="message" class="<?php echo esc_attr( $notice['class'] ); ?> notice is-dismissible"> 1978 1979 <?php else: ?> 1980 1981 <div class="<?php echo esc_attr( $notice['class'] ); ?> notice is-dismissible"> 1982 1983 <?php endif; ?> 1984 1985 <p><?php echo $notice['message']; ?></p> 1986 1987 <?php if ( ! empty( $_REQUEST['notactivated'] ) || ! empty( $_REQUEST['notdeleted'] ) || ! empty( $_REQUEST['notsent'] ) ) :?> 1988 1989 <ul><?php $this->signups_display_errors();?></ul> 1990 1991 <?php endif ;?> 1992 1993 </div> 1994 1995 <?php endif; 1996 1997 // Show the proper screen. 1998 switch ( $doaction ) { 1999 case 'activate' : 2000 case 'delete' : 2001 case 'resend' : 2002 $this->signups_admin_manage( $doaction ); 2003 break; 2004 2005 default: 2006 $this->signups_admin_index(); 2007 break; 2008 2009 } 2010 } 2011 2012 /** 2013 * This is the list of the Pending accounts (signups). 2014 * 2015 * @since 2.0.0 2016 * 2017 * @global $plugin_page 2018 * @global $bp_members_signup_list_table 2019 */ 2020 public function signups_admin_index() { 2021 global $plugin_page, $bp_members_signup_list_table; 2022 2023 $usersearch = ! empty( $_REQUEST['s'] ) ? stripslashes( $_REQUEST['s'] ) : ''; 2024 2025 // Prepare the group items for display. 2026 $bp_members_signup_list_table->prepare_items(); 2027 2028 if ( is_network_admin() ) { 2029 $form_url = network_admin_url( 'users.php' ); 2030 } else { 2031 $form_url = bp_get_admin_url( 'users.php' ); 2032 } 2033 2034 $form_url = add_query_arg( 2035 array( 2036 'page' => 'bp-signups', 2037 ), 2038 $form_url 2039 ); 2040 2041 $search_form_url = remove_query_arg( 2042 array( 2043 'action', 2044 'deleted', 2045 'notdeleted', 2046 'error', 2047 'updated', 2048 'delete', 2049 'activate', 2050 'activated', 2051 'notactivated', 2052 'resend', 2053 'resent', 2054 'notresent', 2055 'do_delete', 2056 'do_activate', 2057 'do_resend', 2058 'action2', 2059 '_wpnonce', 2060 'signup_ids' 2061 ), $_SERVER['REQUEST_URI'] 2062 ); 2063 2064 ?> 2065 2066 <div class="wrap"> 2067 <h1 class="wp-heading-inline"><?php _e( 'Users', 'buddypress' ); ?></h1> 2068 2069 <?php if ( current_user_can( 'create_users' ) ) : ?> 2070 2071 <a href="user-new.php" class="page-title-action"><?php echo esc_html_x( 'Add New', 'user', 'buddypress' ); ?></a> 2072 2073 <?php elseif ( is_multisite() && current_user_can( 'promote_users' ) ) : ?> 2074 2075 <a href="user-new.php" class="page-title-action"><?php echo esc_html_x( 'Add Existing', 'user', 'buddypress' ); ?></a> 2076 2077 <?php endif; 2078 2079 if ( $usersearch ) { 2080 printf( '<span class="subtitle">' . __( 'Search results for “%s”', 'buddypress' ) . '</span>', esc_html( $usersearch ) ); 2081 } 2082 ?> 2083 2084 <hr class="wp-header-end"> 2085 2086 <?php // Display each signups on its own row. ?> 2087 <?php $bp_members_signup_list_table->views(); ?> 2088 2089 <form id="bp-signups-search-form" action="<?php echo esc_url( $search_form_url ) ;?>"> 2090 <input type="hidden" name="page" value="<?php echo esc_attr( $plugin_page ); ?>" /> 2091 <?php $bp_members_signup_list_table->search_box( __( 'Search Pending Users', 'buddypress' ), 'bp-signups' ); ?> 2092 </form> 2093 2094 <form id="bp-signups-form" action="<?php echo esc_url( $form_url );?>" method="post"> 2095 <?php $bp_members_signup_list_table->display(); ?> 2096 </form> 2097 </div> 2098 <?php 2099 } 2100 2101 /** 2102 * This is the confirmation screen for actions. 2103 * 2104 * @since 2.0.0 2105 * 2106 * @param string $action Delete, activate, or resend activation link. 2107 * 2108 * @return null|false 2109 */ 2110 public function signups_admin_manage( $action = '' ) { 2111 if ( ! current_user_can( $this->capability ) || empty( $action ) ) { 2112 die( '-1' ); 2113 } 2114 2115 // Get the user IDs from the URL. 2116 $ids = false; 2117 if ( ! empty( $_POST['allsignups'] ) ) { 2118 $ids = wp_parse_id_list( $_POST['allsignups'] ); 2119 } elseif ( ! empty( $_GET['signup_id'] ) ) { 2120 $ids = absint( $_GET['signup_id'] ); 2121 } 2122 2123 if ( empty( $ids ) ) { 2124 return false; 2125 } 2126 2127 // Query for signups, and filter out those IDs that don't 2128 // correspond to an actual signup. 2129 $signups_query = BP_Signup::get( array( 2130 'include' => $ids, 2131 ) ); 2132 2133 $signups = $signups_query['signups']; 2134 $signup_ids = wp_list_pluck( $signups, 'signup_id' ); 2135 2136 // Set up strings. 2137 switch ( $action ) { 2138 case 'delete' : 2139 $header_text = __( 'Delete Pending Accounts', 'buddypress' ); 2140 if ( 1 == count( $signup_ids ) ) { 2141 $helper_text = __( 'You are about to delete the following account:', 'buddypress' ); 2142 } else { 2143 $helper_text = __( 'You are about to delete the following accounts:', 'buddypress' ); 2144 } 2145 break; 2146 2147 case 'activate' : 2148 $header_text = __( 'Activate Pending Accounts', 'buddypress' ); 2149 if ( 1 == count( $signup_ids ) ) { 2150 $helper_text = __( 'You are about to activate the following account:', 'buddypress' ); 2151 } else { 2152 $helper_text = __( 'You are about to activate the following accounts:', 'buddypress' ); 2153 } 2154 break; 2155 2156 case 'resend' : 2157 $header_text = __( 'Resend Activation Emails', 'buddypress' ); 2158 if ( 1 == count( $signup_ids ) ) { 2159 $helper_text = __( 'You are about to resend an activation email to the following account:', 'buddypress' ); 2160 } else { 2161 $helper_text = __( 'You are about to resend an activation email to the following accounts:', 'buddypress' ); 2162 } 2163 break; 2164 } 2165 2166 // These arguments are added to all URLs. 2167 $url_args = array( 'page' => 'bp-signups' ); 2168 2169 // These arguments are only added when performing an action. 2170 $action_args = array( 2171 'action' => 'do_' . $action, 2172 'signup_ids' => implode( ',', $signup_ids ) 2173 ); 2174 2175 if ( is_network_admin() ) { 2176 $base_url = network_admin_url( 'users.php' ); 2177 } else { 2178 $base_url = bp_get_admin_url( 'users.php' ); 2179 } 2180 2181 $cancel_url = add_query_arg( $url_args, $base_url ); 2182 $action_url = wp_nonce_url( 2183 add_query_arg( 2184 array_merge( $url_args, $action_args ), 2185 $base_url 2186 ), 2187 'signups_' . $action 2188 ); 2189 2190 // Prefetch registration field data. 2191 $fdata = array(); 2192 if ( 'activate' === $action && bp_is_active( 'xprofile' ) ) { 2193 $field_groups = bp_xprofile_get_groups( array( 2194 'exclude_fields' => 1, 2195 'update_meta_cache' => false, 2196 'fetch_fields' => true, 2197 ) ); 2198 2199 foreach( $field_groups as $fg ) { 2200 foreach( $fg->fields as $f ) { 2201 $fdata[ $f->id ] = $f->name; 2202 } 2203 } 2204 } 2205 2206 ?> 2207 2208 <div class="wrap"> 2209 <h1 class="wp-heading-inline"><?php echo esc_html( $header_text ); ?></h1> 2210 <hr class="wp-header-end"> 2211 2212 <p><?php echo esc_html( $helper_text ); ?></p> 2213 2214 <ol class="bp-signups-list"> 2215 <?php foreach ( $signups as $signup ) : 2216 $last_notified = mysql2date( 'Y/m/d g:i:s a', $signup->date_sent ); 2217 $profile_field_ids = array(); 2218 2219 // Get all xprofile field IDs except field 1. 2220 if ( ! empty( $signup->meta['profile_field_ids'] ) ) { 2221 $profile_field_ids = array_flip( explode( ',', $signup->meta['profile_field_ids'] ) ); 2222 unset( $profile_field_ids[1] ); 2223 } ?> 2224 2225 <li> 2226 <strong><?php echo esc_html( $signup->user_login ) ?></strong> 2227 2228 <?php if ( 'activate' == $action ) : ?> 2229 <table class="wp-list-table widefat fixed striped"> 2230 <tbody> 2231 <tr> 2232 <td class="column-fields"><?php esc_html_e( 'Display Name', 'buddypress' ); ?></td> 2233 <td><?php echo esc_html( $signup->user_name ); ?></td> 2234 </tr> 2235 2236 <tr> 2237 <td class="column-fields"><?php esc_html_e( 'Email', 'buddypress' ); ?></td> 2238 <td><?php echo sanitize_email( $signup->user_email ); ?></td> 2239 </tr> 2240 2241 <?php if ( bp_is_active( 'xprofile' ) && ! empty( $profile_field_ids ) ) : ?> 2242 <?php foreach ( $profile_field_ids as $pid => $noop ) : 2243 $field_value = isset( $signup->meta[ "field_{$pid}" ] ) ? $signup->meta[ "field_{$pid}" ] : ''; ?> 2244 <tr> 2245 <td class="column-fields"><?php echo esc_html( $fdata[ $pid ] ); ?></td> 2246 <td><?php echo $this->format_xprofile_field_for_display( $field_value ); ?></td> 2247 </tr> 2248 2249 <?php endforeach; ?> 2250 2251 <?php endif; ?> 2252 2253 <?php 2254 /** 2255 * Fires inside the table listing the activate action confirmation details. 2256 * 2257 * @since 6.0.0 2258 * 2259 * @param object $signup The Sign-up Object. 2260 */ 2261 do_action( 'bp_activate_signup_confirmation_details', $signup ); 2262 ?> 2263 2264 </tbody> 2265 </table> 2266 2267 <?php 2268 /** 2269 * Fires outside the table listing the activate action confirmation details. 2270 * 2271 * @since 6.0.0 2272 * 2273 * @param object $signup The Sign-up Object. 2274 */ 2275 do_action( 'bp_activate_signup_confirmation_after_details', $signup ); 2276 ?> 2277 2278 <?php endif; ?> 2279 2280 <?php if ( 'resend' == $action ) : ?> 2281 2282 <p class="description"> 2283 <?php 2284 /* translators: %s: notification date */ 2285 printf( esc_html__( 'Last notified: %s', 'buddypress'), $last_notified ); 2286 ?> 2287 2288 <?php if ( ! empty( $signup->recently_sent ) ) : ?> 2289 2290 <span class="attention wp-ui-text-notification"> <?php esc_html_e( '(less than 24 hours ago)', 'buddypress' ); ?></span> 2291 2292 <?php endif; ?> 2293 </p> 2294 2295 <?php endif; ?> 2296 2297 </li> 2298 2299 <?php endforeach; ?> 2300 </ol> 2301 2302 <?php if ( 'delete' === $action ) : ?> 2303 2304 <p><strong><?php esc_html_e( 'This action cannot be undone.', 'buddypress' ) ?></strong></p> 2305 2306 <?php endif ; ?> 2307 2308 <a class="button-primary" href="<?php echo esc_url( $action_url ); ?>"><?php esc_html_e( 'Confirm', 'buddypress' ); ?></a> 2309 <a class="button" href="<?php echo esc_url( $cancel_url ); ?>"><?php esc_html_e( 'Cancel', 'buddypress' ) ?></a> 2310 </div> 2311 2312 <?php 2313 } 2314 2315 /** Users List Management ****************************************************/ 2316 2317 /** 2318 * Display a dropdown to bulk change the member type of selected user(s). 2319 * 2320 * @since 2.7.0 2321 * 2322 * @param string $which Where this dropdown is displayed - top or bottom. 2323 */ 2324 public function users_table_output_type_change_select( $which = 'top' ) { 2325 2326 // Bail if current user cannot promote users. 2327 if ( ! bp_current_user_can( 'promote_users' ) ) { 2328 return; 2329 } 2330 2331 // `$which` is only passed in WordPress 4.6+. Avoid duplicating controls in earlier versions. 2332 static $displayed = false; 2333 if ( version_compare( bp_get_major_wp_version(), '4.6', '<' ) && $displayed ) { 2334 return; 2335 } 2336 $displayed = true; 2337 2338 $id_name = 'bottom' === $which ? 'bp_change_type2' : 'bp_change_type'; 2339 2340 $types = bp_get_member_types( array(), 'objects' ); ?> 2341 2342 <label class="screen-reader-text" for="<?php echo $id_name; ?>"><?php _e( 'Change member type to…', 'buddypress' ) ?></label> 2343 <select name="<?php echo $id_name; ?>" id="<?php echo $id_name; ?>" style="display:inline-block;float:none;"> 2344 <option value=""><?php _e( 'Change member type to…', 'buddypress' ) ?></option> 2345 2346 <?php foreach( $types as $type ) : ?> 2347 2348 <option value="<?php echo esc_attr( $type->name ); ?>"><?php echo esc_html( $type->labels['singular_name'] ); ?></option> 2349 2350 <?php endforeach; ?> 2351 2352 <option value="remove_member_type"><?php _e( 'No Member Type', 'buddypress' ) ?></option> 2353 2354 </select> 2355 <?php 2356 wp_nonce_field( 'bp-bulk-users-change-type-' . bp_loggedin_user_id(), 'bp-bulk-users-change-type-nonce' ); 2357 submit_button( __( 'Change', 'buddypress' ), 'button', 'bp_change_member_type', false ); 2358 } 2359 2360 /** 2361 * Process bulk member type change submission from the WP admin users list table. 2362 * 2363 * @since 2.7.0 2364 */ 2365 public function users_table_process_bulk_type_change() { 2366 // Output the admin notice. 2367 $this->users_type_change_notice(); 2368 2369 // Bail if no users are specified or if this isn't a BuddyPress action. 2370 if ( empty( $_REQUEST['users'] ) 2371 || ( empty( $_REQUEST['bp_change_type'] ) && empty( $_REQUEST['bp_change_type2'] ) ) 2372 || empty( $_REQUEST['bp_change_member_type'] ) 2373 ) { 2374 return; 2375 } 2376 2377 // Bail if nonce check fails. 2378 check_admin_referer( 'bp-bulk-users-change-type-' . bp_loggedin_user_id(), 'bp-bulk-users-change-type-nonce' ); 2379 2380 // Bail if current user cannot promote users. 2381 if ( ! bp_current_user_can( 'promote_users' ) ) { 2382 return; 2383 } 2384 2385 $new_type = ''; 2386 if ( ! empty( $_REQUEST['bp_change_type2'] ) ) { 2387 $new_type = sanitize_text_field( $_REQUEST['bp_change_type2'] ); 2388 } elseif ( ! empty( $_REQUEST['bp_change_type'] ) ) { 2389 $new_type = sanitize_text_field( $_REQUEST['bp_change_type'] ); 2390 } 2391 2392 // Check that the selected type actually exists. 2393 if ( 'remove_member_type' != $new_type && null === bp_get_member_type_object( $new_type ) ) { 2394 $error = true; 2395 } else { 2396 // Run through user ids. 2397 $error = false; 2398 foreach ( (array) $_REQUEST['users'] as $user_id ) { 2399 $user_id = (int) $user_id; 2400 2401 // Get the old member types to check against. 2402 $current_types = bp_get_member_type( $user_id, false ); 2403 2404 if ( $current_types && 'remove_member_type' === $new_type ) { 2405 $member_types = array(); 2406 } elseif ( ! $current_types || 1 !== count( $current_types ) || $new_type !== $current_types[0] ) { 2407 // Set the new member type. 2408 $member_types = array( $new_type ); 2409 } 2410 2411 if ( isset( $member_types ) ) { 2412 $set = bp_set_member_type( $user_id, $member_types ); 2413 if ( false === $set || is_wp_error( $set ) ) { 2414 $error = true; 2415 } 2416 unset( $member_types ); 2417 } 2418 } 2419 } 2420 2421 // If there were any errors, show the error message. 2422 if ( $error ) { 2423 $redirect = add_query_arg( array( 'updated' => 'member-type-change-error' ), wp_get_referer() ); 2424 } else { 2425 $redirect = add_query_arg( array( 'updated' => 'member-type-change-success' ), wp_get_referer() ); 2426 } 2427 2428 wp_redirect( $redirect ); 2429 exit(); 2430 } 2431 2432 /** 2433 * Display an admin notice upon member type bulk update. 2434 * 2435 * @since 2.7.0 2436 */ 2437 public function users_type_change_notice() { 2438 $updated = isset( $_REQUEST['updated'] ) ? $_REQUEST['updated'] : false; 2439 2440 // Display feedback. 2441 if ( $updated && in_array( $updated, array( 'member-type-change-error', 'member-type-change-success' ), true ) ) { 2442 2443 if ( 'member-type-change-error' === $updated ) { 2444 $notice = __( 'There was an error while changing member type. Please try again.', 'buddypress' ); 2445 $type = 'error'; 2446 } else { 2447 $notice = __( 'Member type was changed successfully.', 'buddypress' ); 2448 $type = 'updated'; 2449 } 2450 2451 bp_core_add_admin_notice( $notice, $type ); 2452 } 2453 } 2454 2455 /** 2456 * Add member type column to the WordPress admin users list table. 2457 * 2458 * @since 2.7.0 2459 * 2460 * @param array $columns Users table columns. 2461 * 2462 * @return array $columns 2463 */ 2464 public function users_table_add_type_column( $columns = array() ) { 2465 $columns[ bp_get_member_type_tax_name() ] = _x( 'Member Type', 'Label for the WP users table member type column', 'buddypress' ); 2466 2467 return $columns; 2468 } 2469 2470 /** 2471 * Return member's type for display in the WP admin users list table. 2472 * 2473 * @since 2.7.0 2474 * 2475 * @param string $retval 2476 * @param string $column_name 2477 * @param int $user_id 2478 * 2479 * @return string Member type as a link to filter all users. 2480 */ 2481 public function users_table_populate_type_cell( $retval = '', $column_name = '', $user_id = 0 ) { 2482 // Only looking for member type column. 2483 if ( bp_get_member_type_tax_name() !== $column_name ) { 2484 return $retval; 2485 } 2486 2487 // Get the member type. 2488 $member_type = bp_get_member_type( $user_id, false ); 2489 2490 // Build the Output. 2491 if ( $member_type ) { 2492 $member_types = array_filter( array_map( 'bp_get_member_type_object', $member_type ) ); 2493 if ( ! $member_types ) { 2494 return $retval; 2495 } 2496 2497 $type_links = array(); 2498 foreach ( $member_types as $type ) { 2499 $url = add_query_arg( array( 'bp-member-type' => urlencode( $type->name ) ) ); 2500 $type_links[] = sprintf( 2501 '<a href="%1$s">%2$s</a>', 2502 esc_url( $url ), 2503 esc_html( $type->labels['singular_name'] ) 2504 ); 2505 } 2506 2507 $retval = implode( ', ', $type_links ); 2508 } 2509 2510 return $retval; 2511 } 2512 2513 /** 2514 * Filter WP Admin users list table to include users of the specified type. 2515 * 2516 * @param WP_Query $query 2517 * 2518 * @since 2.7.0 2519 */ 2520 public function users_table_filter_by_type( $query ) { 2521 global $pagenow; 2522 2523 if ( is_admin() && 'users.php' === $pagenow && ! empty( $_REQUEST['bp-member-type'] ) ) { 2524 $type_slug = sanitize_text_field( $_REQUEST['bp-member-type'] ); 2525 2526 // Check that the type is registered. 2527 if ( null == bp_get_member_type_object( $type_slug ) ) { 2528 return; 2529 } 2530 2531 // Get the list of users that are assigned to this member type. 2532 $type = bp_get_term_by( 'slug', $type_slug, bp_get_member_type_tax_name() ); 2533 2534 if ( empty( $type->term_id ) ) { 2535 return; 2536 } 2537 2538 $user_ids = bp_get_objects_in_term( $type->term_id, bp_get_member_type_tax_name() ); 2539 2540 if ( $user_ids && ! is_wp_error( $user_ids ) ) { 2541 $query->set( 'include', (array) $user_ids ); 2542 } 2543 } 2544 } 2545 2546 /** 2547 * Formats a signup's xprofile field data for display. 2548 * 2549 * Operates recursively on arrays, which are then imploded with commas. 2550 * 2551 * @since 2.8.0 2552 * 2553 * @param string|array $value Field value. 2554 * @return string 2555 */ 2556 protected function format_xprofile_field_for_display( $value ) { 2557 if ( is_array( $value ) ) { 2558 $value = array_map( array( $this, 'format_xprofile_field_for_display' ), $value ); 2559 $value = implode( ', ', $value ); 2560 } else { 2561 $value = stripslashes( $value ); 2562 $value = esc_html( $value ); 2563 } 2564 2565 return $value; 2566 } 2567 } 2568 endif; // End class_exists check.
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Feb 26 01:01:36 2021 | Cross-referenced by PHPXref 0.7.1 |