Completed
Push — master ( fc6097...930cc3 )
by Mike
08:01
created

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

Complexity

Conditions 1
Paths 1

Size

Total Lines 26
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 8
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 26
rs 8.8571
1
<?php
2
/**
3
 * WooCommerce Customer Functions
4
 *
5
 * Functions for customers.
6
 *
7
 * @author 		WooThemes
8
 * @category 	Core
9
 * @package 	WooCommerce/Functions
10
 * @version 	2.2.0
11
 */
12
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit; // Exit if accessed directly
15
}
16
17
/**
18
 * Prevent any user who cannot 'edit_posts' (subscribers, customers etc) from seeing the admin bar.
19
 *
20
 * Note: get_option( 'woocommerce_lock_down_admin', true ) is a deprecated option here for backwards compat. Defaults to true.
21
 *
22
 * @access public
23
 * @param bool $show_admin_bar
24
 * @return bool
25
 */
26
function wc_disable_admin_bar( $show_admin_bar ) {
27
	if ( apply_filters( 'woocommerce_disable_admin_bar', get_option( 'woocommerce_lock_down_admin', 'yes' ) === 'yes' ) && ! ( current_user_can( 'edit_posts' ) || current_user_can( 'manage_woocommerce' ) ) ) {
28
		$show_admin_bar = false;
29
	}
30
31
	return $show_admin_bar;
32
}
33
add_filter( 'show_admin_bar', 'wc_disable_admin_bar', 10, 1 );
34
35
if ( ! function_exists( 'wc_create_new_customer' ) ) {
36
37
	/**
38
	 * Create a new customer.
39
	 *
40
	 * @param  string $email Customer email.
41
	 * @param  string $username Customer username.
42
	 * @param  string $password Customer password.
43
	 * @return int|WP_Error Returns WP_Error on failure, Int (user ID) on success.
44
	 */
45
	function wc_create_new_customer( $email, $username = '', $password = '' ) {
46
47
		// Check the email address.
48
		if ( empty( $email ) || ! is_email( $email ) ) {
49
			return new WP_Error( 'registration-error-invalid-email', __( 'Please provide a valid email address.', 'woocommerce' ) );
50
		}
51
52
		if ( email_exists( $email ) ) {
53
			return new WP_Error( 'registration-error-email-exists', __( 'An account is already registered with your email address. Please login.', 'woocommerce' ) );
54
		}
55
56
		// Handle username creation.
57
		if ( 'no' === get_option( 'woocommerce_registration_generate_username' ) || ! empty( $username ) ) {
58
			$username = sanitize_user( $username );
59
60
			if ( empty( $username ) || ! validate_username( $username ) ) {
61
				return new WP_Error( 'registration-error-invalid-username', __( 'Please enter a valid account username.', 'woocommerce' ) );
62
			}
63
64
			if ( username_exists( $username ) ) {
65
				return new WP_Error( 'registration-error-username-exists', __( 'An account is already registered with that username. Please choose another.', 'woocommerce' ) );
66
			}
67
		} else {
68
			$username = sanitize_user( current( explode( '@', $email ) ), true );
69
70
			// Ensure username is unique.
71
			$append     = 1;
72
			$o_username = $username;
73
74
			while ( username_exists( $username ) ) {
75
				$username = $o_username . $append;
76
				$append++;
77
			}
78
		}
79
80
		// Handle password creation.
81
		if ( 'yes' === get_option( 'woocommerce_registration_generate_password' ) && empty( $password ) ) {
82
			$password           = wp_generate_password();
83
			$password_generated = true;
84
		} elseif ( empty( $password ) ) {
85
			return new WP_Error( 'registration-error-missing-password', __( 'Please enter an account password.', 'woocommerce' ) );
86
		} else {
87
			$password_generated = false;
88
		}
89
90
		// Use WP_Error to handle registration errors.
91
		$errors = new WP_Error();
92
93
		do_action( 'woocommerce_register_post', $username, $email, $errors );
94
95
		$errors = apply_filters( 'woocommerce_registration_errors', $errors, $username, $email );
96
97
		if ( $errors->get_error_code() ) {
98
			return $errors;
99
		}
100
101
		$new_customer_data = apply_filters( 'woocommerce_new_customer_data', array(
102
			'user_login' => $username,
103
			'user_pass'  => $password,
104
			'user_email' => $email,
105
			'role'       => 'customer',
106
		) );
107
108
		$customer_id = wp_insert_user( $new_customer_data );
109
110
		if ( is_wp_error( $customer_id ) ) {
111
			return new WP_Error( 'registration-error', '<strong>' . __( 'ERROR', 'woocommerce' ) . '</strong>: ' . __( 'Couldn&#8217;t register you&hellip; please contact us if you continue to have problems.', 'woocommerce' ) );
112
		}
113
114
		do_action( 'woocommerce_created_customer', $customer_id, $new_customer_data, $password_generated );
115
116
		return $customer_id;
117
	}
118
}
119
120
/**
121
 * Login a customer (set auth cookie and set global user object).
122
 *
123
 * @param int $customer_id
124
 */
