PluginProbe
Lasso Lite – Affiliate Link Manager & Product Displays / 113
Lasso Lite – Affiliate Link Manager & Product Displays v113
158 157 155 156 154 153 152 151 150 149 148 trunk 0.9.9 104 105 106 107 108 109 110 111 112 113 114 115 All 57 releases
← All changes | classes/class-amazon-api.php +52 -669 158113 View file →
@@ -6,9 +6,8 @@
6 6 */
7 7
8 8 namespace LassoLite\Classes;
9 9
10 -use LassoLite\Admin\Constant;
11 10 use LassoLite\Classes\Affiliate_Link;
12 11 use LassoLite\Classes\Cache_Per_Process;
13 12 use LassoLite\Classes\Helper;
14 13 use LassoLite\Classes\Setting;
@@ -14,10 +13,8 @@
14 13 use LassoLite\Classes\Setting;
15 14
16 15 use LassoLite\Libs\Amazon_Api_V5\AwsV5;
17 16
18 -use LassoLite\Models\Amazon_Products;
19 -
20 17 /**
21 18 * Config
22 19 */
23 20 class Amazon_Api {
@@ -28,9 +25,8 @@
28 25 const SHORT_LINK_DOMAINS = array( 'amzn.com', 'amzn.to' );
29 26 const FILTER_AMAZON_PRODUCT = 'filter_amazon_product';
30 27 const TRACKING_ID_REGEX = '^[a-zA-Z0-9-]+-\d{2,3}$';
31 28 const CURRENCY_ISO = array( 'USD', 'AUD', 'CAD', 'EUR', 'MXN', 'CNY', 'JPY', 'INR', 'SEK', 'BRL', 'TRY', 'GBP', 'PLN', 'EGP', 'SGD', 'AED' );
32 - const VARIATION_PAGE_LIMIT = 2;
33 29
34 30 /**
35 31 * Get amazon API countries
36 32 */
@@ -400,9 +396,9 @@
400 396 * Check whether a url is amazon link or not
401 397 *
402 398 * @param string $url Url.
403 399 */
404 - public static function is_amazon_shortened_url( $url ) {
400 + public static function is_amazon_shortented_url( $url ) {
405 401 $is_amazon_url = self::is_amazon_url( $url );
406 402 $is_shortented_url = strpos( $url, 'amzn.to' ) || strpos( $url, 'amzn.com' );
407 403
408 404 return $is_amazon_url && $is_shortented_url;
@@ -457,38 +453,18 @@
457 453 * @param string $product_id Amazon product id.
458 454 * @param bool $store_product Store product into DB or not. Default to false.
459 455 * @param bool|string $updated_at Set date time or not. Default to false.
460 456 * @param string $amz_link Amazon link. Default to empty.
461 - * @param bool $url_version_param Is add version param to request api url to ignore cache. Default to false.
462 - * @param bool $force_bls Force fetch product from BLS or not. Default to false.
463 - * @param bool $refresh_image Bypass cache and fetch fresh product image/metadata. Default to false.
464 457 * @return mixed
465 458 */
466 - public function fetch_product_info( $product_id, $store_product = false, $updated_at = false, $amz_link = '', $url_version_param = false, $force_bls = false, $refresh_image = false ) {
459 + public function fetch_product_info( $product_id, $store_product = false, $updated_at = false, $amz_link = '' ) {
467 460 $lasso_db = new Lasso_DB();
468 461
469 462 $lasso_settings = Setting::get_settings();
470 463 $is_amazon_configured = $lasso_settings['amazon_access_key_id'] && $lasso_settings['amazon_secret_key'] && $lasso_settings['amazon_tracking_id'];
471 -
472 - if (
473 - self::is_amazon_creators_verified( $lasso_settings )
474 - && $this->is_same_domain( $amz_link )
475 - ) {
476 - $creators_result = $this->fetch_product_info_from_creators_api(
477 - $product_id,
478 - $store_product,
479 - $updated_at,
480 - $amz_link,
481 - $lasso_settings
482 - );
483 - if ( null !== $creators_result ) {
484 - return $creators_result;
485 - }
486 - }
487 -
488 - $result = ! $force_bls && $is_amazon_configured && $this->is_same_domain( $amz_link ) ? $this->get_product_by_id_v5( $product_id ) : false;
464 + $result = $is_amazon_configured && $this->is_same_domain( $amz_link ) ? $this->get_product_by_id_v5( $product_id ) : false;
489 465 // phpcs:ignore
490 - if ( is_object( $result ) && isset( $result->Errors[0] ) && (
466 + if ( isset( $result->Errors[0] ) && (
491 467 "The ItemId $product_id provided in the request is invalid." === $result->Errors[0]->Message // phpcs:ignore
492 468 || "The value [$product_id] provided in the request for ItemIds is invalid." === $result->Errors[0]->Message // phpcs:ignore
493 469 )
494 470 ) {
@@ -498,9 +474,9 @@
498 474 'full_item' => array(),
499 475 'status' => 'failed',
500 476 'error_code' => 'NotFound',
501 477 );
502 - } elseif ( is_object( $result ) && isset( $result->ItemsResult->Items[0] ) ) { // phpcs:ignore
478 + } elseif ( isset( $result->ItemsResult->Items[0] ) ) { // phpcs:ignore
503 479 $item = $result->ItemsResult->Items[0]; // phpcs:ignore
504 480
505 481 $product = $this->extract_search_result_v5( $item, true );
506 482 $product_url = $amz_link ? $amz_link : $product['url'];
@@ -506,19 +482,23 @@
506 482 $product_url = $amz_link ? $amz_link : $product['url'];
507 483 $product['status_code'] = 200;
508 484 $product['url'] = self::get_amazon_product_url( $product_url );
509 485
510 - // ? If $item->Offers is missing, we try to get the quantity from variation data
511 - if ( ! isset( $item->Offers ) ) { // phpcs:ignore
512 - sleep( 1 ); // ? Delay for a while before call the next request
513 - $variation_product = $this->get_product_variation( $product_id, $product_url );
514 - if ( $variation_product && isset( $variation_product['quantity'] ) && $variation_product['quantity'] ) {
515 - $product = $variation_product;
516 - }
486 + // ? Get Lasso ID
487 + $query = '
488 + SELECT post_id
489 + FROM ' . $lasso_db->postmeta . "
490 + WHERE meta_key = 'amazon_product_id' AND meta_value = '" . $product['product_id'] . "'
491 + ";
492 + $lasso_id = $lasso_db->get_var( $query );
493 + $product['lasso_id'] = ( isset( $lasso_id ) ) ? $lasso_id : 0;
494 +
495 + if ( $store_product ) {
496 + $amazon_tracking_id = Setting::get_setting( 'amazon_tracking_id', '' );
497 + $product['default_url'] = '' === $amazon_tracking_id ? $amz_link : $product['default_url'];
498 + $this->update_amazon_product_in_db( $product, $updated_at );
517 499 }
518 500
519 - $product = $this->enrich_fetched_amazon_product( $product, $store_product, $updated_at, $amz_link );
520 -
521 501 return array(
522 502 'product' => $product,
523 503 'api' => 'yes',
524 504 'full_item' => $item,
@@ -524,152 +504,20 @@
524 504 'full_item' => $item,
525 505 'status' => 'success',
526 506 'error_code' => '',
527 507 );
528 - } elseif ( '' !== $lasso_settings['license_serial'] || $force_bls ) {
529 - list( $product, $status ) = $this->fetch_product_from_bls( $product_id, $store_product, $updated_at, $amz_link, $url_version_param, $force_bls, $refresh_image );
530 -
531 - return array(
532 - 'product' => $product,
533 - 'api' => 'no',
534 - 'full_item' => array(),
535 - 'status' => 200 === $status ? 'success' : 'fail',
536 - 'error_code' => 404 === $status ? 'NotFound' : '',
537 - );
538 - }
539 -
540 - return array(
541 - 'product' => array(),
542 - 'api' => 'no',
543 - 'full_item' => array(),
544 - 'status' => 'failed',
545 - 'error_code' => 'NotFound',
546 - );
547 - }
548 -
549 - /**
550 - * Fetch amazon product from BLS (Lambda)
551 - *
552 - * @param string $product_id Amazon product id.
553 - * @param bool $store_product Store product into DB or not. Default to false.
554 - * @param bool|string $updated_at Set date time or not. Default to false.
555 - * @param string $amz_link Amazon link. Default to empty.
556 - * @param bool $url_version_param Is add version param to request api url to ignore cache. Default to false.
557 - * @param bool $force_bls Force fetch product from BLS or not. Default to false.
558 - * @param bool $refresh_image Bypass cache and fetch fresh product image/metadata. Default to false.
559 - */
560 - public function fetch_product_from_bls( $product_id, $store_product = false, $updated_at = false, $amz_link = '', $url_version_param = false, $force_bls = false, $refresh_image = false ) {
561 - $url = strpos( $amz_link, 'amazon.' ) !== false ? $amz_link : $this->get_amazon_link_by_product_id( $product_id, $amz_link );
562 - $m_link = self::get_amazon_product_url( $url );
563 - $url = self::get_amazon_product_url( $url, false );
564 -
565 - $amazon_product = array(
566 - 'title' => '',
567 - 'image' => '',
568 - 'url' => $m_link,
569 - 'price' => '',
570 - 'currency' => '',
571 - 'savings_amount' => 0,
572 - 'savings_percent' => 0,
573 - 'savings_basis' => 0,
574 - );
575 -
576 - try {
577 - $res = Helper::get_url_status_code_by_broken_link_service( $url, true, false, $url_version_param, $force_bls, $refresh_image );
578 - } catch ( \Throwable $e ) {
579 - $res = array(
580 - 'status_code' => 500,
581 - 'response' => null,
582 - );
583 - }
584 -
585 - $bls_response = ( isset( $res['response'] ) && is_object( $res['response'] ) ) ? $res['response'] : null;
586 - $bls_status = ( null !== $bls_response && isset( $bls_response->status ) ) ? intval( $bls_response->status ) : 0;
587 -
588 - if ( 200 === $res['status_code'] && 200 === $bls_status ) {
589 - $img_url = $bls_response->imgUrl ?? '';
590 - $img_url = '' !== $img_url ? $img_url : '';
591 - $product_name = $bls_response->productName ?? '';
592 - $product_name = '' === $product_name ? ( $bls_response->pageTitle ?? '' ) : $product_name;
593 - $quantity = $bls_response->quantity ?? 200;
594 - $price = $bls_response->price ?? '';
595 - $product_id = self::get_product_id_by_url( $url );
596 -
597 - $temp_url = $bls_response->finalUrl ?? $url;
598 - $url = '' !== $temp_url ? $temp_url : $url;
599 - $m_link = self::get_amazon_product_url( $amz_link ? $amz_link : $url );
600 -
601 - if ( strpos( $product_name, 'Amazon.com:' ) === 0 ) {
602 - $product_name = str_replace( 'Amazon.com:', '', $product_name );
603 - $product_name = trim( $product_name );
604 - }
605 -
606 - if ( $product_id && $store_product ) {
607 - $store_data = array(
608 - 'product_id' => $product_id,
609 - 'title' => $product_name,
610 - 'price' => $price,
611 - 'default_url' => $url,
612 - 'url' => $m_link,
613 - 'image' => trim( $img_url ),
614 - 'quantity' => intval( $quantity ), // Manual checks won't show out of stock for now. TODO: Add BLS to out of stock checks.
615 - 'is_manual' => 1,
616 - );
617 -
618 - // ? Set additional data for amazon product
619 - if ( isset( $bls_response->additionalData ) && ! empty( $bls_response->additionalData ) ) {
620 - $basis_price = $bls_response->additionalData->basis_price ?? '';
621 - $basis_price = Helper::get_price_value_from_price_text( $basis_price );
622 - $savings_amount = $bls_response->additionalData->saving_amount ?? '';
623 - $savings_amount = Helper::get_price_value_from_price_text( $savings_amount );
624 -
625 - $store_data['currency'] = $bls_response->additionalData->currency_name ?? '';
626 - $store_data['savings_basis'] = $basis_price;
627 - $store_data['savings_amount'] = $savings_amount;
628 - $store_data['savings_percent'] = $bls_response->additionalData->saving_amount_percent ?? '';
629 -
630 - $amazon_product['currency'] = $store_data['currency'];
631 - $amazon_product['savings_basis'] = $store_data['savings_basis'];
632 - $amazon_product['savings_amount'] = $store_data['savings_amount'];
633 - $amazon_product['savings_percent'] = $store_data['savings_percent'];
634 - }
635 -
636 - $this->update_amazon_product_in_db( $store_data, $updated_at, true ); // allow_partial: BLS may omit imgUrl.
637 - }
638 -
639 - $amazon_product['title'] = $product_name;
640 - $amazon_product['image'] = $img_url;
641 - $amazon_product['url'] = $m_link;
642 - $amazon_product['price'] = $price;
643 - $amazon_product['quantity'] = $quantity;
644 - $amazon_product['status_code'] = $bls_status;
645 - }
646 - if ( 404 === $res['status_code'] || ( 200 === $res['status_code'] && 404 === $bls_status ) ) {
647 - $amz_model = new Amazon_Products();
648 - $last_updated = gmdate( 'Y-m-d H:i:s', time() );
649 - $amz_model->update_amazon_field( $product_id, 'last_updated', $last_updated );
650 - $amz_model->update_amazon_field( $product_id, 'out_of_stock', 0 );
651 - }
652 -
653 - if ( $bls_status ) {
654 - $status = $bls_status;
655 - } elseif ( 200 === intval( $res['status_code'] ?? 0 ) ) {
656 - $status = 500;
657 508 } else {
658 - $status = intval( $res['status_code'] ?? 500 );
509 + return array();
659 510 }
660 -
661 - return array( $amazon_product, intval( $status ) );
662 511 }
663 512
664 513 /**
665 514 * Insert or Update Amazon Product Data
666 515 *
667 - * @param array $product Amazon product.
668 - * @param bool|string $updated_at Set update date time. Default to false.
669 - * @param bool $allow_partial When true, allow empty image (BLS may omit imgUrl). Default false.
516 + * @param array $product Amazon product.
517 + * @param bool|string $updated_at Set update date time. Default to false.
670 518 */
671 - public function update_amazon_product_in_db( $product, $updated_at = false, $allow_partial = false ) {
519 + public function update_amazon_product_in_db( $product, $updated_at = false ) {
672 520 global $wpdb;
673 521
674 522 $lasso_db = new Lasso_DB();
675 523
@@ -691,11 +539,9 @@
691 539 $is_manual = $product['is_manual'] ?? 0;
692 540 $quantity = intval( $product['quantity'] ?? 200 );
693 541 $out_of_stock = 0 === $quantity ? 1 : 0;
694 542
695 - $image_required = ! $allow_partial;
696 - if ( '' === $amazon_id || '' === $default_product_name
697 - || ( $image_required && '' === $default_image )
543 + if ( '' === $amazon_id || '' === $default_product_name || '' === $default_image
698 544 || ( '' !== $default_image && Helper::validate_url( $default_image ) === false && strpos( $default_image, 'data:image' ) !== 0 )
699 545 ) {
700 546 return false;
701 547 }
@@ -817,14 +663,13 @@
817 663 * Extract result to an array
818 664 *
819 665 * @param object $response Data from Amazon.
820 666 * @param bool $large_image Get large image size. Default to false.
821 - * @param string $product_id Product Id. Default to empty.
822 - * @param string $product_url Product url. Default to empty.
823 667 *
824 668 * @return array
825 669 */
826 - private function extract_search_result_v5( $response, $large_image = false, $product_id = '', $product_url = '' ) {
670 + private function extract_search_result_v5( $response, $large_image = false ) {
671 +
827 672 $image = '';
828 673 if ( isset( $response->Images->Primary ) ) { // phpcs:ignore
829 674 $image = $large_image ? $response->Images->Primary->Large->URL : $response->Images->Primary->Small->URL; // phpcs:ignore
830 675 }
@@ -830,11 +675,11 @@
830 675 }
831 676
832 677 // @codingStandardsIgnoreStart
833 678 $result = array(
834 - 'product_id' => $product_id ? $product_id : ( $response->ASIN ?? 0 ),
679 + 'product_id' => $response->ASIN ?? 0,
835 680 'title' => $response->ItemInfo->Title->DisplayValue ?? '',
836 - 'url' => $product_url ? $product_url : ( $response->DetailPageURL ?? '' ),
681 + 'url' => $response->DetailPageURL ?? '',
837 682 'default_url' => $response->DetailPageURL ?? '',
838 683 'image' => $image,
839 684 'quantity' => $response->Offers->Summaries[0]->OfferCount ?? 0,
840 685 'is_prime' => $response->Offers->Listings[0]->DeliveryInfo->IsPrimeEligible ?? false,
@@ -1024,44 +869,8 @@
1024 869 return isset( $matches[1] ) && ! empty( $matches[1] ) ? $matches[1] : false;
1025 870 }
1026 871
1027 872 /**
1028 - * Keep URL arguments for Amazon URL
1029 - *
1030 - * @param string $product_url Amazon product url.
1031 - *
1032 - * @return array $results
1033 - */
1034 - private static function keep_args( $product_url ) {
1035 - // ? amazon link but it is not product url
1036 - if ( ! self::is_amazon_url( $product_url ) || self::is_amazon_shortened_url( $product_url ) ) {
1037 - return array();
1038 - }
1039 -
1040 - $results = array();
1041 - $url_params = array(
1042 - 'maas',
1043 - 'ref_',
1044 - 's',
1045 - 'aa_campaignid',
1046 - 'aa_creativeid',
1047 - 'aa_adgroupid',
1048 - 'campaignId',
1049 - 'linkCode',
1050 - 'linkId',
1051 - );
1052 -
1053 - foreach ( $url_params as $param_name ) {
1054 - $param_value = Helper::get_argument_from_url( $product_url, $param_name );
1055 - if ( $param_value ) {
1056 - $results[] = $param_name . '=' . $param_value;
1057 - }
1058 - }
1059 -
1060 - return $results;
1061 - }
1062 -
1063 - /**
1064 873 * Get amazon tracking id by url
1065 874 * This function will be deprecated in the future. Please use Helper::get_argument_from_url() instead
1066 875 *
1067 876 * @param string $link Amazon link.
@@ -1075,18 +884,8 @@
1075 884 return $matches[2] ?? '';
1076 885 }
1077 886
1078 887 /**
1079 - * Clean Amazon URL that contains maas parameter
1080 - *
1081 - * @param string $product_url Amazon product URL.
1082 - * @return string
1083 - */
1084 - public static function clean_maas_url( $product_url ) {
1085 - return $product_url;
1086 - }
1087 -
1088 - /**
1089 888 * Make product url to shorten url if this setting is enabled
1090 889 *
1091 890 * @param string $product_url Amazon product url.
1092 891 * @param bool $monetize Monetize link or not. Default to true.
@@ -1094,67 +893,62 @@
1094 893 * @param string $custom_tracking_id Allow to use custom tracking id.
1095 894 */
1096 895 public static function get_amazon_product_url( $product_url, $monetize = true, $check_lasso_post = true, $custom_tracking_id = '' ) {
1097 896 // ? amazon link but it is not product url
1098 - if ( ! self::is_amazon_url( $product_url ) || self::is_amazon_shortened_url( $product_url ) ) {
897 + if ( ! self::is_amazon_url( $product_url ) || self::is_amazon_shortented_url( $product_url ) ) {
1099 898 return $product_url;
1100 899 }
1101 900
1102 - // If MAAS param exists and the original tag is exactly "maas", leave the URL untouched
1103 - $__maas_arg = Helper::get_argument_from_url( $product_url, 'maas' );
1104 - $__orig_tag = Helper::get_argument_from_url( $product_url, 'tag' );
1105 - if ( $__maas_arg && strtolower( $__orig_tag ) === 'maas' ) {
1106 - return $product_url;
1107 - }
901 + $product_id = self::get_product_id_by_url( $product_url );
1108 902
1109 - $product_id = self::get_product_id_by_url( $product_url );
903 + $tag = Helper::get_argument_from_url( $product_url, 'tag' );
904 + $maas = Helper::get_argument_from_url( $product_url, 'maas' );
905 + $ref_ = Helper::get_argument_from_url( $product_url, 'ref_' );
906 + $s_args = Helper::get_argument_from_url( $product_url, 's' );
1110 907
908 + $maas_args = $maas ? 'maas=' . $maas : '';
909 + $ref__args = $ref_ ? 'ref_=' . $ref_ : '';
910 + $s_args = $s_args ? 's=' . $s_args : '';
911 +
1111 912 // ? remove all url queries, just keep needed args
1112 913 $url_without_params = explode( '?', $product_url )[0];
1113 914 if ( $product_id && ! $monetize ) {
1114 - $keep_args = self::keep_args( $product_url );
1115 - $args = Helper::build_url_parameter_string( $keep_args );
915 + $args = Helper::build_url_parameter_string( array( $maas_args, $ref__args, $s_args ) );
1116 916
1117 - $product_url = $args ? $url_without_params . '?' . $args : $url_without_params;
1118 - $product_url = self::clean_maas_url( $product_url );
917 + return $args ? $url_without_params . '?' . $args : $url_without_params;
918 + }
1119 919
1120 - return $product_url;
920 + $lasso_settings = Setting::get_settings();
921 + $amazon_multiple_tracking_id = $lasso_settings['amazon_multiple_tracking_id'] ?? true;
922 + $amazon_tracking_id_whitelist = $lasso_settings['amazon_tracking_id_whitelist'] ?? array();
923 + $amazon_tracking_id = trim( $lasso_settings['amazon_tracking_id'] ?? '' );
924 +
925 + if ( ! $amazon_multiple_tracking_id ) {
926 + $amazon_tracking_id_whitelist = array();
1121 927 }
1122 928
1123 - $lasso_settings = Setting::get_settings();
1124 - $amazon_tracking_id = trim( $lasso_settings['amazon_tracking_id'] ?? '' );
1125 - $amazon_add_tracking_id_to_attribution = $lasso_settings['amazon_add_tracking_id_to_attribution'] ?? true;
1126 -
1127 929 $lasso_db = new Lasso_DB();
1128 930 $amz_cache_key = self::OBJECT_KEY . '_' . self::FUNCTION_NAME_GET_LASSO_ID_BY_PRODUCT_ID_AND_TYPE . '_' . $product_id . '_' . self::PRODUCT_TYPE;
1129 931 $lasso_id = Cache_Per_Process::get_instance()->get_cache( $amz_cache_key, null );
1130 932 if ( null === $lasso_id ) {
1131 - $lasso_id = $lasso_db->get_lasso_id_by_product_id_and_type( $product_id, self::PRODUCT_TYPE );
933 + $lasso_id = $lasso_db->get_lasso_id_by_product_id_and_type( $product_id );
1132 934 Cache_Per_Process::get_instance()->set_cache( $amz_cache_key, $lasso_id );
1133 935 }
1134 936
1135 937 if ( $check_lasso_post && ! $lasso_id ) {
1136 - $product_url = self::clean_maas_url( $product_url );
1137 938 return $product_url;
1138 939 }
1139 940
1140 - $tag = Helper::get_argument_from_url( $product_url, 'tag' );
1141 941 $tag = $custom_tracking_id ? $custom_tracking_id : $tag;
1142 942 $tag = $tag ? $tag : '';
1143 - $tag = ! empty( $tag ) ? $tag : $amazon_tracking_id;
943 + $tag = ! empty( $amazon_tracking_id ) && ! in_array( $tag, $amazon_tracking_id_whitelist, true )
944 + ? $amazon_tracking_id : $tag;
1144 945
1145 946 // ? Return the remove all url queries for product url
1146 947 if ( $product_id ) {
1147 - $tag_args = $tag ? 'tag=' . $tag : '';
1148 - $keep_args = self::keep_args( $product_url );
1149 - $maas = Helper::get_argument_from_url( $product_url, 'maas' );
1150 - $add_tag_to_url = ( $maas && $amazon_add_tracking_id_to_attribution ) || ! $maas;
948 + $tag_args = $tag ? 'tag=' . $tag : '';
949 + $args = Helper::build_url_parameter_string( array( $tag_args, $maas_args, $ref__args, $s_args ) );
1151 950
1152 - if ( $add_tag_to_url ) {
1153 - array_unshift( $keep_args, $tag_args );
1154 - }
1155 -
1156 - $args = Helper::build_url_parameter_string( $keep_args );
1157 951 $product_url = $args ? $url_without_params . '?' . $args : $url_without_params;
1158 952 } else {
1159 953 $product_url = str_replace( '&', '&', $product_url );
1160 954 $parse = wp_parse_url( $product_url );
@@ -1176,10 +970,8 @@
1176 970 $product_url = trim( $product_url );
1177 971 $product_url = trim( $product_url, '?' );
1178 972 }
1179 973
1180 - $product_url = self::clean_maas_url( $product_url );
1181 -
1182 974 return $product_url;
1183 975 }
1184 976
1185 977 /**
@@ -1389,415 +1181,6 @@
1389 1181 $currency_position = preg_match( '/[€]|R\$|TL|kr|zł/', $currency_symbol ) ? 'end' : 'begin';
1390 1182 $price_format = preg_match( '/[€]|R\$|TL|kr|zł/', $currency_symbol ) ? number_format( $price_value, 2, ',', '.' ) : number_format( $price_value, 2, '.', ',' );
1391 1183
1392 1184 return 'begin' === $currency_position ? $currency_symbol . $price_format : $price_format . $currency_symbol;
1393 - }
1394 -
1395 - /**
1396 - * Get the variation item in stock
1397 - *
1398 - * @param string $product_id Product id.
1399 - * @param string $product_url Product url.
1400 - * @param int $variation_page Variation page.
1401 - * @return array
1402 - */
1403 - public function get_product_variation( $product_id, $product_url, $variation_page = 1 ) {
1404 - $result = $this->get_product_variations_by_id_v5( $product_id, $variation_page );
1405 - $items = $result->VariationsResult->Items ?? array(); // phpcs:ignore
1406 -
1407 - if ( ! empty( $items ) ) {
1408 - $items = $result->VariationsResult->Items; // phpcs:ignore
1409 - $product_variations = array();
1410 -
1411 - // ? Get product variation list
1412 - foreach ( $items as $item ) {
1413 - $product_variations[] = $this->extract_search_result_v5( $item, true, $product_id, $product_url );
1414 - }
1415 -
1416 - // ? Sort price from lowest to highest
1417 - usort(
1418 - $product_variations,
1419 - function( $a, $b ) {
1420 - return strcmp( $a['amount'], $b['amount'] );
1421 - }
1422 - );
1423 -
1424 - // ? Get the in-stock product
1425 - foreach ( $product_variations as $product_variation ) {
1426 - if ( $product_variation['quantity'] && $product_variation['price'] ) {
1427 - return $product_variation;
1428 - }
1429 - }
1430 -
1431 - // ? If all variation products in this page unavailable, we request to the next page
1432 - $page_count = $result->VariationsResult->VariationSummary->PageCount ?? 1; // phpcs:ignore
1433 - if ( $variation_page < self::VARIATION_PAGE_LIMIT && $variation_page < $page_count ) {
1434 - sleep( 1 ); // ? Delay for a while before call the next request
1435 - return $this->get_product_variation( $product_id, $product_url, $variation_page + 1 );
1436 - }
1437 - }
1438 -
1439 - return array();
1440 - }
1441 -
1442 - /**
1443 - * Get Amazon product variations by product id
1444 - *
1445 - * @param string $product_id Amazon product id.
1446 - * @param int $variation_page Variation page.
1447 - *
1448 - * @return object
1449 - */
1450 - public function get_product_variations_by_id_v5( $product_id, $variation_page = 1 ) {
1451 - $parameters = array(
1452 - 'Operation' => 'GetVariations',
1453 - 'ASIN' => $product_id,
1454 - 'Condition' => 'New',
1455 - 'VariationPage' => $variation_page,
1456 - 'Resources' => array(
1457 - 'Images.Primary.Small',
1458 - 'Images.Primary.Large',
1459 - 'ItemInfo.Title',
1460 - 'ItemInfo.ContentRating',
1461 - 'ItemInfo.Features',
1462 - 'ItemInfo.ProductInfo',
1463 - 'ItemInfo.TechnicalInfo',
1464 - 'Offers.Listings.Price',
1465 - 'Offers.Listings.SavingBasis',
1466 - 'Offers.Summaries.OfferCount',
1467 - 'Offers.Listings.DeliveryInfo.IsPrimeEligible',
1468 - ),
1469 - );
1470 -
1471 - $json_response = $this->query_amazon_v5( $parameters );
1472 -
1473 - return $json_response;
1474 - }
1475 -
1476 - /**
1477 - * Build discount pricing html.
1478 - *
1479 - * @param string $latest_price Latest price.
1480 - * @param mixed $basis_price Basis price value.
1481 - * @param string $currency Currency ISO.
1482 - */
1483 - public static function build_discount_pricing_html( $latest_price, $basis_price, $currency ) {
1484 - $result = '';
1485 -
1486 - try {
1487 - $latest_price_value = Helper::get_price_value_from_price_text( $latest_price );
1488 - $basis_price_value = Helper::get_price_value_from_price_text( $basis_price );
1489 -
1490 - if ( $basis_price_value && ( round( $latest_price_value, 2 ) < round( $basis_price_value, 2 ) ) ) {
1491 - $currency_symbol = Helper::get_currency_symbol_from_iso_code( $currency );
1492 - $currency_position = preg_match( '/[€]|R\$|TL|kr|zł/', $latest_price ) ? 'end' : 'begin';
1493 - $basis_price_format = preg_match( '/[€]|R\$|TL|kr|zł/', $latest_price ) ? number_format( $basis_price_value, 2, ',', '.' ) : number_format( $basis_price_value, 2, '.', ',' );
1494 - $format_price = 'begin' === $currency_position ? $currency_symbol . $basis_price_format : $basis_price_format . ' ' . $currency_symbol;
1495 -
1496 - $result = "<strike>$format_price</strike>";
1497 - }
1498 - } catch ( \Exception $e ) {
1499 - $result = '';
1500 - }
1501 -
1502 - return $result;
1503 - }
1504 -
1505 - /**
1506 - * Check amazon setting is configured or not
1507 - *
1508 - * @return boolean
1509 - */
1510 - public static function is_amazon_setting_configured() {
1511 - $lasso_settings = Setting::get_settings();
1512 - $is_amazon_configured = $lasso_settings['amazon_access_key_id'] && $lasso_settings['amazon_secret_key'] && $lasso_settings['amazon_tracking_id'];
1513 -
1514 - return $is_amazon_configured || self::is_amazon_creators_verified( $lasso_settings );
1515 - }
1516 -
1517 - /**
1518 - * Whether Amazon Creators API credentials are complete in settings.
1519 - *
1520 - * @param array|false $lasso_settings Settings array. Default false loads current settings.
1521 - * @return bool
1522 - */
1523 - public static function is_amazon_creators_configured( $lasso_settings = false ) {
1524 - if ( ! is_array( $lasso_settings ) ) {
1525 - $lasso_settings = Setting::get_settings();
1526 - }
1527 -
1528 - $fields = array(
1529 - 'amazon_creators_credential_id',
1530 - 'amazon_creators_secret',
1531 - 'amazon_creators_version',
1532 - 'amazon_creators_partner_tag',
1533 - );
1534 -
1535 - foreach ( $fields as $field ) {
1536 - if ( '' === trim( (string) ( $lasso_settings[ $field ] ?? '' ) ) ) {
1537 - return false;
1538 - }
1539 - }
1540 -
1541 - return true;
1542 - }
1543 -
1544 - /**
1545 - * Whether Creators credentials were verified successfully (signature matches stored settings).
1546 - *
1547 - * @param array|false $lasso_settings Settings array. Default false loads current settings.
1548 - * @return bool
1549 - */
1550 - public static function is_amazon_creators_verified( $lasso_settings = false ) {
1551 - if ( ! self::is_amazon_creators_configured( $lasso_settings ) ) {
1552 - return false;
1553 - }
1554 -
1555 - if ( ! is_array( $lasso_settings ) ) {
1556 - $lasso_settings = Setting::get_settings();
1557 - }
1558 -
1559 - $current_signature = self::get_amazon_creators_signature( $lasso_settings );
1560 - $saved_signature = (string) Helper::get_option( Constant::LASSO_OPTION_AMAZON_CREATORS_VERIFIED_SIGNATURE, '' );
1561 -
1562 - return '' !== $current_signature && '' !== $saved_signature && hash_equals( $saved_signature, $current_signature );
1563 - }
1564 -
1565 - /**
1566 - * Build a stable signature for the Creators payload.
1567 - *
1568 - * @param array $settings Settings values.
1569 - * @return string Empty when Creators credentials are incomplete.
1570 - */
1571 - public static function get_amazon_creators_signature( $settings ) {
1572 - if ( ! self::is_amazon_creators_configured( $settings ) ) {
1573 - return '';
1574 - }
1575 -
1576 - return hash(
1577 - 'sha256',
1578 - wp_json_encode(
1579 - array(
1580 - 'credential_id' => (string) ( $settings['amazon_creators_credential_id'] ?? '' ),
1581 - 'secret' => (string) ( $settings['amazon_creators_secret'] ?? '' ),
1582 - 'credential_version' => (string) ( $settings['amazon_creators_version'] ?? '' ),
1583 - 'partner_tag' => (string) ( $settings['amazon_creators_partner_tag'] ?? '' ),
1584 - 'country' => (string) ( $settings['amazon_default_tracking_country'] ?? '' ),
1585 - )
1586 - )
1587 - );
1588 - }
1589 -
1590 - /**
1591 - * Resolve Creators API country from an Amazon URL or default tracking country.
1592 - *
1593 - * @param string $amazon_url Amazon product URL (optional).
1594 - * @param array|false $lasso_settings Settings array. Default false loads current settings.
1595 - * @return string
1596 - */
1597 - public static function get_country_for_creators_api( $amazon_url, $lasso_settings = false ) {
1598 - if ( ! is_array( $lasso_settings ) ) {
1599 - $lasso_settings = Setting::get_settings();
1600 - }
1601 -
1602 - if ( $amazon_url && self::is_amazon_url( $amazon_url ) ) {
1603 - $base_domain = strtolower( Helper::get_base_domain( $amazon_url ) );
1604 - if ( '' !== $base_domain ) {
1605 - foreach ( self::get_amazon_api_countries() as $country_code => $country_data ) {
1606 - $amazon_domain = strtolower( Helper::get_base_domain( (string) ( $country_data['amazon_domain'] ?? '' ) ) );
1607 - if ( $base_domain === $amazon_domain ) {
1608 - return (string) $country_code;
1609 - }
1610 - }
1611 - }
1612 - }
1613 -
1614 - return (string) ( $lasso_settings['amazon_default_tracking_country'] ?? '' );
1615 - }
1616 -
1617 - /**
1618 - * Whether the Lite install is linked to a Lasso account email.
1619 - *
1620 - * @return bool
1621 - */
1622 - public static function is_lite_account_connected() {
1623 - $email = Helper::get_option( Constant::LASSO_ACCOUNT_EMAIL, '' );
1624 -
1625 - return is_string( $email ) && '' !== trim( $email );
1626 - }
1627 -
1628 - /**
1629 - * Fetch product data via direct Amazon Creators API (replaces deprecated PA-API GetItems).
1630 - *
1631 - * @param string $product_id Amazon ASIN.
1632 - * @param bool $store_product Store in local DB.
1633 - * @param bool|string $updated_at Optional updated timestamp.
1634 - * @param string $amz_link Amazon URL.
1635 - * @param array $lasso_settings Plugin settings.
1636 - * @return array|null Same shape as fetch_product_info success/failure, or null to fall back.
1637 - */
1638 - private function fetch_product_info_from_creators_api( $product_id, $store_product, $updated_at, $amz_link, $lasso_settings ) {
1639 - if ( ! self::is_amazon_creators_configured( $lasso_settings ) ) {
1640 - return null;
1641 - }
1642 -
1643 - $api_result = Amazon_Creators_Api::fetch_product(
1644 - $product_id,
1645 - self::get_country_for_creators_api( $amz_link, $lasso_settings ),
1646 - array(
1647 - 'product_only' => false,
1648 - )
1649 - );
1650 -
1651 - if ( 'fail' === ( $api_result['status'] ?? '' ) ) {
1652 - $error_code = (string) ( $api_result['error_code'] ?? '' );
1653 -
1654 - if ( 'NotFound' === $error_code ) {
1655 - return $this->build_fetch_product_info_response( array(), 'yes', array(), 'failed', 'NotFound' );
1656 - }
1657 -
1658 - return null;
1659 - }
1660 -
1661 - $product_data = $api_result['product'] ?? array();
1662 - if ( ! is_array( $product_data ) || empty( $product_data ) ) {
1663 - return null;
1664 - }
1665 -
1666 - $full_item = $api_result['item'] ?? array();
1667 - $product = $this->finalize_fetch_product_info_product(
1668 - $product_data,
1669 - $product_id,
1670 - $store_product,
1671 - $updated_at,
1672 - $amz_link
1673 - );
1674 -
1675 - return $this->build_fetch_product_info_response( $product, 'yes', $full_item, 'success', '' );
1676 - }
1677 -
1678 - /**
1679 - * Build fetch_product_info() return array (same contract as get_product_by_id_v5 path).
1680 - *
1681 - * @param array $product Product fields.
1682 - * @param string $api API source flag.
1683 - * @param array|object $full_item Raw item payload.
1684 - * @param string $status success|failed.
1685 - * @param string $error_code Error code.
1686 - * @return array
1687 - */
1688 - private function build_fetch_product_info_response( $product, $api, $full_item, $status, $error_code ) {
1689 - return array(
1690 - 'product' => $product,
1691 - 'api' => $api,
1692 - 'full_item' => $full_item,
1693 - 'status' => $status,
1694 - 'error_code' => $error_code,
1695 - );
1696 - }
1697 -
1698 - /**
1699 - * Apply the same post-processing as the PA-API branch in fetch_product_info().
1700 - *
1701 - * @param array $product Product fields from API.
1702 - * @param string $product_id Amazon ASIN.
1703 - * @param bool $store_product Store in local DB.
1704 - * @param bool|string $updated_at Optional updated timestamp.
1705 - * @param string $amz_link Amazon URL.
1706 - * @return array
1707 - */
1708 - private function finalize_fetch_product_info_product( $product, $product_id, $store_product, $updated_at, $amz_link ) {
1709 - if ( empty( $product['product_id'] ) ) {
1710 - $product['product_id'] = $product_id;
1711 - }
1712 -
1713 - return $this->enrich_fetched_amazon_product( $product, $store_product, $updated_at, $amz_link );
1714 - }
1715 -
1716 - /**
1717 - * Shared post-fetch enrichment for PA-API and Creators product payloads.
1718 - *
1719 - * @param array $product Product fields.
1720 - * @param bool $store_product Store in local DB.
1721 - * @param bool|string $updated_at Optional updated timestamp.
1722 - * @param string $amz_link Amazon URL.
1723 - * @return array
1724 - */
1725 - private function enrich_fetched_amazon_product( $product, $store_product, $updated_at, $amz_link ) {
1726 - global $wpdb;
1727 -
1728 - $lasso_db = new Lasso_DB();
1729 - $product_url = $amz_link ? $amz_link : ( $product['url'] ?? '' );
1730 - $product['status_code'] = 200;
1731 - $product['url'] = self::get_amazon_product_url( $product_url );
1732 -
1733 - $amazon_product_id = (string) ( $product['product_id'] ?? '' );
1734 - $query = $wpdb->prepare(
1735 - 'SELECT post_id FROM ' . $lasso_db->postmeta . " WHERE meta_key = 'amazon_product_id' AND meta_value = %s",
1736 - $amazon_product_id
1737 - );
1738 - $lasso_id = $lasso_db->get_var( $query );
1739 - $product['lasso_id'] = ( isset( $lasso_id ) ) ? $lasso_id : 0;
1740 -
1741 - if ( $store_product ) {
1742 - $amazon_tracking_id = Setting::get_setting( 'amazon_tracking_id', '' );
1743 - $product['default_url'] = '' === $amazon_tracking_id ? $amz_link : ( $product['default_url'] ?? '' );
1744 - $this->update_amazon_product_in_db( $product, $updated_at );
1745 - }
1746 -
1747 - return $product;
1748 - }
1749 -
1750 - /**
1751 - * Get final url of the amazon shortlink from cache
1752 - *
1753 - * @param string $shortlink Amazon shortlink.
1754 - * @return string|null
1755 - */
1756 - public static function get_shortlink_final_url_cached( $shortlink ) {
1757 - if ( ! self::is_amazon_shortened_url( $shortlink ) ) {
1758 - return null;
1759 - }
1760 - $final_url_cache = get_option( self::build_shortlink_cache_key( $shortlink ) );
1761 -
1762 - if ( $final_url_cache === $shortlink ) {
1763 - return null;
1764 - }
1765 -
1766 - return $final_url_cache ? $final_url_cache : null;
1767 - }
1768 -
1769 - /**
1770 - * Build amazon shortlink cache key
1771 - *
1772 - * @param string $shortlink Amazon shortlink.
1773 - * @return string|null
1774 - */
1775 - public static function build_shortlink_cache_key( $shortlink ) {
1776 - if ( ! self::is_amazon_shortened_url( $shortlink ) ) {
1777 - return null;
1778 - }
1779 -
1780 - $parse = wp_parse_url( $shortlink );
1781 - $host = str_replace( '.', '_', $parse['host'] );
1782 - $id = trim( $parse['path'] ?? '', '/' );
1783 -
1784 - return $host . '_' . $id;
1785 - }
1786 -
1787 - /**
1788 - * Format Amazon URLs
1789 - *
1790 - * @param string $url Amazon product url.
1791 - * @return string URL.
1792 - */
1793 - public static function format_amazon_url( $url ) {
1794 - $is_amazon_link = self::is_amazon_url( $url );
1795 - $product_id = self::get_product_id_by_url( $url );
1796 -
1797 - if ( $is_amazon_link && $product_id && strpos( $url, 'smile.amazon.' ) !== false ) {
1798 - $url = str_replace( 'smile.amazon.', 'amazon.', $url );
1799 - }
1800 -
1801 - return $url;
1802 1185 }
1803 1186 }