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 ) |
|||
0 ignored issues
–
show
It seems like
get_user_status(User_Approval\STATUS_APPROVED) can also be of type array ; however, parameter $args of sprintf() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
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 ); |
|||
0 ignored issues
–
show
It seems like
$user_id can also be of type string ; however, parameter $user_id of get_userdata() does only seem to accept integer , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
145 | 1 | $user_status = get_user_meta( $user_id, STATUS_META_KEY, true ); |
|||
0 ignored issues
–
show
It seems like
$user_id can also be of type string ; however, parameter $user_id of get_user_meta() does only seem to accept integer , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
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 ); |
|||
0 ignored issues
–
show
It seems like
get_option('blogname') can also be of type false ; however, parameter $string of wp_specialchars_decode() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
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(); |
|||
0 ignored issues
–
show
Are you sure the assignment to
$current_screen is correct as get_current_screen() seems to always return null .
This check looks for function or method calls that always return null and whose return value is assigned to a variable. class A
{
function getObject()
{
return null;
}
}
$a = new A();
$object = $a->getObject();
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||
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 |