125
function wc_set_customer_auth_cookie( $customer_id ) {
126
	global $current_user;
127
128
	$current_user = get_user_by( 'id', $customer_id );
129
130
	wp_set_auth_cookie( $customer_id, true );
131
}
132
133
/**
134
 * Get past orders (by email) and update them.
135
 *
136
 * @param  int $customer_id
137
 * @return int
138
 */
139
function wc_update_new_customer_past_orders( $customer_id ) {
140
	$linked          = 0;
141
	$complete        = 0;
142
	$customer        = get_user_by( 'id', absint( $customer_id ) );
143
	$customer_orders = wc_get_orders( array(
144
		'limit'    => -1,
145
		'customer' => array( array( 0, $customer->user_email ) ),
146
		'return'   => 'ids',
147
	) );
148
149
	if ( ! empty( $customer_orders ) ) {
150
		foreach ( $customer_orders as $order_id ) {
0 ignored issues
show
Bug introduced by
The expression $customer_orders of type array|object<stdClass> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
151
			update_post_meta( $order_id, '_customer_user', $customer->ID );
152
153
			do_action( 'woocommerce_update_new_customer_past_order', $order_id, $customer );
154
155
			if ( get_post_status( $order_id ) === 'wc-completed' ) {
156
				$complete++;
157
			}
158
159
			$linked++;
160
		}
161
	}
162
163
	if ( $complete ) {
164
		update_user_meta( $customer_id, 'paying_customer', 1 );
165
		update_user_meta( $customer_id, '_order_count', '' );
166
		update_user_meta( $customer_id, '_money_spent', '' );
167
	}
168
169
	return $linked;
170
}
171
172
/**
173
 * Order Status completed - This is a paying customer.
174
 *
175
 * @access public
176
 * @param int $order_id
177
 */
178
function wc_paying_customer( $order_id ) {
179
	$order = wc_get_order( $order_id );
180
181
	if ( $order->user_id > 0 && 'refund' !== $order->order_type ) {
182
		update_user_meta( $order->user_id, 'paying_customer', 1 );
183
184
		$old_spent = absint( get_user_meta( $order->user_id, '_money_spent', true ) );
185
		update_user_meta( $order->user_id, '_money_spent', $old_spent + $order->order_total );
186
	}
187
	if ( $order->user_id > 0 && 'simple' === $order->order_type ) {
188
		$old_count = absint( get_user_meta( $order->user_id, '_order_count', true ) );
189
		update_user_meta( $order->user_id, '_order_count', $old_count + 1 );
190
	}
191
}
192
add_action( 'woocommerce_order_status_completed', 'wc_paying_customer' );
193
194
/**
195
 * Checks if a user (by email or ID or both) has bought an item.
196
 * @param string $customer_email
197
 * @param int $user_id
198
 * @param int $product_id
199
 * @return bool
200
 */
