| @@ -6,8 +6,9 @@ | ||
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | namespace LassoLite\Classes; |
| 9 | 9 | |
| 10 | +use LassoLite\Admin\Constant; | |
| 10 | 11 | use LassoLite\Classes\Affiliate_Link; |
| 11 | 12 | use LassoLite\Classes\Cache_Per_Process; |
| 12 | 13 | use LassoLite\Classes\Helper; |
| 13 | 14 | use LassoLite\Classes\Setting; |
| @@ -456,18 +457,38 @@ | ||
| 456 | 457 | * @param string $product_id Amazon product id. |
| 457 | 458 | * @param bool $store_product Store product into DB or not. Default to false. |
| 458 | 459 | * @param bool|string $updated_at Set date time or not. Default to false. |
| 459 | 460 | * @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. | |
| 460 | 464 | * @return mixed |
| 461 | 465 | */ |
| 462 | - public function fetch_product_info( $product_id, $store_product = false, $updated_at = false, $amz_link = '' ) { | |
| 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 ) { | |
| 463 | 467 | $lasso_db = new Lasso_DB(); |
| 464 | 468 | |
| 465 | 469 | $lasso_settings = Setting::get_settings(); |
| 466 | 470 | $is_amazon_configured = $lasso_settings['amazon_access_key_id'] && $lasso_settings['amazon_secret_key'] && $lasso_settings['amazon_tracking_id']; |
| 467 | - $result = $is_amazon_configured && $this->is_same_domain( $amz_link ) ? $this->get_product_by_id_v5( $product_id ) : false; | |
| 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; | |
| 468 | 489 | // phpcs:ignore |
| 469 | - if ( isset( $result->Errors[0] ) && ( | |
| 490 | + if ( is_object( $result ) && isset( $result->Errors[0] ) && ( | |
| 470 | 491 | "The ItemId $product_id provided in the request is invalid." === $result->Errors[0]->Message // phpcs:ignore |
| 471 | 492 | || "The value [$product_id] provided in the request for ItemIds is invalid." === $result->Errors[0]->Message // phpcs:ignore |
| 472 | 493 | ) |
| 473 | 494 | ) { |
| @@ -477,9 +498,9 @@ | ||
| 477 | 498 | 'full_item' => array(), |
| 478 | 499 | 'status' => 'failed', |
| 479 | 500 | 'error_code' => 'NotFound', |
| 480 | 501 | ); |
| 481 | - } elseif ( isset( $result->ItemsResult->Items[0] ) ) { // phpcs:ignore | |
| 502 | + } elseif ( is_object( $result ) && isset( $result->ItemsResult->Items[0] ) ) { // phpcs:ignore | |
| 482 | 503 | $item = $result->ItemsResult->Items[0]; // phpcs:ignore |
| 483 | 504 | |
| 484 | 505 | $product = $this->extract_search_result_v5( $item, true ); |
| 485 | 506 | $product_url = $amz_link ? $amz_link : $product['url']; |
| @@ -494,23 +515,10 @@ | ||
| 494 | 515 | $product = $variation_product; |
| 495 | 516 | } |
| 496 | 517 | } |
| 497 | 518 | |
| 498 | - // ? Get Lasso ID | |
| 499 | - $query = ' | |
| 500 | - SELECT post_id | |
| 501 | - FROM ' . $lasso_db->postmeta . " | |
| 502 | - WHERE meta_key = 'amazon_product_id' AND meta_value = '" . $product['product_id'] . "' | |
| 503 | - "; | |
| 504 | - $lasso_id = $lasso_db->get_var( $query ); | |
| 505 | - $product['lasso_id'] = ( isset( $lasso_id ) ) ? $lasso_id : 0; | |
| 519 | + $product = $this->enrich_fetched_amazon_product( $product, $store_product, $updated_at, $amz_link ); | |
| 506 | 520 | |
| 507 | - if ( $store_product ) { | |
| 508 | - $amazon_tracking_id = Setting::get_setting( 'amazon_tracking_id', '' ); | |
| 509 | - $product['default_url'] = '' === $amazon_tracking_id ? $amz_link : $product['default_url']; | |
| 510 | - $this->update_amazon_product_in_db( $product, $updated_at ); | |
| 511 | - } | |
| 512 | - | |
| 513 | 521 | return array( |
| 514 | 522 | 'product' => $product, |
| 515 | 523 | 'api' => 'yes', |
| 516 | 524 | 'full_item' => $item, |
| @@ -516,10 +524,10 @@ | ||
| 516 | 524 | 'full_item' => $item, |
| 517 | 525 | 'status' => 'success', |
| 518 | 526 | 'error_code' => '', |
| 519 | 527 | ); |
| 520 | - } elseif ( '' !== $lasso_settings['license_serial'] ) { | |
| 521 | - list( $product, $status ) = $this->fetch_product_from_bls( $product_id, $store_product, $updated_at, $amz_link ); | |
| 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 ); | |
| 522 | 530 | |
| 523 | 531 | return array( |
| 524 | 532 | 'product' => $product, |
| 525 | 533 | 'api' => 'no', |
| @@ -527,8 +535,16 @@ | ||
| 527 | 535 | 'status' => 200 === $status ? 'success' : 'fail', |
| 528 | 536 | 'error_code' => 404 === $status ? 'NotFound' : '', |
| 529 | 537 | ); |
| 530 | 538 | } |
| 539 | + | |
| 540 | + return array( | |
| 541 | + 'product' => array(), | |
| 542 | + 'api' => 'no', | |
| 543 | + 'full_item' => array(), | |
| 544 | + 'status' => 'failed', | |
| 545 | + 'error_code' => 'NotFound', | |
| 546 | + ); | |
| 531 | 547 | } |
| 532 | 548 | |
| 533 | 549 | /** |
| 534 | 550 | * Fetch amazon product from BLS (Lambda) |
| @@ -536,10 +552,13 @@ | ||
| 536 | 552 | * @param string $product_id Amazon product id. |
| 537 | 553 | * @param bool $store_product Store product into DB or not. Default to false. |
| 538 | 554 | * @param bool|string $updated_at Set date time or not. Default to false. |
| 539 | 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. | |
| 540 | 559 | */ |
| 541 | - public function fetch_product_from_bls( $product_id, $store_product = false, $updated_at = false, $amz_link = '' ) { | |
| 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 ) { | |
| 542 | 561 | $url = strpos( $amz_link, 'amazon.' ) !== false ? $amz_link : $this->get_amazon_link_by_product_id( $product_id, $amz_link ); |
| 543 | 562 | $m_link = self::get_amazon_product_url( $url ); |
| 544 | 563 | $url = self::get_amazon_product_url( $url, false ); |
| 545 | 564 | |
| @@ -553,19 +572,30 @@ | ||
| 553 | 572 | 'savings_percent' => 0, |
| 554 | 573 | 'savings_basis' => 0, |
| 555 | 574 | ); |
| 556 | 575 | |
| 557 | - $res = Helper::get_url_status_code_by_broken_link_service( $url, true ); | |
| 558 | - if ( 200 === $res['status_code'] && 200 === $res['response']->status ) { | |
| 559 | - $img_url = $res['response']->imgUrl ?? ''; | |
| 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 ?? ''; | |
| 560 | 590 | $img_url = '' !== $img_url ? $img_url : ''; |
| 561 | - $product_name = $res['response']->productName ?? ''; | |
| 562 | - $product_name = '' === $product_name ? ( $res['response']->pageTitle ?? '' ) : $product_name; | |
| 563 | - $quantity = $res['response']->quantity ?? 200; | |
| 564 | - $price = $res['response']->price ?? ''; | |
| 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 ?? ''; | |
| 565 | 595 | $product_id = self::get_product_id_by_url( $url ); |
| 566 | 596 | |
| 567 | - $temp_url = $res['response']->finalUrl ?? $url; | |
| 597 | + $temp_url = $bls_response->finalUrl ?? $url; | |
| 568 | 598 | $url = '' !== $temp_url ? $temp_url : $url; |
| 569 | 599 | $m_link = self::get_amazon_product_url( $amz_link ? $amz_link : $url ); |
| 570 | 600 | |
| 571 | 601 | if ( strpos( $product_name, 'Amazon.com:' ) === 0 ) { |
| @@ -585,18 +615,18 @@ | ||
| 585 | 615 | 'is_manual' => 1, |
| 586 | 616 | ); |
| 587 | 617 | |
| 588 | 618 | // ? Set additional data for amazon product |
| 589 | - if ( isset( $res['response']->additionalData ) && ! empty( $res['response']->additionalData ) ) { | |
| 590 | - $basis_price = $res['response']->additionalData->basis_price ?? ''; | |
| 619 | + if ( isset( $bls_response->additionalData ) && ! empty( $bls_response->additionalData ) ) { | |
| 620 | + $basis_price = $bls_response->additionalData->basis_price ?? ''; | |
| 591 | 621 | $basis_price = Helper::get_price_value_from_price_text( $basis_price ); |
| 592 | - $savings_amount = $res['response']->additionalData->saving_amount ?? ''; | |
| 622 | + $savings_amount = $bls_response->additionalData->saving_amount ?? ''; | |
| 593 | 623 | $savings_amount = Helper::get_price_value_from_price_text( $savings_amount ); |
| 594 | 624 | |
| 595 | - $store_data['currency'] = $res['response']->additionalData->currency_name ?? ''; | |
| 625 | + $store_data['currency'] = $bls_response->additionalData->currency_name ?? ''; | |
| 596 | 626 | $store_data['savings_basis'] = $basis_price; |
| 597 | 627 | $store_data['savings_amount'] = $savings_amount; |
| 598 | - $store_data['savings_percent'] = $res['response']->additionalData->saving_amount_percent ?? ''; | |
| 628 | + $store_data['savings_percent'] = $bls_response->additionalData->saving_amount_percent ?? ''; | |
| 599 | 629 | |
| 600 | 630 | $amazon_product['currency'] = $store_data['currency']; |
| 601 | 631 | $amazon_product['savings_basis'] = $store_data['savings_basis']; |
| 602 | 632 | $amazon_product['savings_amount'] = $store_data['savings_amount']; |
| @@ -602,9 +632,9 @@ | ||
| 602 | 632 | $amazon_product['savings_amount'] = $store_data['savings_amount']; |
| 603 | 633 | $amazon_product['savings_percent'] = $store_data['savings_percent']; |
| 604 | 634 | } |
| 605 | 635 | |
| 606 | - $this->update_amazon_product_in_db( $store_data, $updated_at, true ); | |
| 636 | + $this->update_amazon_product_in_db( $store_data, $updated_at, true ); // allow_partial: BLS may omit imgUrl. | |
| 607 | 637 | } |
| 608 | 638 | |
| 609 | 639 | $amazon_product['title'] = $product_name; |
| 610 | 640 | $amazon_product['image'] = $img_url; |
| @@ -610,11 +640,11 @@ | ||
| 610 | 640 | $amazon_product['image'] = $img_url; |
| 611 | 641 | $amazon_product['url'] = $m_link; |
| 612 | 642 | $amazon_product['price'] = $price; |
| 613 | 643 | $amazon_product['quantity'] = $quantity; |
| 614 | - $amazon_product['status_code'] = $res['response']->status; | |
| 644 | + $amazon_product['status_code'] = $bls_status; | |
| 615 | 645 | } |
| 616 | - if ( 404 === $res['status_code'] || ( 200 === $res['status_code'] && 404 === $res['response']->status ) ) { | |
| 646 | + if ( 404 === $res['status_code'] || ( 200 === $res['status_code'] && 404 === $bls_status ) ) { | |
| 617 | 647 | $amz_model = new Amazon_Products(); |
| 618 | 648 | $last_updated = gmdate( 'Y-m-d H:i:s', time() ); |
| 619 | 649 | $amz_model->update_amazon_field( $product_id, 'last_updated', $last_updated ); |
| 620 | 650 | $amz_model->update_amazon_field( $product_id, 'out_of_stock', 0 ); |
| @@ -619,9 +649,15 @@ | ||
| 619 | 649 | $amz_model->update_amazon_field( $product_id, 'last_updated', $last_updated ); |
| 620 | 650 | $amz_model->update_amazon_field( $product_id, 'out_of_stock', 0 ); |
| 621 | 651 | } |
| 622 | 652 | |
| 623 | - $status = $res['response']->status ?? 200; | |
| 653 | + if ( $bls_status ) { | |
| 654 | + $status = $bls_status; | |
| 655 | + } elseif ( 200 === intval( $res['status_code'] ?? 0 ) ) { | |
| 656 | + $status = 500; | |
| 657 | + } else { | |
| 658 | + $status = intval( $res['status_code'] ?? 500 ); | |
| 659 | + } | |
| 624 | 660 | |
| 625 | 661 | return array( $amazon_product, intval( $status ) ); |
| 626 | 662 | } |
| 627 | 663 | |
| @@ -627,12 +663,13 @@ | ||
| 627 | 663 | |
| 628 | 664 | /** |
| 629 | 665 | * Insert or Update Amazon Product Data |
| 630 | 666 | * |
| 631 | - * @param array $product Amazon product. | |
| 632 | - * @param bool|string $updated_at Set update date time. Default to false. | |
| 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. | |
| 633 | 670 | */ |
| 634 | - public function update_amazon_product_in_db( $product, $updated_at = false ) { | |
| 671 | + public function update_amazon_product_in_db( $product, $updated_at = false, $allow_partial = false ) { | |
| 635 | 672 | global $wpdb; |
| 636 | 673 | |
| 637 | 674 | $lasso_db = new Lasso_DB(); |
| 638 | 675 | |
| @@ -654,9 +691,11 @@ | ||
| 654 | 691 | $is_manual = $product['is_manual'] ?? 0; |
| 655 | 692 | $quantity = intval( $product['quantity'] ?? 200 ); |
| 656 | 693 | $out_of_stock = 0 === $quantity ? 1 : 0; |
| 657 | 694 | |
| 658 | - if ( '' === $amazon_id || '' === $default_product_name || '' === $default_image | |
| 695 | + $image_required = ! $allow_partial; | |
| 696 | + if ( '' === $amazon_id || '' === $default_product_name | |
| 697 | + || ( $image_required && '' === $default_image ) | |
| 659 | 698 | || ( '' !== $default_image && Helper::validate_url( $default_image ) === false && strpos( $default_image, 'data:image' ) !== 0 ) |
| 660 | 699 | ) { |
| 661 | 700 | return false; |
| 662 | 701 | } |
| @@ -1088,9 +1127,9 @@ | ||
| 1088 | 1127 | $lasso_db = new Lasso_DB(); |
| 1089 | 1128 | $amz_cache_key = self::OBJECT_KEY . '_' . self::FUNCTION_NAME_GET_LASSO_ID_BY_PRODUCT_ID_AND_TYPE . '_' . $product_id . '_' . self::PRODUCT_TYPE; |
| 1090 | 1129 | $lasso_id = Cache_Per_Process::get_instance()->get_cache( $amz_cache_key, null ); |
| 1091 | 1130 | if ( null === $lasso_id ) { |
| 1092 | - $lasso_id = $lasso_db->get_lasso_id_by_product_id_and_type( $product_id, self::PRODUCT_TYPE, $product_url ); | |
| 1131 | + $lasso_id = $lasso_db->get_lasso_id_by_product_id_and_type( $product_id, self::PRODUCT_TYPE ); | |
| 1093 | 1132 | Cache_Per_Process::get_instance()->set_cache( $amz_cache_key, $lasso_id ); |
| 1094 | 1133 | } |
| 1095 | 1134 | |
| 1096 | 1135 | if ( $check_lasso_post && ! $lasso_id ) { |
| @@ -1471,9 +1510,242 @@ | ||
| 1471 | 1510 | public static function is_amazon_setting_configured() { |
| 1472 | 1511 | $lasso_settings = Setting::get_settings(); |
| 1473 | 1512 | $is_amazon_configured = $lasso_settings['amazon_access_key_id'] && $lasso_settings['amazon_secret_key'] && $lasso_settings['amazon_tracking_id']; |
| 1474 | 1513 | |
| 1475 | - return $is_amazon_configured; | |
| 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; | |
| 1476 | 1748 | } |
| 1477 | 1749 | |
| 1478 | 1750 | /** |
| 1479 | 1751 | * Get final url of the amazon shortlink from cache |