Completed
Push — master ( fb5f9c...377d79 )
by Mike
64:31 queued 55:52
created

includes/wc-user-functions.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

Code
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
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
	 * @return int|WP_Error Returns WP_Error on failure, Int (user ID) on success.
39
	 */
40
	function wc_create_new_customer( $email, $username = '', $password = '' ) {
41
42
		// Check the email address.
43 63
		if ( empty( $email ) || ! is_email( $email ) ) {
44 1
			return new WP_Error( 'registration-error-invalid-email', __( 'Please provide a valid email address.', 'woocommerce' ) );
45
		}
46
47 63
		if ( email_exists( $email ) ) {
48 1
			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 ) );
49
		}
50
51
		// Handle username creation.
52 63
		if ( 'no' === get_option( 'woocommerce_registration_generate_username' ) || ! empty( $username ) ) {
53 63
			$username = sanitize_user( $username );
54
55 63
			if ( empty( $username ) || ! validate_username( $username ) ) {
56
				return new WP_Error( 'registration-error-invalid-username', __( 'Please enter a valid account username.', 'woocommerce' ) );
57
			}
58
59 63
			if ( username_exists( $username ) ) {
60 63
				return new WP_Error( 'registration-error-username-exists', __( 'An account is already registered with that username. Please choose another.', 'woocommerce' ) );
61
			}
62
		} else {
63 1
			$username = sanitize_user( current( explode( '@', $email ) ), true );
64
65
			// Ensure username is unique.
66 1
			$append     = 1;
67 1
			$o_username = $username;
68
69 1
			while ( username_exists( $username ) ) {
70 1
				$username = $o_username . $append;
71 1
				$append++;
72
			}
73
		}
74
75
		// Handle password creation.
76 63
		$password_generated = false;
77 63
		if ( 'yes' === get_option( 'woocommerce_registration_generate_password' ) && empty( $password ) ) {
78 1
			$password           = wp_generate_password();
79 1
			$password_generated = true;
80
		}
81
82 63
		if ( empty( $password ) ) {
83 1
			return new WP_Error( 'registration-error-missing-password', __( 'Please enter an account password.', 'woocommerce' ) );
84
		}
85
86
		// Use WP_Error to handle registration errors.
87 63
		$errors = new WP_Error();
88
89 63
		do_action( 'woocommerce_register_post', $username, $email, $errors );
90
91 63
		$errors = apply_filters( 'woocommerce_registration_errors', $errors, $username, $email );
92
93 63
		if ( $errors->get_error_code() ) {
94
			return $errors;
95
		}
96
97 63
		$new_customer_data = apply_filters(
98 63
			'woocommerce_new_customer_data',
99 63
			array(
100 63
				'user_login' => $username,
101 63
				'user_pass'  => $password,
102 63
				'user_email' => $email,
103
				'role'       => 'customer',
104
			)
105
		);
106 63
107
		$customer_id = wp_insert_user( $new_customer_data );
108 63
109
		if ( is_wp_error( $customer_id ) ) {
110
			return new WP_Error( 'registration-error', __( 'Couldn&#8217;t register you&hellip; please contact us if you continue to have problems.', 'woocommerce' ) );
111
		}
112 63
113
		do_action( 'woocommerce_created_customer', $customer_id, $new_customer_data, $password_generated );
114 63
115
		return $customer_id;
116
	}
117
}
118
119
/**
120
 * Login a customer (set auth cookie and set global user object).
121
 *
122
 * @param int $customer_id Customer ID.
123
 */
124
function wc_set_customer_auth_cookie( $customer_id ) {
125
	wp_set_current_user( $customer_id );
126
	wp_set_auth_cookie( $customer_id, true );
127
128
	// Update session.
129
	WC()->session->init_session_cookie();
0 ignored issues
show
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...
130
}
131
132
/**
133
 * Get past orders (by email) and update them.
134
 *
135
 * @param  int $customer_id Customer ID.
136
 * @return int
137
 */