201
function wc_customer_bought_product( $customer_email, $user_id, $product_id ) {
202
	global $wpdb;
203
204
	$transient_name = 'wc_cbp_' . md5( $customer_email . $user_id . WC_Cache_Helper::get_transient_version( 'orders' ) );
205
206
	if ( false === ( $result = get_transient( $transient_name ) ) ) {
207
		$customer_data = array( $user_id );
208
209
		if ( $user_id ) {
210
			$user = get_user_by( 'id', $user_id );
211
212
			if ( isset( $user->user_email ) ) {
213
				$customer_data[] = $user->user_email;
214
			}
215
		}
216
217
		if ( is_email( $customer_email ) ) {
218
			$customer_data[] = $customer_email;
219
		}
220
221
		$customer_data = array_map( 'esc_sql', array_filter( array_unique( $customer_data ) ) );
222
223
		if ( sizeof( $customer_data ) == 0 ) {
224
			return false;
225
		}
226
227
		$result = $wpdb->get_col( "
228
			SELECT im.meta_value FROM {$wpdb->posts} AS p
229
			INNER JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id
230
			INNER JOIN {$wpdb->prefix}woocommerce_order_items AS i ON p.ID = i.order_id
231
			INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS im ON i.order_item_id = im.order_item_id
232
			WHERE p.post_status IN ( 'wc-completed', 'wc-processing' )
233
			AND pm.meta_key IN ( '_billing_email', '_customer_user' )
234
			AND im.meta_key IN ( '_product_id', '_variation_id' )
235
			AND im.meta_value != 0
236
			AND pm.meta_value IN ( '" . implode( "','", $customer_data ) . "' )
237
		" );
238
		$result = array_map( 'absint', $result );
239
240
		set_transient( $transient_name, $result, DAY_IN_SECONDS * 30 );
241
	}
242
	return in_array( absint( $product_id ), $result );
243
}
244
245
/**
246
 * Checks if a user has a certain capability.
247
 *
248
 * @access public
249
 * @param array $allcaps
250
 * @param array $caps
251
 * @param array $args
252
 * @return bool
253
 */
254
function wc_customer_has_capability( $allcaps, $caps, $args ) {
255
	if ( isset( $caps[0] ) ) {
256
		switch ( $caps[0] ) {
257 View Code Duplication
			case 'view_order' :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
258
				$user_id = $args[1];
259
				$order   = wc_get_order( $args[2] );
260
261
				if ( $order && $user_id == $order->user_id ) {
262
					$allcaps['view_order'] = true;
263
				}
264
			break;
265
			case 'pay_for_order' :
266
				$user_id  = $args[1];
267
				$order_id = isset( $args[2] ) ? $args[2] : null;
268
269
				// When no order ID, we assume it's a new order
270
				// and thus, customer can pay for it
271
				if ( ! $order_id ) {
272
					$allcaps['pay_for_order'] = true;
273
					break;
274
				}
275
276
				$order = wc_get_order( $order_id );
277
				if ( $user_id == $order->user_id || empty( $order->user_id ) ) {
278
					$allcaps['pay_for_order'] = true;
279
				}
280
			break;
281 View Code Duplication
			case 'order_again' :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
282
				$user_id = $args[1];
283
				$order   = wc_get_order( $args[2] );
284
285
				if ( $user_id == $order->user_id ) {
286
					$allcaps['order_again'] = true;
287
				}
288
			break;
289 View Code Duplication
			case 'cancel_order' :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
290
				$user_id = $args[1];
291
				$order   = wc_get_order( $args[2] );
292
293
				if ( $user_id == $order->user_id ) {
294
					$allcaps['cancel_order'] = true;
295
				}
296
			break;
297
			case 'download_file' :
298
				$user_id  = $args[1];
299
				$download = $args[2];
300
301
				if ( $user_id == $download->user_id ) {
302
					$allcaps['download_file'] = true;
303
				}
304
			break;
305
		}
306
	}
307
	return $allcaps;
308
}
309
add_filter( 'user_has_cap', 'wc_customer_has_capability', 10, 3 );
310
311
/**
312
 * Modify the list of editable roles to prevent non-admin adding admin users.
313
 * @param  array $roles
314
 * @return array
315
 */
316
function wc_modify_editable_roles( $roles ){
317
	if ( ! current_user_can( 'administrator' ) ) {
318
		unset( $roles[ 'administrator' ] );
319
	}
320
    return $roles;
321
}
322
add_filter( 'editable_roles', 'wc_modify_editable_roles' );
323
324
/**
325
 * Modify capabiltiies to prevent non-admin users editing admin users.
326
 *
327
 * $args[0] will be the user being edited in this case.
328
 *
329
 * @param  array $caps Array of caps
330
 * @param  string $cap Name of the cap we are checking
331
 * @param  int $user_id ID of the user being checked against
332
 * @param  array $args
333
 * @return array
334
 */
335
function wc_modify_map_meta_cap( $caps, $cap, $user_id, $args ) {
336
	switch ( $cap ) {
337
		case 'edit_user' :
338
		case 'remove_user' :
339
		case 'promote_user' :
340
		case 'delete_user' :
341
			if ( ! isset( $args[0] ) || $args[0] === $user_id ) {
342
				break;
343
			} else {
344
				if ( user_can( $args[0], 'administrator' ) && ! current_user_can( 'administrator' ) ) {
345
					$caps[] = 'do_not_allow';
346
				}
347
			}
348
		break;
349
	}
350
	return $caps;
351
}
352
add_filter( 'map_meta_cap', 'wc_modify_map_meta_cap', 10, 4 );
353
354
/**
355
 * Get customer download permissions from the database.
356
 *
357
 * @param int $customer_id Customer/User ID
358
 * @return array
359
 */
360
function wc_get_customer_download_permissions( $customer_id ) {
361
	global $wpdb;
362
363
	return apply_filters( 'woocommerce_permission_list', $wpdb->get_results(
364
		$wpdb->prepare( "
365
			SELECT * FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions as permissions
366
			WHERE user_id = %d
367
			AND permissions.order_id > 0
368
			AND
369
				(
370
					permissions.downloads_remaining > 0
371
					OR permissions.downloads_remaining = ''
372
				)
373
			AND
374
				(
375
					permissions.access_expires IS NULL
376
					OR permissions.access_expires >= %s
377
					OR permissions.access_expires = '0000-00-00 00:00:00'
378
				)
379
			ORDER BY permissions.order_id, permissions.product_id, permissions.permission_id;
380
			",
381
			$customer_id,
382
			date( 'Y-m-d', current_time( 'timestamp' ) )
383
		)
384
	), $customer_id );
385
}
386
387
/**
388
 * Get customer available downloads.
389
 *
390
 * @param int $customer_id Customer/User ID
391
 * @return array
392
 */
393
function wc_get_customer_available_downloads( $customer_id ) {
394
	$downloads   = array();
395
	$_product    = null;
396
	$order       = null;
397
	$file_number = 0;
398
399
	// Get results from valid orders only
400
	$results = wc_get_customer_download_permissions( $customer_id );
401
402
	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...
403
		foreach ( $results as $result ) {
404
			if ( ! $order || $order->id != $result->order_id ) {
405
				// new order
406
				$order    = wc_get_order( $result->order_id );
407
				$_product = null;
408
			}
409
410
			// Make sure the order exists for this download
411
			if ( ! $order ) {
412
				continue;
413
			}
414
415
			// Downloads permitted?
416
			if ( ! $order->is_download_permitted() ) {
417
				continue;
418
			}
419
420
			$product_id = intval( $result->product_id );
421
422
			if ( ! $_product || $_product->id != $product_id ) {
423
				// new product
424
				$file_number = 0;
425
				$_product    = wc_get_product( $product_id );
426
			}
427
428
			// Check product exists and has the file
429
			if ( ! $_product || ! $_product->exists() || ! $_product->has_file( $result->download_id ) ) {
430
				continue;
431
			}
432
433
			$download_file = $_product->get_file( $result->download_id );
434
435
			// Download name will be 'Product Name' for products with a single downloadable file, and 'Product Name - File X' for products with multiple files
436
			$download_name = apply_filters(
437
				'woocommerce_downloadable_product_name',
438
				$_product->get_title() . ' &ndash; ' . $download_file['name'],
439
				$_product,
440
				$result->download_id,
441
				$file_number
442
			);
443
444
			$downloads[] = array(
445
				'download_url'        => add_query_arg(
446
					array(
447
						'download_file' => $product_id,
448
						'order'         => $result->order_key,
449
						'email'         => $result->user_email,
450
						'key'           => $result->download_id
451
					),
452
					home_url( '/' )
453
				),
454
				'download_id'         => $result->download_id,
455
				'product_id'          => $product_id,
456
				'download_name'       => $download_name,
457
				'order_id'            => $order->id,
458
				'order_key'           => $order->order_key,
459
				'downloads_remaining' => $result->downloads_remaining,
460
				'access_expires' 	  => $result->access_expires,
461
				'file'                => $download_file
462
			);
463
464
			$file_number++;
465
		}
466
	}
467
468
	return $downloads;
469
}
470
471
/**
472
 * Get total spent by customer.
473
 * @param  int $user_id
474
 * @return string
475
 */
