feat: Add endpoint for optimizing products based on clicks, including client identification and response examples in documentation
This commit is contained in:
10
.vscode/ftp-kr.sync.cache.json
vendored
10
.vscode/ftp-kr.sync.cache.json
vendored
@@ -9,8 +9,8 @@
|
|||||||
},
|
},
|
||||||
"api.php": {
|
"api.php": {
|
||||||
"type": "-",
|
"type": "-",
|
||||||
"size": 5529,
|
"size": 10947,
|
||||||
"lmtime": 1772790264251,
|
"lmtime": 1772982639016,
|
||||||
"modified": false
|
"modified": false
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -341,6 +341,12 @@
|
|||||||
"size": 657,
|
"size": 657,
|
||||||
"lmtime": 1772115859276,
|
"lmtime": 1772115859276,
|
||||||
"modified": false
|
"modified": false
|
||||||
|
},
|
||||||
|
"api-public-product-management.md": {
|
||||||
|
"type": "-",
|
||||||
|
"size": 6206,
|
||||||
|
"lmtime": 1772982690134,
|
||||||
|
"modified": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"feeds": {
|
"feeds": {
|
||||||
|
|||||||
86
api.php
86
api.php
@@ -340,6 +340,92 @@ if ( \S::get( 'action' ) == 'product_google_category_get' )
|
|||||||
] );
|
] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pobranie 10 produktow do optymalizacji (wg klikniec, bez nowego tytulu lub kategorii Google)
|
||||||
|
if ( \S::get( 'action' ) == 'products_to_optimize' )
|
||||||
|
{
|
||||||
|
api_validate_api_key( $mdb );
|
||||||
|
|
||||||
|
$client_id = trim( (string) \S::get( 'client_id' ) );
|
||||||
|
$google_ads_id = trim( (string) \S::get( 'google_ads_id' ) );
|
||||||
|
$merchant_id = trim( (string) \S::get( 'merchant_id' ) );
|
||||||
|
$limit = (int) \S::get( 'limit' );
|
||||||
|
|
||||||
|
if ( $limit <= 0 || $limit > 100 )
|
||||||
|
{
|
||||||
|
$limit = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve client_id from whichever parameter was provided
|
||||||
|
$resolved_client_id = null;
|
||||||
|
|
||||||
|
if ( $client_id !== '' )
|
||||||
|
{
|
||||||
|
$resolved_client_id = (int) $mdb -> get( 'clients', 'id', [ 'id' => (int) $client_id ] );
|
||||||
|
}
|
||||||
|
elseif ( $google_ads_id !== '' )
|
||||||
|
{
|
||||||
|
$google_ads_id_clean = str_replace( '-', '', $google_ads_id );
|
||||||
|
$resolved_client_id = (int) $mdb -> query(
|
||||||
|
'SELECT id FROM clients WHERE REPLACE( google_ads_customer_id, \'-\', \'\' ) = :gid LIMIT 1',
|
||||||
|
[ ':gid' => $google_ads_id_clean ]
|
||||||
|
) -> fetchColumn();
|
||||||
|
}
|
||||||
|
elseif ( $merchant_id !== '' )
|
||||||
|
{
|
||||||
|
$merchant_id_clean = str_replace( '-', '', $merchant_id );
|
||||||
|
$resolved_client_id = (int) $mdb -> query(
|
||||||
|
'SELECT id FROM clients WHERE REPLACE( google_merchant_account_id, \'-\', \'\' ) = :mid LIMIT 1',
|
||||||
|
[ ':mid' => $merchant_id_clean ]
|
||||||
|
) -> fetchColumn();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
api_json_response( [ 'result' => 'error', 'message' => 'Missing required param: client_id, google_ads_id or merchant_id' ], 422 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !$resolved_client_id )
|
||||||
|
{
|
||||||
|
api_json_response( [ 'result' => 'error', 'message' => 'Client not found' ], 404 );
|
||||||
|
}
|
||||||
|
|
||||||
|
$products = $mdb -> query(
|
||||||
|
'SELECT p.id,
|
||||||
|
p.offer_id,
|
||||||
|
p.name AS original_name,
|
||||||
|
p.title AS custom_title,
|
||||||
|
p.google_product_category,
|
||||||
|
p.product_url,
|
||||||
|
SUM( pa.clicks_30 ) AS clicks_30,
|
||||||
|
SUM( pa.clicks_all_time ) AS clicks_all_time,
|
||||||
|
SUM( pa.impressions_30 ) AS impressions_30,
|
||||||
|
SUM( pa.cost_30 ) AS cost_30,
|
||||||
|
SUM( pa.conversions_30 ) AS conversions_30,
|
||||||
|
SUM( pa.conversion_value_30 ) AS conversion_value_30
|
||||||
|
FROM products AS p
|
||||||
|
INNER JOIN products_aggregate AS pa ON pa.product_id = p.id
|
||||||
|
WHERE p.client_id = :client_id
|
||||||
|
AND (
|
||||||
|
TRIM( COALESCE( p.title, \'\' ) ) = \'\'
|
||||||
|
OR TRIM( COALESCE( p.google_product_category, \'\' ) ) = \'\'
|
||||||
|
)
|
||||||
|
GROUP BY p.id
|
||||||
|
HAVING clicks_all_time > 0
|
||||||
|
ORDER BY clicks_all_time DESC
|
||||||
|
LIMIT :limit',
|
||||||
|
[
|
||||||
|
':client_id' => $resolved_client_id,
|
||||||
|
':limit' => $limit
|
||||||
|
]
|
||||||
|
) -> fetchAll( \PDO::FETCH_ASSOC );
|
||||||
|
|
||||||
|
api_json_response( [
|
||||||
|
'result' => 'ok',
|
||||||
|
'client_id' => $resolved_client_id,
|
||||||
|
'count' => count( $products ),
|
||||||
|
'products' => $products
|
||||||
|
] );
|
||||||
|
}
|
||||||
|
|
||||||
// Open Page Rank - zapis
|
// Open Page Rank - zapis
|
||||||
if ( \S::get( 'action' ) == 'domain_opr_save' )
|
if ( \S::get( 'action' ) == 'domain_opr_save' )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -212,7 +212,99 @@ Jesli kategoria nie jest ustawiona:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.5 Ustawienie custom_label_4 (istniejacy endpoint)
|
### 4.5 Pobranie produktow do optymalizacji
|
||||||
|
|
||||||
|
- `action=products_to_optimize`
|
||||||
|
- Cel: zwraca liste produktow posortowanych wg klikniec (malejaco), ktore nie maja ustawionego custom tytulu (`title`) lub kategorii Google (`google_product_category`)
|
||||||
|
|
||||||
|
Identyfikacja klienta (wymagany dokladnie jeden z trzech):
|
||||||
|
- `client_id` (int) - lokalny identyfikator klienta w adsPRO
|
||||||
|
- `google_ads_id` (string) - ID konta Google Ads (z myslnikami lub bez, np. `123-456-7890` lub `1234567890`)
|
||||||
|
- `merchant_id` (string) - ID konta Google Merchant Center (z myslnikami lub bez)
|
||||||
|
|
||||||
|
Parametry dodatkowe:
|
||||||
|
- `api_key` (string, wymagany)
|
||||||
|
- `limit` (int, opcjonalny) - liczba produktow do zwrocenia (domyslnie 10, max 100)
|
||||||
|
|
||||||
|
Logika:
|
||||||
|
- Wybiera produkty, ktorych `title` jest pusty/NULL **lub** `google_product_category` jest pusty/NULL
|
||||||
|
- Pomija produkty z 0 klikniec (all-time)
|
||||||
|
- Sortuje po `clicks_all_time` malejaco (produkty z najwiekszym ruchem na gorze)
|
||||||
|
- Agreguje dane z `products_aggregate` (suma klikniec ze wszystkich kampanii/grup reklam)
|
||||||
|
|
||||||
|
Przyklad z `client_id`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -G "https://example.com/api.php" \
|
||||||
|
--data-urlencode "action=products_to_optimize" \
|
||||||
|
--data-urlencode "api_key=YOUR_API_KEY" \
|
||||||
|
--data-urlencode "client_id=12" \
|
||||||
|
--data-urlencode "limit=10"
|
||||||
|
```
|
||||||
|
|
||||||
|
Przyklad z `google_ads_id`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -G "https://example.com/api.php" \
|
||||||
|
--data-urlencode "action=products_to_optimize" \
|
||||||
|
--data-urlencode "api_key=YOUR_API_KEY" \
|
||||||
|
--data-urlencode "google_ads_id=123-456-7890"
|
||||||
|
```
|
||||||
|
|
||||||
|
Przyklad z `merchant_id`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -G "https://example.com/api.php" \
|
||||||
|
--data-urlencode "action=products_to_optimize" \
|
||||||
|
--data-urlencode "api_key=YOUR_API_KEY" \
|
||||||
|
--data-urlencode "merchant_id=987654321"
|
||||||
|
```
|
||||||
|
|
||||||
|
Przyklad odpowiedzi:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"result": "ok",
|
||||||
|
"client_id": 12,
|
||||||
|
"count": 3,
|
||||||
|
"products": [
|
||||||
|
{
|
||||||
|
"id": 987,
|
||||||
|
"offer_id": "SKU-123",
|
||||||
|
"original_name": "Buty sportowe Nike Air",
|
||||||
|
"custom_title": null,
|
||||||
|
"google_product_category": null,
|
||||||
|
"product_url": "https://example.com/buty-nike-air",
|
||||||
|
"clicks_30": 45,
|
||||||
|
"clicks_all_time": 312,
|
||||||
|
"impressions_30": 1200,
|
||||||
|
"cost_30": "89.500000",
|
||||||
|
"conversions_30": "3.000000",
|
||||||
|
"conversion_value_30": "450.000000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 654,
|
||||||
|
"offer_id": "SKU-456",
|
||||||
|
"original_name": "Koszulka Adidas",
|
||||||
|
"custom_title": "Koszulka sportowa Adidas Originals",
|
||||||
|
"google_product_category": null,
|
||||||
|
"product_url": "https://example.com/koszulka-adidas",
|
||||||
|
"clicks_30": 22,
|
||||||
|
"clicks_all_time": 198,
|
||||||
|
"impressions_30": 800,
|
||||||
|
"cost_30": "45.200000",
|
||||||
|
"conversions_30": "1.000000",
|
||||||
|
"conversion_value_30": "120.000000"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bledy specyficzne:
|
||||||
|
- Brak parametru identyfikujacego klienta: `422` z `"Missing required param: client_id, google_ads_id or merchant_id"`
|
||||||
|
- Klient nie znaleziony: `404` z `"Client not found"`
|
||||||
|
|
||||||
|
### 4.6 Ustawienie custom_label_4 (istniejacy endpoint)
|
||||||
|
|
||||||
- `action=product_custom_label_4_set`
|
- `action=product_custom_label_4_set`
|
||||||
- Cel: zapisuje `products.custom_label_4`
|
- Cel: zapisuje `products.custom_label_4`
|
||||||
@@ -270,9 +362,11 @@ Przy integracji AI zawsze ustawiaj jawnie `action` i weryfikuj, czy odpowiedz to
|
|||||||
|
|
||||||
## 7. Minimalny scenariusz end-to-end
|
## 7. Minimalny scenariusz end-to-end
|
||||||
|
|
||||||
1. Ustaw tytul (`product_title_set`)
|
1. Pobierz liste produktow do optymalizacji (`products_to_optimize`)
|
||||||
2. Potwierdz zmiane (`product_title_changed_check`)
|
2. Dla kazdego produktu z listy:
|
||||||
3. Ustaw kategorie (`product_google_category_set`)
|
a. Jesli `custom_title` jest `null` - ustaw tytul (`product_title_set`)
|
||||||
4. Odczytaj kategorie (`product_google_category_get`)
|
b. Potwierdz zmiane tytulu (`product_title_changed_check`)
|
||||||
|
c. Jesli `google_product_category` jest `null` - ustaw kategorie (`product_google_category_set`)
|
||||||
|
d. Odczytaj kategorie (`product_google_category_get`)
|
||||||
|
|
||||||
To daje prosty, deterministyczny przeplyw dla automatyzacji AI.
|
To daje prosty, deterministyczny przeplyw dla automatyzacji AI.
|
||||||
|
|||||||
Reference in New Issue
Block a user