138 2
function wc_update_new_customer_past_orders( $customer_id ) {
139 2
	$linked          = 0;
140 2
	$complete        = 0;
141 2
	$customer        = get_user_by( 'id', absint( $customer_id ) );
142
	$customer_orders = wc_get_orders(
143 2
		array(
144 2
			'limit'    => -1,
145 2
			'customer' => array( array( 0, $customer->user_email ) ),
146
			'return'   => 'ids',
147
		)
148
	);
149 2
150 1
	if ( ! empty( $customer_orders ) ) {
151 1
		foreach ( $customer_orders as $order_id ) {
152 1
			$order = wc_get_order( $order_id );
153
			if ( ! $order ) {
154
				continue;
155
			}
156 1
157 1
			$order->set_customer_id( $customer->ID );
158
			$order->save();
159 1
160 1
			if ( $order->has_downloadable_item() ) {
161 1
				$data_store = WC_Data_Store::load( 'customer-download' );
162 1
				$data_store->delete_by_order_id( $order->get_id() );
163
				wc_downloadable_product_permissions( $order->get_id(), true );
164
			}
165 1
166
			do_action( 'woocommerce_update_new_customer_past_order', $order_id, $customer );
167 1
168 1
			if ( get_post_status( $order_id ) === 'wc-completed' ) {
169
				$complete++;
170
			}
171 1
172
			$linked++;
173
		}
174
	}
175 2
176 1
	if ( $complete ) {
177 1
		update_user_meta( $customer_id, 'paying_customer', 1 );
178 1
		update_user_meta( $customer_id, '_order_count', '' );
179
		update_user_meta( $customer_id, '_money_spent', '' );
180
	}
181 2
182
	return $linked;
183
}
184
185
/**
186
 * Order Status completed - This is a paying customer.
187
 *
188
 * @param int $order_id Order ID.
189
 */
190 15
function wc_paying_customer( $order_id ) {
191 15
	$order       = wc_get_order( $order_id );
192
	$customer_id = $order->get_customer_id();
193 15
194 10
	if ( $customer_id > 0 && 'shop_order_refund' !== $order->get_type() ) {
195 10
		$customer = new WC_Customer( $customer_id );
196 10
		$customer->set_is_paying_customer( true );
197
		$customer->save();
198
	}
199
}
200
add_action( 'woocommerce_order_status_completed', 'wc_paying_customer' );
201
202
/**
203
 * Checks if a user (by email or ID or both) has bought an item.
204
 *
205
 * @param string $customer_email Customer email to check.
206
 * @param int    $user_id User ID to check.
207
 * @param int    $product_id Product ID to check.
208
 * @return bool
209
 */
210
function wc_customer_bought_product( $customer_email, $user_id, $product_id ) {
211
	global $wpdb;
212 13
213
	$result = apply_filters( 'woocommerce_pre_customer_bought_product', null, $customer_email, $user_id, $product_id );
214 13
215
	if ( null !== $result ) {
216
		return $result;
217
	}
218 13
219 13
	$transient_name    = 'wc_customer_bought_product_' . md5( $customer_email . $user_id );
220
	$transient_version = WC_Cache_Helper::get_transient_version( 'orders' );
221 13
	$transient_value   = get_transient( $transient_name );
222 13
223
	if ( isset( $transient_value['value'], $transient_value['version'] ) && $transient_value['version'] === $transient_version ) {
224 13
		$result = $transient_value['value'];
225 1
	} else {
226
		$customer_data = array( $user_id );
227 1
228 1
		if ( $user_id ) {
229
			$user = get_user_by( 'id', $user_id );
230
231
			if ( isset( $user->user_email ) ) {
232 13
				$customer_data[] = $user->user_email;
233 13
			}
234
		}
235
236 13
		if ( is_email( $customer_email ) ) {
237 13
			$customer_data[] = $customer_email;
238
		}
239 13
240
		$customer_data = array_map( 'esc_sql', array_filter( array_unique( $customer_data ) ) );
241
		$statuses      = array_map( 'esc_sql', wc_get_is_paid_statuses() );
242
243 13
		if ( count( $customer_data ) === 0 ) {
244
			return false;
245 13
		}
246 13
247 13
		$result = $wpdb->get_col(
248 13
			"
249 13
			SELECT im.meta_value FROM {$wpdb->posts} AS p
250
			INNER JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id
251
			INNER JOIN {$wpdb->prefix}woocommerce_order_items AS i ON p.ID = i.order_id
252
			INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS im ON i.order_item_id = im.order_item_id
253 13
			WHERE p.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' )
254
			AND pm.meta_key IN ( '_billing_email', '_customer_user' )
255
			AND im.meta_key IN ( '_product_id', '_variation_id' )
256 13
			AND im.meta_value != 0
257
			AND pm.meta_value IN ( '" . implode( "','", $customer_data ) . "' )
258 13
		"
259
		); // WPCS: unprepared SQL ok.
260 13
		$result = array_map( 'absint', $result );
261
262
		$transient_value = array(
263
			'version' => $transient_version,
264
			'value'   => $result,
265
		);
266
267
		set_transient( $transient_name, $transient_value, DAY_IN_SECONDS * 30 );
268
	}
269
	return in_array( absint( $product_id ), $result, true );
270 20
}
271
272
/**
273
 * Checks if the current user has a role.
274
 *
275
 * @param string $role The role.
276
 * @return bool
277
 */