476
function wc_get_customer_total_spent( $user_id ) {
477
	$spent = get_user_meta( $user_id, '_money_spent', true );
478
	if ( '' === $spent ) {
479
		global $wpdb;
480
481
		$spent = $wpdb->get_var( "SELECT SUM(meta2.meta_value)
482
			FROM $wpdb->posts as posts
483
484
			LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id
485
			LEFT JOIN {$wpdb->postmeta} AS meta2 ON posts.ID = meta2.post_id
486
487
			WHERE   meta.meta_key       = '_customer_user'
488
			AND     meta.meta_value     = $user_id
489
			AND     posts.post_type     IN ('" . implode( "','", wc_get_order_types( 'reports' ) ) . "')
490
			AND     posts.post_status   IN ( 'wc-completed', 'wc-processing' )
491
			AND     meta2.meta_key      = '_order_total'
492
		" );
493
494
		update_user_meta( $user_id, '_money_spent', $spent );
495
	}
496
497
	return $spent;
498
}
499
500
/**
501
 * Get total orders by customer.
502
 * @param  int $user_id
503
 * @return int
504
 */
505
function wc_get_customer_order_count( $user_id ) {
506
	$count = get_user_meta( $user_id, '_order_count', true );
507
	if ( '' === $count ) {
508
		global $wpdb;
509
510
		$count = $wpdb->get_var( "SELECT COUNT(*)
511
			FROM $wpdb->posts as posts
512
513
			LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id
514
515
			WHERE   meta.meta_key       = '_customer_user'
516
			AND     posts.post_type     IN ('" . implode( "','", wc_get_order_types( 'order-count' ) ) . "')
517
			AND     posts.post_status   IN ('" . implode( "','", array_keys( wc_get_order_statuses() ) )  . "')
518
			AND     meta_value          = $user_id
519
		" );
520
521
		update_user_meta( $user_id, '_order_count', absint( $count ) );
522
	}
523
524
	return absint( $count );
525
}
526
527
/**
528
 * Reset _customer_user on orders when a user is deleted.
529
 * @param int $user_id
530
 */
531
function wc_reset_order_customer_id_on_deleted_user( $user_id ) {
532
	global $wpdb;
533
534
	$wpdb->update( $wpdb->postmeta, array( 'meta_value' => 0 ), array( 'meta_key' => '_customer_user', 'meta_value' => $user_id ) );
535
}
536
537
add_action( 'deleted_user', 'wc_reset_order_customer_id_on_deleted_user' );
538
539
/**
540
 * Get review verification status.
541
 * @param  int $comment_id
542
 * @return bool
543
 */
544
function wc_review_is_from_verified_owner( $comment_id ) {
545
	$verified = get_comment_meta( $comment_id, 'verified', true );
546
547
	// If no "verified" meta is present, generate it (if this is a product review).
548
	if ( '' === $verified ) {
549
		$verified = WC_Comments::add_comment_purchase_verification( $comment_id );
550
	}
551
552
	return (bool) $verified;
553
}
554
555
/**
556
 * Disable author archives for customers.
557
 *
558
 * @since 2.5.0
559
 */
560
function wc_disable_author_archives_for_customers() {
561
	global $wp_query, $author;
562
563
	if ( is_author() ) {
564
		$user = get_user_by( 'id', $author );
565
566
		if ( isset( $user->roles[0] ) && 'customer' === $user->roles[0] ) {
567
			wp_redirect( wc_get_page_permalink( 'shop' ) );
568
		}
569
	}
570
}
571
572
add_action( 'template_redirect', 'wc_disable_author_archives_for_customers' );
573
574
/**
575
 * Hooks into the `profile_update` hook to set the user last updated timestamp.
576
 *
577
 * @since 2.6.0
578
 * @param int   $user_id The user that was updated.
579
 * @param array $old     The profile fields pre-change.
580
 */
581
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...
582
	wc_set_user_last_update_time( $user_id );
583
}
584
585
add_action( 'profile_update', 'wc_update_profile_last_update_time', 10, 2 );
586
587
/**
588
 * Hooks into the update user meta function to set the user last updated timestamp.
589
 *
590
 * @since 2.6.0
591
 * @param int    $meta_id     ID of the meta object that was changed.
592
 * @param int    $user_id     The user that was updated.
593
 * @param string $meta_key    Name of the meta key that was changed.
594
 * @param string $_meta_value Value of the meta that was changed.
595
 */
596
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...
597
	$keys_to_track = apply_filters( 'woocommerce_user_last_update_fields', array( 'first_name', 'last_name' ) );
598
	$update_time   = false;
599
	if ( in_array( $meta_key, $keys_to_track ) ) {
600
		$update_time = true;
601
	}
602
	if ( 'billing_' === substr( $meta_key, 0, 8 ) ) {
603
		$update_time = true;
604
	}
605
	if ( 'shipping_' === substr( $meta_key, 0, 9 ) ) {
606
		$update_time = true;
607
	}
608
609
	if ( $update_time ) {
610
		wc_set_user_last_update_time( $user_id );
611
	}
612
}
613
614
add_action( 'update_user_meta', 'wc_meta_update_last_update_time', 10, 4 );
615
616
/**
617
 * Sets a user's "last update" time to the current timestamp.
618
 *
619
 * @since 2.6.0
620
 * @param int $user_id The user to set a timestamp for.
621
 */
