From 2c0478757fd76a2cb1156155d7de5eee3801c381 Mon Sep 17 00:00:00 2001 From: Mykyta Synelnikov Date: Wed, 18 Sep 2024 14:03:18 +0300 Subject: [PATCH] - added bulk actions to WordPress native dropdown; --- includes/admin/class-admin.php | 13 + includes/admin/class-users-columns.php | 499 ++++++++++++++++++++++ includes/admin/core/class-admin-users.php | 30 +- 3 files changed, 515 insertions(+), 27 deletions(-) create mode 100644 includes/admin/class-users-columns.php diff --git a/includes/admin/class-admin.php b/includes/admin/class-admin.php index 0afb0a04..5a3717cd 100644 --- a/includes/admin/class-admin.php +++ b/includes/admin/class-admin.php @@ -83,6 +83,7 @@ if ( ! class_exists( 'um\admin\Admin' ) ) { $this->notices(); $this->secure(); $this->site_health(); + $this->users_columns(); } public function init_variables() { @@ -2130,5 +2131,17 @@ if ( ! class_exists( 'um\admin\Admin' ) ) { } return UM()->classes['um\admin\site_health']; } + + /** + * @since 2.8.7 + * + * @return Users_Columns + */ + public function users_columns() { + if ( empty( UM()->classes['um\admin\users_columns'] ) ) { + UM()->classes['um\admin\users_columns'] = new Users_Columns(); + } + return UM()->classes['um\admin\users_columns']; + } } } diff --git a/includes/admin/class-users-columns.php b/includes/admin/class-users-columns.php new file mode 100644 index 00000000..6273de0a --- /dev/null +++ b/includes/admin/class-users-columns.php @@ -0,0 +1,499 @@ + __( 'Approve Membership', 'ultimate-member' ), + 'um_reject_membership' => __( 'Reject Membership', 'ultimate-member' ), + 'um_put_as_pending' => __( 'Put as Pending Review', 'ultimate-member' ), + 'um_resend_activation' => __( 'Resend Activation E-mail', 'ultimate-member' ), + 'um_deactivate' => __( 'Deactivate', 'ultimate-member' ), + 'um_reactivate' => __( 'Reactivate', 'ultimate-member' ), + ); + /** + * Filters wp-admin > Users List Table bulk actions. + * + * @since 1.3.x + * @since 2.8.7 changed format from `$action_slug => array( 'label' => $action_title )` to `$action_slug => $action_title` + * @hook um_admin_bulk_user_actions_hook + * + * @param {array} $um_actions Users admin actions. + * + * @return {array} Users admin actions. + * + * @example Add `$action_title` to Users List Table bulk actions. + * function um_custom_admin_bulk_user_actions_hook( $um_actions ) { + * $um_actions[ $action_slug ] = $action_title; + * return $um_actions; + * } + * add_filter( 'um_admin_bulk_user_actions_hook', 'um_custom_admin_bulk_user_actions_hook' ); + */ + return apply_filters( 'um_admin_bulk_user_actions_hook', $um_actions ); + } + + /** + * @param array $actions + * + * @return array + */ + public function add_bulk_actions( $actions ) { + $rolename = UM()->roles()->get_priority_user_role( get_current_user_id() ); + $role = get_role( $rolename ); + + if ( null === $role ) { + return $actions; + } + + // Add Ultimate Member bulk actions only when the current user has 'edit_users' capability. + if ( ! current_user_can( 'edit_users' ) && ! $role->has_cap( 'edit_users' ) ) { + return $actions; + } + + $actions[ esc_html__( 'Ultimate Member', 'ultimate-member' ) ] = $this->get_user_bulk_actions(); + return $actions; + } + + /** + * Add query args to list of query variable names to remove. + * + * @param array $removable_query_args An array of query variable names to remove from a URL + * + * @return array + */ + public function add_removable_query_args( $removable_query_args ) { + $removable_query_args[] = '_um_wpnonce'; + $removable_query_args[] = 'approved_count'; + $removable_query_args[] = 'rejected_count'; + $removable_query_args[] = 'reactivated_count'; + $removable_query_args[] = 'deactivated_count'; + $removable_query_args[] = 'pending_count'; + $removable_query_args[] = 'resend_activation_count'; + return $removable_query_args; + } + + /** + * Get the user statuses list. + * + * @return array + */ + public function get_user_statuses() { + $statuses = apply_filters( + 'um_admin_get_user_statuses', + array( + 'approved' => __( 'Approved', 'ultimate-member' ), + 'awaiting_admin_review' => __( 'Pending review', 'ultimate-member' ), + 'awaiting_email_confirmation' => __( 'Waiting e-mail confirmation', 'ultimate-member' ), + 'inactive' => __( 'Inactive', 'ultimate-member' ), + 'rejected' => __( 'Rejected', 'ultimate-member' ), + ) + ); + + return $statuses; + } + + /** + * Function for handling custom bulk actions on the Users List Table + * + * @param string $sendback URL for redirect after handling bulk action + * @param string $current_action Bulk action key + * @param array $userids User IDs + * + * @return string URL for redirect after handling bulk action + */ + public function handle_bulk_actions( $sendback, $current_action, $userids ) { + $um_actions = $this->get_user_bulk_actions(); + + if ( ! array_key_exists( $current_action, $um_actions ) ) { + return $sendback; + } + + // need to handle there additional nonce field because WordPress native _wpnonce field isn't visible on the users.php screen then custom actions + check_admin_referer( 'bulk-users', '_um_wpnonce' ); + + $rolename = UM()->roles()->get_priority_user_role( get_current_user_id() ); + $role = get_role( $rolename ); + + // Make Ultimate Member bulk actions only when the current user has 'edit_users' capability. + if ( ! current_user_can( 'edit_users' ) && ! $role->has_cap( 'edit_users' ) ) { + wp_die( esc_html__( 'You do not have enough permissions to do that.', 'ultimate-member' ) ); + } + + $users = array_map( 'absint', $userids ); + + switch ( $current_action ) { + case 'um_approve_membership': + $approved_count = 0; + foreach ( $users as $user_id ) { + $res = UM()->common()->user()->approve( $user_id ); + if ( $res ) { + $approved_count++; + } + } + + $sendback = add_query_arg( + array( + 'approved_count' => $approved_count, + 'update' => 'um_approved', + ), + $this->set_redirect_uri( $sendback ) + ); + break; + case 'um_reactivate': + $reactivated_count = 0; + foreach ( $users as $user_id ) { + $res = UM()->common()->user()->reactivate( $user_id ); + if ( $res ) { + $reactivated_count++; + } + } + + $sendback = add_query_arg( + array( + 'reactivated_count' => $reactivated_count, + 'update' => 'um_reactivated', + ), + $this->set_redirect_uri( $sendback ) + ); + break; + case 'um_reject_membership': + $rejected_count = 0; + foreach ( $users as $user_id ) { + $res = UM()->common()->user()->reject( $user_id ); + if ( $res ) { + $rejected_count++; + } + } + + $sendback = add_query_arg( + array( + 'rejected_count' => $rejected_count, + 'update' => 'um_rejected', + ), + $this->set_redirect_uri( $sendback ) + ); + break; + case 'um_deactivate': + $deactivated_count = 0; + foreach ( $users as $user_id ) { + $res = UM()->common()->user()->deactivate( $user_id ); + if ( $res ) { + $deactivated_count++; + } + } + + $sendback = add_query_arg( + array( + 'deactivated_count' => $deactivated_count, + 'update' => 'um_deactivate', + ), + $this->set_redirect_uri( $sendback ) + ); + break; + case 'um_put_as_pending': + $pending_count = 0; + foreach ( $users as $user_id ) { + $res = UM()->common()->user()->set_as_pending( $user_id ); + if ( $res ) { + $pending_count++; + } + } + + $sendback = add_query_arg( + array( + 'pending_count' => $pending_count, + 'update' => 'um_pending', + ), + $this->set_redirect_uri( $sendback ) + ); + break; + case 'um_resend_activation': + $email_pending_count = 0; + foreach ( $users as $user_id ) { + $res = UM()->common()->user()->resend_activation( $user_id ); + if ( $res ) { + $email_pending_count++; + } + } + + $sendback = add_query_arg( + array( + 'resend_activation_count' => $email_pending_count, + 'update' => 'um_resend_activation', + ), + $this->set_redirect_uri( $sendback ) + ); + break; + default: + // hook for the handling custom UM actions added via 'um_admin_bulk_user_actions_hook' hook + $sendback = apply_filters( "um_handle_bulk_actions-users-{$current_action}", $sendback, $userids ); + break; + } + + return $sendback; + } + + /** + * Adds HTML with the filter by the Ultimate Member status. + * + * @param string $which Where the callback's hook fired. + */ + public function filter_by_status_action( $which ) { + $id = 'bottom' === $which ? 'um_status2' : 'um_status'; + $button_id = 'bottom' === $which ? 'um_filter_action2' : 'um_filter_action'; + + if ( 'top' === $which ) { + // need to add there additional nonce field because WordPress native _wpnonce field isn't visible on the users.php screen then custom actions + wp_nonce_field('bulk-users', '_um_wpnonce', false ); + } + + // Set default statuses if not already done. + UM()->install()->set_default_user_status(); + + $statuses = $this->get_user_statuses(); + ?> +
+ + + +
+ ID; + + // Link to Ultimate Member Profile. + $actions['frontend_profile'] = '' . esc_html__( 'View profile', 'ultimate-member' ) . ''; + + // The link for open popup with the registration data submitted through Ultimate Member Registration form. + $submitted = get_user_meta( $user_id, 'submitted', true ); + if ( ! empty( $submitted ) ) { + $actions['view_info'] = '' . esc_html__( 'Info', 'ultimate-member' ) . ''; + } + + // Remove row actions for now Administrator role and who cannot view profiles of row's user. + // @todo make the um_can_view_profile() function review. Maybe rewrite it. + if ( ! current_user_can( 'manage_options' ) && ! um_can_view_profile( $user_id ) ) { + unset( $actions['frontend_profile'], $actions['view_info'], $actions['view'] ); + } + + /** + * Filters the rows actions for the user in wp-admin > Users List Table screen. + * + * Note: Row actions format is 'key' => 'action_link_html' + * + * @since 2.8.7 + * @hook um_admin_user_row_actions + * + * @param {array} $actions User's row actions. + * @param {int} $user_id Row's user ID. + * + * @return {array} User's row actions. + */ + return apply_filters( 'um_admin_user_row_actions', $actions, $user_id ); + } + + /** + * Hide users who are hidden by role access for not Administrator user + * + * @param array $args + * @return array + */ + public function hide_by_caps( $args ) { + if ( current_user_can( 'administrator' ) ) { + return $args; + } + + // @todo avoid um_user() function using + $can_view_roles = um_user( 'can_view_roles' ); + if ( um_user( 'can_view_all' ) && ! empty( $can_view_roles ) ) { + $args['role__in'] = $can_view_roles; + } + + return $args; + } + + /** + * Change default sorting at WP Users list table + * + * @param \WP_User_Query $query + */ + public function sort_by_newest( $query ) { + global $pagenow; + + if ( is_admin() && 'users.php' === $pagenow ) { + if ( ! isset( $_REQUEST['orderby'] ) ) { + $query->query_vars['order'] = 'desc'; + $query->query_orderby = ' ORDER BY user_registered ' . ( 'desc' === $query->query_vars['order'] ? 'desc ' : 'asc ' ); //set sort order + } + } + } + + /** + * Filter WP users by UM Status + * + * @param \WP_User_Query $query + */ + public function filter_users_by_status( $query ) { + global $wpdb, $pagenow; + + if ( is_admin() && 'users.php' === $pagenow && ! empty( $_REQUEST['um_status'] ) ) { + $status = sanitize_key( $_REQUEST['um_status'] ); + + $skip_status_filter = apply_filters( 'um_skip_filter_users_by_status', false, $status ); + if ( ! $skip_status_filter ) { + $query->query_where = str_replace( + 'WHERE 1=1', + "WHERE 1=1 AND {$wpdb->users}.ID IN ( + SELECT {$wpdb->usermeta}.user_id FROM $wpdb->usermeta + WHERE {$wpdb->usermeta}.meta_key = 'account_status' + AND {$wpdb->usermeta}.meta_value = '{$status}')", + $query->query_where + ); + } + } + } + + /** + * Does an action to user asap + * + * @param string $action + */ + public function user_action_hook( $action ) { + switch ( $action ) { + default: + /** + * UM hook + * + * @type action + * @title um_admin_custom_hook_{$action} + * @description Integration hook on user action + * @input_vars + * [{"var":"$user_id","type":"int","desc":"User ID"}] + * @change_log + * ["Since: 2.0"] + * @usage add_action( 'um_admin_custom_hook_{$action}', 'function_name', 10, 1 ); + * @example + * + */ + do_action( "um_admin_custom_hook_{$action}", UM()->user()->id ); + break; + +// case 'um_put_as_pending': +// UM()->user()->pending(); +// break; + +// case 'um_approve_membership': +// case 'um_reenable': +// +// add_filter( 'um_template_tags_patterns_hook', array( UM()->password(), 'add_placeholder' ), 10, 1 ); +// add_filter( 'um_template_tags_replaces_hook', array( UM()->password(), 'add_replace_placeholder' ), 10, 1 ); +// +// UM()->user()->approve(); +// break; + +// case 'um_reject_membership': +// UM()->user()->reject(); +// break; + +// case 'um_resend_activation': +// +// add_filter( 'um_template_tags_patterns_hook', array( UM()->user(), 'add_activation_placeholder' ), 10, 1 ); +// add_filter( 'um_template_tags_replaces_hook', array( UM()->user(), 'add_activation_replace_placeholder' ), 10, 1 ); +// +// UM()->user()->email_pending(); +// break; + +// case 'um_deactivate': +// UM()->user()->deactivate(); +// break; + + case 'um_delete': + if ( is_admin() ) { + wp_die( __( 'This action is not allowed in backend.', 'ultimate-member' ) ); + } + UM()->user()->delete(); + break; + } + } + + /** + * Sets redirect URI after bulk action + * + * @param string $uri + * @return string + */ + private function set_redirect_uri( $uri ) { + if ( ! empty( $_REQUEST['s'] ) ) { + $uri = add_query_arg( 's', sanitize_text_field( $_REQUEST['s'] ), $uri ); + } + + if ( ! empty( $_REQUEST['um_status'] ) ) { + $uri = add_query_arg( 'um_status', sanitize_key( $_REQUEST['um_status'] ), $uri ); + } + + return $uri; + } + } +} diff --git a/includes/admin/core/class-admin-users.php b/includes/admin/core/class-admin-users.php index 6db6d889..85936125 100644 --- a/includes/admin/core/class-admin-users.php +++ b/includes/admin/core/class-admin-users.php @@ -22,8 +22,6 @@ if ( ! class_exists( 'um\admin\core\Admin_Users' ) ) { * Admin_Users constructor. */ public function __construct() { - add_action( 'restrict_manage_users', array( &$this, 'restrict_manage_users' ) ); - add_filter( 'user_row_actions', array( &$this, 'user_row_actions' ), 10, 2 ); add_filter( 'user_has_cap', array( &$this, 'map_caps_by_role' ), 10, 4 ); @@ -181,7 +179,7 @@ if ( ! class_exists( 'um\admin\core\Admin_Users' ) ) { /** * Add UM Bulk actions to Users List Table - * + * @deprecated 2.8.7 */ public function restrict_manage_users() { ?> @@ -207,33 +205,11 @@ if ( ! class_exists( 'um\admin\core\Admin_Users' ) ) { /** * Get UM bulk actions HTML * + * @deprecated 2.8.7 + * * @return string */ public function get_bulk_admin_actions() { - - /** - * UM hook - * - * @type filter - * @title um_admin_bulk_user_actions_hook - * @description Admin Users List Table bulk actions - * @input_vars - * [{"var":"$actions","type":"array","desc":"User List Table bulk actions"}] - * @change_log - * ["Since: 2.0"] - * @usage add_filter( 'um_admin_bulk_user_actions_hook', 'function_name', 10, 1 ); - * @example - * 'My Custom Bulk Action' - * ); - * return $actions; - * } - * ?> - */ $actions = apply_filters( 'um_admin_bulk_user_actions_hook', array( 'um_approve_membership' => array( 'label' => __( 'Approve Membership', 'ultimate-member' )