278
function wc_current_user_has_role( $role ) {
279
	return wc_user_has_role( wp_get_current_user(), $role );
280
}
281 20
282 1
/**
283
 * Checks if a user has a role.
284
 *
285 20
 * @param int|\WP_User $user The user.
286 6
 * @param string       $role The role.
287
 * @return bool
288
 */
289 14
function wc_user_has_role( $user, $role ) {
290
	if ( ! is_object( $user ) ) {
291
		$user = get_userdata( $user );
292
	}
293
294
	if ( ! $user || ! $user->exists() ) {
295
		return false;
296
	}
297
298
	return in_array( $role, $user->roles, true );
299
}
300
301 480
/**
302 480
 * Checks if a user has a certain capability.
303 480
 *
304 1
 * @param array $allcaps All capabilities.
305 1
 * @param array $caps    Capabilities.
306
 * @param array $args    Arguments.
307 1
 *
308 1
 * @return array The filtered array of all capabilities.
309
 */
310 1
function wc_customer_has_capability( $allcaps, $caps, $args ) {
311 480
	if ( isset( $caps[0] ) ) {
312 1
		switch ( $caps[0] ) {
313 1 View Code Duplication
			case 'view_order':
314
				$user_id = intval( $args[1] );
315
				$order   = wc_get_order( $args[2] );
316
317 1
				if ( $order && $user_id === $order->get_user_id() ) {
318 1
					$allcaps['view_order'] = true;
319 1
				}
320
				break;
321
			case 'pay_for_order':
322 1
				$user_id  = intval( $args[1] );
323
				$order_id = isset( $args[2] ) ? $args[2] : null;
324 1
325 1
				// When no order ID, we assume it's a new order
326
				// and thus, customer can pay for it.
327 1
				if ( ! $order_id ) {
328 480
					$allcaps['pay_for_order'] = true;
329 1
					break;
330 1
				}
331
332 1
				$order = wc_get_order( $order_id );
333 1
334
				if ( $order && ( $user_id === $order->get_user_id() || ! $order->get_user_id() ) ) {
335 1
					$allcaps['pay_for_order'] = true;
336 480
				}
337 1
				break;
338 1 View Code Duplication
			case 'order_again':
339
				$user_id = intval( $args[1] );
340 1
				$order   = wc_get_order( $args[2] );
341 1
342
				if ( $order && $user_id === $order->get_user_id() ) {
343 1
					$allcaps['order_again'] = true;
344 480
				}
345 1
				break;
346 1 View Code Duplication
			case 'cancel_order':
347
				$user_id = intval( $args[1] );
348 1
				$order   = wc_get_order( $args[2] );
349 1
350
				if ( $order && $user_id === $order->get_user_id() ) {
351 1
					$allcaps['cancel_order'] = true;
352
				}
353
				break;
354 480 View Code Duplication
			case 'download_file':
355
				$user_id  = intval( $args[1] );
356
				$download = $args[2];
357
358
				if ( $download && $user_id === $download->get_user_id() ) {
359
					$allcaps['download_file'] = true;
360
				}
361
				break;
362
		}
363
	}
364
	return $allcaps;
365 1
}
366
add_filter( 'user_has_cap', 'wc_customer_has_capability', 10, 3 );
367
368 1
/**
369 1
 * Safe way of allowing shop managers restricted capabilities that will remove
370
 * access to the capabilities if WooCommerce is deactivated.
371 1
 *
372 1
 * @since 3.5.4
373 1
 * @param bool[]   $allcaps Array of key/value pairs where keys represent a capability name and boolean values
374
 *                          represent whether the user has that capability.
375
 * @param string[] $caps    Required primitive capabilities for the requested capability.
376
 * @param array    $args Arguments that accompany the requested capability check.
377 1
 * @param WP_User  $user    The user object.
378
 * @return bool[]
379
 */
