Completed
Push — master ( 0b1136...4cad50 )
by
unknown
44:52 queued 11s
created

wc-user-functions.php ➔ wc_create_new_customer_username()   B

Complexity

Conditions 7
Paths 48

Size

Total Lines 52

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 7.2944

Importance

Changes 0
Metric Value
cc 7
nc 48
nop 3
dl 0
loc 52
ccs 18
cts 22
cp 0.8182
crap 7.2944
rs 8.1138
c 0
b 0
f 0

How to fix   Long Method   

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
 * WooCommerce Customer Functions
4
 *
5
 * Functions for customers.
6
 *
7
 * @package WooCommerce/Functions
8
 * @version 2.2.0
9
 */
10
11
defined( 'ABSPATH' ) || exit;
12
13
/**
14
 * Prevent any user who cannot 'edit_posts' (subscribers, customers etc) from seeing the admin bar.
15
 *
16
 * Note: get_option( 'woocommerce_lock_down_admin', true ) is a deprecated option here for backwards compatibility. Defaults to true.
17
 *
18
 * @param bool $show_admin_bar If should display admin bar.
19
 * @return bool
20
 */
21
function wc_disable_admin_bar( $show_admin_bar ) {
22
	if ( apply_filters( 'woocommerce_disable_admin_bar', true ) && ! ( current_user_can( 'edit_posts' ) || current_user_can( 'manage_woocommerce' ) ) ) {
23
		$show_admin_bar = false;
24
	}
25
26
	return $show_admin_bar;
27
}
28
add_filter( 'show_admin_bar', 'wc_disable_admin_bar', 10, 1 ); // phpcs:ignore WordPress.VIP.AdminBarRemoval.RemovalDetected
0 ignored issues
show
introduced by
Removal of admin bar is prohibited.
Loading history...
29
30
if ( ! function_exists( 'wc_create_new_customer' ) ) {
31
32
	/**
33
	 * Create a new customer.
34
	 *
35
	 * @param  string $email    Customer email.
36
	 * @param  string $username Customer username.
37
	 * @param  string $password Customer password.
38
	 * @param  array  $args     List of arguments to pass to `wp_insert_user()`.
39
	 * @return int|WP_Error Returns WP_Error on failure, Int (user ID) on success.
40
	 */
41
	function wc_create_new_customer( $email, $username = '', $password = '', $args = array() ) {
42
		if ( empty( $email ) || ! is_email( $email ) ) {
43
			return new WP_Error( 'registration-error-invalid-email', __( 'Please provide a valid email address.', 'woocommerce' ) );
44 63
		}
45 1
46
		if ( email_exists( $email ) ) {
47
			return new WP_Error( 'registration-error-email-exists', apply_filters( 'woocommerce_registration_error_email_exists', __( 'An account is already registered with your email address. Please log in.', 'woocommerce' ), $email ) );
48 63
		}
49 1
50
		if ( 'yes' === get_option( 'woocommerce_registration_generate_username', 'yes' ) && empty( $username ) ) {
51
			$username = wc_create_new_customer_username( $email, $args );
52
		}
53 63
54 63
		$username = sanitize_user( $username );
55
56 63
		if ( empty( $username ) || ! validate_username( $username ) ) {
57
			return new WP_Error( 'registration-error-invalid-username', __( 'Please enter a valid account username.', 'woocommerce' ) );
58
		}
59
60 63
		if ( username_exists( $username ) ) {
61 63
			return new WP_Error( 'registration-error-username-exists', __( 'An account is already registered with that username. Please choose another.', 'woocommerce' ) );
62
		}
63
64 1
		// Handle password creation.
65
		$password_generated = false;
66
		if ( 'yes' === get_option( 'woocommerce_registration_generate_password' ) && empty( $password ) ) {
67 1
			$password           = wp_generate_password();
68 1
			$password_generated = true;
69
		}
70 1
71 1
		if ( empty( $password ) ) {
72 1
			return new WP_Error( 'registration-error-missing-password', __( 'Please enter an account password.', 'woocommerce' ) );
73
		}
74
75
		// Use WP_Error to handle registration errors.
76
		$errors = new WP_Error();
77 63
78 63
		do_action( 'woocommerce_register_post', $username, $email, $errors );
79 1
80 1
		$errors = apply_filters( 'woocommerce_registration_errors', $errors, $username, $email );
81
82
		if ( $errors->get_error_code() ) {
83 63
			return $errors;
84 1
		}
85
86
		$new_customer_data = apply_filters(
87
			'woocommerce_new_customer_data',
88 63
			array_merge(
89
				$args,
90 63
				array(
91
					'user_login' => $username,
92 63
					'user_pass'  => $password,
93
					'user_email' => $email,
94 63
					'role'       => 'customer',
95
				)
96
			)
97
		);
98 63
99 63
		$customer_id = wp_insert_user( $new_customer_data );
100 63
101 63
		if ( is_wp_error( $customer_id ) ) {
102
			return new WP_Error( 'registration-error', __( 'Couldn&#8217;t register you&hellip; please contact us if you continue to have problems.', 'woocommerce' ) );
103 63
		}
104 63
105 63
		do_action( 'woocommerce_created_customer', $customer_id, $new_customer_data, $password_generated );
106 63
107
		return $customer_id;
108
	}
109
}
110
111 63
/**
112
 * Create a unique username for a new customer.
113 63
 *
114
 * @since 3.6.0
115
 * @param string $email New customer email address.
116
 * @param array  $new_user_args Array of new user args, maybe including first and last names.
117 63
 * @param string $suffix Append string to username to make it unique.
118
 * @return string Generated username.
119 63
 */
