1 | <?php |
||
2 | /** |
||
3 | * User account management - approval/block. |
||
4 | * |
||
5 | * @package user-approval |
||
6 | */ |
||
7 | |||
8 | namespace User_Approval\Management; |
||
9 | |||
10 | use function User_Approval\filter_input; |
||
11 | use function User_Approval\get_default_user_role; |
||
12 | use function User_Approval\get_pre_approved_user_roles; |
||
13 | use function User_Approval\get_user_status; |
||
14 | |||
15 | use const User_Approval\STATUS_APPROVED; |
||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
16 | use const User_Approval\STATUS_APPROVED_NONCE; |
||
0 ignored issues
–
show
|
|||
17 | use const User_Approval\STATUS_BLOCKED; |
||
0 ignored issues
–
show
|
|||
18 | use const User_Approval\STATUS_BLOCKED_NONCE; |
||
0 ignored issues
–
show
|
|||
19 | use const User_Approval\STATUS_META_KEY; |
||
0 ignored issues
–
show
|
|||
20 | use const User_Approval\STATUS_PENDING; |
||
0 ignored issues
–
show
|
|||
21 | use const User_Approval\STATUS_PRE_APPROVED; |
||
0 ignored issues
–
show
|
|||
22 | |||
23 | use WP_User; |
||
24 | 1 | ||
25 | /** |
||
26 | 1 | * Hook up all the filters and actions. |
|
27 | 1 | */ |
|
28 | function bootstrap() { |
||
29 | 1 | add_action( 'manage_users_columns', __NAMESPACE__ . '\\user_verification_column', 1 ); |
|
30 | |||
31 | 1 | add_filter( 'manage_users_custom_column', __NAMESPACE__ . '\\add_user_verification_status', 10, 3 ); |
|
32 | add_filter( 'user_row_actions', __NAMESPACE__ . '\\add_user_verification_action', 10, 2 ); |
||
33 | 1 | ||
34 | 1 | add_action( 'admin_action_aj_user_status', __NAMESPACE__ . '\\aj_user_status_update' ); |
|
35 | |||
36 | 1 | add_filter( 'wp_new_user_notification_email', __NAMESPACE__ . '\\update_approved_new_user_email', 50, 3 ); |
|
37 | |||
38 | add_filter( 'manage_users_extra_tablenav', __NAMESPACE__ . '\\add_user_status_filters', 10 ); |
||
39 | add_filter( 'users_list_table_query_args', __NAMESPACE__ . '\\filter_user_list_by_status', 100 ); |
||
40 | |||
41 | } |
||
42 | |||
43 | /** |
||
44 | * Add new column for users list page for user status. |
||
45 | * |
||
46 | * @param array $columns Columns list of user data. |
||
47 | 1 | * |
|
48 | * @return array |
||
49 | 1 | */ |
|
50 | function user_verification_column( $columns ) { |
||
51 | |||
52 | $columns[ STATUS_META_KEY ] = esc_html__( 'Status', 'user-approval' ); |
||
53 | |||
54 | return $columns; |
||
55 | } |
||
56 | |||
57 | /** |
||
58 | * Add a user status to status column of respective user row. |
||
59 | * |
||
60 | * @param string $val Default value of column. |
||
61 | * @param string $column_name Column id/name. |
||
62 | * @param int $user_id User id of respective user row. |
||
63 | 2 | * |
|
64 | * @return array|string |
||
65 | */ |
||
66 | function add_user_verification_status( $val, $column_name, $user_id ) { |
||
67 | 2 | ||
68 | 2 | if ( STATUS_META_KEY !== $column_name ) { |
|
69 | 2 | return $val; |
|
70 | } |
||
71 | 2 | ||
72 | $user_status = get_user_meta( $user_id, STATUS_META_KEY, true ) ?: STATUS_PENDING; |
||
73 | $user = get_userdata( $user_id ); |
||
74 | $user_status = ( ! empty( $user ) && in_array( get_default_user_role(), $user->roles, true ) ) ? $user_status : STATUS_PRE_APPROVED; |
||
75 | |||
76 | return get_user_status( $user_status ); |
||
77 | } |
||
78 | |||
79 | /** |
||
80 | * Add action links to respective user row to approve/block the user. |
||
81 | * |
||
82 | * @param array $actions All action link lists. |
||
83 | * @param WP_User $user WP_User object for respective user row. |
||
84 | 1 | * |
|
85 | 1 | * @return array |
|
86 | */ |
||
87 | function add_user_verification_action( $actions, $user ) { |
||
88 | 1 | ||
89 | if ( ! in_array( get_default_user_role(), $user->roles, true ) ) { |
||
90 | return $actions; |
||
91 | 1 | } |
|
92 | 1 | ||
93 | 1 | $user_current_status = get_user_meta( $user->ID, STATUS_META_KEY, true ); |
|
94 | |||
95 | $query_args = [ |
||
96 | 'user' => $user->ID, |
||
97 | 1 | 'action' => STATUS_META_KEY, |
|
98 | 1 | 'status' => STATUS_APPROVED, |
|
99 | 1 | ]; |
|
100 | |||
101 | 1 | // Approve action link. |
|
102 | $approve_link = add_query_arg( $query_args ); |
||
103 | $approve_link = remove_query_arg( [ 'new_role' ], $approve_link ); |
||
104 | 1 | $approve_link = wp_nonce_url( $approve_link, STATUS_APPROVED_NONCE ); |
|
105 | 1 | ||
106 | 1 | $query_args['status'] = STATUS_BLOCKED; |
|
107 | |||
108 | 1 | // Block action link. |
|
109 | 1 | $block_link = add_query_arg( $query_args ); |
|
110 | 1 | $block_link = remove_query_arg( [ 'new_role' ], $block_link ); |
|
111 | 1 | $block_link = wp_nonce_url( $block_link, STATUS_BLOCKED_NONCE ); |
|
112 | |||
113 | $approve_action = sprintf( |
||
114 | 1 | '<a href="%s">%s</a>', |
|
115 | 1 | esc_url( $approve_link ), |
|
116 | 1 | get_user_status( STATUS_APPROVED ) |
|
117 | 1 | ); |
|
118 | |||
119 | $block_action = sprintf( |
||
120 | 1 | '<a href="%s">%s</a>', |
|
121 | 1 | esc_url( $block_link ), |
|
122 | 1 | get_user_status( STATUS_BLOCKED ) |
|
123 | ); |
||
124 | |||
125 | 1 | $actions = array_merge( $actions, [ |
|
126 | 1 | 'approved' => $approve_action, |
|
127 | 'blocked' => $block_action, |
||
128 | ] ); |
||
129 | 1 | ||
130 | if ( isset( $actions[ $user_current_status ] ) ) { |
||
131 | unset( $actions[ $user_current_status ] ); |
||
132 | } |
||
133 | |||
134 | return $actions; |
||
135 | } |
||
136 | 1 | ||
137 | 1 | /** |
|
138 | * Update user status on post request. |
||
139 | 1 | */ |
|
140 | 1 | function aj_user_status_update() { |
|
141 | $user_id = filter_input( INPUT_GET, 'user', FILTER_VALIDATE_INT ); |
||
142 | $status = filter_input( INPUT_GET, 'status', FILTER_SANITIZE_STRING ); |
||
143 | 1 | ||
144 | 1 | $user = get_userdata( $user_id ); |
|
145 | 1 | $user_status = get_user_meta( $user_id, STATUS_META_KEY, true ); |
|
146 | 1 | ||
147 | if ( |
||
148 | ! $user instanceof WP_User |
||
149 | || ! in_array( get_default_user_role(), $user->roles, true ) |
||
150 | || ( $status === $user_status ) // Avoid any refresh page. |
||
151 | 1 | || ! current_user_can( 'list_users' ) |
|
152 | ) { |
||
153 | 1 | return; |
|
154 | 1 | } |
|
155 | 1 | ||
156 | 1 | $current_user_id = get_current_user_id(); |
|
157 | 1 | ||
158 | 1 | if ( STATUS_APPROVED === $status && check_admin_referer( STATUS_APPROVED_NONCE ) ) { |
|
159 | 1 | update_user_meta( $user_id, STATUS_META_KEY, STATUS_APPROVED ); |
|
160 | 1 | wp_send_new_user_notifications( $user_id, 'user' ); |
|
161 | update_user_meta( $user_id, 'aj_user_verified_by', $current_user_id ); |
||
162 | 1 | } elseif ( STATUS_BLOCKED === $status && check_admin_referer( STATUS_BLOCKED_NONCE ) ) { |
|
163 | update_user_meta( $user_id, STATUS_META_KEY, STATUS_BLOCKED ); |
||
164 | send_user_blocked_email( $user ); |
||
165 | update_user_meta( $user_id, 'aj_user_verified_by', $current_user_id ); |
||
166 | } |
||
167 | } |
||
168 | |||
169 | /** |
||
170 | * Send a notification/email to approved user. |
||
171 | * |
||
172 | * @param array $email_data { |
||
173 | * Used to build wp_mail(). |
||
174 | * |
||
175 | * @type string $to The intended recipient - New user email address. |
||
176 | * @type string $subject The subject of the email. |
||
177 | * @type string $message The body of the email. |
||
178 | * @type string $headers The headers of the email. |
||
179 | * } |
||
180 | * @param WP_User $user User object for new user. |
||
181 | * @param string $blogname The site title. |
||
182 | 1 | * |
|
183 | * @return array Updated email data for wp_mail. |
||
184 | */ |
||
185 | function update_approved_new_user_email( $email_data, $user, $blogname ) { |
||
186 | 1 | ||
187 | if ( empty( $user ) || ! in_array( get_default_user_role(), $user->roles, true ) ) { |
||
188 | 1 | return $email_data; |
|
189 | 1 | } |
|
190 | |||
191 | 1 | $message = sprintf( |
|
192 | 1 | /* translators: %s: User login. */ |
|
193 | esc_html__( 'You have been approved to access %s', 'user-approval' ), |
||
194 | $blogname |
||
195 | 1 | ); |
|
196 | 1 | $message .= "\r\n\r\n"; |
|
197 | $message .= $email_data['message']; |
||
198 | 1 | ||
199 | /* translators: Login details notification email subject. %s: Site title. */ |
||
200 | $email_data['subject'] = esc_html__( '[%s] Login Details [Account Approved]', 'user-approval' ); |
||
201 | $email_data['message'] = $message; |
||
202 | |||
203 | return apply_filters( 'user_approval_approved_user_email_data', $email_data ); |
||
204 | } |
||
205 | |||
206 | /** |
||
207 | 1 | * Send a notification/email to blocked user. |
|
208 | * |
||
209 | 1 | * @param WP_User $user WP_User object. |
|
210 | */ |
||
211 | 1 | function send_user_blocked_email( $user ) { |
|
212 | 1 | $blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ); |
|
213 | |||
214 | $message = sprintf( |
||
215 | 1 | /* translators: %s: Site title. */ |
|
216 | esc_html__( 'You have been denied access to %s.', 'user-approval' ), |
||
217 | 1 | $blogname |
|
218 | 1 | ); |
|
219 | |||
220 | $subject = sprintf( |
||
221 | /* translators: %s: Site title. */ |
||
222 | 1 | esc_html__( '[%s] Account Blocked.', 'user-approval' ), |
|
223 | 1 | $blogname |
|
224 | 1 | ); |
|
225 | 1 | ||
226 | $email_data = [ |
||
227 | 'to' => $user->user_email, |
||
228 | 1 | 'subject' => $subject, |
|
229 | 'message' => $message, |
||
230 | 'headers' => '', |
||
231 | 1 | ]; |
|
232 | 1 | ||
233 | 1 | /** |
|
234 | 1 | * Filters the contents of account blocked notification email sent to the blogger. |
|
235 | 1 | * |
|
236 | * @param array $email_data { |
||
237 | 1 | * Used to build wp_mail(). |
|
238 | * |
||
239 | * @type string $to The intended recipient - site admin email address. |
||
240 | * @type string $subject The subject of the email. |
||
241 | * @type string $message The body of the email. |
||
242 | * @type string $headers The headers of the email. |
||
243 | * } |
||
244 | * @param WP_User $user User object for new user. |
||
245 | * @param string $blogname The site title. |
||
246 | 1 | */ |
|
247 | 1 | $email_data = apply_filters( 'user_approval_blocked_user_email_data', $email_data, $user, $blogname ); |
|
248 | |||
249 | // phpcs:ignore WordPressVIPMinimum.VIP.RestrictedFunctions.wp_mail_wp_mail, WordPressVIPMinimum.Functions.RestrictedFunctions.wp_mail_wp_mail |
||
250 | 1 | wp_mail( |
|
251 | 1 | $email_data['to'], |
|
252 | wp_specialchars_decode( $email_data['subject'] ), |
||
253 | $email_data['message'], |
||
254 | 1 | $email_data['headers'] |
|
255 | ); |
||
256 | } |
||
257 | |||
258 | 1 | /** |
|
259 | 1 | * Add a filter to list users based on user status. |
|
260 | 1 | * |
|
261 | 1 | * @param string $which The location of the extra table nav markup: 'top' or 'bottom'. |
|
262 | 1 | */ |
|
263 | function add_user_status_filters( $which ) { |
||
264 | 1 | ||
265 | if ( 'top' !== $which ) { |
||
266 | 1 | return; |
|
267 | 1 | } |
|
268 | 1 | ||
269 | 1 | $status = filter_input( INPUT_GET, 'user_status', FILTER_SANITIZE_STRING ); |
|
270 | 1 | $all_user_status = get_user_status( 'all' ); |
|
271 | |||
272 | ?> |
||
273 | <div class="alignleft actions"> |
||
274 | 1 | <label for="filter-by-date" class="screen-reader-text">Filter by user status</label> |
|
275 | <select name="user_status" id="filter-by-user-status"> |
||
276 | <?php |
||
277 | printf( |
||
278 | 1 | '<option %s value="%s">%s</option>', |
|
279 | ( 'all' === $status ) ? esc_html( 'selected="selected"' ) : '', |
||
280 | esc_attr( 'all' ), |
||
281 | esc_html__( 'All', 'user-approval' ) |
||
282 | ); |
||
283 | foreach ( $all_user_status as $value => $label ) { |
||
284 | |||
285 | printf( |
||
286 | '<option %s value="%s">%s</option>', |
||
287 | ( $value === $status ) ? esc_html( 'selected="selected"' ) : '', |
||
288 | esc_attr( $value ), |
||
289 | esc_html( $label ) |
||
290 | 1 | ); |
|
291 | } |
||
292 | 1 | ?> |
|
293 | </select> |
||
294 | <button type="submit" name="filter_action" class="button"><?php esc_html_e( 'Filter', 'user-approval' ) ?></button> |
||
295 | 1 | </div> |
|
296 | 1 | <?php |
|
297 | 1 | } |
|
298 | 1 | ||
299 | 1 | /** |
|
300 | * Filter user list in WP Admin filter by user status. |
||
301 | 1 | * |
|
302 | * @param array $args Arguments passed to WP_User_Query to retrieve items for the current |
||
303 | * users list table. |
||
304 | 1 | * |
|
305 | 1 | * @return array |
|
306 | 1 | */ |
|
307 | 1 | function filter_user_list_by_status( $args ) { |
|
308 | 1 | ||
309 | 1 | $current_screen = get_current_screen(); |
|
310 | 1 | ||
311 | $status = filter_input( INPUT_GET, 'user_status', FILTER_SANITIZE_STRING ); |
||
312 | 1 | ||
313 | if ( |
||
314 | 1 | ! is_admin() |
|
315 | 1 | || empty( $current_screen ) |
|
316 | || 'users' !== $current_screen->id |
||
317 | || empty( $status ) |
||
318 | || is_array( get_user_status( $status ) ) |
||
319 | 1 | ) { |
|
320 | return $args; |
||
321 | } |
||
322 | |||
323 | if ( in_array( $status, [ STATUS_APPROVED, STATUS_BLOCKED ], true ) ) { |
||
324 | $args['meta_key'] = STATUS_META_KEY; // phpcs:ignore WordPress.VIP.SlowDBQuery.slow_db_query_meta_key |
||
325 | $args['meta_value'] = $status; // phpcs:ignore WordPress.VIP.SlowDBQuery.slow_db_query_meta_value, WordPress.DB.SlowDBQuery.slow_db_query_meta_value |
||
326 | } elseif ( STATUS_PENDING === $status ) { |
||
327 | $args['role'] = get_default_user_role(); |
||
328 | $args['meta_key'] = STATUS_META_KEY; // phpcs:ignore WordPress.VIP.SlowDBQuery.slow_db_query_meta_key |
||
329 | $args['meta_compare'] = 'NOT EXISTS'; |
||
330 | } else { |
||
331 | $user_roles_data = get_pre_approved_user_roles(); |
||
332 | |||
333 | if ( ! empty( $user_roles_data ) ) { |
||
334 | $args['role__in'] = array_keys( $user_roles_data ); |
||
335 | } |
||
336 | } |
||
337 | |||
338 | return $args; |
||
339 | } |
||
340 |