622
function wc_set_user_last_update_time( $user_id ) {
623
	update_user_meta( $user_id, 'last_update', time() );
624
}
625
626
/**
627
 * Get customer saved payment methods list.
628
 *
629
 * @since 2.6.0
630
 * @param int $customer_id
631
 * @return array
632
 */
633
function wc_get_customer_saved_methods_list( $customer_id ) {
634
	return apply_filters( 'woocommerce_saved_payment_methods_list', array(), $customer_id );
635
}
636
637
/**
638
 * Get info about customer's last order.
639
 *
640
 * @since 2.6.0
641
 * @param int $customer_id Customer ID.
642
 * @return WC_Order Order object if successful or false.
643
 */
644
function wc_get_customer_last_order( $customer_id ) {
645
	global $wpdb;
646
647
	$customer_id = absint( $customer_id );
648
649
	$id = $wpdb->get_var( "SELECT id
650
		FROM $wpdb->posts AS posts
651
		LEFT JOIN {$wpdb->postmeta} AS meta on posts.ID = meta.post_id
652
		WHERE meta.meta_key = '_customer_user'
653
		AND   meta.meta_value = {$customer_id}
654
		AND   posts.post_type = 'shop_order'
655
		AND   posts.post_status IN ( '" . implode( "','", array_keys( wc_get_order_statuses() ) ) . "' )
656
		ORDER BY posts.ID DESC
657
	" );
658
659
	return wc_get_order( $id );
660
}
661
662
/**
663
 * Wrapper for @see get_avatar() which doesn't simply return
664
 * the URL so we need to pluck it from the HTML img tag.
665
 *
666
 * Kudos to https://github.com/WP-API/WP-API for offering a better solution.
667
 *
668
 * @since 2.6.0
669
 * @param string $email the customer's email.
670
 * @return string the URL to the customer's avatar.
671
 */
672 View Code Duplication
function wc_get_customer_avatar_url( $email ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
673
	$avatar_html = get_avatar( $email );
674
675
	// Get the URL of the avatar from the provided HTML.
676
	preg_match( '/src=["|\'](.+)[\&|"|\']/U', $avatar_html, $matches );
677
678
	if ( isset( $matches[1] ) && ! empty( $matches[1] ) ) {
679
		return esc_url_raw( $matches[1] );
680
	}
681
682
	return null;
683
}
684