Completed
Push — 671-feature/add-mutisite-suppo... ( 8e884d...8e134f )
by
unknown
137:44 queued 134:51
created

UsersModule::delete_users_from_query()   C

Complexity

Conditions 12
Paths 24

Size

Total Lines 50
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 12.667

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 12
eloc 24
c 3
b 0
f 0
nc 24
nop 2
dl 0
loc 50
ccs 15
cts 18
cp 0.8333
crap 12.667
rs 6.9666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace BulkWP\BulkDelete\Core\Users;
4
5
use BulkWP\BulkDelete\Core\Base\BaseModule;
6
7 1
defined( 'ABSPATH' ) || exit; // Exit if accessed directly.
8
9
/**
10
 * Encapsulates the Bulk Delete User Meta box Module Logic.
11
 * All Bulk Delete User Meta box Modules should extend this class.
12
 *
13
 * @see BaseModule
14
 * @since 5.5.2
15
 * @since 6.0.0 Renamed to UsersModule.
16
 */
17
abstract class UsersModule extends BaseModule {
18
	/**
19
	 * Build query params for WP_User_Query by using delete options.
20
	 *
21
	 * Return an empty query array to short-circuit deletion.
22
	 *
23
	 * @since 6.0.0
24
	 *
25
	 * @param array $options Delete options.
26
	 *
27
	 * @return array Query.
28
	 */
29
	abstract protected function build_query( $options );
30
31
	protected function parse_common_filters( $request ) {
32
		$options = array();
33
34
		$options['login_restrict'] = bd_array_get_bool( $request, "smbd_{$this->field_slug}_login_restrict", false );
35
		$options['login_days']     = absint( bd_array_get( $request, "smbd_{$this->field_slug}_login_days", 0 ) );
36
37
		$options['registered_restrict'] = bd_array_get_bool( $request, "smbd_{$this->field_slug}_registered_restrict", false );
38
		$options['registered_date_op']  = bd_array_get( $request, 'smbd_' . $this->field_slug . '_op' );
39
		$options['registered_days']     = absint( bd_array_get( $request, "smbd_{$this->field_slug}_registered_days", 0 ) );
40
41
		$options['no_posts']            = bd_array_get_bool( $request, "smbd_{$this->field_slug}_no_posts", false );
42
		$options['no_posts_post_types'] = bd_array_get( $request, "smbd_{$this->field_slug}_no_post_post_types", array() );
43
44
		$options['reassign_user']    = bd_array_get_bool( $request, "smbd_{$this->field_slug}_post_reassign", false );
45
		$options['reassign_user_id'] = absint( bd_array_get( $request, "smbd_{$this->field_slug}_reassign_user_id", 0 ) );
46
		$options['limit_to']         = absint( bd_array_get( $request, "smbd_{$this->field_slug}_limit_to", 0 ) );
47
48
		return $options;
49
	}
50
51 69
	protected function do_delete( $options ) {
52 69
		$query = $this->build_query( $options );
53
54 69
		if ( empty( $query ) ) {
55
			// Short circuit deletion, if nothing needs to be deleted.
56 2
			return 0;
57
		}
58
59 67
		$query = $this->exclude_users_from_deletion( $query );
60 67
		$query = $this->exclude_current_user( $query );
61
62 67
		return $this->delete_users_from_query( $query, $options );
63
	}
64
65
	/**
66
	 * Query and Delete users.
67
	 *
68
	 * @since  5.5.2
69
	 * @access protected
70
	 *
71
	 * @param array $query   Options to query users.
72
	 * @param array $options Delete options.
73
	 *
74
	 * @return int Number of users who were deleted.
75
	 */
76 73
	protected function delete_users_from_query( $query, $options ) {
77 73
		$count = 0;
78 73
		$users = $this->query_users( $query );
79
80 73
		if ( ! function_exists( 'wp_delete_user' ) ) {
81
			require_once ABSPATH . 'wp-admin/includes/user.php';
82
		}
83
84 73
		foreach ( $users as $user ) {
85 66
			if ( ! $this->can_delete_by_logged_date( $options, $user ) ) {
86
				continue;
87
			}
88
89 66
			if ( ! $this->can_delete_by_post_count( $options, $user ) ) {
90 13
				continue;
91
			}
92
93
			/**
94
			 * Can a user be deleted.
95
			 *
96
			 * @since 6.0.0
97
			 *
98
			 * @param bool                                             Can Delete the User. (Default true)
99
			 * @param \WP_User                                $user    User Object of the user who is about to be deleted.
100
			 * @param array                                   $options Delete options.
101
			 * @param \BulkWP\BulkDelete\Core\Base\BaseModule $this    Module that is triggering deletion.
102
			 */
103 64
			if ( ! apply_filters( 'bd_can_delete_user', true, $user, $options, $this ) ) {
104
				continue;
105
			}
106
107 64
			switch ( is_network_admin() && is_multisite() ) {
108 1
				case true:
109
					$deleted = wpmu_delete_user( $user->ID );
110 63
					break;
111
				case false:
112
					if ( isset( $options['reassign_user'] ) && $options['reassign_user'] ) {
113 64
						$deleted = wp_delete_user( $user->ID, $options['reassign_user_id'] );
114 64
					} else {
115
						$deleted = wp_delete_user( $user->ID );
116
					}
117
					break;
118 73
			}
119
120
			if ( $deleted ) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $deleted does not seem to be defined for all execution paths leading up to this point.
Loading history...
121
				$count ++;
122
			}
123
		}
124
125
		return $count;
126
	}