380
function wc_shop_manager_has_capability( $allcaps, $caps, $args, $user ) {
381
382
	if ( wc_user_has_role( $user, 'shop_manager' ) ) {
383
		/**
384
		 * @see wc_modify_map_meta_cap, which limits editing to customers.
385
		 */
386
		$allcaps['edit_users'] = true;
387
	}
388
389
	return $allcaps;
390
}
391
add_filter( 'user_has_cap', 'wc_shop_manager_has_capability', 10, 4 );
392
393 479
/**
394
 * Modify the list of editable roles to prevent non-admin adding admin users.
395
 *
396
 * @param  array $roles Roles.
397 479
 * @return array
398 479
 */
399 479
function wc_modify_editable_roles( $roles ) {
400 479
	if ( is_multisite() && is_super_admin() ) {
401 1
		return $roles;
402
	}
403
	if ( ! wc_current_user_has_role( 'administrator' ) ) {
404 1
		unset( $roles['administrator'] );
405 1
406 1
		if ( wc_current_user_has_role( 'shop_manager' ) ) {
407 1
			$shop_manager_editable_roles = apply_filters( 'woocommerce_shop_manager_editable_roles', array( 'customer' ) );
408
			return array_intersect_key( $roles, array_flip( $shop_manager_editable_roles ) );
409 1
		}
410 1
	}
411 1
412 1
	return $roles;
413
}
414
add_filter( 'editable_roles', 'wc_modify_editable_roles' );
415
416
/**
417 1
 * Modify capabilities to prevent non-admin users editing admin users.
418
 *
419 479
 * $args[0] will be the user being edited in this case.
420
 *
421
 * @param  array  $caps    Array of caps.
422
 * @param  string $cap     Name of the cap we are checking.
423
 * @param  int    $user_id ID of the user being checked against.
424
 * @param  array  $args    Arguments.
425
 * @return array
426
 */
427
function wc_modify_map_meta_cap( $caps, $cap, $user_id, $args ) {
428
	if ( is_multisite() && is_super_admin() ) {
429
		return $caps;
430 4
	}
431 4
	switch ( $cap ) {
432
		case 'edit_user':
433
		case 'remove_user':
434
		case 'promote_user':
435
		case 'delete_user':
436
			if ( ! isset( $args[0] ) || $args[0] === $user_id ) {
437
				break;
438
			} else {
439
				if ( ! wc_current_user_has_role( 'administrator' ) ) {
440
					if ( wc_user_has_role( $args[0], 'administrator' ) ) {
441 3
						$caps[] = 'do_not_allow';
442 3
					} elseif ( wc_current_user_has_role( 'shop_manager' ) ) {
443 3
						// Shop managers can only edit customer info.
444 3
						$userdata = get_userdata( $args[0] );
445
						$shop_manager_editable_roles = apply_filters( 'woocommerce_shop_manager_editable_roles', array( 'customer' ) );
446
						if ( property_exists( $userdata, 'roles' ) && ! empty( $userdata->roles ) && ! array_intersect( $userdata->roles, $shop_manager_editable_roles ) ) {
447 3
							$caps[] = 'do_not_allow';
448
						}
449 3
					}
450 2
				}
451 2
			}
452
			break;
453 2
	}
454
	return $caps;
455 2
}
456 2
add_filter( 'map_meta_cap', 'wc_modify_map_meta_cap', 10, 4 );
457
458
/**
459
 * Get customer download permissions from the database.
460 2
 *
461
 * @param int $customer_id Customer/User ID.
462
 * @return array
463
 */
