Fix: migrate Google Merchant API endpoints from v1beta to v1
The v1beta version was discontinued on February 28, 2026, causing all API calls to return HTTP 409 errors. Updated all three endpoint paths (products list, test connection, reports search) to use v1. Also updated product attribute access to match v1 schema changes: - Product.attributes → Product.productAttributes - attributes.gtin / attributes.gtins → productAttributes.gtins Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -300,13 +300,13 @@ class Informatiq_SP_Google_API {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fallback: Use product's own price as reference.
|
// Fallback: Use product's own price as reference.
|
||||||
// Price is nested inside attributes in the new Merchant API.
|
// In v1, price is nested inside productAttributes.
|
||||||
if ( isset( $product['attributes']['price']['amountMicros'] ) ) {
|
if ( isset( $product['productAttributes']['price']['amountMicros'] ) ) {
|
||||||
$price = (float) $product['attributes']['price']['amountMicros'] / 1000000;
|
$price = (float) $product['productAttributes']['price']['amountMicros'] / 1000000;
|
||||||
$this->logger->warning( "No competitive data available for SKU={$sku}, using own price as reference" );
|
$this->logger->warning( "No competitive data available for SKU={$sku}, using own price as reference" );
|
||||||
return $price;
|
return $price;
|
||||||
}
|
}
|
||||||
// Also check top-level price (in case API changes).
|
// Also check top-level price as fallback.
|
||||||
if ( isset( $product['price']['amountMicros'] ) ) {
|
if ( isset( $product['price']['amountMicros'] ) ) {
|
||||||
$price = (float) $product['price']['amountMicros'] / 1000000;
|
$price = (float) $product['price']['amountMicros'] / 1000000;
|
||||||
$this->logger->warning( "No competitive data available for SKU={$sku}, using own price as reference (top-level)" );
|
$this->logger->warning( "No competitive data available for SKU={$sku}, using own price as reference (top-level)" );
|
||||||
@@ -326,8 +326,8 @@ class Informatiq_SP_Google_API {
|
|||||||
*
|
*
|
||||||
* Matching logic:
|
* Matching logic:
|
||||||
* 1. SKU matches offerId
|
* 1. SKU matches offerId
|
||||||
* 2. SKU matches gtin (for stores where SKU is the barcode)
|
* 2. SKU matches gtins (for stores where SKU is the barcode)
|
||||||
* 3. GTIN matches gtin
|
* 3. GTIN matches gtins
|
||||||
*
|
*
|
||||||
* @param string $sku Product SKU.
|
* @param string $sku Product SKU.
|
||||||
* @param string $gtin Product GTIN.
|
* @param string $gtin Product GTIN.
|
||||||
@@ -338,7 +338,8 @@ class Informatiq_SP_Google_API {
|
|||||||
$page_token = null;
|
$page_token = null;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
$endpoint = "/products/v1beta/accounts/{$this->merchant_id}/products";
|
// v1 endpoint (v1beta was discontinued on February 28, 2026).
|
||||||
|
$endpoint = "/products/v1/accounts/{$this->merchant_id}/products";
|
||||||
$endpoint .= '?pageSize=250';
|
$endpoint .= '?pageSize=250';
|
||||||
|
|
||||||
if ( $page_token ) {
|
if ( $page_token ) {
|
||||||
@@ -354,27 +355,18 @@ class Informatiq_SP_Google_API {
|
|||||||
return $product;
|
return $product;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if SKU matches Google's GTIN array (for stores where SKU is the barcode).
|
// In v1, GTIN is stored in productAttributes.gtins as an array.
|
||||||
// GTIN is stored in attributes.gtin as an array.
|
if ( ! empty( $product['productAttributes']['gtins'] ) && is_array( $product['productAttributes']['gtins'] ) ) {
|
||||||
if ( ! empty( $product['attributes']['gtin'] ) && is_array( $product['attributes']['gtin'] ) ) {
|
if ( in_array( $sku, $product['productAttributes']['gtins'], true ) ) {
|
||||||
if ( in_array( $sku, $product['attributes']['gtin'], true ) ) {
|
$this->logger->info( "Product matched by productAttributes.gtins={$sku} (SKU used as barcode)" );
|
||||||
$this->logger->info( "Product matched by attributes.gtin={$sku} (SKU used as barcode)" );
|
|
||||||
return $product;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also check attributes.gtins (alternative field).
|
|
||||||
if ( ! empty( $product['attributes']['gtins'] ) && is_array( $product['attributes']['gtins'] ) ) {
|
|
||||||
if ( in_array( $sku, $product['attributes']['gtins'], true ) ) {
|
|
||||||
$this->logger->info( "Product matched by attributes.gtins={$sku} (SKU used as barcode)" );
|
|
||||||
return $product;
|
return $product;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if separate GTIN parameter matches.
|
// Check if separate GTIN parameter matches.
|
||||||
if ( ! empty( $gtin ) ) {
|
if ( ! empty( $gtin ) ) {
|
||||||
if ( ! empty( $product['attributes']['gtin'] ) && is_array( $product['attributes']['gtin'] ) ) {
|
if ( ! empty( $product['productAttributes']['gtins'] ) && is_array( $product['productAttributes']['gtins'] ) ) {
|
||||||
if ( in_array( $gtin, $product['attributes']['gtin'], true ) ) {
|
if ( in_array( $gtin, $product['productAttributes']['gtins'], true ) ) {
|
||||||
$this->logger->info( "Product matched by GTIN parameter={$gtin}" );
|
$this->logger->info( "Product matched by GTIN parameter={$gtin}" );
|
||||||
return $product;
|
return $product;
|
||||||
}
|
}
|
||||||
@@ -404,8 +396,8 @@ class Informatiq_SP_Google_API {
|
|||||||
*/
|
*/
|
||||||
private function fetch_competitive_price_from_reports( $sku, $gtin ) {
|
private function fetch_competitive_price_from_reports( $sku, $gtin ) {
|
||||||
try {
|
try {
|
||||||
// Use the Reports API to search for competitive visibility data.
|
// v1 reports endpoint (v1beta was discontinued on February 28, 2026).
|
||||||
$endpoint = "/reports/v1beta/accounts/{$this->merchant_id}/reports:search";
|
$endpoint = "/reports/v1/accounts/{$this->merchant_id}/reports:search";
|
||||||
|
|
||||||
// Try searching by offer_id first (fields prefixed with product_view.).
|
// Try searching by offer_id first (fields prefixed with product_view.).
|
||||||
$query = array(
|
$query = array(
|
||||||
@@ -465,7 +457,8 @@ class Informatiq_SP_Google_API {
|
|||||||
*/
|
*/
|
||||||
public function get_price_insights() {
|
public function get_price_insights() {
|
||||||
try {
|
try {
|
||||||
$endpoint = "/reports/v1beta/accounts/{$this->merchant_id}/reports:search";
|
// v1 reports endpoint (v1beta was discontinued on February 28, 2026).
|
||||||
|
$endpoint = "/reports/v1/accounts/{$this->merchant_id}/reports:search";
|
||||||
|
|
||||||
$all_insights = array();
|
$all_insights = array();
|
||||||
$page_token = null;
|
$page_token = null;
|
||||||
@@ -566,8 +559,8 @@ class Informatiq_SP_Google_API {
|
|||||||
*/
|
*/
|
||||||
public function test_connection() {
|
public function test_connection() {
|
||||||
try {
|
try {
|
||||||
// Try to list products to test connection.
|
// v1 endpoint (v1beta was discontinued on February 28, 2026).
|
||||||
$endpoint = "/products/v1beta/accounts/{$this->merchant_id}/products?pageSize=1";
|
$endpoint = "/products/v1/accounts/{$this->merchant_id}/products?pageSize=1";
|
||||||
$this->api_request( 'GET', $endpoint );
|
$this->api_request( 'GET', $endpoint );
|
||||||
|
|
||||||
$this->logger->info( 'Google Merchant API connection test successful' );
|
$this->logger->info( 'Google Merchant API connection test successful' );
|
||||||
@@ -590,7 +583,8 @@ class Informatiq_SP_Google_API {
|
|||||||
$page_token = null;
|
$page_token = null;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
$endpoint = "/products/v1beta/accounts/{$this->merchant_id}/products";
|
// v1 endpoint (v1beta was discontinued on February 28, 2026).
|
||||||
|
$endpoint = "/products/v1/accounts/{$this->merchant_id}/products";
|
||||||
$endpoint .= '?pageSize=250';
|
$endpoint .= '?pageSize=250';
|
||||||
|
|
||||||
if ( $page_token ) {
|
if ( $page_token ) {
|
||||||
|
|||||||
Reference in New Issue
Block a user