127
128 73
	/**
129
	 * Query users using options.
130 73
	 *
131
	 * @param array $options Query options.
132
	 *
133 73
	 * @return \WP_User[] List of users.
134
	 */
135 73
	protected function query_users( $options ) {
136
		$defaults = array(
137
			'count_total' => false,
138
		);
139
140
		$options = wp_parse_args( $options, $defaults );
141
142
		$wp_user_query = new \WP_User_Query( $options );
143
144 73
		/**
145
		 * This action before the query happens.
146 73
		 *
147
		 * @since 6.0.0
148
		 *
149
		 * @param \WP_User_Query $wp_user_query Query object.
150
		 */
151
		do_action( 'bd_before_query', $wp_user_query );
152
153
		$users = (array) $wp_user_query->get_results();
154
155 73
		/**
156
		 * This action runs after the query happens.
157 73
		 *
158
		 * @since 6.0.0
159
		 *
160
		 * @param \WP_User_Query $wp_user_query Query object.
161
		 */
162
		do_action( 'bd_after_query', $wp_user_query );
163
164
		return $users;
165
	}
166
167
	/**
168
	 * Can the user be deleted based on the 'post count' option?
169
	 *
170
	 * This doesn't work well in batches.
171
	 *
172
	 * @link https://github.com/sudar/bulk-delete/issues/511 Github issue.
173
	 * @since  5.5.2
174 66
	 * @access protected
175
	 *
176 66
	 * @param array    $delete_options Delete Options.
177 66
	 * @param \WP_User $user           User object that needs to be deleted.
178
	 *
179
	 * @return bool True if the user can be deleted, false otherwise.
180
	 */
181
	protected function can_delete_by_post_count( $delete_options, $user ) {
182
		return ! (
183
			$delete_options['no_posts'] &&
184
			count_user_posts( $user->ID, $delete_options['no_posts_post_types'] ) > 0
185
		);
186
	}
187
188
	/**
189
	 * Get the date query part for WP_User_Query.
190
	 *
191
	 * Date query corresponds to user registered date.
192 70
	 *
193 70
	 * @since 6.0.0
194 41
	 *
195
	 * @param array $options Delete options.
196
	 *
197 29
	 * @return array Date Query.
198 1
	 */
199
	protected function get_date_query( $options ) {
200
		if ( ! $options['registered_restrict'] ) {
201 28
			return array();
202
		}
203 24
204
		if ( $options['registered_days'] <= 0 ) {
205
			return array();
206
		}
207 4
208
		if ( ! isset( $options['registered_date_op'] ) ) {
209 4
			return array(
210
				'before' => $options['registered_days'] . ' days ago',
211
			);
212
		}
213
214
		if ( 'before' === $options['registered_date_op'] || 'after' === $options['registered_date_op'] ) {
215
			return array(
216
				$options['registered_date_op'] => $options['registered_days'] . ' days ago',
217
			);
218
		}
219
220
		return array();
221
	}
222
223
	/**
224
	 * Can the user be deleted based on the 'logged in date' option?
225
	 *
226
	 * This doesn't work well in batches.
227
	 *
228
	 * @link https://github.com/sudar/bulk-delete/issues/511 Github issue.
229
	 * @since  5.5.2
230 66
	 * @access protected
231 66
	 *
232
	 * @param array    $delete_options Delete Options.
233
	 * @param \WP_User $user           User object that needs to be deleted.
234
	 *
235
	 * @return bool True if the user can be deleted, false otherwise.
236
	 */