120
function wc_create_new_customer_username( $email, $new_user_args, $suffix = '' ) {
121
	$username_parts = array();
122
123
	if ( isset( $new_user_args['first_name'] ) ) {
124
		$username_parts[] = sanitize_user( $new_user_args['first_name'], true );
125
	}
126
127
	if ( isset( $new_user_args['last_name'] ) ) {
128
		$username_parts[] = sanitize_user( $new_user_args['last_name'], true );
129
	}
130
131
	// Remove empty parts.
132
	$username_parts = array_filter( $username_parts );
133
134
	// If there are no parts, e.g. name had unicode chars, or was not provided, fallback to email.
135
	if ( empty( $username_parts ) ) {
136
		$email_parts    = explode( '@', $email );
137
		$email_username = $email_parts[0];
138
139
		// Exclude common prefixes.
140
		if ( in_array(
141
			$email_username,
142
			array(
143 2
				'sales',
144 2
				'hello',
145 2
				'mail',
146 2
				'contact',
147
				'info',
148 2
			),
149 2
			true
150 2
		) ) {
151
			// Get the domain part.
152
			$email_username = $email_parts[1];
153
		}
154 2
155 1
		$username_parts[] = sanitize_user( $email_username, true );
156 1
	}
157 1
158
	$username = wc_strtolower( implode( '', $username_parts ) );
159
160
	if ( $suffix ) {
161 1
		$username .= $suffix;
162 1
	}
163
164 1
	if ( username_exists( $username ) ) {
165 1
		// Generate something unique to append to the username in case of a conflict with another user.
166 1
		$suffix = '-' . zeroise( wp_rand( 0, 9999 ), 4 );
167 1
		return wc_create_new_customer_username( $email, $new_user_args, $suffix );
168
	}
169
170 1
	return $username;
171
}
172 1
173 1
/**
174
 * Login a customer (set auth cookie and set global user object).
175
 *
176 1
 * @param int $customer_id Customer ID.
177
 */
178
function wc_set_customer_auth_cookie( $customer_id ) {
179
	wp_set_current_user( $customer_id );
180 2
	wp_set_auth_cookie( $customer_id, true );
181 1
182 1
	// Update session.
183 1
	WC()->session->init_session_cookie();
0 ignored issues
show
Bug introduced by
The method init_session_cookie does only exist in WC_Session_Handler, but not in WC_Session.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
184
}
185
186 2
/**
187
 * Get past orders (by email) and update them.
188
 *
189
 * @param  int $customer_id Customer ID.
190
 * @return int
191
 */
