PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 6.2.1
MainWP Dashboard: Self-hosted WordPress Management for Agencies v6.2.1
6.2.2 6.2.1 6.2 6.1.8 6.1.7 6.1.6 6.1.5 6.1.4 6.1.3 6.1.2 6.1.1 6.1 6.0.12 6.0.11 4.6.0.1 5.0 5.0.1 5.0.2 5.0.3 5.0.3.1 5.0.3.2 5.1 5.1.1 5.2 5.2.1 All 155 releases
← All changes | pages/page-mainwp-user.php +396 -258 5.1 → 6.2.1 View file →
@@ -8,8 +8,13 @@
8 8 */
9 9
10 10 namespace MainWP\Dashboard;
11 11
12 +// Exit if accessed directly.
13 +if ( ! defined( 'ABSPATH' ) ) {
14 + exit;
15 +}
16 +
12 17 /**
13 18 * Class MainWP_User
14 19 *
15 20 * @uses page-mainwp-bulk-add::MainWP_Bulk_Add()
@@ -141,9 +146,9 @@
141 146 <div id="menu-mainwp-Users" class="mainwp-submenu-wrapper">
142 147 <div class="wp-submenu sub-open" style="">
143 148 <div class="mainwp_boxout">
144 149 <div class="mainwp_boxoutin"></div>
145 - <?php if ( mainwp_current_user_have_right( 'dashboard', 'manage_users' ) ) { ?>
150 + <?php if ( \mainwp_current_user_can( 'dashboard', 'manage_users' ) ) { ?>
146 151 <a href="<?php echo esc_url( admin_url( 'admin.php?page=UserBulkManage' ) ); ?>" class="mainwp-submenu"><?php esc_html_e( 'Manage Users', 'mainwp' ); ?></a>
147 152 <?php } ?>
148 153 <?php if ( ! MainWP_Menu::is_disable_menu_item( 3, 'UserBulkAdd' ) ) { ?>
149 154 <a href="<?php echo esc_url( admin_url( 'admin.php?page=UserBulkAdd' ) ); ?>" class="mainwp-submenu"><?php esc_html_e( 'Add New', 'mainwp' ); ?></a>
@@ -153,8 +158,11 @@
153 158 <?php } ?>
154 159 <?php if ( ! MainWP_Menu::is_disable_menu_item( 3, 'UpdateAdminPasswords' ) ) { ?>
155 160 <a href="<?php echo esc_url( admin_url( 'admin.php?page=UpdateAdminPasswords' ) ); ?>" class="mainwp-submenu"><?php esc_html_e( 'Admin Passwords', 'mainwp' ); ?></a>
156 161 <?php } ?>
162 + <?php if ( ! MainWP_Menu::is_disable_menu_item( 3, 'PasswordPolicy' ) ) { ?>
163 + <a href="<?php echo esc_url( admin_url( 'admin.php?page=PasswordPolicy' ) ); ?>" class="mainwp-submenu"><?php esc_html_e( 'Password Policy', 'mainwp' ); ?></a>
164 + <?php } ?>
157 165 <?php
158 166 if ( isset( static::$subPages ) && is_array( static::$subPages ) ) {
159 167 foreach ( static::$subPages as $subPage ) {
160 168 if ( MainWP_Menu::is_disable_menu_item( 3, 'UserBulk' . $subPage['slug'] ) ) {
@@ -182,14 +190,16 @@
182 190 * @uses \MainWP\Dashboard\MainWP_Utility::enabled_wp_seo()
183 191 */
184 192 public static function get_manage_columns() {
185 193 return array(
186 - 'name' => esc_html__( 'Name', 'mainwp' ),
187 - 'username' => esc_html__( 'Username', 'mainwp' ),
188 - 'email' => esc_html__( 'E-mail', 'mainwp' ),
189 - 'role' => esc_html__( 'Role', 'mainwp' ),
190 - 'posts' => esc_html__( 'Posts', 'mainwp' ),
191 - 'website' => esc_html__( 'Website', 'mainwp' ),
194 + 'name' => esc_html__( 'Name', 'mainwp' ),
195 + 'username' => esc_html__( 'Username', 'mainwp' ),
196 + 'email' => esc_html__( 'E-mail', 'mainwp' ),
197 + 'last_password_change' => esc_html__( 'Last Password Change', 'mainwp' ),
198 + 'password_status' => esc_html__( 'Password Status', 'mainwp' ),
199 + 'role' => esc_html__( 'Role', 'mainwp' ),
200 + 'posts' => esc_html__( 'Posts', 'mainwp' ),
201 + 'website' => esc_html__( 'Website', 'mainwp' ),
192 202 );
193 203 }
194 204
195 205 /**
@@ -275,8 +285,15 @@
275 285 'href' => 'admin.php?page=UpdateAdminPasswords',
276 286 'slug' => 'UpdateAdminPasswords',
277 287 'right' => '',
278 288 ),
289 + array(
290 + 'title' => esc_html__( 'Password Policy', 'mainwp' ),
291 + 'parent_key' => 'UserBulkManage',
292 + 'href' => 'admin.php?page=PasswordPolicy',
293 + 'slug' => 'PasswordPolicy',
294 + 'right' => '',
295 + ),
279 296 );
280 297
281 298 MainWP_Menu::init_subpages_left_menu( $subPages, $init_sub_subleftmenu, 'UserBulkManage', 'UserBulk' );
282 299
@@ -306,9 +323,9 @@
306 323 MainWP_UI::render_top_header( $params );
307 324
308 325 $renderItems = array();
309 326
310 - if ( mainwp_current_user_have_right( 'dashboard', 'manage_users' ) ) {
327 + if ( \mainwp_current_user_can( 'dashboard', 'manage_users' ) ) {
311 328 $renderItems[] = array(
312 329 'title' => esc_html__( 'Manage Users', 'mainwp' ),
313 330 'href' => 'admin.php?page=UserBulkManage',
314 331 'active' => ( '' === $shownPage ) ? true : false,
@@ -338,8 +355,16 @@
338 355 'active' => ( 'UpdateAdminPasswords' === $shownPage ) ? true : false,
339 356 );
340 357 }
341 358
359 + if ( ! MainWP_Menu::is_disable_menu_item( 3, 'PasswordPolicy' ) ) {
360 + $renderItems[] = array(
361 + 'title' => esc_html__( 'Password Policy', 'mainwp' ),
362 + 'href' => 'admin.php?page=PasswordPolicy',
363 + 'active' => ( 'PasswordPolicy' === $shownPage ) ? true : false,
364 + );
365 + }
366 +
342 367 if ( isset( static::$subPages ) && is_array( static::$subPages ) ) {
343 368 foreach ( static::$subPages as $subPage ) {
344 369 if ( MainWP_Menu::is_disable_menu_item( 3, 'UserBulk' . $subPage['slug'] ) ) {
345 370 continue;
@@ -372,10 +397,10 @@
372 397 *
373 398 * @uses \MainWP\Dashboard\MainWP_Cache::get_cached_context()
374 399 */
375 400 public static function render() {
376 - if ( ! mainwp_current_user_have_right( 'dashboard', 'manage_users' ) ) {
377 - mainwp_do_not_have_permissions( esc_html__( 'manage users', 'mainwp' ) );
401 + if ( ! \mainwp_current_user_can( 'dashboard', 'manage_users' ) ) {
402 + \mainwp_do_not_have_permissions( esc_html__( 'manage users', 'mainwp' ) );
378 403
379 404 return;
380 405 }
381 406
@@ -396,15 +421,15 @@
396 421 }
397 422
398 423 static::render_header( '' );
399 424 ?>
400 - <div id="mainwp-manage-users" class="ui alt segment">
425 + <div id="mainwp-manage-users">
401 426 <div class="mainwp-main-content">
402 427 <div class="mainwp-actions-bar ui mini form">
403 428 <div class="ui grid">
404 429 <div class="ui two column row">
405 430 <div class="column">
406 - <select class="ui mini dropdown" id="mainwp-bulk-actions">
431 + <select class="ui mini dropdown disabled" id="mainwp-bulk-actions">
407 432 <option value=""><?php esc_html_e( 'Bulk Actions', 'mainwp' ); ?></option>
408 433 <option value="edit"><?php esc_html_e( 'Edit', 'mainwp' ); ?></option>
409 434 <option value="delete"><?php esc_html_e( 'Delete', 'mainwp' ); ?></option>
410 435 <?php
@@ -420,9 +445,9 @@
420 445 */
421 446 do_action( 'mainwp_users_bulk_action' );
422 447 ?>
423 448 </select>
424 - <button class="ui mini button" id="mainwp-do-users-bulk-actions"><?php esc_html_e( 'Apply', 'mainwp' ); ?></button>
449 + <button class="ui mini button disabled" id="mainwp-do-users-bulk-actions"><?php esc_html_e( 'Apply', 'mainwp' ); ?></button>
425 450 <?php
426 451 /**
427 452 * Users actions bar (left)
428 453 *
@@ -448,21 +473,29 @@
448 473 </div>
449 474 </div>
450 475 </div>
451 476 <div id="mainwp-loading-users-row" style="display: none;">
452 - <div class="ui active inverted dimmer">
453 - <div class="ui indeterminate large text loader"><?php esc_html_e( 'Loading Users...', 'mainwp' ); ?>
477 + <div class="ui active page dimmer">
478 + <div class="ui double text loader">
479 + <?php esc_html_e( 'Loading...', 'mainwp' ); ?>
454 480 <span id="mainwp_users_loading_info" class="mainwp-grabbing-info-note"><br /><?php esc_html_e( 'Automatically refreshing to get up to date information.', 'mainwp' ); ?></span>
455 481 </div>
456 482 </div>
457 483 </div>
458 - <div class="ui segment" id="mainwp_users_wrap_table">
484 + <div class="ui padded segment" id="mainwp_users_wrap_table">
459 485 <?php if ( MainWP_Utility::show_mainwp_message( 'notice', 'mainwp-manage-users-info-message' ) ) : ?>
460 486 <div class="ui info message">
461 487 <i class="close icon mainwp-notice-dismiss" notice-id="mainwp-manage-users-info-message"></i>
462 - <?php printf( esc_html__( 'Manage existing users on your child sites. Here you can Delete, Edit or Change Role for existing users. For additional help, please check this %1$shelp documentation%2$s.', 'mainwp' ), '<a href="https://kb.mainwp.com/docs/manage-users/" target="_blank">', '</a>' ); ?>
488 + <?php /* translators: 1: opening anchor tag, 2: closing anchor tag */ printf( esc_html__( 'Manage existing users on your child sites. Here you can Delete, Edit or Change Role for existing users. For additional help, please check this %1$shelp documentation%2$s.', 'mainwp' ), '<a href="https://docs.mainwp.com/sites/users/manage-users/" target="_blank">', '</a>' ); ?>
463 489 </div>
464 490 <?php endif; ?>
491 + <?php if ( MainWP_Utility::show_mainwp_message( 'notice', 'mainwp-password-policy-feature-info-message' ) ) : ?>
492 + <div class="ui info message">
493 + <i class="close icon mainwp-notice-dismiss" notice-id="mainwp-password-policy-feature-info-message"></i>
494 + <div><?php esc_html_e( 'MainWP shows the Last password change and Status for each user. WordPress doesn\'t store a reliable password-change date by default, so tracking starts after this version of MainWP Child is installed/updated. Until a user changes their password, the date may appear as Unknown.', 'mainwp' ); ?></div><br/>
495 + <div><?php esc_html_e( 'If your password policy is set to Never, MainWP will still record password changes, but no due/overdue notices are shown and status may remain OK/Disabled. When a policy is enabled, users with an Unknown date can still become Due/Overdue based on no password change recorded since the policy was enabled.', 'mainwp' ); ?></div>
496 + </div>
497 + <?php endif; ?>
465 498 <div class="ui message" id="mainwp-message-zone" style="display:none"></div>
466 499 <?php static::render_table( true ); ?>
467 500 </div>
468 501 <div id="mainwp-update-users-box" class="ui segment">
@@ -544,9 +577,9 @@
544 577 */
545 578 do_action( 'mainwp_manage_users_before_search_options' );
546 579 ?>
547 580 <div class="ui mini form">
548 - <div class="field" data-tooltip="<?php esc_attr_e( 'Select specific roles that you want to search for.', 'mainwp' ); ?>" data-inverted="" data-position="top right">
581 + <div class="field">
549 582 <select multiple="" class="ui fluid mini dropdown" id="mainwp_user_roles">
550 583 <option value=""><?php esc_html_e( 'Select wanted role(s)', 'mainwp' ); ?></option>
551 584 <?php
552 585 foreach ( $user_roles as $r => $n ) {
@@ -634,9 +667,9 @@
634 667 }
635 668 ?>
636 669
637 670 <div class="ui mini form">
638 - <div class="field" data-tooltip="<?php esc_attr_e( 'Enter specific username that you want to search for.', 'mainwp' ); ?>" data-inverted="" data-position="top right">
671 + <div class="field">
639 672 <div class="ui input fluid">
640 673 <input type="text" placeholder="<?php esc_attr_e( 'Username', 'mainwp' ); ?>" id="mainwp_search_users" class="text" value="<?php echo ( null !== $cachedSearch ) ? esc_attr( $cachedSearch['keyword'] ) : ''; ?>" />
641 674 </div>
642 675 </div>
@@ -680,124 +713,114 @@
680 713 ?>
681 714 <div id="mainwp-edit-users-modal" class="ui modal">
682 715 <i class="close icon"></i>
683 716 <div class="header"><?php esc_html_e( 'Edit User', 'mainwp' ); ?></div>
684 - <div class="ui message"><?php esc_html_e( 'Empty fields will not be passed to child sites.', 'mainwp' ); ?></div>
685 - <form id="update_user_profile">
686 - <?php wp_nonce_field( 'mainwp-admin-nonce' ); ?>
687 - <div class="ui segment">
688 - <div class="ui form">
689 - <h3><?php esc_html_e( 'Name', 'mainwp' ); ?></h3>
690 - <div class="ui grid field">
691 - <label class="six wide column middle aligned"><?php esc_html_e( 'Role', 'mainwp' ); ?></label>
692 - <div class="ui six wide column">
693 - <div class="ui left labeled input">
694 - <select name="role" id="role">
695 - <?php
696 - foreach ( $editable_roles as $role_id => $role_name ) {
697 - echo '<option value="' . esc_attr( $role_id ) . '" ' . ( 'donotupdate' === $role_id ? 'selected="selected"' : '' ) . '>' . esc_html( $role_name ) . '</option>';
698 - }
699 - ?>
700 - </select>
701 - </div>
702 - </div>
717 + <div class="scrolling content">
718 + <div class="ui info message"><?php esc_html_e( 'Blank fields will not be changed.', 'mainwp' ); ?></div>
719 + <form id="update_user_profile" class="ui form">
720 + <?php MainWP_UI::generate_wp_nonce( 'mainwp-admin-nonce' ); ?>
721 +
722 + <h3 class="ui header"><?php esc_html_e( 'Name', 'mainwp' ); ?></h3>
723 +
724 + <div class="ui grid field">
725 + <label class="six wide column middle aligned"><?php esc_html_e( 'Role', 'mainwp' ); ?></label>
726 + <div class="ui six wide column">
727 + <select name="role" id="role" class="ui selection dropdown">
728 + <?php
729 + foreach ( $editable_roles as $role_id => $role_name ) {
730 + echo '<option value="' . esc_attr( $role_id ) . '" ' . ( 'donotupdate' === $role_id ? 'selected="selected"' : '' ) . '>' . esc_html( $role_name ) . '</option>';
731 + }
732 + ?>
733 + </select>
703 734 </div>
735 + </div>
704 736
705 - <div class="ui grid field">
706 - <label class="six wide column middle aligned"><?php esc_html_e( 'First Name', 'mainwp' ); ?></label>
707 - <div class="ui six wide column">
708 - <div class="ui left labeled input">
709 - <input type="text" name="first_name" id="first_name" value="" class="regular-text" />
710 - </div>
737 + <div class="ui grid field">
738 + <label class="six wide column middle aligned"><?php esc_html_e( 'First Name', 'mainwp' ); ?></label>
739 + <div class="ui six wide column">
740 + <div class="ui input">
741 + <input type="text" name="first_name" id="first_name" value="" />
711 742 </div>
712 743 </div>
744 + </div>
713 745
714 - <div class="ui grid field">
715 - <label class="six wide column middle aligned"><?php esc_html_e( 'Last Name', 'mainwp' ); ?></label>
716 - <div class="ui six wide column">
717 - <div class="ui left labeled input">
718 - <input type="text" name="last_name" id="last_name" value="" class="regular-text" />
719 - </div>
746 + <div class="ui grid field">
747 + <label class="six wide column middle aligned"><?php esc_html_e( 'Last Name', 'mainwp' ); ?></label>
748 + <div class="ui six wide column">
749 + <div class="ui input">
750 + <input type="text" name="last_name" id="last_name" value="" />
720 751 </div>
721 752 </div>
753 + </div>
722 754
723 - <div class="ui grid field">
724 - <label class="six wide column middle aligned"><?php esc_html_e( 'Nickname', 'mainwp' ); ?></label>
725 - <div class="ui six wide column">
726 - <div class="ui left labeled input">
727 - <input type="text" name="nickname" id="nickname" value="" class="regular-text" />
728 - </div>
755 + <div class="ui grid field">
756 + <label class="six wide column middle aligned"><?php esc_html_e( 'Nickname', 'mainwp' ); ?></label>
757 + <div class="ui six wide column">
758 + <div class="ui input">
759 + <input type="text" name="nickname" id="nickname" value="" />
729 760 </div>
730 761 </div>
762 + </div>
731 763
732 - <div class="ui grid field">
733 - <label class="six wide column middle aligned"><?php esc_html_e( 'Display name publicly as', 'mainwp' ); ?></label>
734 - <div class="ui six wide column">
735 - <div class="ui left labeled input">
736 - <select name="display_name" id="display_name"></select>
737 - </div>
764 + <div class="ui grid field">
765 + <label class="six wide column middle aligned"><?php esc_html_e( 'Display name publicly as', 'mainwp' ); ?></label>
766 + <div class="ui six wide column">
767 + <div class="ui input">
768 + <select name="display_name" id="display_name" class="ui selection dropdown"></select>
738 769 </div>
739 770 </div>
771 + </div>
740 772
741 - <h3><?php esc_html_e( 'Contact Info', 'mainwp' ); ?></h3>
773 + <h3 class="ui header"><?php esc_html_e( 'Contact Info', 'mainwp' ); ?></h3>
742 774
743 - <div class="ui grid field">
744 - <label class="six wide column middle aligned"><?php esc_html_e( 'Email', 'mainwp' ); ?></label>
745 - <div class="ui six wide column">
746 - <div class="ui left labeled input">
747 - <input type="email" name="email" id="email" value="" class="regular-text ltr" />
748 - </div>
775 + <div class="ui grid field">
776 + <label class="six wide column middle aligned"><?php esc_html_e( 'Email', 'mainwp' ); ?></label>
777 + <div class="ui six wide column">
778 + <div class="ui input">
779 + <input type="email" name="email" id="email" value="" />
749 780 </div>
750 781 </div>
782 + </div>
751 783
752 - <div class="ui grid field">
753 - <label class="six wide column middle aligned"><?php esc_html_e( 'Website', 'mainwp' ); ?></label>
754 - <div class="ui six wide column">
755 - <div class="ui left labeled input">
756 - <input type="url" name="url" id="url" value="" class="regular-text code" />
757 - </div>
784 + <div class="ui grid field">
785 + <label class="six wide column middle aligned"><?php esc_html_e( 'Website', 'mainwp' ); ?></label>
786 + <div class="ui six wide column">
787 + <div class="ui input">
788 + <input type="url" name="url" id="url" value="" />
758 789 </div>
759 790 </div>
791 + </div>
760 792
761 - <h3><?php esc_html_e( 'About the user', 'mainwp' ); ?></h3>
793 + <h3 class="ui header"><?php esc_html_e( 'About the user', 'mainwp' ); ?></h3>
762 794
763 - <div class="ui grid field">
764 - <label class="six wide column middle aligned"><?php esc_html_e( 'Biographical Info', 'mainwp' ); ?></label>
765 - <div class="ui six wide column">
766 - <div class="ui left labeled input">
767 - <textarea name="description" id="description" rows="5" cols="30"></textarea>
768 - <p class="description"><?php esc_html_e( 'Share a little biographical information to fill out your profile. This may be shown publicly.', 'mainwp' ); ?></p>
769 - </div>
795 + <div class="ui grid field">
796 + <label class="six wide column middle aligned"><?php esc_html_e( 'Biographical Info', 'mainwp' ); ?></label>
797 + <div class="ui six wide column">
798 + <div class="ui input">
799 + <textarea name="description" id="description" rows="5" cols="30" style="width:100%"></textarea>
770 800 </div>
771 801 </div>
802 + </div>
772 803
773 - <h3><?php esc_html_e( 'Account Management', 'mainwp' ); ?></h3>
804 + <h3 class="ui header"><?php esc_html_e( 'Account Management', 'mainwp' ); ?></h3>
774 805
775 - <div class="ui grid field">
776 - <label class="six wide column middle aligned"><?php esc_html_e( 'Password', 'mainwp' ); ?></label>
777 - <div class="ui six wide column">
778 - <div class="ui left labeled action input">
779 - <input class="hidden" value=" "/>
780 - <input type="text" id="password" name="password" autocomplete="off" value="">
781 - </div>
806 + <div class="ui grid field">
807 + <label class="six wide column middle aligned"><?php esc_html_e( 'Password', 'mainwp' ); ?></label>
808 + <div class="ui six wide column">
809 + <div class="ui action input">
810 + <input class="hidden" value=" "/>
811 + <input type="text" id="password" name="password" autocomplete="off" value="">
782 812 </div>
783 813 </div>
784 814 </div>
785 - </div>
786 - </form>
787 - <?php
788 - $is_demo = MainWP_Demo_Handle::is_demo_mode();
789 - ?>
815 +
816 + </form>
817 + </div>
818 +
790 819 <div class="actions">
791 820 <div id="mainwp_update_password_error" style="display: none"></div>
792 821 <span id="mainwp_users_updating"><i class="ui active inline loader tiny"></i></span>
793 - <?php
794 - if ( $is_demo ) {
795 - MainWP_Demo_Handle::get_instance()->render_demo_disable_button( '<input type="button" class="ui green button disabled" disabled="disabled" value="' . esc_attr__( 'Update', 'mainwp' ) . '">' );
796 - } else {
797 - ?>
798 - <input type="button" class="ui green button" id="mainwp_btn_update_user" value="<?php esc_attr_e( 'Update', 'mainwp' ); ?>">
799 - <?php } ?>
822 + <input type="button" class="ui green button" id="mainwp_btn_update_user" value="<?php esc_attr_e( 'Update', 'mainwp' ); ?>">
800 823 </div>
801 824 </div>
802 825 <?php
803 826 }
@@ -815,8 +838,10 @@
815 838 * @uses \MainWP\Dashboard\MainWP_Cache::echo_body()
816 839 */
817 840 public static function render_table( $cached = true, $role = '', $groups = '', $sites = '', $search = null, $clients = '' ) {
818 841
842 + $has_cached_results = $cached && isset( $_SESSION['MainWPUsersSearch'] ) && ! empty( $_SESSION['MainWPUsersSearch'] );
843 +
819 844 /**
820 845 * Action: mainwp_before_users_table
821 846 *
822 847 * Fires before the User table.
@@ -823,9 +848,11 @@
823 848 *
824 849 * @since 4.1
825 850 */
826 851 do_action( 'mainwp_before_users_table' );
827 - ?>
852 +
853 + if ( ! $cached || $has_cached_results ) {
854 + ?>
828 855 <table id="mainwp-users-table" class="ui unstackable single line table" style="width:100%">
829 856 <thead>
830 857 <tr>
831 858 <th class="no-sort collapsing check-column"><span class="ui checkbox"><input id="cb-select-all-top" type="checkbox" /></span></th>
@@ -832,8 +859,10 @@
832 859 <?php do_action( 'mainwp_users_table_header' ); ?>
833 860 <th id="name"><?php esc_html_e( 'Name', 'mainwp' ); ?></th>
834 861 <th id="username"><?php esc_html_e( 'Username', 'mainwp' ); ?></th>
835 862 <th id="email"><?php esc_html_e( 'E-mail', 'mainwp' ); ?></th>
863 + <th id="last_password_change" class="right aligned"><?php esc_html_e( 'Last Password Change', 'mainwp' ); ?></th>
864 + <th id="password_status" class="center aligned"><?php esc_html_e( 'Password Status', 'mainwp' ); ?></th>
836 865 <th id="role"><?php esc_html_e( 'Role', 'mainwp' ); ?></th>
837 866 <th id="posts"><?php esc_html_e( 'Posts', 'mainwp' ); ?></th>
838 867 <th id="website"><?php esc_html_e( 'Website', 'mainwp' ); ?></th>
839 868 <th id="mainwp-users-actions" class="no-sort collapsing"></th>
@@ -843,14 +872,22 @@
843 872 <?php
844 873 if ( $cached ) {
845 874 MainWP_Cache::echo_body( 'Users' );
846 875 } else {
876 + MainWP_Cache::init_cache( 'Users' );
847 877 static::render_table_body( $role, $groups, $sites, $search, $clients );
848 878 }
849 879 ?>
850 880 </tbody>
851 881 </table>
852 - <?php
882 + <?php
883 + } else {
884 + MainWP_UI::render_empty_page_placeholder(
885 + esc_html__( 'Find Users', 'mainwp' ),
886 + esc_html__( 'Select the Child Sites you want, choose any filters, then click Show Users.', 'mainwp' ),
887 + '<em data-emoji=":busts_in_silhouette:" class="big"></em>'
888 + );
889 + }
853 890 /**
854 891 * Action: mainwp_after_users_table
855 892 *
856 893 * Fires after the User table.
@@ -899,19 +936,29 @@
899 936 "order": <?php echo esc_html( $table_features['order'] ); ?>,
900 937 "scrollX" : <?php echo esc_html( $table_features['scrollX'] ); ?>,
901 938 "lengthMenu": [ [10, 25, 50, 100, -1], [10, 25, 50, 100, "All"] ],
902 939 "language" : { "emptyTable": "<?php esc_html_e( 'Please use the search options to find wanted users.', 'mainwp' ); ?>" },
903 - "columnDefs": [ {
904 - "targets": 'no-sort',
905 - "orderable": false
906 - } ],
907 - "preDrawCallback": function() {
908 - console.log('preDrawCallback mainwp-users-table');
940 + "columnDefs": [
941 + {
942 + "targets": 'no-sort',
943 + "orderable": false
944 + },
945 + {
946 + "targets": '#last_password_change',
947 + "type": 'string'
948 + },
949 + {
950 + "targets": '#password_status',
951 + "type": 'string'
952 + }
953 + ],
954 + "drawCallback": function() {
909 955 setTimeout(() => {
910 956 jQuery('#mainwp-users-table .ui.dropdown').dropdown();
911 957 jQuery('#mainwp-users-table .ui.checkbox').checkbox();
912 - mainwp_datatable_fix_menu_overflow();
958 + mainwp_datatable_fix_menu_overflow('#mainwp-users-table');
913 959 mainwp_table_check_columns_init(); // ajax: to fix checkbox all.
960 + updateUsersBulkActionsState();
914 961 }, 1000);
915 962 },
916 963 select: {
917 964 items: 'row',
@@ -922,8 +969,9 @@
922 969 if( 'row' == type ){
923 970 dt.rows(indexes)
924 971 .nodes()
925 972 .to$().find('td.check-column .ui.checkbox' ).checkbox('set checked');
973 + updateUsersBulkActionsState();
926 974 }
927 975 }).on('deselect', function (e, dt, type, indexes) {
928 976 if( 'row' == type ){
929 977 dt.rows(indexes)
@@ -928,15 +976,15 @@
928 976 if( 'row' == type ){
929 977 dt.rows(indexes)
930 978 .nodes()
931 979 .to$().find('td.check-column .ui.checkbox' ).checkbox('set unchecked');
980 + updateUsersBulkActionsState();
932 981 }
933 982 }).on( 'columns-reordered', function () {
934 - console.log('columns-reordered');
935 983 setTimeout(() => {
936 984 jQuery( '#mainwp-users-table .ui.dropdown' ).dropdown();
937 985 jQuery( '#mainwp-users-table .ui.checkbox' ).checkbox();
938 - mainwp_datatable_fix_menu_overflow();
986 + mainwp_datatable_fix_menu_overflow('#mainwp-users-table');
939 987 mainwp_table_check_columns_init(); // ajax: to fix checkbox all.
940 988 }, 1000);
941 989 });
942 990 } catch ( err ) {
@@ -955,8 +1003,14 @@
955 1003 } );
956 1004 };
957 1005 _init_manage_sites_screen();
958 1006
1007 + updateUsersBulkActionsState();
1008 +
1009 + jQuery(document).on('change', '#mainwp-users-table .check-column INPUT:checkbox', function() {
1010 + updateUsersBulkActionsState();
1011 + });
1012 +
959 1013 } );
960 1014 </script>
961 1015 <?php
962 1016 }
@@ -981,10 +1035,8 @@
981 1035 * @uses \MainWP\Dashboard\MainWP_Utility::ctype_digit()
982 1036 * @uses \MainWP\Dashboard\MainWP_Utility::map_site()
983 1037 */
984 1038 public static function render_table_body( $role = '', $groups = '', $sites = '', $search = '', $clients = '' ) { // phpcs:ignore -- NOSONAR - current complexity required to achieve desired results. Pull request solutions appreciated.
985 - MainWP_Cache::init_cache( 'Users' );
986 -
987 1039 $output = new \stdClass();
988 1040 $output->errors = array();
989 1041 $output->users = 0;
990 1042
@@ -1152,9 +1204,9 @@
1152 1204 'Users',
1153 1205 array(
1154 1206 'count' => $output->users,
1155 1207 'keyword' => $search,
1156 - 'status' => ( isset( $_POST['role'] ) ? sanitize_text_field( wp_unslash( $_POST['role'] ) ) : 'administrator' ), // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1208 + 'status' => $role,
1157 1209 'sites' => '' !== $sites ? $sites : '',
1158 1210 'groups' => '' !== $groups ? $groups : '',
1159 1211 'clients' => ( '' !== $clients ) ? $clients : '',
1160 1212 )
@@ -1213,9 +1265,9 @@
1213 1265 * @return mixed Search results table.
1214 1266 *
1215 1267 * @uses \MainWP\Dashboard\MainWP_Cache::add_body()
1216 1268 */
1217 - protected static function users_search_handler_renderer( $users, $website ) {
1269 + protected static function users_search_handler_renderer( $users, $website ) { // phpcs:ignore -- NOSONAR -complex.
1218 1270 $return = 0;
1219 1271 $is_demo = MainWP_Demo_Handle::is_demo_mode();
1220 1272
1221 1273 foreach ( $users as $user ) {
@@ -1226,22 +1278,70 @@
1226 1278 ?>
1227 1279 <tr>
1228 1280 <td class="check-column"><span class="ui checkbox"><input type="checkbox" name="user[]" value="1"></span></td>
1229 1281 <?php do_action( 'mainwp_users_table_column', $user, $website ); ?>
1230 - <td class="name column-name">
1282 + <td class="name column-name not-selectable">
1231 1283 <?php echo ! empty( $user['display_name'] ) ? esc_html( $user['display_name'] ) : '&nbsp;'; ?>
1232 1284 </td>
1233 - <td class="username column-username"><strong><abbr title="<?php echo esc_attr( $user['login'] ); ?>"><?php echo esc_html( $user['login'] ); ?></abbr></strong></td>
1234 - <td class="email column-email"><a href="mailto:<?php echo esc_attr( $user['email'] ); ?>"><?php echo esc_html( $user['email'] ); ?></a></td>
1235 - <td class="role column-role"><?php echo static::get_role( $user['role'] ); // phpcs:ignore WordPress.Security.EscapeOutput ?></td>
1236 - <td class="posts column-posts"><a href="<?php echo esc_url( admin_url( 'admin.php?page=PostBulkManage&siteid=' . intval( $website->id ) ) . '&userid=' . $user['id'] ); ?>"><?php echo esc_html( $user['post_count'] ); ?></a></td>
1237 - <td class="website column-website"><a href="<?php echo esc_url( $website->url ); ?>" target="_blank"><?php echo esc_html( $website->url ); ?></a></td>
1285 + <td class="username column-username not-selectable"><strong><abbr title="<?php echo esc_attr( $user['login'] ); ?>"><?php echo esc_html( $user['login'] ); ?></abbr></strong></td>
1286 + <td class="email column-email not-selectable"><a href="mailto:<?php echo esc_attr( $user['email'] ); ?>"><?php echo esc_html( $user['email'] ); ?></a></td>
1287 + <td class="last_password_change column-last_password_change not-selectable right aligned" data-order="<?php echo ! empty( $user['last_password_change'] ) ? intval( $user['last_password_change'] ) : 0; ?>">
1288 + <?php
1289 + if ( ! empty( $user['last_password_change'] ) ) {
1290 + $timestamp = date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $user['last_password_change'] );
1291 + echo '<span data-tooltip="' . esc_attr( $timestamp ) . '" data-inverted="" data-position="left center">' . esc_html( MainWP_Utility::time_elapsed_string( $user['last_password_change'] ) ) . '</span>';
1292 + } else {
1293 + echo '<span class="ui grey text" data-tooltip="' . esc_attr__( 'Password change hasn\'t been tracked yet.', 'mainwp' ) . '" data-inverted="" data-position="left center">' . esc_html__( 'Unknown', 'mainwp' ) . '</span>';
1294 + }
1295 + ?>
1296 + </td>
1297 + <?php
1298 + $status = isset( $user['password_status'] ) ? $user['password_status'] : '';
1299 + $status_order = 0;
1300 + if ( 'OVERDUE' === $status ) {
1301 + $status_order = 3;
1302 + } elseif ( 'DUE' === $status ) {
1303 + $status_order = 2;
1304 + } elseif ( 'OK' === $status ) {
1305 + $status_order = 1;
1306 + }
1307 + ?>
1308 + <td class="password_status column-password_status not-selectable center aligned" data-order="<?php echo intval( $status_order ); ?>">
1309 + <?php
1310 + if ( 'OK' === $status && empty( $user['last_password_change'] ) ) {
1311 + echo '<span class="ui grey mini label" data-tooltip="' . esc_attr__( 'Password change hasn\'t been tracked yet.', 'mainwp' ) . '" data-inverted="" data-position="left center">' . esc_html__( 'Unknown', 'mainwp' ) . '</span>';
1312 + } elseif ( 'OK' === $status ) {
1313 + echo '<span class="ui green mini label">' . esc_html__( 'Fresh', 'mainwp' ) . '</span>';
1314 + } elseif ( 'DUE' === $status ) {
1315 + if ( ! empty( $user['password_due_time'] ) ) {
1316 + $due_date = MainWP_Utility::format_timestamp( $user['password_due_time'] );
1317 + echo '<span class="ui yellow mini label" data-tooltip="' . esc_attr__( 'Due: ', 'mainwp' ) . esc_attr( $due_date ) . '" data-inverted="" data-position="left center">' . esc_html__( 'Due Soon', 'mainwp' ) . '</span>';
1318 + } else {
1319 + echo '<span class="ui yellow mini label">' . esc_html__( 'Due Soon', 'mainwp' ) . '</span>';
1320 + }
1321 + } elseif ( 'OVERDUE' === $status ) {
1322 + if ( ! empty( $user['password_due_time'] ) ) {
1323 + $overdue_date = MainWP_Utility::format_timestamp( $user['password_due_time'] );
1324 + echo '<span class="ui red mini label" data-tooltip="' . esc_attr__( 'Was due: ', 'mainwp' ) . esc_attr( $overdue_date ) . '" data-inverted="" data-position="left center">' . esc_html__( 'Overdue', 'mainwp' ) . '</span>';
1325 + } else {
1326 + echo '<span class="ui red mini label">' . esc_html__( 'Overdue', 'mainwp' ) . '</span>';
1327 + }
1328 + } elseif ( 'DISABLED' === $status || empty( $status ) ) {
1329 + echo '<span class="ui grey mini label">' . esc_html__( 'Disabled', 'mainwp' ) . '</span>';
1330 + } else {
1331 + echo '<span class="ui grey text">' . esc_html( $status ) . '</span>';
1332 + }
1333 + ?>
1334 + </td>
1335 + <td class="role column-role not-selectable"><?php echo static::get_role( $user['role'] ); // phpcs:ignore WordPress.Security.EscapeOutput ?></td>
1336 + <td class="posts column-posts not-selectable"><a href="<?php echo esc_url( admin_url( 'admin.php?page=PostBulkManage&siteid=' . intval( $website->id ) ) . '&userid=' . $user['id'] ); ?>"><?php echo esc_html( $user['post_count'] ); ?></a></td>
1337 + <td class="website column-website not-selectable"><a href="<?php echo esc_url( $website->url ); ?>" target="_blank"><?php echo esc_html( $website->url ); ?></a></td>
1238 1338 <td class="right aligned not-selectable">
1239 1339 <input class="userId" type="hidden" name="id" value="<?php echo esc_attr( $user['id'] ); ?>" />
1240 1340 <input class="userName" type="hidden" name="name" value="<?php echo esc_attr( $user['login'] ); ?>" />
1241 1341 <input class="websiteId" type="hidden" name="id" value="<?php echo intval( $website->id ); ?>" />
1242 - <div class="ui left pointing dropdown icon mini basic green button" style="z-index: 999">
1243 - <a href="javascript:void(0)"><i class="ellipsis horizontal icon"></i></a>
1342 + <div class="ui right pointing dropdown" style="z-index: 999">
1343 + <a href="javascript:void(0)"><i class="ellipsis vertical icon"></i></a>
1244 1344 <div class="menu">
1245 1345 <a class="item user_getedit" href="#"><?php esc_html_e( 'Edit', 'mainwp' ); ?></a>
1246 1346 <?php if ( ( 1 !== (int) $user['id'] ) && ( $user['login'] !== $website->adminname ) ) { ?>
1247 1347 <a class="item user_submitdelete" href="#"><?php esc_html_e( 'Delete', 'mainwp' ); ?></a>
@@ -1248,9 +1348,9 @@
1248 1348 <?php } elseif ( ( 1 === (int) $user['id'] ) || ( $user['login'] === $website->adminname ) ) { ?>
1249 1349 <a href="javascript:void(0)" class="item" data-tooltip="This user is used for our secure link, it can not be deleted." data-inverted="" data-position="left center"><?php esc_html_e( 'Delete', 'mainwp' ); ?></a>
1250 1350 <?php } ?>
1251 1351 <?php if ( ! $is_demo ) : ?>
1252 - <a class="item" href="<?php echo 'admin.php?page=SiteOpen&newWindow=yes&websiteid=' . intval( $website->id ); ?>&_opennonce=<?php echo esc_html( wp_create_nonce( 'mainwp-admin-nonce' ) ); ?>" data-tooltip="<?php esc_attr_e( 'Jump to the site WP Admin', 'mainwp' ); ?>" data-position="bottom right" data-inverted="" class="open_newwindow_wpadmin ui green basic icon button" target="_blank"><?php esc_html_e( 'Go to WP Admin', 'mainwp' ); ?></a>
1352 + <a class="item" href="<?php MainWP_Site_Open::get_open_site_admin_link( $website->id, true ); ?>" data-tooltip="<?php esc_attr_e( 'Jump to the site WP Admin', 'mainwp' ); ?>" data-position="bottom right" data-inverted="" class="open_newwindow_wpadmin ui green basic icon button" target="_blank"><?php esc_html_e( 'Go to WP Admin', 'mainwp' ); ?></a>
1253 1353 <?php else : ?>
1254 1354 <a class="item" href="<?php echo esc_url( $website->url ) . 'wp-admin.html'; ?>" data-tooltip="<?php esc_attr_e( 'Jump to the site WP Admin', 'mainwp' ); ?>" data-position="bottom right" data-inverted="" class="open_newwindow_wpadmin ui green basic icon button" target="_blank"><?php esc_html_e( 'Go to WP Admin', 'mainwp' ); ?></a>
1255 1355 <?php endif; ?>
1256 1356 <?php
@@ -1493,9 +1593,9 @@
1493 1593 $pass_complexity = apply_filters( 'mainwp_new_user_password_complexity', '24' );
1494 1594 static::render_header( 'Add' );
1495 1595 // phpcs:disable WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1496 1596 ?>
1497 - <div class="ui alt segment" id="mainwp-add-users">
1597 + <div id="mainwp-add-users">
1498 1598 <?php
1499 1599 /**
1500 1600 * Action: mainwp_before_new_user_form
1501 1601 *
@@ -1505,17 +1605,23 @@
1505 1605 */
1506 1606 do_action( 'mainwp_before_new_user_form' );
1507 1607 ?>
1508 1608 <form action="" method="post" name="createuser" id="createuser" class="add:users: validate">
1509 - <?php wp_nonce_field( 'mainwp-admin-nonce' ); ?>
1510 - <div class="mainwp-main-content">
1511 - <div class="ui hidden divider"></div>
1609 + <?php MainWP_UI::generate_wp_nonce( 'mainwp-admin-nonce' ); ?>
1610 + <div class="mainwp-main-content ui padded segment">
1512 1611 <?php if ( MainWP_Utility::show_mainwp_message( 'notice', 'mainwp-add-user-info-message' ) ) : ?>
1513 1612 <div class="ui info message">
1514 1613 <i class="close icon mainwp-notice-dismiss" notice-id="mainwp-add-user-info-message"></i>
1515 - <?php printf( esc_html__( 'Use the provided form to create a new user on your child site. For additional help, please check this %1$shelp documentation%2$s.', 'mainwp' ), '<a href="https://kb.mainwp.com/docs/create-a-new-user/" target="_blank">', '</a>' ); ?>
1614 + <div class="header"><?php esc_html_e( 'Create users on all selected Child Sites.', 'mainwp' ); ?></div>
1615 + <?php esc_html_e( 'Select one or more sites, tags or clients before submitting.', 'mainwp' ); ?>
1516 1616 </div>
1517 1617 <?php endif; ?>
1618 + <?php if ( isset( $_GET['success'] ) && 1 === (int) $_GET['success'] ) : ?>
1619 + <div class="ui green message">
1620 + <i class="close icon"></i>
1621 + <?php esc_html_e( 'User created successfully. You can now manage this user from the Manage Users page, or create another one here.', 'mainwp' ); ?>
1622 + </div>
1623 + <?php endif; ?>
1518 1624 <div class="ui message" id="mainwp-message-zone" style="display:none;"></div>
1519 1625 <div id="mainwp-add-new-user-form" >
1520 1626 <?php
1521 1627 /**
@@ -1528,19 +1634,19 @@
1528 1634 do_action( 'mainwp_before_new_user_form_fields' );
1529 1635 ?>
1530 1636 <div class="ui form">
1531 1637 <div class="ui grid field">
1532 - <label class="six wide column middle aligned"><?php esc_html_e( 'Username', 'mainwp' ); ?></label>
1638 + <label class="six wide column middle aligned"><?php esc_html_e( 'Username', 'mainwp' ); ?> <span class="ui small red text"><?php esc_html_e( '(Required)', 'mainwp' ); ?></span></label>
1533 1639 <div class="ui six wide column">
1534 - <div class="ui left labeled input">
1640 + <div class="ui input">
1535 1641 <input type="text" id="user_login" name="user_login" value="<?php echo ( isset( $_POST['user_login'] ) ) ? esc_html( sanitize_text_field( wp_unslash( $_POST['user_login'] ) ) ) : ''; ?>">
1536 1642 </div>
1537 1643 </div>
1538 1644 </div>
1539 1645 <div class="ui grid field">
1540 - <label class="six wide column middle aligned"><?php esc_html_e( 'E-mail', 'mainwp' ); ?></label>
1646 + <label class="six wide column middle aligned"><?php esc_html_e( 'E-mail', 'mainwp' ); ?> <span class="ui small red text"><?php esc_html_e( '(Required)', 'mainwp' ); ?></span></label>
1541 1647 <div class="ui six wide column">
1542 - <div class="ui left labeled input">
1648 + <div class="ui input">
1543 1649 <input type="text" id="email" name="email" value="<?php echo ( isset( $_POST['email'] ) ) ? esc_html( sanitize_text_field( wp_unslash( $_POST['email'] ) ) ) : ''; ?>">
1544 1650 </div>
1545 1651 </div>
1546 1652 </div>
@@ -1546,9 +1652,9 @@
1546 1652 </div>
1547 1653 <div class="ui grid field">
1548 1654 <label class="six wide column middle aligned"><?php esc_html_e( 'First Name', 'mainwp' ); ?></label>
1549 1655 <div class="ui six wide column">
1550 - <div class="ui left labeled input">
1656 + <div class="ui input">
1551 1657 <input type="text" id="first_name" name="first_name" value="<?php echo ( isset( $_POST['first_name'] ) ) ? esc_html( sanitize_text_field( wp_unslash( $_POST['first_name'] ) ) ) : ''; ?>">
1552 1658 </div>
1553 1659 </div>
1554 1660 </div>
@@ -1554,9 +1660,9 @@
1554 1660 </div>
1555 1661 <div class="ui grid field">
1556 1662 <label class="six wide column middle aligned"><?php esc_html_e( 'Last Name', 'mainwp' ); ?></label>
1557 1663 <div class="ui six wide column">
1558 - <div class="ui left labeled input">
1664 + <div class="ui input">
1559 1665 <input type="text" id="last_name" name="last_name" value="<?php echo ( isset( $_POST['last_name'] ) ) ? esc_html( sanitize_text_field( wp_unslash( $_POST['last_name'] ) ) ) : ''; ?>">
1560 1666 </div>
1561 1667 </div>
1562 1668 </div>
@@ -1562,20 +1668,20 @@
1562 1668 </div>
1563 1669 <div class="ui grid field">
1564 1670 <label class="six wide column middle aligned"><?php esc_html_e( 'Website', 'mainwp' ); ?></label>
1565 1671 <div class="ui six wide column">
1566 - <div class="ui left labeled input">
1672 + <div class="ui input">
1567 1673 <input type="text" id="url" name="url" value="<?php echo ( isset( $_POST['url'] ) ) ? esc_url_raw( wp_unslash( $_POST['url'] ) ) : ''; ?>">
1568 1674 </div>
1569 1675 </div>
1570 1676 </div>
1571 1677 <div class="ui grid field">
1572 - <label class="six wide column middle aligned"><?php esc_html_e( 'Password', 'mainwp' ); ?></label>
1678 + <label class="six wide column middle aligned"><?php esc_html_e( 'Password', 'mainwp' ); ?> <span class="ui small red text"><?php esc_html_e( '(Required)', 'mainwp' ); ?></span></label>
1573 1679 <div class="ui six wide column">
1574 - <div class="ui left labeled action input">
1575 - <input class="hidden" value=" "/>
1680 + <input class="hidden" value=" "/>
1681 + <div class="ui icon input">
1576 1682 <input type="text" id="password" name="password" autocomplete="off" value="<?php echo esc_attr( wp_generate_password( $pass_complexity ) ); ?>">
1577 - <button class="ui green right button wp-generate-pw"><?php esc_html_e( 'Generate Password', 'mainwp' ); ?></button>
1683 + <i class="sync alternate link icon mainwp-generate-password-button"></i>
1578 1684 </div>
1579 1685 </div>
1580 1686 </div>
1581 1687
@@ -1580,11 +1686,14 @@
1580 1686 </div>
1581 1687
1582 1688 <div class="ui grid field">
1583 1689 <label class="six wide column middle aligned"><?php esc_html_e( 'Send Password?', 'mainwp' ); ?></label>
1584 - <div class="six wide column ui toggle checkbox">
1690 + <div class="one wide column ui toggle checkbox">
1585 1691 <input type="checkbox" name="send_password" id="send_password" <?php echo ( isset( $_POST['send_password'] ) ) ? esc_html( 'checked' ) : ''; ?> >
1586 1692 </div>
1693 + <div class="nine wide column">
1694 + <span class="ui small text"><?php esc_html_e( 'If enabled, the new user will receive their login credentials via email.', 'mainwp' ); ?></span>
1695 + </div>
1587 1696 </div>
1588 1697
1589 1698 <?php
1590 1699 $user_roles = array(
@@ -1681,17 +1790,11 @@
1681 1790 *
1682 1791 * @since 4.1
1683 1792 */
1684 1793 do_action( 'mainwp_add_new_user_before_submit_button' );
1685 -
1686 - $is_demo = MainWP_Demo_Handle::is_demo_mode();
1687 - if ( $is_demo ) {
1688 - MainWP_Demo_Handle::get_instance()->render_demo_disable_button( '<input type="button" class="ui green big button disabled" disabled="disabled" value="' . esc_attr__( 'Add New User', 'mainwp' ) . '"/>' );
1689 - } else {
1690 - ?>
1691 - <input type="button" name="createuser" id="bulk_add_createuser" class="ui big green fluid button" value="<?php esc_attr_e( 'Add New User', 'mainwp' ); ?> "/>
1692 - <?php
1693 - }
1794 + ?>
1795 + <input type="button" name="createuser" id="bulk_add_createuser" class="ui big green fluid button" value="<?php esc_attr_e( 'Add New User', 'mainwp' ); ?> "/>
1796 + <?php
1694 1797 /**
1695 1798 * Action: mainwp_add_new_user_after_submit_button
1696 1799 *
1697 1800 * Fires after the Submit button on the Add New user page.
@@ -1713,8 +1816,14 @@
1713 1816 ?>
1714 1817 </div>
1715 1818 <div style="clear:both"></div>
1716 1819 </form>
1820 + <script type="text/javascript">
1821 + jQuery( document ).ready( function () {
1822 + // Initialize button state based on site selection
1823 + mainwp_init_button_site_selection_dependency( 'bulk_add_createuser' );
1824 + } );
1825 + </script>
1717 1826 <?php
1718 1827 /**
1719 1828 * Action: mainwp_after_new_user_form
1720 1829 *
@@ -1744,9 +1853,9 @@
1744 1853 ?>
1745 1854 <?php static::render_header( 'Import' ); ?>
1746 1855 <div id="MainWP_Bulk_AddUser">
1747 1856 <form action="" method="post" name="createuser" id="createuser" class="add:users: validate" enctype="multipart/form-data">
1748 - <?php wp_nonce_field( 'mainwp-admin-nonce' ); ?>
1857 + <?php MainWP_UI::generate_wp_nonce( 'mainwp-admin-nonce' ); ?>
1749 1858 <?php static::render_import_users(); ?>
1750 1859 </form>
1751 1860 </div>
1752 1861 <?php
@@ -1759,13 +1868,13 @@
1759 1868 * Render Import Users page.
1760 1869 */
1761 1870 public static function render_import_users() {
1762 1871 ?>
1763 - <div class="ui segment" id="mainwp-import-sites">
1872 + <div class="ui padded segment" id="mainwp-import-sites">
1764 1873 <?php if ( MainWP_Utility::show_mainwp_message( 'notice', 'mainwp-import-users-info-message' ) ) : ?>
1765 1874 <div class="ui info message">
1766 1875 <i class="close icon mainwp-notice-dismiss" notice-id="mainwp-import-users-info-message"></i>
1767 - <?php printf( esc_html__( 'Use the form to bulk import users. You can download the sample CSV file to see how to fomat the import file properly. For additional help, please check this %1$shelp documentation%2$s.', 'mainwp' ), '<a href="https://kb.mainwp.com/docs/import-users/" target="_blank">', '</a>' ); ?>
1876 + <?php /* translators: 1: opening anchor tag, 2: closing anchor tag */ printf( esc_html__( 'Use the form to bulk import users. You can download the sample CSV file to see how to fomat the import file properly. For additional help, please check this %1$shelp documentation%2$s.', 'mainwp' ), '<a href="https://docs.mainwp.com/sites/users/manage-users#import-users-via-csv/" target="_blank">', '</a>' ); ?>
1768 1877 </div>
1769 1878 <?php endif; ?>
1770 1879
1771 1880 <div id="mainwp-message-zone" class="ui message" style="display:none"></div>
@@ -1777,17 +1886,16 @@
1777 1886 *
1778 1887 * @since 4.1
1779 1888 */
1780 1889 do_action( 'mainwp_before_import_users' );
1781 - $is_demo = MainWP_Demo_Handle::is_demo_mode();
1782 1890 ?>
1783 1891 <div id="mainwp-message-zone" class="ui message" style="display:none"></div>
1784 1892 <div class="ui form">
1785 1893 <form method="POST" action="" enctype="multipart/form-data" id="mainwp_managesites_bulkadd_form">
1786 - <?php wp_nonce_field( 'mainwp-admin-nonce' ); ?>
1894 + <?php MainWP_UI::generate_wp_nonce( 'mainwp-admin-nonce' ); ?>
1787 1895 <div class="ui grid field">
1788 - <label class="six wide column middle aligned"><?php esc_html_e( 'Upload the CSV file', 'mainwp' ); ?></label>
1789 - <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Click to upload the import file.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1896 + <label class="six wide column middle aligned"><?php esc_html_e( 'Upload the CSV file', 'mainwp' ); ?> (<a href="<?php echo esc_url( MAINWP_PLUGIN_URL . 'assets/csv/sample_users.csv' ); ?>" ><?php esc_html_e( 'Download Sample CSV file', 'mainwp' ); ?></a>)</label>
1897 + <div class="ten wide column" data-tooltip="<?php esc_attr_e( 'Click to upload the import file.', 'mainwp' ); ?>" data-inverted="" data-position="left center">
1790 1898 <div class="ui file input">
1791 1899 <input type="file" name="import_user_file_bulkupload" id="import_user_file_bulkupload" accept="text/comma-separated-values" />
1792 1900 </div>
1793 1901 </div>
@@ -1793,21 +1901,14 @@
1793 1901 </div>
1794 1902 </div>
1795 1903 <div class="ui grid field">
1796 1904 <label class="six wide column middle aligned"><?php esc_html_e( 'CSV file contains a header', 'mainwp' ); ?></label>
1797 - <div class="ui toggle checkbox" data-tooltip="<?php esc_attr_e( 'Enable if the import file contains a header.', 'mainwp' ); ?>" data-inverted="" data-position="top left">
1905 + <div class="ui toggle checkbox" data-tooltip="<?php esc_attr_e( 'Enable if the import file contains a header.', 'mainwp' ); ?>" data-inverted="" data-position="left center">
1798 1906 <input type="checkbox" name="import_user_chk_header_first" checked="checked" id="import_user_chk_header_first" value="1" />
1799 1907 </div>
1800 1908 </div>
1801 1909 <div class="ui divider"></div>
1802 - <?php
1803 - if ( $is_demo ) {
1804 - MainWP_Demo_Handle::get_instance()->render_demo_disable_button( '<input type="button" class="ui big green button disabled" disabled="disabled" value="' . esc_attr__( 'Import Users', 'mainwp' ) . '"/>' );
1805 - } else {
1806 - ?>
1807 - <input type="button" name="createuser" id="bulk_import_createuser" class="ui big green button" value="<?php esc_attr_e( 'Import Users', 'mainwp' ); ?>" />
1808 - <?php } ?>
1809 - <a href="<?php echo esc_url( MAINWP_PLUGIN_URL . 'assets/csv/sample_users.csv' ); ?>" class="ui big green basic right floated button"><?php esc_html_e( 'Download Sample CSV file', 'mainwp' ); ?></a>
1910 + <input type="button" name="createuser" id="bulk_import_createuser" class="ui big green button" value="<?php esc_attr_e( 'Import Users', 'mainwp' ); ?>" />
1810 1911 </form>
1811 1912 </div>
1812 1913 <?php
1813 1914 /**
@@ -1938,15 +2039,14 @@
1938 2039 MainWP_DB::free_result( $websites );
1939 2040 }
1940 2041 }
1941 2042 }
1942 -
2043 + $output = new \stdClass();
1943 2044 if ( ! empty( $dbwebsites ) ) {
1944 2045 $post_data = array(
1945 2046 'new_user' => base64_encode( wp_json_encode( $user_to_add ) ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
1946 2047 'send_password' => ( isset( $_POST['send_password'] ) ? intval( $_POST['send_password'] ) : '' ),
1947 2048 );
1948 - $output = new \stdClass();
1949 2049 $output->ok = array();
1950 2050 $output->errors = array();
1951 2051
1952 2052 /**
@@ -2003,23 +2103,40 @@
2003 2103 public static function render_bulk_add_modal( $dbwebsites, $output ) {
2004 2104 // phpcs:disable WordPress.Security.EscapeOutput
2005 2105 ?>
2006 2106 <div id="mainwp-creating-new-user-modal" class="ui modal">
2007 - <i class="close icon"></i>
2008 - <div class="header"><?php esc_html_e( 'New User', 'mainwp' ); ?></div>
2009 - <div class="content">
2010 - <div class="ui middle aligned divided selection list">
2011 - <?php foreach ( $dbwebsites as $website ) : ?>
2012 - <div class="item ui grid">
2013 - <span class="content"><a href="<?php echo esc_url( admin_url( 'admin.php?page=managesites&dashboard=' . $website->id ) ); ?>"><?php echo esc_html( stripslashes( $website->name ) ); ?></a></span>
2014 - <span class="right floated content"><?php echo isset( $output->ok[ $website->id ] ) && 1 === (int) $output->ok[ $website->id ] ? '<i class="check green icon"></i> ' : '<i class="times red icon"></i> ' . $output->errors[ $website->id ]; ?></span>
2015 - </div>
2016 - <?php endforeach; ?>
2107 + <i class="close mainwp-reload icon"></i>
2108 + <div class="header"><?php esc_html_e( 'New User', 'mainwp' ); ?></div>
2109 + <div class="content">
2110 + <div class="ui middle aligned divided list">
2111 + <?php foreach ( $dbwebsites as $website ) : ?>
2112 + <div class="item ui grid">
2113 + <span class="content"><a href="<?php echo esc_url( admin_url( 'admin.php?page=managesites&dashboard=' . $website->id ) ); ?>"><?php echo esc_html( stripslashes( $website->name ) ); ?></a></span>
2114 + <span class="right floated content"><?php echo isset( $output->ok[ $website->id ] ) && 1 === (int) $output->ok[ $website->id ] ? '<i class="check green icon"></i> ' : '<span data-tooltip="' . esc_attr( $output->errors[ $website->id ] ) . '" data-position="left center" data-inverted=""><i class="times red icon"></i></span>'; ?></span>
2017 2115 </div>
2116 + <?php endforeach; ?>
2018 2117 </div>
2019 - <div class="actions">
2020 - </div>
2118 + <script type="text/javascript">
2119 + setTimeout(() => {
2120 + // Check if all items have green check icons (no red times icons)
2121 + let allSuccess = true;
2122 + jQuery('#mainwp-creating-new-user-modal .ui.list .item').each(function() {
2123 + // Check if this item has a red times icon
2124 + if (jQuery(this).find('.times.red.icon').length > 0) {
2125 + allSuccess = false;
2126 + return false; // Break the loop
2127 + }
2128 + });
2129 +
2130 + // If all items are successful, redirect to success page
2131 + if (allSuccess) {
2132 + jQuery('#createuser')[0].reset();
2133 + location.href = 'admin.php?page=UserBulkAdd&success=1';
2134 + }
2135 + }, 3000);
2136 + </script>
2021 2137 </div>
2138 + </div>
2022 2139 <?php
2023 2140 // phpcs:enable
2024 2141 }
2025 2142
@@ -2033,22 +2150,39 @@
2033 2150 static::render_header( 'Import' );
2034 2151 // phpcs:disable WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2035 2152 $errors = array();
2036 2153 if ( isset( $_FILES['import_user_file_bulkupload']['error'] ) && UPLOAD_ERR_OK === $_FILES['import_user_file_bulkupload']['error'] ) {
2037 - if ( isset( $_FILES['import_user_file_bulkupload']['tmp_name'] ) && is_uploaded_file( $_FILES['import_user_file_bulkupload']['tmp_name'] ) ) {
2038 - $tmp_path = isset( $_FILES['import_user_file_bulkupload']['tmp_name'] ) ? sanitize_text_field( wp_unslash( $_FILES['import_user_file_bulkupload']['tmp_name'] ) ) : '';
2039 - MainWP_System_Utility::get_wp_file_system();
2040 - // phpcs:enable
2041 - /**
2042 - * WordPress files system object.
2043 - *
2044 - * @global object
2045 - */
2046 - global $wp_filesystem;
2154 + $upld_success = false;
2155 + if ( isset( $_FILES['import_user_file_bulkupload']['tmp_name'] ) ) {
2156 + $tmp_path = $_FILES['import_user_file_bulkupload']['tmp_name'];
2157 + if ( is_uploaded_file( $tmp_path ) ) {
2158 + $upld_success = true;
2159 + }
2160 + }
2047 2161
2048 - $content = $wp_filesystem->get_contents( $tmp_path );
2049 - $lines = explode( "\r\n", $content );
2162 + if ( ! $upld_success ) {
2163 + $errors[] = esc_html__( 'File could not be uploaded. Temporary file cold not be created. Please make sure that the tmpfile() PHP function is enabled on your server.', 'mainwp' );
2164 + } else {
2165 + $lines = array();
2050 2166
2167 + $hasWPFileSystem = MainWP_System_Utility::get_wp_file_system();
2168 +
2169 + // phpcs:enable
2170 + /**
2171 + * WordPress files system object.
2172 + *
2173 + * @global object
2174 + */
2175 + global $wp_filesystem;
2176 +
2177 + if ( $hasWPFileSystem && ! empty( $wp_filesystem ) ) {
2178 + $content = $wp_filesystem->get_contents( $tmp_path );
2179 + if ( is_string( $content ) ) {
2180 + $lines = explode( "\r\n", $content );
2181 + }
2182 + }
2183 + $header_line = '';
2184 + $valid_rows_count = 0;
2051 2185 if ( is_array( $lines ) && ! empty( $lines ) ) {
2052 2186 $i = 0;
2053 2187 // phpcs:disable WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2054 2188 if ( ! empty( $_POST['import_user_chk_header_first'] ) ) {
@@ -2066,36 +2200,38 @@
2066 2200 }
2067 2201
2068 2202 $items = str_getcsv( $line, ',' );
2069 2203
2070 - if ( 3 > count( $items ) ) {
2204 + if ( 10 > count( $items ) ) {
2071 2205 continue;
2072 2206 }
2073 2207
2074 2208 $import_data = array(
2075 - 'user_login' => trim( $items[0] ),
2076 - 'email' => trim( $items[1] ),
2077 - 'first_name' => trim( $items[2] ),
2078 - 'last_name' => trim( $items[3] ),
2079 - 'url' => trim( $items[4] ),
2080 - 'pass1' => trim( $items[5] ),
2209 + 'user_login' => sanitize_text_field( wp_unslash( $items[0] ) ),
2210 + 'email' => sanitize_text_field( wp_unslash( $items[1] ) ),
2211 + 'first_name' => sanitize_text_field( wp_unslash( $items[2] ) ),
2212 + 'last_name' => sanitize_text_field( wp_unslash( $items[3] ) ),
2213 + 'url' => sanitize_text_field( wp_unslash( $items[4] ) ),
2214 + 'pass1' => sanitize_text_field( wp_unslash( $items[5] ) ),
2081 2215 'send_password' => intval( $items[6] ),
2082 - 'role' => trim( strtolower( $items[7] ) ),
2083 - 'select_sites' => trim( $items[8] ),
2084 - 'select_groups' => trim( $items[9] ),
2216 + 'role' => sanitize_text_field( wp_unslash( strtolower( $items[7] ) ) ),
2217 + 'select_sites' => sanitize_text_field( wp_unslash( $items[8] ) ),
2218 + 'select_groups' => sanitize_text_field( wp_unslash( $items[9] ) ),
2085 2219 );
2086 2220 $encoded = wp_json_encode( $import_data );
2087 2221 ?>
2088 - <input type="hidden" id="user_import_csv_line_<?php echo intval( $i + 1 ); ?>" original-line="<?php echo esc_html( $line ); ?>" encoded-data="<?php echo esc_html( $encoded ); ?>" />
2089 - <?php
2090 - ++$i;
2222 + <input type="hidden" id="user_import_csv_line_<?php echo intval( $i + 1 ); ?>" original-line="<?php echo esc_attr( sanitize_text_field( $line ) ); ?>" encoded-data="<?php echo esc_html( $encoded ); ?>" />
2223 + <?php
2224 + ++$i;
2225 + ++$valid_rows_count;
2091 2226 }
2092 2227 $header_line = trim( $header_line );
2093 - ?>
2094 - <div class="ui modal" id="mainwp-import-users-modal">
2095 - <i class="close icon"></i>
2096 - <div class="header"><?php esc_html_e( 'Importing new users and add them to your sites.', 'mainwp' ); ?></div>
2097 - <div class="scrolling content">
2228 + if ( $valid_rows_count ) {
2229 + ?>
2230 + <div class="ui modal" id="mainwp-import-users-modal">
2231 + <i class="close icon"></i>
2232 + <div class="header"><?php esc_html_e( 'Importing new users and add them to your sites.', 'mainwp' ); ?></div>
2233 + <div class="scrolling content">
2098 2234 <?php
2099 2235 /**
2100 2236 * Action: mainwp_import_users_modal_top
2101 2237 *
@@ -2104,53 +2240,53 @@
2104 2240 * @since 4.1
2105 2241 */
2106 2242 do_action( 'mainwp_import_users_modal_top' );
2107 2243 ?>
2108 - <div id="MainWPBulkUploadUserLoading" style="display: none;"><i class="ui active inline loader tiny"></i> <?php esc_html_e( 'Importing Users', 'mainwp' ); ?></div>
2109 - <input type="hidden" id="import_user_do_import" value="1"/>
2110 - <input type="hidden" id="import_user_total_import" value="<?php echo esc_attr( $i ); ?>"/>
2111 - <p>
2112 - <div class="import_user_import_listing" id="import_user_import_logging">
2113 - <pre class="log"><?php echo esc_html( $header_line ) . "\n"; ?></pre>
2244 + <div id="MainWPBulkUploadUserLoading" style="display: none;"><i class="ui active inline loader tiny"></i> <?php esc_html_e( 'Importing Users', 'mainwp' ); ?></div>
2245 + <input type="hidden" id="import_user_do_import" value="1"/>
2246 + <input type="hidden" id="import_user_total_import" value="<?php echo esc_attr( $i ); ?>"/>
2247 + <p>
2248 + <div class="import_user_import_listing" id="import_user_import_logging">
2249 + <pre class="log"><?php echo esc_html( $header_line ) . "\n"; ?></pre>
2250 + </div>
2251 + </p>
2252 + <div id="import_user_import_failed_rows" style="display: none;">
2253 + <span><?php echo esc_html( $header_line ); ?></span>
2114 2254 </div>
2115 - </p>
2116 - <div id="import_user_import_failed_rows" style="display: none;">
2117 - <span><?php echo esc_html( $header_line ); ?></span>
2255 + <?php
2256 + /**
2257 + * Action: mainwp_import_users_modal_bottom
2258 + *
2259 + * Fires on the bottom of the Import Users modal.
2260 + *
2261 + * @since 4.1
2262 + */
2263 + do_action( 'mainwp_import_users_modal_bottom' );
2264 + ?>
2118 2265 </div>
2119 - <?php
2120 - /**
2121 - * Action: mainwp_import_users_modal_bottom
2122 - *
2123 - * Fires on the bottom of the Import Users modal.
2124 - *
2125 - * @since 4.1
2126 - */
2127 - do_action( 'mainwp_import_users_modal_bottom' );
2128 - ?>
2266 + <div class="actions">
2267 + <input type="button" name="import_user_btn_import" id="import_user_btn_import" class="ui basic button" value="<?php esc_attr_e( 'Pause', 'mainwp' ); ?>"/>
2268 + <input type="button" name="import_user_btn_save_csv" id="import_user_btn_save_csv" style="display:none;" class="ui basic green button" value="<?php esc_attr_e( 'Save failed', 'mainwp' ); ?>"/>
2269 + </div>
2129 2270 </div>
2130 - <div class="actions">
2131 - <input type="button" name="import_user_btn_import" id="import_user_btn_import" class="ui basic button" value="<?php esc_attr_e( 'Pause', 'mainwp' ); ?>"/>
2132 - <input type="button" name="import_user_btn_save_csv" id="import_user_btn_save_csv" style="display:none;" class="ui basic green button" value="<?php esc_attr_e( 'Save failed', 'mainwp' ); ?>"/>
2133 - </div>
2134 - </div>
2135 - <script type="text/javascript">
2136 - jQuery( document ).ready( function () {
2137 - jQuery( "#mainwp-import-users-modal" ).modal( {
2138 - closable: false,
2139 - onHide: function() {
2140 - location.href = 'admin.php?page=BulkImportUsers';
2141 - }
2142 - } ).modal( 'show' );
2143 - } );
2144 - </script>
2271 + <script type="text/javascript">
2272 + jQuery( document ).ready( function () {
2273 + jQuery( "#mainwp-import-users-modal" ).modal( {
2274 + closable: false,
2275 + onHide: function() {
2276 + mainwp_forceReload('admin.php?page=BulkImportUsers');
2277 + }
2278 + } ).modal( 'show' );
2279 + } );
2280 + </script>
2145 2281
2146 - <?php
2147 -
2282 + <?php
2283 + } else {
2284 + $errors[] = esc_html__( 'No valid data rows found. Please make sure the import file is formatted correctly.', 'mainwp' );
2285 + }
2148 2286 } else {
2149 2287 $errors[] = esc_html__( 'Invalid data. Please make sure that the Import file has been formated properly.', 'mainwp' );
2150 2288 }
2151 - } else {
2152 - $errors[] = esc_html__( 'File could not be uploaded. Temporary file cold not be created. Please make sure that the tmpfile() PHP function is enabled on your server.', 'mainwp' );
2153 2289 }
2154 2290 } else {
2155 2291 $errors[] = esc_html__( 'File could not be uploaded. Please try again. If process keeps failing, please review MainWP Knowledgebase, and if you still have issues, please let us know in the MainWP Community.', 'mainwp' );
2156 2292 }
@@ -2340,20 +2476,22 @@
2340 2476 die( wp_json_encode( $ret ) );
2341 2477 }
2342 2478
2343 2479 /**
2344 - * Hooks the section help content to the Help Sidebar element.
2480 + * Method mainwp_help_content()
2481 + *
2482 + * Creates the MainWP Help Documentation List for the help component in the sidebar.
2345 2483 */
2346 2484 public static function mainwp_help_content() {
2347 2485 if ( isset( $_GET['page'] ) && ( 'UserBulkManage' === $_GET['page'] || 'UserBulkAdd' === $_GET['page'] || 'UpdateAdminPasswords' === $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2348 2486 ?>
2349 2487 <p><?php esc_html_e( 'If you need help with managing users, please review following help documents', 'mainwp' ); ?></p>
2350 - <div class="ui relaxed bulleted list">
2351 - <div class="item"><a href="https://kb.mainwp.com/docs/manage-users/" target="_blank">Manage Users</a> <i class="external alternate icon"></i></div>
2352 - <div class="item"><a href="https://kb.mainwp.com/docs/create-a-new-user/" target="_blank">Create a New User</a> <i class="external alternate icon"></i></div>
2353 - <div class="item"><a href="https://kb.mainwp.com/docs/edit-an-existing-user/" target="_blank">Edit an Existing User</a> <i class="external alternate icon"></i></div>
2354 - <div class="item"><a href="https://kb.mainwp.com/docs/bulk-update-administrator-passwords/" target="_blank">Bulk Update Administrator Passwords</a> <i class="external alternate icon"></i></div>
2355 - <div class="item"><a href="https://kb.mainwp.com/docs/delete-users/" target="_blank">Delete User(s)</a> <i class="external alternate icon"></i></div>
2488 + <div class="ui list">
2489 + <div class="item"><i class="external alternate icon"></i> <a href="https://docs.mainwp.com/sites/users/manage-users" target="_blank">Manage Users</a></div>
2490 + <div class="item"><i class="external alternate icon"></i> <a href="https://docs.mainwp.com/sites/users/manage-users#create-a-new-user" target="_blank">Create a New User</a></div>
2491 + <div class="item"><i class="external alternate icon"></i> <a href="https://docs.mainwp.com/sites/users/manage-users#edit-existing-users" target="_blank">Edit an Existing User</a></div>
2492 + <div class="item"><i class="external alternate icon"></i> <a href="https://docs.mainwp.com/sites/users/manage-users#bulk-update-admin-passwords" target="_blank">Bulk Update Administrator Passwords</a></div>
2493 + <div class="item"><i class="external alternate icon"></i> <a href="https://docs.mainwp.com/sites/users/manage-users#delete-users" target="_blank">Delete User(s)</a></div>
2356 2494 <?php
2357 2495 /**
2358 2496 * Action: mainwp_users_help_item
2359 2497 *