diff --git a/.claude/settings.local.json b/.claude/settings.local.json index ee4f3af..320efbc 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -34,7 +34,9 @@ "mcp__serena__get_symbols_overview", "mcp__serena__search_for_pattern", "mcp__serena__read_file", - "mcp__serena__replace_content" + "mcp__serena__replace_content", + "mcp__serena__replace_symbol_body", + "mcp__serena__check_onboarding_performed" ] }, "statusLine": { diff --git a/.vscode/ftp-kr.sync.cache.json b/.vscode/ftp-kr.sync.cache.json index 5efd7b0..8e7a274 100644 --- a/.vscode/ftp-kr.sync.cache.json +++ b/.vscode/ftp-kr.sync.cache.json @@ -1,12 +1,6 @@ { "ftp://host700513.hostido.net.pl@www@adspro.projectpro.pl": { "public_html": { - "AGENTS.md": { - "type": "-", - "size": 2540, - "lmtime": 0, - "modified": false - }, "ajax.php": { "type": "-", "size": 1208, @@ -71,13 +65,13 @@ "controls": { "class.Allegro.php": { "type": "-", - "size": 6456, + "size": 6939, "lmtime": 0, - "modified": false + "modified": true }, "class.Api.php": { "type": "-", - "size": 19626, + "size": 20317, "lmtime": 1744498273470, "modified": true }, @@ -101,14 +95,14 @@ }, "class.Clients.php": { "type": "-", - "size": 11854, + "size": 12653, "lmtime": 1771619242656, - "modified": false + "modified": true }, "class.Cron.php": { "type": "-", - "size": 198900, - "lmtime": 1771619004019, + "size": 182399, + "lmtime": 1771755214561, "modified": false }, "class.FacebookAds.php": { @@ -117,11 +111,17 @@ "lmtime": 1771619366367, "modified": false }, + "class.Logs.php": { + "type": "-", + "size": 4821, + "lmtime": 0, + "modified": false + }, "class.Products.php": { "type": "-", - "size": 44261, - "lmtime": 1771440055487, - "modified": true + "size": 45248, + "lmtime": 1771757540415, + "modified": false }, "class.Site.php": { "type": "-", @@ -131,9 +131,9 @@ }, "class.Users.php": { "type": "-", - "size": 19292, + "size": 20039, "lmtime": 1771617570626, - "modified": false + "modified": true }, "class.XmlFiles.php": { "type": "-", @@ -151,8 +151,8 @@ }, "class.Campaigns.php": { "type": "-", - "size": 11156, - "lmtime": 1771626553779, + "size": 11208, + "lmtime": 1771755241179, "modified": false }, "class.Clients.php": { @@ -173,11 +173,17 @@ "lmtime": 1771619061605, "modified": false }, + "class.Logs.php": { + "type": "-", + "size": 4819, + "lmtime": 0, + "modified": false + }, "class.Products.php": { "type": "-", - "size": 32530, - "lmtime": 1771170224109, - "modified": true + "size": 33709, + "lmtime": 1771757529304, + "modified": false }, "class.Users.php": { "type": "-", @@ -248,8 +254,8 @@ ".claude": { "settings.local.json": { "type": "-", - "size": 730, - "lmtime": 1771617115553, + "size": 1421, + "lmtime": 1771755894778, "modified": false } }, @@ -342,14 +348,14 @@ }, "style.css": { "type": "-", - "size": 54205, - "lmtime": 1771494983015, + "size": 57679, + "lmtime": 1771757366015, "modified": false }, "style.css.map": { "type": "-", - "size": 145847, - "lmtime": 1771488979745, + "size": 154096, + "lmtime": 1771757366015, "modified": false }, "style-old.css": { @@ -366,8 +372,8 @@ }, "style.scss": { "type": "-", - "size": 65819, - "lmtime": 1771494864189, + "size": 67231, + "lmtime": 1771757365508, "modified": false } }, @@ -569,16 +575,28 @@ "lmtime": 0, "modified": false }, + "022_facebook_ads_roas_all_time.sql": { + "type": "-", + "size": 478, + "lmtime": 1771616256503, + "modified": false + }, + "023_logs.sql": { + "type": "-", + "size": 573, + "lmtime": 0, + "modified": false + }, "demo_data.sql": { "type": "-", "size": 21146, "lmtime": 0, "modified": true }, - "022_facebook_ads_roas_all_time.sql": { + "024_campaign_ad_groups_status.sql": { "type": "-", - "size": 478, - "lmtime": 1771616256503, + "size": 131, + "lmtime": 1771755182086, "modified": false } }, @@ -588,42 +606,30 @@ "lmtime": 1744488227849, "modified": false }, - "temp_fb_authentication.html": { - "type": "-", - "size": 1167861, - "lmtime": 0, - "modified": false - }, - "temp_fb_authorization.html": { - "type": "-", - "size": 1182404, - "lmtime": 0, - "modified": false - }, - "temp_fb_get_started.html": { - "type": "-", - "size": 1160708, - "lmtime": 0, - "modified": false - }, - "temp_fb_insights_async.html": { - "type": "-", - "size": 1190062, - "lmtime": 0, - "modified": false - }, - "temp_fb_system_users.html": { - "type": "-", - "size": 1172574, - "lmtime": 0, - "modified": false + ".serena": { + "cache": { + "typescript": { + "raw_document_symbols.pkl": { + "type": "-", + "size": 23480, + "lmtime": 1771755819379, + "modified": false + }, + "document_symbols.pkl": { + "type": "-", + "size": 142667, + "lmtime": 1771755819382, + "modified": false + } + } + } }, "templates": { "products": { "main_view.php": { "type": "-", - "size": 64362, - "lmtime": 1771717398898, + "size": 68170, + "lmtime": 1771757685790, "modified": false }, "product_history.php": { @@ -709,12 +715,6 @@ } }, "tmp": {}, - "TODO.md": { - "type": "-", - "size": 0, - "lmtime": 0, - "modified": false - }, "tools": {}, "upload": {}, "xml": {} diff --git a/autoload/services/class.GoogleAdsApi.php b/autoload/services/class.GoogleAdsApi.php index 69cfa63..a5d5564 100644 --- a/autoload/services/class.GoogleAdsApi.php +++ b/autoload/services/class.GoogleAdsApi.php @@ -107,8 +107,38 @@ class GoogleAdsApi return false; } - $remaining = array_fill_keys( $offer_ids, true ); + // 1. Proba bezposredniego GET po skonstruowanym productId $found = []; + $remaining_ids = []; + + foreach ( $offer_ids as $oid ) + { + $item = $this -> try_direct_merchant_product_get( $merchant_account_id, $oid, $access_token ); + if ( $item !== null ) + { + $link = trim( (string) ( $item['link'] ?? '' ) ); + if ( $this -> is_valid_merchant_product_url( $link ) ) + { + $found[ $oid ] = $link; + continue; + } + } + $remaining_ids[] = $oid; + } + + if ( empty( $remaining_ids ) ) + { + self::set_setting( 'google_merchant_last_error', null ); + return $found; + } + + // 2. Fallback: listowanie z case-insensitive matching + $remaining_lower = []; + foreach ( $remaining_ids as $oid ) + { + $remaining_lower[ strtolower( $oid ) ] = $oid; + } + $page_token = ''; $safety_limit = 500; @@ -157,8 +187,14 @@ class GoogleAdsApi foreach ( $items as $item ) { - $offer_id = trim( (string) ( $item['offerId'] ?? '' ) ); - if ( $offer_id === '' || !isset( $remaining[ $offer_id ] ) ) + $item_offer_id = trim( (string) ( $item['offerId'] ?? '' ) ); + if ( $item_offer_id === '' ) + { + continue; + } + + $item_offer_id_lower = strtolower( $item_offer_id ); + if ( !isset( $remaining_lower[ $item_offer_id_lower ] ) ) { continue; } @@ -169,11 +205,12 @@ class GoogleAdsApi continue; } - $found[ $offer_id ] = $link; - unset( $remaining[ $offer_id ] ); + $original_key = $remaining_lower[ $item_offer_id_lower ]; + $found[ $original_key ] = $link; + unset( $remaining_lower[ $item_offer_id_lower ] ); } - if ( empty( $remaining ) ) + if ( empty( $remaining_lower ) ) { break; } @@ -214,8 +251,36 @@ class GoogleAdsApi return false; } - $remaining = array_fill_keys( $offer_ids, true ); + // 1. Proba bezposredniego GET po skonstruowanym productId (szybkie, pewne) $found = []; + $remaining_ids = []; + + foreach ( $offer_ids as $oid ) + { + $item = $this -> try_direct_merchant_product_get( $merchant_account_id, $oid, $access_token ); + if ( $item !== null ) + { + $found[ $oid ] = $item; + } + else + { + $remaining_ids[] = $oid; + } + } + + if ( empty( $remaining_ids ) ) + { + self::set_setting( 'google_merchant_last_error', null ); + return $found; + } + + // 2. Fallback: listowanie produktow z case-insensitive matching + $remaining_lower = []; + foreach ( $remaining_ids as $oid ) + { + $remaining_lower[ strtolower( $oid ) ] = $oid; + } + $page_token = ''; $safety_limit = 500; @@ -264,17 +329,24 @@ class GoogleAdsApi foreach ( $items as $item ) { - $offer_id = trim( (string) ( $item['offerId'] ?? '' ) ); - if ( $offer_id === '' || !isset( $remaining[ $offer_id ] ) ) + $item_offer_id = trim( (string) ( $item['offerId'] ?? '' ) ); + if ( $item_offer_id === '' ) { continue; } - $found[ $offer_id ] = $item; - unset( $remaining[ $offer_id ] ); + $item_offer_id_lower = strtolower( $item_offer_id ); + if ( !isset( $remaining_lower[ $item_offer_id_lower ] ) ) + { + continue; + } + + $original_key = $remaining_lower[ $item_offer_id_lower ]; + $found[ $original_key ] = $item; + unset( $remaining_lower[ $item_offer_id_lower ] ); } - if ( empty( $remaining ) ) + if ( empty( $remaining_lower ) ) { break; } @@ -290,6 +362,62 @@ class GoogleAdsApi return $found; } + /** + * Bezposredni GET produktu z Merchant Center po skonstruowanym productId. + * Format: online:{contentLanguage}:{feedLabel}:{offerId} + * Probuje kilka wariantow lang/country wyekstrahowanych z offer_id. + */ + private function try_direct_merchant_product_get( $merchant_account_id, $offer_id, $access_token ) + { + $candidates = []; + + // Ekstrakcja jezyka/kraju z Shopify-style offer_id: shopify_XX_... + if ( preg_match( '/^shopify_([a-z]{2})_/i', $offer_id, $m ) ) + { + $lang = strtolower( $m[1] ); + $country = strtoupper( $m[1] ); + $candidates[] = 'online:' . $lang . ':' . $country . ':' . $offer_id; + } + + // Domyslnie polski rynek + $candidates[] = 'online:pl:PL:' . $offer_id; + $candidates[] = 'online:en:PL:' . $offer_id; + + $candidates = array_unique( $candidates ); + + foreach ( $candidates as $product_id ) + { + $url = self::$MERCHANT_BASE_URL . '/' . rawurlencode( $merchant_account_id ) + . '/products/' . rawurlencode( $product_id ); + + $ch = curl_init( $url ); + curl_setopt_array( $ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + 'Authorization: Bearer ' . $access_token, + 'Accept: application/json' + ], + CURLOPT_SSL_VERIFYPEER => true, + CURLOPT_TIMEOUT => 30, + ] ); + + $response = curl_exec( $ch ); + $http_code = curl_getinfo( $ch, CURLINFO_HTTP_CODE ); + curl_close( $ch ); + + if ( $http_code === 200 && $response ) + { + $item = json_decode( (string) $response, true ); + if ( is_array( $item ) && !empty( $item['id'] ) ) + { + return $item; + } + } + } + + return null; + } + public function update_merchant_product_fields_by_offer_id( $merchant_account_id, $offer_id, $fields ) { $merchant_account_id = preg_replace( '/\D+/', '', (string) $merchant_account_id ); diff --git a/templates/products/main_view.php b/templates/products/main_view.php index f8c9346..10cf077 100644 --- a/templates/products/main_view.php +++ b/templates/products/main_view.php @@ -1517,7 +1517,7 @@ $( function() ( AI_CLAUDE_ENABLED ? '' : '' ) + ( AI_GEMINI_ENABLED ? '' : '' ) + '' + - '0/150 znaków' + + '0/150 znaków' + '
' + '' + '