192
function wc_update_new_customer_past_orders( $customer_id ) {
193
	$linked          = 0;
194
	$complete        = 0;
195 15
	$customer        = get_user_by( 'id', absint( $customer_id ) );
196 15
	$customer_orders = wc_get_orders(
197
		array(
198 15
			'limit'    => -1,
199 10
			'customer' => array( array( 0, $customer->user_email ) ),
200 10
			'return'   => 'ids',
201 10
		)
202
	);
203
204
	if ( ! empty( $customer_orders ) ) {
205
		foreach ( $customer_orders as $order_id ) {
206
			$order = wc_get_order( $order_id );
207
			if ( ! $order ) {
208
				continue;
209
			}
210
211
			$order->set_customer_id( $customer->ID );
212
			$order->save();
213
214
			if ( $order->has_downloadable_item() ) {
215
				$data_store = WC_Data_Store::load( 'customer-download' );
216
				$data_store->delete_by_order_id( $order->get_id() );
0 ignored issues
show
Documentation Bug introduced by
The method delete_by_order_id does not exist on object<WC_Data_Store>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
217 13
				wc_downloadable_product_permissions( $order->get_id(), true );
218
			}
219 13
220
			do_action( 'woocommerce_update_new_customer_past_order', $order_id, $customer );
221
222
			if ( get_post_status( $order_id ) === 'wc-completed' ) {
0 ignored issues
show
introduced by
Found "=== '". Use Yoda Condition checks, you must
Loading history...
223 13
				$complete++;
224 13
			}
225 13
226
			$linked++;
227 13
		}
228 5
	}
229
230 13
	if ( $complete ) {
231
		update_user_meta( $customer_id, 'paying_customer', 1 );
0 ignored issues
show
introduced by
update_user_meta() usage is highly discouraged, check VIP documentation on "Working with wp_users"
Loading history...
232 13
		update_user_meta( $customer_id, '_order_count', '' );
0 ignored issues
show
introduced by
update_user_meta() usage is highly discouraged, check VIP documentation on "Working with wp_users"
Loading history...
233 1
		update_user_meta( $customer_id, '_money_spent', '' );
0 ignored issues
show
introduced by
update_user_meta() usage is highly discouraged, check VIP documentation on "Working with wp_users"
Loading history...
234
	}
235 1
236 1
	return $linked;
237
}
238
239
/**
240 13
 * Order Status completed - This is a paying customer.
241 13
 *
242
 * @param int $order_id Order ID.
243
 */
244 13
function wc_paying_customer( $order_id ) {
245 13
	$order       = wc_get_order( $order_id );
246
	$customer_id = $order->get_customer_id();
247 13
248
	if ( $customer_id > 0 && 'shop_order_refund' !== $order->get_type() ) {
249
		$customer = new WC_Customer( $customer_id );
250
		$customer->set_is_paying_customer( true );
251 13
		$customer->save();
252
	}
253 13
}
254 13
add_action( 'woocommerce_order_status_completed', 'wc_paying_customer' );
255 13
256 13
/**
257 13
 * Checks if a user (by email or ID or both) has bought an item.
258
 *
259
 * @param string $customer_email Customer email to check.
260
 * @param int    $user_id User ID to check.
261 13
 * @param int    $product_id Product ID to check.
262
 * @return bool
263
 */
264 13
function wc_customer_bought_product( $customer_email, $user_id, $product_id ) {
265
	global $wpdb;
266
267 13
	$result = apply_filters( 'woocommerce_pre_customer_bought_product', null, $customer_email, $user_id, $product_id );
268 13
269
	if ( null !== $result ) {
270
		return $result;
271 13
	}
272
273 13
	$transient_name    = 'wc_customer_bought_product_' . md5( $customer_email . $user_id );
274
	$transient_version = WC_Cache_Helper::get_transient_version( 'orders' );
275
	$transient_value   = get_transient( $transient_name );
276
277
	if ( isset( $transient_value['value'], $transient_value['version'] ) && $transient_value['version'] === $transient_version ) {
278
		$result = $transient_value['value'];
279
	} else {
280
		$customer_data = array( $user_id );
281
282
		if ( $user_id ) {
283 20
			$user = get_user_by( 'id', $user_id );
284
285
			if ( isset( $user->user_email ) ) {
286
				$customer_data[] = $user->user_email;
287
			}
288
		}
289
290
		if ( is_email( $customer_email ) ) {
291
			$customer_data[] = $customer_email;
292
		}
293
294 503
		$customer_data = array_map( 'esc_sql', array_filter( array_unique( $customer_data ) ) );
295 1
		$statuses      = array_map( 'esc_sql', wc_get_is_paid_statuses() );
296
297
		if ( count( $customer_data ) === 0 ) {
0 ignored issues
show
introduced by
Found "=== 0". Use Yoda Condition checks, you must
Loading history...
298 503
			return false;
299 502
		}
300
301
		$result = $wpdb->get_col(
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
introduced by
Usage of a direct database call without caching is prohibited. Use wp_cache_get / wp_cache_set.
Loading history...
302 300
			"
303
			SELECT im.meta_value FROM {$wpdb->posts} AS p
304
			INNER JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id
305
			INNER JOIN {$wpdb->prefix}woocommerce_order_items AS i ON p.ID = i.order_id
306
			INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS im ON i.order_item_id = im.order_item_id
307
			WHERE p.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' )
308
			AND pm.meta_key IN ( '_billing_email', '_customer_user' )
309
			AND im.meta_key IN ( '_product_id', '_variation_id' )
310
			AND im.meta_value != 0
311
			AND pm.meta_value IN ( '" . implode( "','", $customer_data ) . "' )
312
		"
313
		); // WPCS: unprepared SQL ok.
314
		$result = array_map( 'absint', $result );
315 504
316 504
		$transient_value = array(
317
			'version' => $transient_version,
318 1
			'value'   => $result,
319 1
		);
320
321 1
		set_transient( $transient_name, $transient_value, DAY_IN_SECONDS * 30 );
322 1
	}
323
	return in_array( absint( $product_id ), $result, true );
324 1
}
325
326 1
/**
327 1
 * Checks if the current user has a role.
328
 *
329
 * @param string $role The role.
330
 * @return bool
331 1
 */