464
function wc_get_customer_download_permissions( $customer_id ) {
465 2
	$data_store = WC_Data_Store::load( 'customer-download' );
466
	return apply_filters( 'woocommerce_permission_list', $data_store->get_downloads_for_customer( $customer_id ), $customer_id );
467
}
468
469 2
/**
470
 * Get customer available downloads.
471 2
 *
472
 * @param int $customer_id Customer/User ID.
473 2
 * @return array
474 2
 */
475
function wc_get_customer_available_downloads( $customer_id ) {
476
	$downloads   = array();
477
	$_product    = null;
478 2
	$order       = null;
479
	$file_number = 0;
480
481
	// Get results from valid orders only.
482 2
	$results = wc_get_customer_download_permissions( $customer_id );
483
484
	if ( $results ) {
485 2
		foreach ( $results as $result ) {
486 2
			$order_id = intval( $result->order_id );
487 2
488 2 View Code Duplication
			if ( ! $order || $order->get_id() !== $order_id ) {
489 2
				// New order.
490 2
				$order    = wc_get_order( $order_id );
491
				$_product = null;
492
			}
493 2
494 2
			// Make sure the order exists for this download.
495
			if ( ! $order ) {
496 2
				continue;
497 2
			}
498 2
499 2
			// Check if downloads are permitted.
500
			if ( ! $order->is_download_permitted() ) {
501 2
				continue;
502
			}
503 2
504 2
			$product_id = intval( $result->product_id );
505 2
506 2
			if ( ! $_product || $_product->get_id() !== $product_id ) {
507 2
				// New product.
508 2
				$file_number = 0;
509 2
				$_product    = wc_get_product( $product_id );
510 2
			}
511 2
512
			// Check product exists and has the file.
513 2
			if ( ! $_product || ! $_product->exists() || ! $_product->has_file( $result->download_id ) ) {
514 2
				continue;
515
			}
516
517
			$download_file = $_product->get_file( $result->download_id );
518 2
519
			// Download name will be 'Product Name' for products with a single downloadable file, and 'Product Name - File X' for products with multiple files.
520
			$download_name = apply_filters(
521
				'woocommerce_downloadable_product_name',
522 3
				$download_file['name'],
523
				$_product,
524
				$result->download_id,
525
				$file_number
526
			);
527
528
			$downloads[] = array(
529
				'download_url'        => add_query_arg(
530
					array(
531
						'download_file' => $product_id,
532 1
						'order'         => $result->order_key,
533 1
						'email'         => rawurlencode( $result->user_email ),
534
						'key'           => $result->download_id,
535
					),
536
					home_url( '/' )
537
				),
538
				'download_id'         => $result->download_id,
539
				'product_id'          => $_product->get_id(),
540
				'product_name'        => $_product->get_name(),
541
				'product_url'         => $_product->is_visible() ? $_product->get_permalink() : '', // Since 3.3.0.
542
				'download_name'       => $download_name,
543 1
				'order_id'            => $order->get_id(),
544 1
				'order_key'           => $order->get_order_key(),
545
				'downloads_remaining' => $result->downloads_remaining,
546
				'access_expires'      => $result->access_expires,
547
				'file'                => array(
548
					'name' => $download_file->get_name(),
549
					'file' => $download_file->get_file(),
550
				),
551
			);
552
553
			$file_number++;
554
		}
555 8
	}
556 8
557 8
	return apply_filters( 'woocommerce_customer_available_downloads', $downloads, $customer_id );
558 8
}
559
560
/**
561
 * Get total spent by customer.
562
 *
563
 * @param  int $user_id User ID.
564
 * @return string
565
 */
566
function wc_get_customer_total_spent( $user_id ) {
567
	$customer = new WC_Customer( $user_id );
568
	return $customer->get_total_spent();
569
}
570
571
/**
572 12
 * Get total orders by customer.
573 12
 *
574
 * @param  int $user_id User ID.
575
 * @return int
576
 */
