PluginProbe
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments / 4.3.1
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments v4.3.1
4.7.2 4.7.1 4.7.0 4.6.6 4.6.5 4.6.4 4.6.3 4.6.2 4.6.1 4.6.0 4.5.1 4.5.0 4.4.2 4.4.1 4.4.0 4.3.3 4.3.2 4.3.1 4.3.0 4.2.3 4.2.2 4.2.1 1.0.3 1.0.4 1.0.5 All 281 releases
surecart / app / src / Models / User.php
User.php
697 lines 14.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace SureCart\Models;
3
4 use ArrayAccess;
5 use JsonSerializable;
6 use SureCart\Models\Traits\SyncsCustomer;
7 use WP_Error;
8
9 /**
10 * User class.
11 */
12 class User implements ArrayAccess, JsonSerializable {
13 use SyncsCustomer;
14
15 /**
16 * Holds the user.
17 *
18 * @var \WP_User|null;
19 */
20 protected $user;
21
22 /**
23 * Holds the customer
24 *
25 * @var \SureCart\Models\Customer;
26 */
27 protected $customer;
28
29 /**
30 * Stores the customer id key.
31 *
32 * @var string
33 */
34 protected $customer_id_key = 'sc_customer_ids';
35
36 /**
37 * Get the customer meta key.
38 *
39 * @return string
40 */
41 protected function getCustomerMetaKey() {
42 return $this->customer_id_key;
43 }
44
45 /**
46 * Get the user's customer id.
47 *
48 * @param string $mode Customer mode.
49 *
50 * @return int|null
51 */
52 protected function customerId( $mode = 'live' ) {
53 if ( empty( $this->user->ID ) ) {
54 return null;
55 }
56 $meta = (array) get_user_meta( $this->user->ID, $this->customer_id_key, true );
57 if ( isset( $meta[ $mode ] ) ) {
58 return $meta[ $mode ];
59 }
60 if ( isset( $meta[0] ) ) {
61 return $meta[0];
62 }
63 return null;
64 }
65
66 /**
67 * Sync the customer ids.
68 *
69 * @return array Array of synced items.
70 */
71 protected function syncCustomerIds() {
72 // syncing disabled.
73 if ( ! $this->shouldSyncCustomer() ) {
74 return false;
75 }
76
77 // get all customers by email address (live and test).
78 $customers = Customer::where(
79 [
80 'email' => strtolower( $this->user->user_email ),
81 ]
82 )->get();
83
84 if ( is_wp_error( $customers ) ) {
85 return $customers;
86 }
87
88 // we have customers.
89 $live_customer = current(
90 array_filter(
91 $customers,
92 function ( $customer ) {
93 return $customer->live_mode;
94 }
95 )
96 );
97
98 $test_customer = current(
99 array_filter(
100 $customers,
101 function ( $customer ) {
102 return ! $customer->live_mode;
103 }
104 )
105 );
106
107 if ( empty( $live_customer->id ) ) {
108 $live_customer = Customer::create(
109 [
110 'name' => $this->user->display_name,
111 'email' => strtolower( $this->user->user_email ),
112 'live_mode' => true,
113 ],
114 false // don't create a user.
115 );
116 }
117 if ( empty( $test_customer->id ) ) {
118 $test_customer = Customer::create(
119 [
120 'name' => $this->user->display_name,
121 'email' => strtolower( $this->user->user_email ),
122 'live_mode' => false,
123 ],
124 false // don't create a user.
125 );
126 }
127
128 if ( ! empty( $live_customer->id ) ) {
129 $this->setCustomerId( $live_customer->id, 'live' );
130 }
131 if ( ! empty( $test_customer->id ) ) {
132 $this->setCustomerId( $test_customer->id, 'test' );
133 }
134
135 return [
136 'live' => $this->customerId( 'live' ),
137 'test' => $this->customerId( 'test' ),
138 ];
139 }
140
141 /**
142 * List the users customer ids.
143 *
144 * @return array
145 */
146 protected function customerIds() {
147 if ( empty( $this->user->ID ) ) {
148 return [];
149 }
150 return array_filter( (array) get_user_meta( $this->user->ID, $this->customer_id_key, true ) );
151 }
152
153 /**
154 * Is this user a customer?
155 *
156 * @return boolean
157 */
158 protected function isCustomer() {
159 return ! empty( array_filter( (array) $this->customerIds() ) );
160 }
161
162 /**
163 * Does the user have this customer id?
164 *
165 * @param string $id The customer id.
166 *
167 * @return boolean
168 */
169 protected function hasCustomerId( $id ) {
170 foreach ( (array) $this->customerIds() as $saved_id ) {
171 if ( $saved_id === $id ) {
172 return true;
173 }
174 }
175 return false;
176 }
177
178 /**
179 * Set the customer id in the user meta.
180 *
181 * @param string $id Customer id.
182 * @return $this|bool
183 */
184 protected function setCustomerId( $id, $mode = 'live', $force = false ) {
185 $meta = (array) get_user_meta( $this->user->ID, $this->customer_id_key, true );
186
187 // if we are setting something here.
188 if ( ! empty( $id ) ) {
189 // if they already have one set for this mode.
190 if ( ! empty( $meta[ $mode ] ) ) {
191 // if we have not passed force = true.
192 if ( ! $force ) {
193 return new \WP_Error( 'already_linked', __( 'This user is already linked to a customer.', 'surecart' ) );
194 }
195 }
196 }
197
198 // update id.
199 $meta[ $mode ] = $id;
200 // update meta.
201 update_user_meta( $this->user->ID, $this->customer_id_key, $meta );
202 return $this;
203 }
204
205 /**
206 * Remove the the customer id from the user meta.
207 *
208 * @param string $mode Customer mode.
209 * @return $this
210 */
211 protected function removeCustomerId( $mode = 'live' ) {
212 $meta = (array) get_user_meta( $this->user->ID, $this->customer_id_key, true );
213
214 // if we are setting something here.
215 if ( ! empty( $meta[ $mode ] ) ) {
216 // set mode empty.
217 unset( $meta[ $mode ] );
218 }
219
220 // update meta.
221 update_user_meta( $this->user->ID, $this->customer_id_key, $meta );
222
223 // return this.
224 return $this;
225 }
226
227 /**
228 * Find an existing live customer by email and link it to this user.
229 *
230 * @return string|null|WP_Error Customer ID if found and linked, null if not found, WP_Error on failure.
231 */
232 protected function findAndLinkLiveCustomerByEmail() {
233 $email = strtolower( $this->user->user_email );
234
235 // Try to find an existing customer by email.
236 $existing_customer = Customer::where(
237 [
238 'email' => $email,
239 'live_mode' => true,
240 ]
241 )->first();
242
243 // No customer found or error occurred.
244 if ( is_wp_error( $existing_customer ) || empty( $existing_customer->id ) ) {
245 return null;
246 }
247
248 // Link the existing customer to this user.
249 $linked = $this->setCustomerId( $existing_customer->id, 'live' );
250 if ( is_wp_error( $linked ) ) {
251 return $linked;
252 }
253
254 return $existing_customer->id;
255 }
256
257 /**
258 * Create a new live customer and link it to this user.
259 *
260 * @return string|WP_Error Customer ID on success, WP_Error on failure.
261 */
262 protected function createAndLinkLiveCustomer() {
263 $email = strtolower( $this->user->user_email );
264
265 $customer = Customer::create(
266 [
267 'name' => $this->user->display_name,
268 'email' => $email,
269 'live_mode' => true,
270 ],
271 false
272 );
273
274 if ( is_wp_error( $customer ) ) {
275 return $customer;
276 }
277
278 $customer_id = $customer->id ?? null;
279 if ( empty( $customer_id ) ) {
280 return new WP_Error(
281 'sc_no_customer_created',
282 __( 'Sorry, no customer is being created, please contact with admin.', 'surecart' )
283 );
284 }
285
286 $linked = $this->setCustomerId( $customer_id, 'live' );
287 if ( is_wp_error( $linked ) ) {
288 return $linked;
289 }
290
291 return $customer_id;
292 }
293
294 /**
295 * Get or create the live customer id for this user.
296 *
297 * This method first checks for an existing linked customer ID,
298 * then tries to find and link an existing customer by email,
299 * and finally creates a new customer if none is found.
300 *
301 * @return string|null|WP_Error Customer ID on success, WP_Error on failure.
302 */
303 protected function getOrCreateLiveCustomerId() {
304 // Check for already linked customer.
305 $customer_id = $this->customerId( 'live' );
306 if ( ! empty( $customer_id ) ) {
307 return $customer_id;
308 }
309
310 // Try to find and link existing customer by email.
311 $found_customer_id = $this->findAndLinkLiveCustomerByEmail();
312 if ( is_wp_error( $found_customer_id ) ) {
313 return $found_customer_id;
314 }
315 if ( ! empty( $found_customer_id ) ) {
316 return $found_customer_id;
317 }
318
319 // No existing customer found, create a new one.
320 return $this->createAndLinkLiveCustomer();
321 }
322
323 /**
324 * Disallow overriding the constructor in child classes and make the code safe that way.
325 */
326 final public function __construct() {
327 }
328
329 /**
330 * Get a user's subscriptions
331 *
332 * @return mixed
333 */
334 protected function subscriptions() {
335 return Subscription::where( [ 'customer_ids' => [ $this->customerId() ] ] );
336 }
337
338 /**
339 * Get a users orders
340 *
341 * @param array $query Query args.
342 * @return SureCart\Models\Order[];
343 */
344 protected function orders() {
345 return Order::where( [ 'customer_ids' => [ $this->customerId() ] ] );
346 }
347
348 /**
349 * Login the user.
350 *
351 * @return true|\WP_Error
352 */
353 protected function login() {
354 if ( empty( $this->user->ID ) ) {
355 return new WP_Error( 'not_found', esc_html__( 'This user could not be found.', 'surecart' ) );
356 }
357
358 clean_user_cache( $this->user->ID );
359 if ( class_exists( \WP_Session_Tokens::class ) ) {
360 \WP_Session_Tokens::get_instance( $this->user->ID )->destroy_all();
361 }
362 wp_set_current_user( $this->user->ID );
363 wp_set_auth_cookie( $this->user->ID );
364 update_user_caches( $this->user );
365
366 return true;
367 }
368
369 /**
370 * Create a new user and return this model context
371 * If the user already exists, just set the customer and role in that case.
372 */
373 protected function create( $args ) {
374 $args = wp_parse_args(
375 $args,
376 [
377 'user_name' => '',
378 'user_email' => '',
379 'user_password' => '',
380 'first_name' => '',
381 'last_name' => '',
382 ]
383 );
384
385 // use the username or the email as a fallback.
386 $name = ! empty( sanitize_user( $args['user_name'], true ) ) ? sanitize_user( $args['user_name'], true ) : $args['user_email'];
387 $username = $this->createUniqueUsername( sanitize_user( $name, true ) );
388
389 $user_password = trim( $args['user_password'] );
390 $user_created = false;
391
392 // password is not provided.
393 if ( empty( $user_password ) ) {
394 $user_password = wp_generate_password( 12, false );
395 $user_id = wp_create_user( sanitize_user( $username, true ), $user_password, $args['user_email'] );
396 // turn off this feature with a filter.
397 if ( apply_filters( 'surecart/default_password_nag', true, $user_id ) ) {
398 update_user_meta( $user_id, 'default_password_nag', true );
399 }
400 $user_created = true;
401 } else {
402 // Password has been provided.
403 $user_id = wp_create_user( sanitize_user( $username, true ), $user_password, $args['user_email'] );
404 $user_created = true;
405 }
406
407 if ( is_wp_error( $user_id ) ) {
408 return $user_id;
409 }
410
411 $user = new \WP_User( $user_id );
412 $user->add_role( 'sc_customer' );
413
414 if ( $args['first_name'] ) {
415 $user->first_name = $args['first_name'];
416 }
417 if ( $args['last_name'] ) {
418 $user->last_name = $args['last_name'];
419 }
420
421 if ( $user_created ) {
422 wp_update_user( $user );
423 }
424
425 return $this->find( $user_id );
426 }
427
428 /**
429 * Create a unique username for the user.
430 *
431 * @param string $name The username.
432 *
433 * @return string
434 */
435 protected function createUniqueUsername( $name ) {
436 $base_name = $name;
437 $i = 0;
438 while ( username_exists( $name ) ) {
439 $name = $base_name . ( ++$i );
440 }
441 return $name;
442 }
443
444 /**
445 * Retrieve user info by a given field
446 *
447 * @param string $field The field to retrieve the user with. id | ID | slug | email | login.
448 * @param int|string $value A value for $field. A user ID, slug, email address, or login name.
449 * @return this|false This object on success, false on failure.
450 */
451 protected function getUserBy( $field, $value ) {
452 $this->user = get_user_by( $field, $value ?? '' );
453 return $this->user ? $this : false;
454 }
455
456 /**
457 * Get the customer from the user.
458 *
459 * @return \SureCart\Models\Customer|false
460 */
461 protected function customer( $mode = 'live' ) {
462 $id = $this->customerId( $mode );
463 if ( ! $id ) {
464 return false;
465 }
466 return Customer::find( $this->customerId( $mode ) );
467 }
468
469 /**
470 * Get the current user
471 *
472 * @return $this
473 */
474 protected function current() {
475 $this->user = wp_get_current_user();
476 return $this;
477 }
478
479 /**
480 * Find the user.
481 *
482 * @param integer $id ID of the WordPress user.
483 * @return $this
484 */
485 protected function find( $id ) {
486 $this->user = get_user_by( 'id', $id );
487 return $this;
488 }
489
490 /**
491 * Find the user by customer id.
492 *
493 * @param string $id Customer id string.
494 * @return $this
495 */
496 protected function findByCustomerId( $id ) {
497 if ( ! is_string( $id ) || empty( $id ) ) {
498 return false;
499 }
500
501 $users = new \WP_User_Query(
502 [
503 'meta_query' => [
504 [
505 'key' => $this->customer_id_key,
506 'value' => $id,
507 'compare' => 'LIKE',
508 ],
509 ],
510 ]
511 );
512
513 if ( empty( $users->results ) ) {
514 return false;
515 }
516
517 $this->user = $users->results[0];
518 return $this;
519 }
520
521 /**
522 * Get the WordPress user.
523 *
524 * @return \WP_User|null;
525 */
526 public function getWPUser() {
527 return $this->user;
528 }
529
530 /**
531 * Get a specific attribute
532 *
533 * @param string $key Attribute name.
534 *
535 * @return mixed
536 */
537 public function getAttribute( $key ) {
538 $attribute = null;
539
540 if ( $this->hasAttribute( $key ) ) {
541 $attribute = $this->user->$key;
542 }
543
544 return $attribute;
545 }
546
547 /**
548 * Sets a user attribute
549 * Optionally calls a mutator based on set{Attribute}Attribute
550 *
551 * @param string $key Attribute key.
552 * @param mixed $value Attribute value.
553 *
554 * @return mixed|void
555 */
556 public function setAttribute( $key, $value ) {
557 $this->user->$key = $value;
558 }
559
560 /**
561 * Does it have the attribute
562 *
563 * @param string $key Attribute key.
564 *
565 * @return boolean
566 */
567 public function hasAttribute( $key ) {
568 return $this->user->$key ?? false;
569 }
570
571 /**
572 * Serialize to json.
573 *
574 * @return Array
575 */
576 #[\ReturnTypeWillChange]
577 public function jsonSerialize() {
578 return $this->user->to_array();
579 }
580
581 /**
582 * Get the attribute
583 *
584 * @param string $key Attribute name.
585 *
586 * @return mixed
587 */
588 public function __get( $key ) {
589 return $this->getAttribute( $key );
590 }
591
592 /**
593 * Set the attribute
594 *
595 * @param string $key Attribute name.
596 * @param mixed $value Value of attribute.
597 *
598 * @return void
599 */
600 public function __set( $key, $value ) {
601 $this->setAttribute( $key, $value );
602 }
603
604 /**
605 * Determine if the given attribute exists.
606 *
607 * @param mixed $offset Name.
608 * @return bool
609 */
610 public function offsetExists( $offset ): bool {
611 return ! is_null( $this->getAttribute( $offset ) );
612 }
613
614 /**
615 * Get the value for a given offset.
616 *
617 * @param mixed $offset Name.
618 * @return mixed
619 */
620 #[\ReturnTypeWillChange]
621 public function offsetGet( $offset ) {
622 return $this->getAttribute( $offset );
623 }
624
625 /**
626 * Set the value for a given offset.
627 *
628 * @param mixed $offset Name.
629 * @param mixed $value Value.
630 * @return void
631 */
632 public function offsetSet( $offset, $value ): void {
633 $this->setAttribute( $offset, $value );
634 }
635
636 /**
637 * Unset the value for a given offset.
638 *
639 * @param mixed $offset Name.
640 * @return void
641 */
642 public function offsetUnset( $offset ): void {
643 $this->user->$offset = null;
644 }
645
646 /**
647 * Get the user object.
648 *
649 * @return \WP_User|null
650 */
651 public function getUser() {
652 return $this->user;
653 }
654
655 /**
656 * Determine if an attribute or relation exists on the model.
657 *
658 * @param string $key Name.
659 * @return bool
660 */
661 public function __isset( $key ) {
662 return $this->offsetExists( $key );
663 }
664
665 /**
666 * Unset an attribute on the model.
667 *
668 * @param string $key Name.
669 * @return void
670 */
671 public function __unset( $key ) {
672 $this->offsetUnset( $key );
673 }
674
675 /**
676 * Forward call to method
677 *
678 * @param string $method Method to call.
679 * @param mixed $params Method params.
680 */
681 public function __call( $method, $params ) {
682 return call_user_func_array( [ $this, $method ], $params );
683 }
684
685 /**
686 * Static Facade Accessor
687 *
688 * @param string $method Method to call.
689 * @param mixed $params Method params.
690 *
691 * @return mixed
692 */
693 public static function __callStatic( $method, $params ) {
694 return call_user_func_array( [ new static(), $method ], $params );
695 }
696 }
697