332 1
function wc_current_user_has_role( $role ) {
333 1
	return wc_user_has_role( wp_get_current_user(), $role );
334
}
335
336 1
/**
337
 * Checks if a user has a role.
338 1
 *
339 1
 * @param int|\WP_User $user The user.
340
 * @param string       $role The role.
341 1
 * @return bool
342
 */
343 1
function wc_user_has_role( $user, $role ) {
344 1
	if ( ! is_object( $user ) ) {
345
		$user = get_userdata( $user );
346 1
	}
347 1
348
	if ( ! $user || ! $user->exists() ) {
349 1
		return false;
350
	}
351 1
352 1
	return in_array( $role, $user->roles, true );
353
}
354 1
355 1
/**
356
 * Checks if a user has a certain capability.
357 1
 *
358
 * @param array $allcaps All capabilities.
359 1
 * @param array $caps    Capabilities.
360 1
 * @param array $args    Arguments.
361
 *
362 1
 * @return array The filtered array of all capabilities.
363 1
 */
364
function wc_customer_has_capability( $allcaps, $caps, $args ) {
365 1
	if ( isset( $caps[0] ) ) {
366
		switch ( $caps[0] ) {
367 View Code Duplication
			case 'view_order':
368 504
				$user_id = intval( $args[1] );
369
				$order   = wc_get_order( $args[2] );
370
371
				if ( $order && $user_id === $order->get_user_id() ) {
372
					$allcaps['view_order'] = true;
373
				}
374
				break;
375
			case 'pay_for_order':
376
				$user_id  = intval( $args[1] );
377
				$order_id = isset( $args[2] ) ? $args[2] : null;
378
379
				// When no order ID, we assume it's a new order
380
				// and thus, customer can pay for it.
381
				if ( ! $order_id ) {
382
					$allcaps['pay_for_order'] = true;
383
					break;
384
				}
385
386 503
				$order = wc_get_order( $order_id );
387
388 13
				if ( $order && ( $user_id === $order->get_user_id() || ! $order->get_user_id() ) ) {
389
					$allcaps['pay_for_order'] = true;
390
				}
391 503
				break;
392 View Code Duplication
			case 'order_again':
393
				$user_id = intval( $args[1] );
394
				$order   = wc_get_order( $args[2] );
395
396
				if ( $order && $user_id === $order->get_user_id() ) {
397
					$allcaps['order_again'] = true;
398
				}
399
				break;
400 View Code Duplication
			case 'cancel_order':
401
				$user_id = intval( $args[1] );
402 1
				$order   = wc_get_order( $args[2] );
403
404
				if ( $order && $user_id === $order->get_user_id() ) {
405 1
					$allcaps['cancel_order'] = true;
406 1
				}
407
				break;
408 1 View Code Duplication
			case 'download_file':
409 1
				$user_id  = intval( $args[1] );
410 1
				$download = $args[2];
411
412
				if ( $download && $user_id === $download->get_user_id() ) {
413
					$allcaps['download_file'] = true;
414 1
				}
415
				break;
416
		}
417
	}
418
	return $allcaps;
419
}
420
add_filter( 'user_has_cap', 'wc_customer_has_capability', 10, 3 );
421
422
/**
423
 * Safe way of allowing shop managers restricted capabilities that will remove
424
 * access to the capabilities if WooCommerce is deactivated.
425
 *
426
 * @since 3.5.4
427
 * @param bool[]   $allcaps Array of key/value pairs where keys represent a capability name and boolean values
428
 *                          represent whether the user has that capability.
429
 * @param string[] $caps    Required primitive capabilities for the requested capability.
430 503
 * @param array    $args Arguments that accompany the requested capability check.
431
 * @param WP_User  $user    The user object.
432
 * @return bool[]
433 503
 */