577
function wc_get_customer_order_count( $user_id ) {
578
	$customer = new WC_Customer( $user_id );
579
	return $customer->get_order_count();
580
}
581
582
/**
583
 * Reset _customer_user on orders when a user is deleted.
584
 *
585
 * @param int $user_id User ID.
586
 */
587
function wc_reset_order_customer_id_on_deleted_user( $user_id ) {
588
	global $wpdb;
589
590
	$wpdb->update(
591
		$wpdb->postmeta,
592
		array(
593
			'meta_value' => 0,
594
		),
595
		array(
596
			'meta_key'   => '_customer_user',
597
			'meta_value' => $user_id,
598
		)
599
	); // WPCS: slow query ok.
600
}
601
602
add_action( 'deleted_user', 'wc_reset_order_customer_id_on_deleted_user' );
603 59
604
/**
605
 * Get review verification status.
606
 *
607
 * @param  int $comment_id Comment ID.
608
 * @return bool
609
 */
610
function wc_review_is_from_verified_owner( $comment_id ) {
611
	$verified = get_comment_meta( $comment_id, 'verified', true );
612
	return '' === $verified ? WC_Comments::add_comment_purchase_verification( $comment_id ) : (bool) $verified;
613
}
614
615
/**
616
 * Disable author archives for customers.
617
 *
618 59
 * @since 2.5.0
619
 */
620 59
function wc_disable_author_archives_for_customers() {
621 59
	global $author;
622 59
623
	if ( is_author() ) {
624 59
		$user = get_user_by( 'id', $author );
625 44
626
		if ( user_can( $user, 'customer' ) && ! user_can( $user, 'edit_posts' ) ) {
627
			wp_redirect( wc_get_page_permalink( 'shop' ) );
628
		}
629
	}
630
}
631
632
add_action( 'template_redirect', 'wc_disable_author_archives_for_customers' );
633
634
/**
635
 * Hooks into the `profile_update` hook to set the user last updated timestamp.
636
 *
637
 * @since 2.6.0
638 59
 * @param int   $user_id The user that was updated.
639
 * @param array $old     The profile fields pre-change.
640
 */
641
function wc_update_profile_last_update_time( $user_id, $old ) {
642
	wc_set_user_last_update_time( $user_id );
643
}
644
645
add_action( 'profile_update', 'wc_update_profile_last_update_time', 10, 2 );
646
647
/**
648
 * Hooks into the update user meta function to set the user last updated timestamp.
649
 *
650
 * @since 2.6.0
651
 * @param int    $meta_id     ID of the meta object that was changed.
652
 * @param int    $user_id     The user that was updated.
653
 * @param string $meta_key    Name of the meta key that was changed.
654
 * @param string $_meta_value Value of the meta that was changed.
655
 */
656
function wc_meta_update_last_update_time( $meta_id, $user_id, $meta_key, $_meta_value ) {
657
	$keys_to_track = apply_filters( 'woocommerce_user_last_update_fields', array( 'first_name', 'last_name' ) );
658
659
	$update_time = in_array( $meta_key, $keys_to_track, true ) ? true : false;
660 1
	$update_time = 'billing_' === substr( $meta_key, 0, 8 ) ? true : $update_time;
661
	$update_time = 'shipping_' === substr( $meta_key, 0, 9 ) ? true : $update_time;
662 1
663
	if ( $update_time ) {
664
		wc_set_user_last_update_time( $user_id );
665
	}
666
}
667
668
add_action( 'update_user_meta', 'wc_meta_update_last_update_time', 10, 4 );
669
670
/**
671
 * Sets a user's "last update" time to the current timestamp.
672
 *
673 4
 * @since 2.6.0
674 4
 * @param int $user_id The user to set a timestamp for.
675
 */
676
function wc_set_user_last_update_time( $user_id ) {
677
	update_user_meta( $user_id, 'last_update', gmdate( 'U' ) );
678
}
679
680
/**
681
 * Get customer saved payment methods list.
682
 *
683
 * @since 2.6.0
684
 * @param int $customer_id Customer ID.
685
 * @return array
686
 */