237
	protected function can_delete_by_logged_date( $delete_options, $user ) {
238
		if ( $delete_options['login_restrict'] ) {
239
			$login_days = $delete_options['login_days'];
240
			$last_login = bd_get_last_login( $user->ID );
241
242
			if ( null !== $last_login ) {
0 ignored issues
show
introduced by
The condition null !== $last_login is always true.
Loading history...
243
				// we have a logged-in entry for the user in simple login log plugin.
244
				if ( strtotime( $last_login ) > strtotime( '-' . $login_days . 'days' ) ) {
245
					return false;
246
				}
247
			} else {
248
				// we don't have a logged-in entry for the user in simple login log plugin.
249 66
				if ( $login_days > 0 ) {
250
					// non-zero value for login date. So don't delete this user.
251
					return false;
252
				}
253
			}
254
		}
255
256
		return true;
257
	}
258
259
	/**
260
	 * Render User Login restrict settings.
261
	 *
262
	 * @since 5.5
263
	 */
264
	protected function render_user_login_restrict_settings() {
265
		?>
266
		<tr>
267
			<td scope="row" colspan="2">
268
				<label for="smbd_<?php echo esc_attr( $this->field_slug ); ?>_registered_restrict">
269
					<input name="smbd_<?php echo esc_attr( $this->field_slug ); ?>_registered_restrict" id="smbd_<?php echo esc_attr( $this->field_slug ); ?>_registered_restrict" value="true" type="checkbox">
270
					<?php _e( 'Restrict to users who are registered in the site ', 'bulk-delete' ); ?>
271
				</label>
272
				<select name="smbd_<?php echo esc_attr( $this->field_slug ); ?>_op" id="smbd_<?php echo esc_attr( $this->field_slug ); ?>_op" disabled>
273
					<option value="before"><?php _e( 'for at least', 'bulk-delete' ); ?></option>
274
					<option value="after"><?php _e( 'in the last', 'bulk-delete' ); ?></option>
275
				</select>
276
				<input type="number" name="smbd_<?php echo esc_attr( $this->field_slug ); ?>_registered_days" id="smbd_<?php echo esc_attr( $this->field_slug ); ?>_registered_days" class="screen-per-page" disabled value="0" min="0"><?php _e( ' days.', 'bulk-delete' ); ?>
277
			</td>
278
		</tr>
279
		<tr>
280
			<td scope="row" colspan="2">
281
				<label>
282
					<input name="smbd_<?php echo esc_attr( $this->field_slug ); ?>_login_restrict" id="smbd_<?php echo esc_attr( $this->field_slug ); ?>_login_restrict"
283
							value="true" type="checkbox" <?php disabled( false, bd_is_simple_login_log_present() ); ?>>
284
					<?php _e( 'Restrict to users who have not logged in the last ', 'bulk-delete' ); ?>
285
				</label>
286
				<input type="number" name="smbd_<?php echo esc_attr( $this->field_slug ); ?>_login_days" id="smbd_<?php echo esc_attr( $this->field_slug ); ?>_login_days" class="screen-per-page" value="0" min="0" disabled> <?php _e( 'days', 'bulk-delete' ); ?>.
287
288
				<?php if ( ! bd_is_simple_login_log_present() ) : ?>
289
					<span style = "color:red">
290
						<?php _e( 'Need the free "Simple Login Log" Plugin', 'bulk-delete' ); ?> <a href = "https://wordpress.org/plugins/simple-login-log/">Install now</a>
291
					</span>
292
				<?php endif; ?>
293
			</td>
294
		</tr>
295
296
		<?php if ( bd_is_simple_login_log_present() ) : ?>
297
			<tr>
298
				<td scope="row" colspan="2">
299
					<?php _e( 'Enter "0 days" to delete users who have never logged in after the "Simple Login Log" plugin has been installed.', 'bulk-delete' ); ?>
300
			</tr>
301
		<?php endif; ?>
302
<?php
303
	}
304
305
	/**
306
	 * Render delete user with no posts settings.
307
	 *
308
	 * @since 5.5
309
	 */
310
	protected function render_user_with_no_posts_settings() {
311
	?>
312
		<tr>
313
			<td scope="row" colspan="2">
314
				<input type="checkbox" value="true"
315
						name="smbd_<?php echo esc_attr( $this->field_slug ); ?>_no_posts"
316
						id="smbd_<?php echo esc_attr( $this->field_slug ); ?>_no_posts" class="user_restrict_to_no_posts_filter">
317
				<label for="smbd_<?php echo esc_attr( $this->field_slug ); ?>_no_posts">
318
					<?php _e( "Restrict to users who don't have any posts.", 'bulk-delete' ); ?>
319
				</label>
320
			</td>
321
		</tr>
322
323
		<tr class="user_restrict_to_no_posts_filter_items visually-hidden">
324
			<td scope="row" colspan="2">
325
				<table class="filter-items">
326
					<tr>
327
						<td scope="row">
328
							<?php _e( 'Select the post types. By default all post types are considered.', 'bulk-delete' ); ?>
329
						</td>
330
					</tr>
331
332
					<?php $this->render_post_type_checkboxes( "smbd_{$this->field_slug}_no_post_post_types" ); ?>
333
				</table>
334
			</td>
335
		</tr>
336
337
	<?php
338
	}