434
function wc_shop_manager_has_capability( $allcaps, $caps, $args, $user ) {
0 ignored issues
show
Unused Code introduced by
The parameter $caps is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
435
436
	if ( wc_user_has_role( $user, 'shop_manager' ) ) {
437
		// @see wc_modify_map_meta_cap, which limits editing to customers.
438 1
		$allcaps['edit_users'] = true;
439
	}
440
441 1
	return $allcaps;
442 1
}
443 1
add_filter( 'user_has_cap', 'wc_shop_manager_has_capability', 10, 4 );
444 1
445
/**
446 1
 * Modify the list of editable roles to prevent non-admin adding admin users.
447 1
 *
448 1
 * @param  array $roles Roles.
449 1
 * @return array
450
 */
451
function wc_modify_editable_roles( $roles ) {
452
	if ( is_multisite() && is_super_admin() ) {
453
		return $roles;
454 1
	}
455
	if ( ! wc_current_user_has_role( 'administrator' ) ) {
456 503
		unset( $roles['administrator'] );
457
458
		if ( wc_current_user_has_role( 'shop_manager' ) ) {
459
			$shop_manager_editable_roles = apply_filters( 'woocommerce_shop_manager_editable_roles', array( 'customer' ) );
460
			return array_intersect_key( $roles, array_flip( $shop_manager_editable_roles ) );
461
		}
462
	}
463
464
	return $roles;
465
}
466
add_filter( 'editable_roles', 'wc_modify_editable_roles' );
467 4
468 4
/**
469
 * Modify capabilities to prevent non-admin users editing admin users.
470
 *
471
 * $args[0] will be the user being edited in this case.
472
 *
473
 * @param  array  $caps    Array of caps.
474
 * @param  string $cap     Name of the cap we are checking.
475
 * @param  int    $user_id ID of the user being checked against.
476
 * @param  array  $args    Arguments.
477
 * @return array
478 3
 */
479 3
function wc_modify_map_meta_cap( $caps, $cap, $user_id, $args ) {
480 3
	if ( is_multisite() && is_super_admin() ) {
481 3
		return $caps;
482
	}
483
	switch ( $cap ) {
484 3
		case 'edit_user':
485
		case 'remove_user':
486 3
		case 'promote_user':
487 2
		case 'delete_user':
488 2
			if ( ! isset( $args[0] ) || $args[0] === $user_id ) {
489
				break;
490 2
			} else {
491
				if ( ! wc_current_user_has_role( 'administrator' ) ) {
492 2
					if ( wc_user_has_role( $args[0], 'administrator' ) ) {
493 2
						$caps[] = 'do_not_allow';
494
					} elseif ( wc_current_user_has_role( 'shop_manager' ) ) {
495
						// Shop managers can only edit customer info.
496
						$userdata = get_userdata( $args[0] );
497 2
						$shop_manager_editable_roles = apply_filters( 'woocommerce_shop_manager_editable_roles', array( 'customer' ) );
498
						if ( property_exists( $userdata, 'roles' ) && ! empty( $userdata->roles ) && ! array_intersect( $userdata->roles, $shop_manager_editable_roles ) ) {
499
							$caps[] = 'do_not_allow';
500
						}
501
					}
502 2
				}
503
			}
504
			break;
505
	}
506 2
	return $caps;
507
}
508 2
add_filter( 'map_meta_cap', 'wc_modify_map_meta_cap', 10, 4 );
509
510 2
/**
511 2
 * Get customer download permissions from the database.
512
 *
513
 * @param int $customer_id Customer/User ID.
514
 * @return array
515 2
 */