687 8
function wc_get_customer_saved_methods_list( $customer_id ) {
688 8
	return apply_filters( 'woocommerce_saved_payment_methods_list', array(), $customer_id );
689
}
690 8
691
/**
692
 * Get info about customer's last order.
693
 *
694
 * @since 2.6.0
695 8
 * @param int $customer_id Customer ID.
696 8
 * @return WC_Order|bool Order object if successful or false.
697
 */
698 8
function wc_get_customer_last_order( $customer_id ) {
699
	$customer = new WC_Customer( $customer_id );
700
701
	return $customer->get_last_order();
702
}
703 8
704
/**
705 8
 * Add support for searching by display_name.
706 1
 *
707
 * @since 3.2.0
708
 * @param array $search_columns Column names.
709
 * @return array
710
 */
711
function wc_user_search_columns( $search_columns ) {
712
	$search_columns[] = 'display_name';
713
	return $search_columns;
714
}
715
add_filter( 'user_search_columns', 'wc_user_search_columns' );
716
717
/**
718
 * When a user is deleted in WordPress, delete corresponding WooCommerce data.
719
 *
720
 * @param int $user_id User ID being deleted.
721
 */
722
function wc_delete_user_data( $user_id ) {
723
	global $wpdb;
724
725
	// Clean up sessions.
726
	$wpdb->delete(
727
		$wpdb->prefix . 'woocommerce_sessions',
728
		array(
729
			'session_key' => $user_id,
730
		)
731
	);
732
733
	// Revoke API keys.
734
	$wpdb->delete(
735
		$wpdb->prefix . 'woocommerce_api_keys',
736
		array(
737
			'user_id' => $user_id,
738
		)
739
	);
740
741
	// Clean up payment tokens.
742
	$payment_tokens = WC_Payment_Tokens::get_customer_tokens( $user_id );
743
744
	foreach ( $payment_tokens as $payment_token ) {
745
		$payment_token->delete();
746
	}
747
}
748
add_action( 'delete_user', 'wc_delete_user_data' );
749
750
/**
751
 * Store user agents. Used for tracker.
752
 *
753
 * @since 3.0.0
754
 * @param string     $user_login User login.
755
 * @param int|object $user       User.
756
 */
757
function wc_maybe_store_user_agent( $user_login, $user ) {
758
	if ( 'yes' === get_option( 'woocommerce_allow_tracking', 'no' ) && user_can( $user, 'manage_woocommerce' ) ) {
759
		$admin_user_agents   = array_filter( (array) get_option( 'woocommerce_tracker_ua', array() ) );
760 161
		$admin_user_agents[] = wc_get_user_agent();
761 58
		update_option( 'woocommerce_tracker_ua', array_unique( $admin_user_agents ) );
762
	}
763 106
}
764
add_action( 'wp_login', 'wc_maybe_store_user_agent', 10, 2 );
765
766
/**
767
 * Update logic triggered on login.
768
 *
769
 * @since 3.4.0
770
 * @param string $user_login User login.
771
 * @param object $user       User.
772
 */
773
function wc_user_logged_in( $user_login, $user ) {
774
	wc_update_user_last_active( $user->ID );
775
	update_user_meta( $user->ID, '_woocommerce_load_saved_cart_after_login', 1 );
776
}
777
add_action( 'wp_login', 'wc_user_logged_in', 10, 2 );
778
779
/**
780
 * Update when the user was last active.
781
 *
782
 * @since 3.4.0
783
 */
784
function wc_current_user_is_active() {
785
	if ( ! is_user_logged_in() ) {
786
		return;
787
	}
788
	wc_update_user_last_active( get_current_user_id() );
789
}
790
add_action( 'wp', 'wc_current_user_is_active', 10 );
791
792
/**
793
 * Set the user last active timestamp to now.
794
 *
795
 * @since 3.4.0
796
 * @param int $user_id User ID to mark active.
797
 */
798
function wc_update_user_last_active( $user_id ) {
799
	if ( ! $user_id ) {
800
		return;
801
	}
802
	update_user_meta( $user_id, 'wc_last_active', (string) strtotime( date( 'Y-m-d', current_time( 'timestamp', true ) ) ) );
803
}
804