339
340
	/**
341
	 * Get unique user meta keys.
342
	 *
343
	 * @since 5.5
344
	 *
345
	 * @return array List of unique meta keys.
346
	 */
347
	protected function get_unique_user_meta_keys() {
348
		global $wpdb;
349
350
		return $wpdb->get_col( "SELECT DISTINCT(meta_key) FROM {$wpdb->prefix}usermeta ORDER BY meta_key" );
351
	}
352
353 68
	/**
354 68
	 * Exclude current user from being deleted.
355
	 *
356 68
	 * @param array $query WP_User_Query args.
357 66
	 *
358
	 * @return array Modified query args.
359
	 */
360 2
	protected function exclude_current_user( $query ) {
361
		$current_user_id = get_current_user_id();
362
363 2
		if ( $current_user_id <= 0 ) {
364
			return $query;
365
		}
366 2
367
		if ( isset( $query['exclude'] ) ) {
368
			$query['exclude'] = array_merge( $query['exclude'], array( $current_user_id ) );
369
		} else {
370
			$query['exclude'] = array( $current_user_id );
371 2
		}
372
373
		if ( isset( $query['include'] ) ) {
374
			$query['include'] = array_diff( $query['include'], $query['exclude'] );
375
			unset( $query['exclude'] );
376
		}
377
378
		return $query;
379
	}
380
381
	/**
382
	 * Exclude users from deletion.
383 68
	 *
384
	 * @since 6.0.0
385
	 *
386
	 * @param array $query Pre-built query.
387
	 *
388
	 * @return array Modified query.
389
	 */
390
	protected function exclude_users_from_deletion( array $query ) {
391 68
		/**
392
		 * Filter the list of user ids that will be excluded from deletion.
393 68
		 *
394
		 * @since 6.0.0
395
		 *
396
		 * @param array $excluded_ids User IDs to be excluded during deletion.
397
		 */
398
		$excluded_user_ids = apply_filters( 'bd_excluded_user_ids', array() );
399
400
		if ( is_array( $excluded_user_ids ) && ! empty( $excluded_user_ids ) ) {
401 68
			if ( isset( $query['exclude'] ) ) {
402
				$query['exclude'] = array_merge( $query['exclude'], $excluded_user_ids );
403
			} else {
404
				$query['exclude'] = $excluded_user_ids;
405
			}
406 68
		}
407
408
		if ( isset( $query['include'] ) ) {
409
			$query['include'] = array_diff( $query['include'], $query['exclude'] );
410
			unset( $query['exclude'] );
411
		}
412
413
		return $query;
414
	}
415
416
	/**
417
	 * Get Users ids from User logins.
418
	 *
419
	 * @param array $user_logins User Logins.
420
	 *
421
	 * @return array User ids.
422
	 */
423
	protected function get_user_ids_from_logins( $user_logins ) {
424
		$args = array(
425
			'fields'    => 'ID',
426
			'login__in' => $user_logins,
427
		);
428
429
		return get_users( $args );
430
	}
431
432
	/**
433
	 * Get Users ids from User emails.
434
	 *
435
	 * This is done in a batch of 500 since it involves a IN query.
436
	 *
437
	 * @param array $user_emails User emails.
438
	 *
439
	 * @return array User ids.
440
	 */
441
	protected function get_user_ids_from_emails( $user_emails ) {
442
		global $wpdb;
443
444
		$user_email_chunks = array_chunk( $user_emails, 500 );
445
446
		$user_ids = array();
447
448
		foreach ( $user_email_chunks as $user_email_chunk ) {
449
			$placeholders = array_fill( 0, count( $user_email_chunk ), '%s' );
450
			$format       = implode( ',', $placeholders );
451
452
			$query      = "SELECT ID FROM $wpdb->users WHERE user_email in ($format)";
453
			$user_ids[] = $wpdb->get_col( $wpdb->prepare( $query, $user_email_chunk ) );
454
		}
455
456
		return $user_ids;
457
	}
458
}
459