516
function wc_get_customer_download_permissions( $customer_id ) {
517
	$data_store = WC_Data_Store::load( 'customer-download' );
518
	return apply_filters( 'woocommerce_permission_list', $data_store->get_downloads_for_customer( $customer_id ), $customer_id );
0 ignored issues
show
Documentation Bug introduced by
The method get_downloads_for_customer does not exist on object<WC_Data_Store>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
519 2
}
520
521
/**
522 2
 * Get customer available downloads.
523 2
 *
524 2
 * @param int $customer_id Customer/User ID.
525 2
 * @return array
526 2
 */
527 2
function wc_get_customer_available_downloads( $customer_id ) {
528
	$downloads   = array();
529
	$_product    = null;
530 2
	$order       = null;
531 2
	$file_number = 0;
532
533 2
	// Get results from valid orders only.
534 2
	$results = wc_get_customer_download_permissions( $customer_id );
535 2
536 2
	if ( $results ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $results of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
537
		foreach ( $results as $result ) {
538 2
			$order_id = intval( $result->order_id );
539
540 2 View Code Duplication
			if ( ! $order || $order->get_id() !== $order_id ) {
541 2
				// New order.
542 2
				$order    = wc_get_order( $order_id );
543 2
				$_product = null;
544 2
			}
545 2
546 2
			// Make sure the order exists for this download.
547 2
			if ( ! $order ) {
548 2
				continue;
549
			}
550 2
551 2
			// Check if downloads are permitted.
552
			if ( ! $order->is_download_permitted() ) {
553
				continue;
554
			}
555 2
556
			$product_id = intval( $result->product_id );
557
558
			if ( ! $_product || $_product->get_id() !== $product_id ) {
559 3
				// New product.
560
				$file_number = 0;
561
				$_product    = wc_get_product( $product_id );
562
			}
563
564
			// Check product exists and has the file.
565
			if ( ! $_product || ! $_product->exists() || ! $_product->has_file( $result->download_id ) ) {
566
				continue;
567
			}
568
569 1
			$download_file = $_product->get_file( $result->download_id );
570 1
571
			// Download name will be 'Product Name' for products with a single downloadable file, and 'Product Name - File X' for products with multiple files.
572
			$download_name = apply_filters(
573
				'woocommerce_downloadable_product_name',
574
				$download_file['name'],
575
				$_product,
576
				$result->download_id,
577
				$file_number
578
			);
579
580 1
			$downloads[] = array(
581 1
				'download_url'        => add_query_arg(
582
					array(
583
						'download_file' => $product_id,
584
						'order'         => $result->order_key,
585
						'email'         => rawurlencode( $result->user_email ),
586
						'key'           => $result->download_id,
587
					),
588
					home_url( '/' )
589
				),
590
				'download_id'         => $result->download_id,
591
				'product_id'          => $_product->get_id(),
592 8
				'product_name'        => $_product->get_name(),
593 8
				'product_url'         => $_product->is_visible() ? $_product->get_permalink() : '', // Since 3.3.0.
594
				'download_name'       => $download_name,
595 8
				'order_id'            => $order->get_id(),
596
				'order_key'           => $order->get_order_key(),
597
				'downloads_remaining' => $result->downloads_remaining,
598 8
				'access_expires'      => $result->access_expires,
599 8
				'file'                => array(
600
					'name' => $download_file->get_name(),
601
					'file' => $download_file->get_file(),
602
				),
603
			);
604
605
			$file_number++;
606
		}
607
	}
608
609
	return apply_filters( 'woocommerce_customer_available_downloads', $downloads, $customer_id );
610
}
611
612
/**
613 12
 * Get total spent by customer.
614 12
 *
615
 * @param  int $user_id User ID.
616
 * @return string
617
 */
618
function wc_get_customer_total_spent( $user_id ) {
619
	$customer = new WC_Customer( $user_id );
620
	return $customer->get_total_spent();
621
}
622
623
/**
624
 * Get total orders by customer.
625
 *
626
 * @param  int $user_id User ID.
627
 * @return int
628
 */
629
function wc_get_customer_order_count( $user_id ) {
630
	$customer = new WC_Customer( $user_id );
631
	return $customer->get_order_count();
632
}
633
634
/**
635
 * Reset _customer_user on orders when a user is deleted.
636
 *
637
 * @param int $user_id User ID.
638
 */
639
function wc_reset_order_customer_id_on_deleted_user( $user_id ) {
640
	global $wpdb;
641
642
	$wpdb->update(
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
643
		$wpdb->postmeta,
644 59
		array(
645
			'meta_value' => 0,
0 ignored issues
show
introduced by
Detected usage of meta_value, possible slow query.
Loading history...
646
		),
647
		array(
648
			'meta_key'   => '_customer_user',
0 ignored issues
show
introduced by
Detected usage of meta_key, possible slow query.
Loading history...
649
			'meta_value' => $user_id,
0 ignored issues
show
introduced by
Detected usage of meta_value, possible slow query.
Loading history...
650
		)
651
	); // WPCS: slow query ok.
652
}
653
654
add_action( 'deleted_user', 'wc_reset_order_customer_id_on_deleted_user' );
655
656
/**
657
 * Get review verification status.
658
 *
659 59
 * @param  int $comment_id Comment ID.
660
 * @return bool
661 59
 */
662 59
function wc_review_is_from_verified_owner( $comment_id ) {
663 59
	$verified = get_comment_meta( $comment_id, 'verified', true );
664
	return '' === $verified ? WC_Comments::add_comment_purchase_verification( $comment_id ) : (bool) $verified;
665 59
}
666 44
667
/**
668
 * Disable author archives for customers.
669
 *
670
 * @since 2.5.0
671
 */
672
function wc_disable_author_archives_for_customers() {
673
	global $author;
674
675
	if ( is_author() ) {
676
		$user = get_user_by( 'id', $author );
677
678
		if ( user_can( $user, 'customer' ) && ! user_can( $user, 'edit_posts' ) ) {
679 59
			wp_redirect( wc_get_page_permalink( 'shop' ) );
680
		}
681
	}
682
}
683
684
add_action( 'template_redirect', 'wc_disable_author_archives_for_customers' );
685
686
/**
687
 * Hooks into the `profile_update` hook to set the user last updated timestamp.
688
 *
689
 * @since 2.6.0
690
 * @param int   $user_id The user that was updated.
691
 * @param array $old     The profile fields pre-change.
692
 */
693
function wc_update_profile_last_update_time( $user_id, $old ) {
0 ignored issues
show
Unused Code introduced by
The parameter $old is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
694
	wc_set_user_last_update_time( $user_id );
695
}
696
697
add_action( 'profile_update', 'wc_update_profile_last_update_time', 10, 2 );
698
699
/**
700
 * Hooks into the update user meta function to set the user last updated timestamp.
701 1
 *
702
 * @since 2.6.0
703 1
 * @param int    $meta_id     ID of the meta object that was changed.
704
 * @param int    $user_id     The user that was updated.
705
 * @param string $meta_key    Name of the meta key that was changed.
706
 * @param string $_meta_value Value of the meta that was changed.
707
 */
708
function wc_meta_update_last_update_time( $meta_id, $user_id, $meta_key, $_meta_value ) {
0 ignored issues
show
Unused Code introduced by
The parameter $meta_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $_meta_value is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
709
	$keys_to_track = apply_filters( 'woocommerce_user_last_update_fields', array( 'first_name', 'last_name' ) );
710
711
	$update_time = in_array( $meta_key, $keys_to_track, true ) ? true : false;
712
	$update_time = 'billing_' === substr( $meta_key, 0, 8 ) ? true : $update_time;
713
	$update_time = 'shipping_' === substr( $meta_key, 0, 9 ) ? true : $update_time;
714 4
715 4
	if ( $update_time ) {
716
		wc_set_user_last_update_time( $user_id );
717
	}
718
}
719
720
add_action( 'update_user_meta', 'wc_meta_update_last_update_time', 10, 4 );
721
722
/**
723
 * Sets a user's "last update" time to the current timestamp.
724
 *
725
 * @since 2.6.0
726
 * @param int $user_id The user to set a timestamp for.
727
 */
728 8
function wc_set_user_last_update_time( $user_id ) {
729 8
	update_user_meta( $user_id, 'last_update', gmdate( 'U' ) );
0 ignored issues
show
introduced by
update_user_meta() usage is highly discouraged, check VIP documentation on "Working with wp_users"
Loading history...
730
}
731 8
732
/**
733
 * Get customer saved payment methods list.
734
 *
735
 * @since 2.6.0
736 8
 * @param int $customer_id Customer ID.
737 8
 * @return array
738
 */
739 8
function wc_get_customer_saved_methods_list( $customer_id ) {
740
	return apply_filters( 'woocommerce_saved_payment_methods_list', array(), $customer_id );
741
}
742
743
/**
744 8
 * Get info about customer's last order.
745
 *
746 8
 * @since 2.6.0
747 1
 * @param int $customer_id Customer ID.
748
 * @return WC_Order|bool Order object if successful or false.
749
 */
750
function wc_get_customer_last_order( $customer_id ) {
751
	$customer = new WC_Customer( $customer_id );
752
753
	return $customer->get_last_order();
754
}
755
756
/**
757
 * Add support for searching by display_name.
758
 *
759
 * @since 3.2.0
760
 * @param array $search_columns Column names.
761
 * @return array
762
 */
763
function wc_user_search_columns( $search_columns ) {
764
	$search_columns[] = 'display_name';
765
	return $search_columns;
766
}
767
add_filter( 'user_search_columns', 'wc_user_search_columns' );
768
769
/**
770
 * When a user is deleted in WordPress, delete corresponding WooCommerce data.
771
 *
772
 * @param int $user_id User ID being deleted.
773
 */
774
function wc_delete_user_data( $user_id ) {
775
	global $wpdb;
776
777
	// Clean up sessions.
778
	$wpdb->delete(
779
		$wpdb->prefix . 'woocommerce_sessions',
780
		array(
781
			'session_key' => $user_id,
782
		)
783
	);
784
785
	// Revoke API keys.
786
	$wpdb->delete(
787
		$wpdb->prefix . 'woocommerce_api_keys',
788
		array(
789
			'user_id' => $user_id,
790
		)
791
	);
792
793
	// Clean up payment tokens.
794
	$payment_tokens = WC_Payment_Tokens::get_customer_tokens( $user_id );
795
796
	foreach ( $payment_tokens as $payment_token ) {
797
		$payment_token->delete();
798
	}
799
}
800
add_action( 'delete_user', 'wc_delete_user_data' );
801 159
802 58
/**
803
 * Store user agents. Used for tracker.
804 104
 *
805
 * @since 3.0.0
806
 * @param string     $user_login User login.
807
 * @param int|object $user       User.
808
 */
809
function wc_maybe_store_user_agent( $user_login, $user ) {
0 ignored issues
show
Unused Code introduced by
The parameter $user_login is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
810
	if ( 'yes' === get_option( 'woocommerce_allow_tracking', 'no' ) && user_can( $user, 'manage_woocommerce' ) ) {
811
		$admin_user_agents   = array_filter( (array) get_option( 'woocommerce_tracker_ua', array() ) );
812
		$admin_user_agents[] = wc_get_user_agent();
813
		update_option( 'woocommerce_tracker_ua', array_unique( $admin_user_agents ) );
814
	}
815
}
816
add_action( 'wp_login', 'wc_maybe_store_user_agent', 10, 2 );
817
818
/**
819
 * Update logic triggered on login.
820
 *
821
 * @since 3.4.0
822
 * @param string $user_login User login.
823
 * @param object $user       User.
824
 */
825
function wc_user_logged_in( $user_login, $user ) {
0 ignored issues
show
Unused Code introduced by
The parameter $user_login is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
826
	wc_update_user_last_active( $user->ID );
827
	update_user_meta( $user->ID, '_woocommerce_load_saved_cart_after_login', 1 );
0 ignored issues
show
introduced by
update_user_meta() usage is highly discouraged, check VIP documentation on "Working with wp_users"
Loading history...
828
}
829
add_action( 'wp_login', 'wc_user_logged_in', 10, 2 );
830
831
/**
832
 * Update when the user was last active.
833
 *
834
 * @since 3.4.0
835
 */
836
function wc_current_user_is_active() {
837
	if ( ! is_user_logged_in() ) {
838
		return;
839
	}
840
	wc_update_user_last_active( get_current_user_id() );
841
}
842
add_action( 'wp', 'wc_current_user_is_active', 10 );
843
844
/**
845
 * Set the user last active timestamp to now.
846
 *
847
 * @since 3.4.0
848
 * @param int $user_id User ID to mark active.
849
 */
850
function wc_update_user_last_active( $user_id ) {
851
	if ( ! $user_id ) {
852
		return;
853
	}
854
	update_user_meta( $user_id, 'wc_last_active', (string) strtotime( date( 'Y-m-d', current_time( 'timestamp', true ) ) ) );
0 ignored issues
show
introduced by
update_user_meta() usage is highly discouraged, check VIP documentation on "Working with wp_users"
Loading history...
855
}
856