Migracja rozszerzeń opartych na zasobach

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

Ten dokument opisuje proces migracji i wyłączenia rozszerzeń opartych na pliku danych. Rozszerzenia oparte na plikach danych zostaną przeniesione zbiorczo do rozszerzeń opartych na zasobach, a w pełni wycofamy je w 2023 r.

Omówienie

Dotychczasowy schemat rozszerzeń opartych na plikach danych został zastąpiony przez rozszerzenia oparte na zasobach. Rozszerzenia oparte na zasobach upraszczają tworzenie rozszerzeń i zarządzanie nimi. Wymagane jest działanie, aby zachować kontrolę nad rozszerzeniami reklam.

Termin „rozszerzenie oparte na plikach danych” odnosi się do wszelkich zasobów lub funkcji powiązanych z tymi usługami:

Jeśli konkretny typ klienta, kampanii lub grupy reklam jest połączony z jednym typem klienta, a także rozszerzeniami opartymi na zasobach i plikami danych, wyświetlane będą rozszerzenia oparte na zasobach. Dotyczy to tylko elementów na tym samym poziomie. Na przykład połączenie zasobu z grupą reklam uniemożliwi wyświetlanie wszystkich plików danych w tej grupie reklam, ale wyświetlanie reklam w innych grupach reklam w tej samej kampanii będzie kontynuowane. Rozszerzenia oparte na zasobach będą domyślnie widoczne w interfejsie Google Ads.

Jeśli masz aktywne rozszerzenia obu typów, w interfejsie Google Ads możesz zobaczyć powiadomienie na stronie „Rozszerzenia”, podobnie jak na poniższym zrzucie ekranu. Rozszerzenia starszego typu opierają się na plikach danych, a rozszerzenia uaktualnione – na podstawie zasobów.

Ekran promocji

Pamiętaj, że po utworzeniu rozszerzeń opartych na zasobach widok domyślny zostanie uaktualniony.

Szczegóły migracji

Pliki danych są przenoszone przez skopiowanie istniejących wartości do nowej instancji rozszerzenia opartej na zasobach. Istniejące rozszerzenia oparte na plikach danych zostaną automatycznie skopiowane do rozszerzeń opartych na zasobach w określonych dniach. Wszystkie rozszerzenia oparte na zasobach mają nowe, niepowtarzalne wartości identyfikatorów.

Zalecamy samodzielne przeprowadzenie procesu migracji za pomocą interfejsu Google Ads API, zgodnie z informacjami w tym przewodniku, ponieważ pomiędzy zasobami utworzonymi automatycznie podczas migracji a tymi z plików danych nie ma powiązania.

Harmonogram migracji

Wszystkie istniejące rozszerzenia oparte na plikach danych zostaną automatycznie przeniesione do rozszerzeń opartych na zasobach. Przeniesione konta odrzucają wywołania mutacji dla elementów opartych na pliku danych.

Historyczne raporty dotyczące plików danych będą dostępne do sierpnia 2022 roku. Po migracji rozszerzenia oparte na plikach danych nie będą już generować nowych danych.

Automatyczny proces migracji spowoduje utworzenie rozszerzeń opartych na zasobach na podstawie rozszerzeń utworzonych na podstawie plików danych oraz zastąpienie wszystkich wystąpień tagów AdGroupFeed, CampaignFeed i CustomerFeed odpowiednikami w tagach AdGroupAsset, CampaignAsset i CustomerAsset. Jeśli grupa reklam, kampania lub klient są już połączone z zasobem, odpowiedni plik danych zostanie zignorowany.

Zmiany w rozszerzeniach opartych na zasobach

Rozszerzenia oparte na zasobach udostępniają te same funkcje co istniejące rozszerzenia oparte na plikach danych, ale niektóre z nich zostały usunięte, np. z funkcji dopasowania i większości pól kierowania.

Pola kierowania na grupy reklam, kampanie, słowa kluczowe, lokalizacje i urządzenia mobilne nie będą dostępne dla rozszerzeń opartych na zasobach.

W przypadku niektórych rozszerzeń opartych na zasobach niektóre pola będą niedostępne. Te pola zostały usunięte i nie zostaną automatycznie przeniesione:

  • Aplikacja: harmonogramy reklam
  • Zadzwoń: godzina rozpoczęcia, godzina zakończenia
  • Cena: czas rozpoczęcia, czas zakończenia, harmonogramy reklam
  • Rozszerzenie informacji: czas rozpoczęcia, czas zakończenia, harmonogramy reklam

Wszystkie pola związane z datą mają teraz format „rrrr-MM-dd”. W rozszerzeniach opartych na zasobach nie można określać pory dnia w żadnym polu daty.

W przypadku rozszerzeń opartych na zasobach zalecamy używanie funkcji kierowania, które są już dostępne na poziomie kampanii i grupy reklam. Jeśli preferujesz korzystanie z komórek, w przypadku wszystkich linków rozważ umieszczenie adresów URL dostosowanych do urządzeń mobilnych.

Funkcje dopasowywania nie będą dostępne w przypadku rozszerzeń opartych na zasobach. Podczas automatycznej migracji zostaną uwzględnione tylko te funkcje dopasowania:

Dopasowanie funkcji Uwagi dotyczące migracji
EQUALS(FEED_ITEM_ID, 1234567) Przeniesiona tak, jak jest
IN(FEED_ITEM_ID,{1234567,1234568,1234569}) Przeniesiona tak, jak jest
IDENTITY(false) Przeniesiony jako excluded_parent_asset_field_types
IDENTITY(true) przeniesione ze wszystkimi połączonymi elementami kanału, z wyjątkiem przypadków specjalnych opisanych poniżej;
AND(
IN(FEED_ITEM_ID,{1234567,1234568,1234569}),
EQUALS(CONTEXT.DEVICE,"Mobile"))
Przeniesiony jako IN(FEED_ITEM_ID,{1234567,1234568,1234569})
AND(
EQUALS(FEED_ITEM_ID, 1234567),
EQUALS(CONTEXT.DEVICE,"Mobile"))
Przeniesiony jako EQUALS(FEED_ITEM_ID,1234567)

Szczególny przypadek IDENTITY(true)

Funkcja dopasowania IDENTITY(true) zostanie zignorowana podczas automatycznej migracji, jeśli zostanie dołączona do rozszerzenia i będzie odpowiadać więcej niż 20 aktywnym elementom pliku danych. Należy dopasować funkcję dopasowania do notacji IN(FEED_ITEM_ID, {1234567,1234568,1234569}).

Możesz też samodzielnie przenieść rozszerzenia i połączyć rozszerzenie oparte na zasobach z innymi elementami. Każdy klient, kampania i grupa reklam można połączyć z maksymalnie 20 aktywnymi rozszerzeniami opartymi na zasobach tego samego typu. Informacje o tym, jak przeprowadzić migrację i dodać rozszerzenia oparte na zasobach, znajdziesz w procedurze migracji.

Uwagi dotyczące śledzenia połączeń

Pola call_tracking_enabled i call_conversion_tracking_disabled zostały usunięte w CallAsset. Śledzenie połączeń jest teraz kontrolowane na poziomie konta za pomocą narzędzia CallReportingSetting. Użyj pola CallAsset.call_conversion_reporting_state, aby włączyć śledzenie konwersji w rozszerzeniach połączeń. call_conversion_reporting_state może mieć jedną z tych wartości:

  • DISABLED, co oznacza, że nie będzie wykonywane działanie powodujące konwersję telefoniczną.
  • USE_ACCOUNT_LEVEL_CALL_CONVERSION_ACTION, co oznacza, że rozszerzenie będzie korzystać z typu konwersji telefonicznych ustawionego na poziomie konta.
  • USE_RESOURCE_LEVEL_CALL_CONVERSION_ACTION, co oznacza, że rozszerzenie będzie używać działania powodującego konwersję określonego w polu CallAsset.call_conversion_action. Pole CallAsset.call_conversion_action będzie ignorowane w przypadku pozostałych wartości call_conversion_reporting_state.

Jeśli w przypadku migracji rozszerzenia połączeń opartego na plikach danych call_conversion_tracking_disabled ma wartość true, nowe CallAsset'call_conversion_reporting_state powinny mieć wartość DISABLED. Domyślna wartość parametru call_conversion_reporting_state to USE_RESOURCE_LEVEL_CALL_CONVERSION_ACTION. Aby nadal uniemożliwić śledzenie konwersji za pomocą tego rozszerzenia, musisz ustawić wartość DISABLED na DISABLED. Ta zmiana zostanie wprowadzona w ramach automatycznej migracji od 8 kwietnia 2022 roku.

Jeśli zdecydujesz się przenieść własne rozszerzenia połączeń oparte na plikach danych i używasz obecnie śledzenia konwersji w reklamach generujących połączenia na komputerach, musisz przenieść wszystkie wystąpienia rozszerzeń połączeń do rozszerzeń opartych na zasobach na koncie jednocześnie. Wiąże się to z przypisaniem numerów Google do przekazywania połączeń, które będą przyznawane rozszerzeniom połączeń opartym na zasobach, tylko jeśli znajdują się na koncie.

Śledzenie rozszerzeń opartych na zasobach przy użyciu parametrów ValueTrack w adresach URL

Wszystkie parametry ValueTrack będą nadal działać w adresach URL w rozszerzeniach opartych na zasobach z wyjątkiem {feeditemid}. Zamiast tego użyj {extensionid}, aby połączyć dowolny końcowy URL,

lub parametr niestandardowy do rozszerzenia opartego na zasobach. Po przeniesieniu rozszerzenia opartego na pliku danych do rozszerzenia opartego na zasobach parametr {feeditemid} nie będzie już zwracać żadnej wartości.

Automatyczna procedura migracji nie spowoduje zmiany wystąpień parametru {feeditemid} na {extensionid}. Musisz zaktualizować wszystkie adresy URL, które używają parametru {feeditemid}, dodając do nich parametr {extensionid}. Dzięki temu będziesz śledzić kliknięcia obu typów rozszerzeń. Pamiętaj jednak, że po kliknięciu zostanie wypełnione tylko jedno z tych pól.

Wyświetlanie rozszerzeń opartych na zasobach

Rozszerzenia oparte na zasobach są dołączone do wyświetlania w kampaniach z linkami do różnych elementów.

AdGroupAsset
Rozszerzenie będzie wyświetlać się w tej grupie reklam.
CampaignAsset
Rozszerzenie będzie wyświetlać się w tej kampanii i we wszystkich jej grupach reklam.
CustomerAsset
Rozszerzenie będzie wyświetlać się w każdej kwalifikującej się kampanii.

Jest to sprzeczne z historycznym zachowaniem:

AdGroupFeed
Rozszerzenie będzie wyświetlać się w tej grupie reklam.
CampaignFeed
Rozszerzenia będą wyświetlać się w tej kampanii z wyjątkiem grup reklam z linkami do plików danych w grupach reklam.
CustomerFeed
Rozszerzenie będzie się wyświetlać w każdej kwalifikującej się kampanii lub grupie reklam z wyjątkiem kampanii i grup reklam z rozszerzeniami połączonymi z plikami danych kampanii lub grupy reklam.

Innymi słowy, przyłącza zasobów niższego poziomu w przeszłości zastąpiłyby wyższe poziomy. Kierowanie będzie jednak sumowane.

Procedura migracji

Aby przenieść rozszerzenie oparte na pliku danych do rozszerzenia opartego na zasobach, wykonaj te czynności:

  1. Określ istniejące rozszerzenie oparte na pliku danych, którego chcesz nadal używać.
  2. Skopiuj zawartość rozszerzenia opartego na pliku danych do nowego wystąpienia odpowiedniego rozszerzenia opartego na zasobach. Na przykład zawartość zasobu ExtensionFeedItem typu Promotion zostanie skopiowana do nowego obiektu PromotionAsset.
  3. Powiąż nowe rozszerzenie oparte na zasobach z tymi samymi grupami reklam i kampaniami.
  4. Sprawdź, czy rozszerzenie oparte na zasobach jest prawidłowo skonfigurowane.
  5. Usuń z konta rozszerzenie oparte na pliku danych.

Po skopiowaniu rozszerzenia opartego na plikach danych do rozszerzenia opartego na zasobach musisz natychmiast zaprzestać manipulowania tym rozszerzeniem za pomocą wymienionych wyżej usług związanych z plikami danych.

Usuń rozszerzenie oparte na pliku danych, gdy potwierdzisz, że zostało ono prawidłowo skopiowane do rozszerzenia opartego na zasobach.

Po usunięciu wszystkich elementów kanału z określonym elementem PlaceholderType typ rozszerzenia jest w pełni przenoszony. Wskazówki znajdziesz w artykule o usuwaniu rozszerzeń.

Poniższy przykład pokazuje każdy z powyższych etapów za pomocą rozszerzenia promocji.

Identyfikacja rozszerzeń opartych na plikach danych

Aby uzyskać listę elementów kanału, których dotyczy problem, musisz uruchomić zapytania GAQL na swoich kontach. Aby ułatwić zrozumienie tego przypadku, udostępniliśmy zapytania GAQL.

Natywne pliki danych

Jeśli Twoje konto ma natywne pliki danych (korzystające z Feed, FeedItem i FeedMapping), użyj poniższych zapytań, aby pobrać elementy kanału, które chcesz przenieść.

Najpierw pobierz wszystkie pliki danych z odpowiednim rozszerzeniem FeedMapping.

SELECT
  feed_mapping.feed,
  feed_mapping.placeholder_type,
  feed_mapping.attribute_field_mappings
FROM feed_mapping
WHERE feed_mapping.placeholder_type IN (
  // Batch 1 extensions (auto-migrating October 2021).
  'CALLOUT',
  'PROMOTION',
  'SITELINK',
  'STRUCTURED_SNIPPET',
  // Batch 2 extensions (auto-migrating April 2022).
  'APP',
  'CALL',
  'PRICE'
)

Teraz możesz użyć feed_mapping.feed do pobrania interesujących obiektów FeedItem.

SELECT feed_item.attribute_values
FROM feed_item
WHERE feed.resource_name = '<INSERT feed_mapping.feed>'

Elementy feed_item.attribute_values są interpretowane zgodnie z symbolami zastępczymi feed_mapping.attribute_field_mappings. Te mapowania pól informują, jak pola rozszerzeń są mapowane na feed_item.attribute_values.

Usługi ustawień rozszerzeń

Gdy rozszerzenia zostały utworzone przez usługi ustawień rozszerzeń (CustomerExtensionSettingService, CampaignExtensionSettingService, AdGroupExtensionSettingService itd.), uzyskanie identyfikatorów elementów kanału jest łatwiejsze.

Aby poprosić o aktywne identyfikatory elementów kanału określonego typu rozszerzenia, skorzystaj z poniższego zapytania dotyczącego języka zapytań Google Ads.

SELECT extension_feed_item.id
FROM extension_feed_item
WHERE extension_feed_item.status = 'ENABLED'
  AND extension_feed_item.extension_type = 'PROMOTION'

Zwrócone identyfikatory mogą posłużyć do pobrania szczegółów rozszerzenia.

Pobierz szczegóły rozszerzenia opartego na pliku danych

Gdy znajdziesz rozszerzenie oparte na pliku danych, które chcesz przenieść, poproś o jego pełne szczegóły, używając identyfikatora z innym zapytaniem Google Ads Language Language.

SELECT
  extension_feed_item.id,
  extension_feed_item.ad_schedules,
  extension_feed_item.device,
  extension_feed_item.status,
  extension_feed_item.start_date_time,
  extension_feed_item.end_date_time,
  extension_feed_item.targeted_campaign,
  extension_feed_item.targeted_ad_group,
  extension_feed_item.promotion_feed_item.discount_modifier,
  extension_feed_item.promotion_feed_item.final_mobile_urls,
  extension_feed_item.promotion_feed_item.final_url_suffix,
  extension_feed_item.promotion_feed_item.final_urls,
  extension_feed_item.promotion_feed_item.language_code,
  extension_feed_item.promotion_feed_item.money_amount_off.amount_micros,
  extension_feed_item.promotion_feed_item.money_amount_off.currency_code,
  extension_feed_item.promotion_feed_item.occasion,
  extension_feed_item.promotion_feed_item.orders_over_amount.amount_micros,
  extension_feed_item.promotion_feed_item.orders_over_amount.currency_code,
  extension_feed_item.promotion_feed_item.percent_off,
  extension_feed_item.promotion_feed_item.promotion_code,
  extension_feed_item.promotion_feed_item.promotion_end_date,
  extension_feed_item.promotion_feed_item.promotion_start_date,
  extension_feed_item.promotion_feed_item.promotion_target,
  extension_feed_item.promotion_feed_item.tracking_url_template
FROM extension_feed_item
WHERE extension_feed_item.extension_type = 'PROMOTION'
  AND extension_feed_item.id = 123456789012
LIMIT 1

Zwracany element ExtensionFeedItem będzie miał wszystkie ustawione wartości zawarte w określonym rozszerzeniu opartym na pliku danych, które można zastosować do rozszerzenia opartego na zasobach.

Jeśli używasz niestandardowych parametrów adresu URL, musisz je pobrać przy użyciu dodatkowego zapytania dotyczącego języka zapytań Google Ads. Dodaj wyniki do instancji ExtensionFeedItem pobranej przez poprzednie zapytanie. Zwróć uwagę, że identyfikator elementu kanału w tym zapytaniu jest taki sam jak identyfikator elementu kanału rozszerzenia używany w poprzednim zapytaniu.

SELECT feed_item.url_custom_parameters
FROM feed_item
WHERE feed_item.id = 123456789012

Utwórz rozszerzenie oparte na zasobach

Wartości pobrane w poprzednim kroku można następnie zastosować do nowego wystąpienia odpowiedniego zasobu.

Java

private String createPromotionAssetFromFeed(
    GoogleAdsClient googleAdsClient, Long customerId, ExtensionFeedItem extensionFeedItem) {
  PromotionFeedItem promotionFeedItem = extensionFeedItem.getPromotionFeedItem();
  // Creates the Promotion asset.
  Asset.Builder asset =
      Asset.newBuilder()
          .setName("Migrated from feed item " + extensionFeedItem.getId())
          .setTrackingUrlTemplate(promotionFeedItem.getTrackingUrlTemplate())
          .setFinalUrlSuffix(promotionFeedItem.getFinalUrlSuffix())
          .setPromotionAsset(
              PromotionAsset.newBuilder()
                  .setPromotionTarget(promotionFeedItem.getPromotionTarget())
                  .setDiscountModifier(promotionFeedItem.getDiscountModifier())
                  .setRedemptionEndDate(promotionFeedItem.getPromotionStartDate())
                  .setRedemptionEndDate(promotionFeedItem.getPromotionEndDate())
                  .setOccasion(promotionFeedItem.getOccasion())
                  .setLanguageCode(promotionFeedItem.getLanguageCode())
                  .addAllAdScheduleTargets(extensionFeedItem.getAdSchedulesList()))
          .addAllFinalUrls(promotionFeedItem.getFinalUrlsList())
          .addAllFinalMobileUrls(promotionFeedItem.getFinalMobileUrlsList())
          .addAllUrlCustomParameters(promotionFeedItem.getUrlCustomParametersList());

  // Either PercentOff or MoneyAmountOff must be set.
  if (promotionFeedItem.getPercentOff() > 0) {
    // Adjusts the percent off scale when copying.
    asset.getPromotionAssetBuilder().setPercentOff(promotionFeedItem.getPercentOff() / 100);
  } else {
    asset.getPromotionAssetBuilder().setMoneyAmountOff(promotionFeedItem.getMoneyAmountOff());
  }
  // Either PromotionCode or OrdersOverAmount must be set.
  if (promotionFeedItem.getPromotionCode() != null
      && promotionFeedItem.getPromotionCode().length() > 0) {
    asset.getPromotionAssetBuilder().setPromotionCode(promotionFeedItem.getPromotionCode());
  } else {
    asset.getPromotionAssetBuilder().setOrdersOverAmount(promotionFeedItem.getOrdersOverAmount());
  }
  // Sets the start and end dates if set in the existing extension.
  if (extensionFeedItem.hasStartDateTime()) {
    asset.getPromotionAssetBuilder().setStartDate(extensionFeedItem.getStartDateTime());
  }
  if (extensionFeedItem.hasEndDateTime()) {
    asset.getPromotionAssetBuilder().setEndDate(extensionFeedItem.getEndDateTime());
  }
  // Builds an operation to create the Promotion asset.
  AssetOperation operation = AssetOperation.newBuilder().setCreate(asset).build();
  // Gets the Asset Service client.
  try (AssetServiceClient assetServiceClient =
      googleAdsClient.getLatestVersion().createAssetServiceClient()) {
    // Issues the request and returns the resource name of the new Promotion asset.
    MutateAssetsResponse response =
        assetServiceClient.mutateAssets(String.valueOf(customerId), ImmutableList.of(operation));
    String resourceName = response.getResults(0).getResourceName();
    System.out.println("Created Promotion asset with resource name " + resourceName);
    return resourceName;
  }
}
      

C#

private string CreatePromotionAssetFromFeed(GoogleAdsClient client, long customerId,
    ExtensionFeedItem extensionFeedItem)
{
    // Get the Asset Service client.
    AssetServiceClient assetServiceClient = client.GetService(Services.V13.AssetService);

    PromotionFeedItem promotionFeedItem = extensionFeedItem.PromotionFeedItem;

    // Create the Promotion asset.
    Asset asset = new Asset
    {
        // Name field is optional.
        Name = $"Migrated from feed item #{extensionFeedItem.Id}",
        PromotionAsset = new PromotionAsset
        {
            PromotionTarget = promotionFeedItem.PromotionTarget,
            DiscountModifier = promotionFeedItem.DiscountModifier,
            RedemptionStartDate = promotionFeedItem.PromotionStartDate,
            RedemptionEndDate = promotionFeedItem.PromotionEndDate,
            Occasion = promotionFeedItem.Occasion,
            LanguageCode = promotionFeedItem.LanguageCode,
        },
        TrackingUrlTemplate = promotionFeedItem.TrackingUrlTemplate,
        FinalUrlSuffix = promotionFeedItem.FinalUrlSuffix
    };

    // Either PercentOff or MoneyAmountOff must be set.
    if (promotionFeedItem.PercentOff > 0)
    {
        // Adjust the percent off scale when copying.
        asset.PromotionAsset.PercentOff = promotionFeedItem.PercentOff / 100;
    }
    else
    {
        asset.PromotionAsset.MoneyAmountOff = new Money
        {
            AmountMicros = promotionFeedItem.MoneyAmountOff.AmountMicros,
            CurrencyCode = promotionFeedItem.MoneyAmountOff.CurrencyCode
        };
    }

    // Either PromotionCode or OrdersOverAmount must be set.
    if (!string.IsNullOrEmpty(promotionFeedItem.PromotionCode))
    {
        asset.PromotionAsset.PromotionCode = promotionFeedItem.PromotionCode;
    }
    else
    {
        asset.PromotionAsset.OrdersOverAmount = new Money
        {
            AmountMicros = promotionFeedItem.OrdersOverAmount.AmountMicros,
            CurrencyCode = promotionFeedItem.OrdersOverAmount.CurrencyCode
        };
    }

    // Set the start and end dates if set in the existing extension.
    if (extensionFeedItem.HasStartDateTime)
    {
        asset.PromotionAsset.StartDate = DateTime.Parse(extensionFeedItem.StartDateTime)
            .ToString("yyyy-MM-dd");
    }

    if (extensionFeedItem.HasEndDateTime)
    {
        asset.PromotionAsset.EndDate = DateTime.Parse(extensionFeedItem.EndDateTime)
            .ToString("yyyy-MM-dd");
    }

    asset.PromotionAsset.AdScheduleTargets.Add(extensionFeedItem.AdSchedules);
    asset.FinalUrls.Add(promotionFeedItem.FinalUrls);
    asset.FinalMobileUrls.Add(promotionFeedItem.FinalMobileUrls);
    asset.UrlCustomParameters.Add(promotionFeedItem.UrlCustomParameters);

    // Build an operation to create the Promotion asset.
    AssetOperation operation = new AssetOperation
    {
        Create = asset
    };

    // Issue the request and return the resource name of the new Promotion asset.
    MutateAssetsResponse response = assetServiceClient.MutateAssets(
        customerId.ToString(), new[] { operation });
    Console.WriteLine("Created Promotion asset with resource name " +
        $"{response.Results.First().ResourceName}");
    return response.Results.First().ResourceName;
}
      

PHP

private static function createPromotionAssetFromFeed(
    GoogleAdsClient $googleAdsClient,
    int $customerId,
    ExtensionFeedItem $extensionFeedItem
): string {
    $promotionFeedItem = $extensionFeedItem->getPromotionFeedItem();
    // Creates the Promotion asset.
    $asset = new Asset([
        // Name field is optional.
        'name' => 'Migrated from feed item #' . $extensionFeedItem->getId(),
        'promotion_asset' => new PromotionAsset([
            'promotion_target' => $promotionFeedItem->getPromotionTarget(),
            'discount_modifier' => $promotionFeedItem->getDiscountModifier(),
            'redemption_start_date' => $promotionFeedItem->getPromotionStartDate(),
            'redemption_end_date' => $promotionFeedItem->getPromotionEndDate(),
            'occasion' => $promotionFeedItem->getOccasion(),
            'language_code' => $promotionFeedItem->getLanguageCode(),
            'ad_schedule_targets' => $extensionFeedItem->getAdSchedules()
        ]),
        'tracking_url_template' => $promotionFeedItem->getTrackingUrlTemplate(),
        'url_custom_parameters' => $promotionFeedItem->getUrlCustomParameters(),
        'final_urls' => $promotionFeedItem->getFinalUrls(),
        'final_mobile_urls' => $promotionFeedItem->getFinalMobileUrls(),
        'final_url_suffix' => $promotionFeedItem->getFinalUrlSuffix(),
    ]);

    // Either percent off or money amount off must be set.
    if ($promotionFeedItem->getPercentOff() > 0) {
        // Adjust the percent off scale when copying.
        $asset->getPromotionAsset()->setPercentOff($promotionFeedItem->getPercentOff() / 100);
    } else {
        $money = new Money([
           'amount_micros' => $promotionFeedItem->getMoneyAmountOff()->getAmountMicros(),
           'currency_code' => $promotionFeedItem->getMoneyAmountOff()->getCurrencyCode()
        ]);
        $asset->getPromotionAsset()->setMoneyAmountOff($money);
    }

    // Either promotion code or orders over amount must be set.
    if (!empty($promotionFeedItem->getPromotionCode())) {
        $asset->getPromotionAsset()->setPromotionCode($promotionFeedItem->getPromotionCode());
    } else {
        $money = new Money([
            'amount_micros' => $promotionFeedItem->getOrdersOverAmount()->getAmountMicros(),
            'currency_code' => $promotionFeedItem->getOrdersOverAmount()->getCurrencyCode()
        ]);
        $asset->getPromotionAsset()->setOrdersOverAmount($money);
    }

    if ($extensionFeedItem->hasStartDateTime()) {
        $startDateTime = new \DateTime($extensionFeedItem->getStartDateTime());
        $asset->getPromotionAsset()->setStartDate($startDateTime->format('yyyy-MM-dd'));
    }
    if ($extensionFeedItem->hasEndDateTime()) {
        $endDateTime = new \DateTime($extensionFeedItem->getEndDateTime());
        $asset->getPromotionAsset()->setEndDate($endDateTime->format('yyyy-MM-dd'));
    }

    // Creates an operation to add the Promotion asset.
    $assetOperation = new AssetOperation();
    $assetOperation->setCreate($asset);

    // Issues a mutate request to add the Promotion asset and prints its information.
    $assetServiceClient = $googleAdsClient->getAssetServiceClient();
    $response = $assetServiceClient->mutateAssets($customerId, [$assetOperation]);
    $assetResourceName = $response->getResults()[0]->getResourceName();
    printf(
        "Created the Promotion asset with resource name: '%s'.%s",
        $assetResourceName,
        PHP_EOL
    );

    return $assetResourceName;
}
      

Python

def create_promotion_asset_from_feed(client, customer_id, extension_feed_item):
    """Retrieves all campaigns associated with the given FeedItem resource name.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
        extension_feed_item: an extension feed item.

    Returns:
        the resource name of a newly created promotion asset.
    """
    asset_service = client.get_service("AssetService")
    promotion_feed_item = extension_feed_item.promotion_feed_item

    # Create an asset operation to start building the new promotion asset using
    # data from the given extension feed item.
    asset_operation = client.get_type("AssetOperation")
    asset = asset_operation.create
    asset.name = f"Migrated from feed item ID '{extension_feed_item.id}'"
    asset.tracking_url_template = promotion_feed_item.tracking_url_template
    asset.final_url_suffix = promotion_feed_item.final_url_suffix
    asset.final_urls.extend(promotion_feed_item.final_urls)
    asset.final_mobile_urls.extend(promotion_feed_item.final_mobile_urls)

    promotion_asset = asset.promotion_asset
    promotion_asset.promotion_target = promotion_feed_item.promotion_target
    promotion_asset.discount_modifier = promotion_feed_item.discount_modifier
    promotion_asset.redemption_start_date = (
        promotion_feed_item.promotion_start_date
    )
    promotion_asset.redemption_end_date = promotion_feed_item.promotion_end_date
    promotion_asset.occasion = promotion_feed_item.occasion
    promotion_asset.language_code = promotion_feed_item.language_code
    promotion_asset.ad_schedule_targets.extend(extension_feed_item.ad_schedules)

    # Either percent_off or money_amount_off must be set.
    if promotion_feed_item.percent_off > 0:
        # Adjust the percent off scale after copying. Extension feed items
        # interpret 1,000,000 as 1% and assets interpret 1,000,000 as 100% so
        # to migrate the correct discount value we must divide it by 100.
        promotion_asset.percent_off = int(promotion_feed_item.percent_off / 100)
    else:
        # If percent_off is not set then copy money_amount_off. This field is
        # an instance of Money in both cases, so setting the field with
        # copy_from is possible. Using regular assignment is also valid here.
        client.copy_from(
            promotion_asset.money_amount_off,
            promotion_feed_item.money_amount_off,
        )

    # Check if promotion_code field is set
    if promotion_feed_item.promotion_code:
        promotion_asset.promotion_code = promotion_feed_item.promotion_code
    else:
        # If promotion_code is not set then copy orders_over_amount. This field
        # is an instance of Money in both cases, so setting the field with
        # copy_from is possible. Using regular assignment is also valid here.
        client.copy_from(
            promotion_asset.orders_over_amount,
            promotion_feed_item.orders_over_amount,
        )

    # Set the start and end dates if set in the existing extension.
    if promotion_feed_item.promotion_start_date:
        promotion_asset.start_date = promotion_feed_item.promotion_start_date

    if promotion_feed_item.promotion_end_date:
        promotion_asset.end_date = promotion_feed_item.promotion_end_date

    response = asset_service.mutate_assets(
        customer_id=customer_id, operations=[asset_operation]
    )
    resource_name = response.results[0].resource_name
    print(f"Created promotion asset with resource name: '{resource_name}'")

    return resource_name


      

Ruby

def create_promotion_asset_from_feed(client, customer_id, extension_feed_item)
  # Create a Promotion asset that copies values from the specified extension feed item.

  asset_service = client.service.asset
  promotion_feed_item = extension_feed_item.promotion_feed_item

  # Create an asset operation to start building the new promotion asset using
  # data from the given extension feed item.
  asset_operation = client.operation.create_resource.asset do |asset|
    asset.name = "Migrated from feed item ID '#{extension_feed_item.id}'"
    asset.tracking_url_template = promotion_feed_item.tracking_url_template
    asset.final_url_suffix = promotion_feed_item.final_url_suffix
    asset.final_urls += promotion_feed_item.final_urls
    asset.final_mobile_urls += promotion_feed_item.final_mobile_urls

    # Create the Promotion asset.
    asset.promotion_asset = client.resource.promotion_asset do |pa|
      pa.promotion_target = promotion_feed_item.promotion_target
      pa.discount_modifier = promotion_feed_item.discount_modifier
      pa.redemption_start_date = promotion_feed_item.promotion_start_date
      pa.redemption_end_date = promotion_feed_item.promotion_end_date
      pa.occasion = promotion_feed_item.occasion
      pa.language_code = promotion_feed_item.language_code
      pa.ad_schedule_targets += extension_feed_item.ad_schedules

      # Either percent_off or money_amount_off must be set.
      if promotion_feed_item.percent_off.positive?
        # Adjust the percent off scale after copying.
        pa.percent_off = int(promotion_feed_item.percent_off / 100)
      else
        # If percent_off is not set then copy money_amount_off. This field is
        # an instance of Money in both cases, so setting the field with
        # copy_from is possible. Using regular assignment is also valid here.
        pa.money_amount_off = promotion_feed_item.money_amount_off
      end

      # Either promotion_code or orders_over_amount must be set.
      if promotion_feed_item.promotion_code.empty?
        pa.orders_over_amount = promotion_feed_item.orders_over_amount
      else
        pa.promotion_code = promotion_feed_item.promotion_code
      end

      # Set the start and end dates if set in the existing extension.
      unless promotion_feed_item.promotion_start_date.empty?
        pa.start_date = promotion_feed_item.promotion_start_date
      end

      unless promotion_feed_item.promotion_end_date.empty?
        pa.end_date = promotion_feed_item.promotion_end_date
      end
    end
  end

  response = asset_service.mutate_assets(customer_id: customer_id, operations: [asset_operation])
  resource_name = response.results.first.resource_name
  puts "Created promotion asset with resource name: '#{resource_name}'"

  resource_name
end
      

Perl

sub create_promotion_asset_from_feed {
  my ($api_client, $customer_id, $extension_feed_item) = @_;

  my $promotion_feed_item = $extension_feed_item->{promotionFeedItem};

  # Create the Promotion asset.
  my $asset = Google::Ads::GoogleAds::V13::Resources::Asset->new({
      name => "Migrated from feed item #" . $extension_feed_item->{id},
      trackingUrlTemplate => $promotion_feed_item->{trackingUrlTemplate},
      finalUrlSuffix      => $promotion_feed_item->{finalUrlSuffix},
      promotionAsset      =>
        Google::Ads::GoogleAds::V13::Common::PromotionAsset->new({
          promotionTarget     => $promotion_feed_item->{promotionTarget},
          discountModifier    => $promotion_feed_item->{discountModifier},
          redemptionStartDate => $promotion_feed_item->{promotionStartDate},
          redemptionEndDate   => $promotion_feed_item->{promotionEndDate},
          occasion            => $promotion_feed_item->{occasion},
          languageCode        => $promotion_feed_item->{languageCode}})});

  push @{$asset->{finalUrls}}, @{$promotion_feed_item->{finalUrls}};

  # Copy optional fields if present in the existing extension.
  if (defined($extension_feed_item->{adSchedules})) {
    push @{$asset->{promotionAsset}{adScheduleTargets}},
      @{$extension_feed_item->{adSchedules}};
  }

  if (defined($promotion_feed_item->{finalMobileUrls})) {
    push @{$asset->{finalMobileUrls}},
      @{$promotion_feed_item->{finalMobileUrls}};
  }

  if (defined($promotion_feed_item->{urlCustomParameters})) {
    push @{$asset->{urlCustomParameters}},
      @{$promotion_feed_item->{urlCustomParameters}};
  }

  # Either percentOff or moneyAmountOff must be set.
  if (defined($promotion_feed_item->{percentOff})) {
    # Adjust the percent off scale when copying.
    $asset->{promotionAsset}{percentOff} =
      $promotion_feed_item->{percentOff} / 100;
  } else {
    $asset->{promotionAsset}{moneyAmountOff} =
      Google::Ads::GoogleAds::V13::Common::Money->new({
        amountMicros => $promotion_feed_item->{moneyAmountOff}{amountMicros},
        currencyCode => $promotion_feed_item->{moneyAmountOff}{currencyCode}});
  }

  # Either promotionCode or ordersOverAmount must be set.
  if (defined($promotion_feed_item->{promotionCode})) {
    $asset->{promotionAsset}{promotionCode} =
      $promotion_feed_item->{promotionCode};
  } else {
    $asset->{promotionAsset}{ordersOverAmount} =
      Google::Ads::GoogleAds::V13::Common::Money->new({
        amountMicros => $promotion_feed_item->{ordersOverAmount}{amountMicros},
        currencyCode => $promotion_feed_item->{ordersOverAmount}{currencyCode}}
      );
  }

  # Set the start and end dates if set in the existing extension.
  if (defined($extension_feed_item->{startDateTime})) {
    $asset->{promotionAsset}{startDate} =
      substr($extension_feed_item->{startDateTime},
      0, index($extension_feed_item->{startDateTime}, ' '));
  }

  if (defined($extension_feed_item->{endDateTime})) {
    $asset->{promotionAsset}{endDate} =
      substr($extension_feed_item->{endDateTime},
      0, index($extension_feed_item->{endDateTime}, ' '));
  }

  # Build an operation to create the Promotion asset.
  my $operation =
    Google::Ads::GoogleAds::V13::Services::AssetService::AssetOperation->new({
      create => $asset
    });

  # Issue the request and return the resource name of the new Promotion asset.
  my $response = $api_client->AssetService()->mutate({
      customerId => $customer_id,
      operations => [$operation]});

  printf
    "Created Promotion asset with resource name '%s'.\n",
    $response->{results}[0]{resourceName};

  return $response->{results}[0]{resourceName};
}
      

Powiązanie zasobu z kampaniami i grupami reklam

Nowy komponent może być teraz powiązany z tymi samymi klientami, kampaniami i grupami reklam co pierwotne rozszerzenie oparte na pliku danych. Najpierw pobierz identyfikatory zasobów, które są obecnie powiązane z ustawieniem rozszerzenia.

Java

private List<Long> getTargetedCampaignIds(
    GoogleAdsServiceClient client, Long customerId, String extensionFeedItemResourceName) {
  String query =
      "SELECT campaign.id, campaign_extension_setting.extension_feed_items "
          + "FROM campaign_extension_setting "
          + "WHERE campaign_extension_setting.extension_type = 'PROMOTION' "
          + "  AND campaign.status != 'REMOVED'";
  ServerStream<SearchGoogleAdsStreamResponse> serverStream =
      client
          .searchStreamCallable()
          .call(
              SearchGoogleAdsStreamRequest.newBuilder()
                  .setCustomerId(String.valueOf(customerId))
                  .setQuery(query)
                  .build());
  List<Long> campaignIds = new ArrayList<>();
  for (SearchGoogleAdsStreamResponse response : serverStream) {
    for (GoogleAdsRow row : response.getResultsList()) {
      Campaign campaign = row.getCampaign();
      CampaignExtensionSetting extensionSetting = row.getCampaignExtensionSetting();
      // Adds the campaign ID to the list of IDs if the extension feed item is
      // associated with this extension setting.
      if (extensionSetting.getExtensionFeedItemsList().contains(extensionFeedItemResourceName)) {
        campaignIds.add(campaign.getId());
        System.out.println("Found matching campaign with ID " + campaign.getId());
      }
    }
  }
  return campaignIds;
}
      

C#

private List<long> GetTargetedCampaignIds(GoogleAdsServiceClient googleAdsServiceClient,
    long customerId, string extensionFeedResourceName)
{
    List<long> campaignIds = new List<long>();

    string query = @"
        SELECT campaign.id, campaign_extension_setting.extension_feed_items
        FROM campaign_extension_setting
        WHERE campaign_extension_setting.extension_type = 'PROMOTION'
          AND campaign.status != 'REMOVED'";

    googleAdsServiceClient.SearchStream(customerId.ToString(), query,
        delegate (SearchGoogleAdsStreamResponse response)
        {
            foreach (GoogleAdsRow googleAdsRow in response.Results)
            {
                // Add the campaign ID to the list of IDs if the extension feed item is
                // associated with this extension setting.
                if (googleAdsRow.CampaignExtensionSetting.ExtensionFeedItems.Contains(
                    extensionFeedResourceName))
                {
                    Console.WriteLine(
                        $"Found matching campaign with ID {googleAdsRow.Campaign.Id}.");
                    campaignIds.Add(googleAdsRow.Campaign.Id);
                }
            }
        }
    );

    return campaignIds;
}
      

PHP

private static function getTargetedCampaignIds(
    GoogleAdsClient $googleAdsClient,
    int $customerId,
    string $extensionFeedItemResourceName
): array {
    $campaignIds = [];
    $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
    // Create a query that will retrieve the campaign extension settings.
    $query = "SELECT campaign.id, campaign_extension_setting.extension_feed_items "
        . "FROM campaign_extension_setting "
        . "WHERE campaign_extension_setting.extension_type = 'PROMOTION' "
        . "AND campaign.status != 'REMOVED'";

    // Issue a search request to get the campaign extension settings.
    /** @var GoogleAdsServerStreamDecorator $stream */
    $stream = $googleAdsServiceClient->searchStream($customerId, $query);
    foreach ($stream->iterateAllElements() as $googleAdsRow) {
        /** @var GoogleAdsRow $googleAdsRow */
        // Add the campaign ID to the list of IDs if the extension feed item is
        // associated with this extension setting.
        if (
            in_array(
                $extensionFeedItemResourceName,
                iterator_to_array(
                    $googleAdsRow->getCampaignExtensionSetting()->getExtensionFeedItems()
                )
            )
        ) {
            printf(
                "Found matching campaign with ID %d.%s",
                $googleAdsRow->getCampaign()->getId(),
                PHP_EOL
            );
            $campaignIds[] = $googleAdsRow->getCampaign()->getId();
        }
    }
    return $campaignIds;
}
      

Python

def get_targeted_campaign_ids(client, customer_id, resource_name):
    """Retrieves all campaigns associated with the given FeedItem resource name.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
        resource_name: an extension feed item resource name.

    Returns:
        a list of campaign IDs.
    """
    ga_service = client.get_service("GoogleAdsService")

    query = """
      SELECT
        campaign.id,
        campaign_extension_setting.extension_feed_items
      FROM campaign_extension_setting
      WHERE
        campaign_extension_setting.extension_type = 'PROMOTION'
        AND campaign.status != 'REMOVED'"""

    stream = ga_service.search_stream(customer_id=customer_id, query=query)

    campaign_ids = []

    for batch in stream:
        for row in batch.results:
            feed_items = row.campaign_extension_setting.extension_feed_items
            if resource_name in feed_items:
                print(f"Found matching campaign with ID: '{row.campaign.id}'")
                campaign_ids.append(row.campaign.id)

    return campaign_ids


      

Ruby

def get_targeted_campaign_ids(client, customer_id, resource_name)
  # Finds and returns all of the campaigns that are associated with the specified
  # Promotion extension feed item.

  query = <<~QUERY
    SELECT
      campaign.id,
      campaign_extension_setting.extension_feed_items
    FROM campaign_extension_setting
    WHERE
      campaign_extension_setting.extension_type = 'PROMOTION'
      AND campaign.status != 'REMOVED'
  QUERY

  responses = client.service.google_ads.search_stream(customer_id: customer_id, query: query)

  campaign_ids = []

  responses.each do |response|
    response.results.each do |row|
      feed_items = row.campaign_extension_setting.extension_feed_items
      if feed_items.include?(resource_name)
        puts "Found matching campaign with ID '#{row.campaign.id}'."
        campaign_ids << row.campaign.id
      end
    end
  end

  campaign_ids
end
      

Perl

sub get_targeted_campaign_ids {
  my ($google_ads_service, $customer_id, $extension_feed_item_resource_name) =
    @_;

  my @campaign_ids;

  my $query = "
        SELECT campaign.id, campaign_extension_setting.extension_feed_items
        FROM campaign_extension_setting
        WHERE campaign_extension_setting.extension_type = 'PROMOTION'
          AND campaign.status != 'REMOVED'";

  my $search_stream_request =
    Google::Ads::GoogleAds::V13::Services::GoogleAdsService::SearchGoogleAdsStreamRequest
    ->new({
      customerId => $customer_id,
      query      => $query
    });

  my $search_stream_handler =
    Google::Ads::GoogleAds::Utils::SearchStreamHandler->new({
      service => $google_ads_service,
      request => $search_stream_request
    });

  $search_stream_handler->process_contents(
    sub {
      my $google_ads_row = shift;

      # Add the campaign ID to the list of IDs if the extension feed item
      # is associated with this extension setting.
      if (grep { $_ eq $extension_feed_item_resource_name }
        @{$google_ads_row->{campaignExtensionSetting}{extensionFeedItems}})
      {
        printf
          "Found matching campaign with ID $google_ads_row->{campaign}{id}.\n";
        push @campaign_ids, $google_ads_row->{campaign}{id};
      }
    });

  return @campaign_ids;
}
      

Następnie utwórz i prześlij nowe zasoby CampaignAsset, AdGroupAsset lub CustomerAsset, aby połączyć zasób z każdym zasobem.

Java

private void associateAssetWithCampaigns(
    GoogleAdsClient googleAdsClient,
    Long customerId,
    String promotionAssetResourceName,
    List<Long> campaignIds) {
  if (campaignIds.isEmpty()) {
    System.out.println("Asset was not associated with any campaigns.");
    return;
  }

  // Constructs an operation to associate the asset with each campaign.
  List<CampaignAssetOperation> campaignAssetOperations =
      campaignIds.stream()
          .map(
              id ->
                  CampaignAssetOperation.newBuilder()
                      .setCreate(
                          CampaignAsset.newBuilder()
                              .setAsset(promotionAssetResourceName)
                              .setFieldType(AssetFieldType.PROMOTION)
                              .setCampaign(ResourceNames.campaign(customerId, id)))
                      .build())
          .collect(Collectors.toList());

  // Creates a service client.
  try (CampaignAssetServiceClient campaignAssetServiceClient =
      googleAdsClient.getLatestVersion().createCampaignAssetServiceClient()) {
    // Issues the mutate request.
    MutateCampaignAssetsResponse response =
        campaignAssetServiceClient.mutateCampaignAssets(
            String.valueOf(customerId), campaignAssetOperations);
    // Prints some information about the result.
    for (MutateCampaignAssetResult result : response.getResultsList()) {
      System.out.println("Created campaign asset with resource name " + result.getResourceName());
    }
  }
}
      

C#

private void AssociateAssetWithCampaigns(GoogleAdsClient client, long customerId,
    string promotionAssetResourceName, List<long> campaignIds)
{
    if (campaignIds.Count == 0)
    {
        Console.WriteLine("Asset was not associated with any campaigns.");
        return;
    }

    CampaignAssetServiceClient campaignAssetServiceClient = client.GetService(Services.V13
        .CampaignAssetService);

    List<CampaignAssetOperation> operations = new List<CampaignAssetOperation>();

    foreach (long campaignId in campaignIds)
    {
        operations.Add(new CampaignAssetOperation
        {
            Create = new CampaignAsset
            {
                Asset = promotionAssetResourceName,
                FieldType = AssetFieldTypeEnum.Types.AssetFieldType.Promotion,
                Campaign = ResourceNames.Campaign(customerId, campaignId),
            }
        });
    }

    MutateCampaignAssetsResponse response = campaignAssetServiceClient.MutateCampaignAssets(
        customerId.ToString(), operations);

    foreach (MutateCampaignAssetResult result in response.Results)
    {
        Console.WriteLine($"Created campaign asset with resource name " +
            $"{result.ResourceName}.");
    }
}
      

PHP

private static function associateAssetWithCampaigns(
    GoogleAdsClient $googleAdsClient,
    int $customerId,
    string $promotionAssetResourceName,
    array $campaignIds
) {
    if (empty($campaignIds)) {
        print 'Asset was not associated with any campaigns.' . PHP_EOL;
        return;
    }
    $operations = [];
    foreach ($campaignIds as $campaignId) {
        $operations[] = new CampaignAssetOperation([
            'create' => new CampaignAsset([
                'asset' => $promotionAssetResourceName,
                'field_type' => AssetFieldType::PROMOTION,
                'campaign' => ResourceNames::forCampaign($customerId, $campaignId)
            ])
        ]);
    }
    // Issues a mutate request to add the campaign assets and prints their information.
    $campaignAssetServiceClient = $googleAdsClient->getCampaignAssetServiceClient();
    $response = $campaignAssetServiceClient->mutateCampaignAssets($customerId, $operations);
    foreach ($response->getResults() as $addedCampaignAsset) {
        /** @var CampaignAsset $addedCampaignAsset */
        printf(
            "Created campaign asset with resource name: '%s'.%s",
            $addedCampaignAsset->getResourceName(),
            PHP_EOL
        );
    }
}
      

Python

def associate_asset_with_campaigns(
    client, customer_id, promotion_asset_resource_name, campaign_ids
):
    """Associates the specified promotion asset with the specified campaigns.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
        promotion_asset_resource_name: the resource name for a promotion asset.
        campaign_ids: a list of campaign IDs.
    """
    if len(campaign_ids) == 0:
        print(f"Asset was not associated with any campaigns.")
        return

    campaign_service = client.get_service("CampaignService")
    campaign_asset_service = client.get_service("CampaignAssetService")

    operations = []

    for campaign_id in campaign_ids:
        operation = client.get_type("CampaignAssetOperation")
        campaign_asset = operation.create
        campaign_asset.asset = promotion_asset_resource_name
        campaign_asset.field_type = client.enums.AssetFieldTypeEnum.PROMOTION
        campaign_asset.campaign = campaign_service.campaign_path(
            customer_id, campaign_id
        )
        operations.append(operation)

    response = campaign_asset_service.mutate_campaign_assets(
        customer_id=customer_id, operations=operations
    )

    for result in response.results:
        print(
            "Created campaign asset with resource name: "
            f"'{result.resource_name}'"
        )


      

Ruby

def associate_asset_with_campaigns(client, customer_id, promotion_asset_resource_name, campaign_ids)
  # Associates the specified promotion asset with the specified campaigns.

  if campaign_ids.empty?
    puts 'Asset was not associated with any campaigns.'
    return
  end

  operations = campaign_ids.map do |campaign_id|
    client.operation.create_resource.campaign_asset do |ca|
      ca.asset = promotion_asset_resource_name
      ca.field_type = :PROMOTION
      ca.campaign = client.path.campaign(customer_id, campaign_id)
    end
  end

  response = client.service.campaign_asset.mutate_campaign_assets(
    customer_id: customer_id,
    operations: operations,
  )

  response.results.each do |result|
    puts "Created campaign asset with resource name '#{result.resource_name}'."
  end
end
      

Perl

sub associate_asset_with_campaigns {
  my ($api_client, $customer_id, $promotion_asset_resource_name, @campaign_ids)
    = @_;

  if (scalar(@campaign_ids) == 0) {
    printf "Asset was not associated with any campaigns.\n";
    return ();
  }

  my $operations = [];

  foreach my $campaign_id (@campaign_ids) {
    my $campaign_asset =
      Google::Ads::GoogleAds::V13::Resources::CampaignAsset->new({
        asset     => $promotion_asset_resource_name,
        fieldType => PROMOTION,
        campaign => Google::Ads::GoogleAds::V13::Utils::ResourceNames::campaign(
          $customer_id, $campaign_id
        )});

    my $operation =
      Google::Ads::GoogleAds::V13::Services::CampaignAssetService::CampaignAssetOperation
      ->new({
        create => $campaign_asset
      });

    push @$operations, $operation;
  }

  my $response = $api_client->CampaignAssetService()->mutate({
    customerId => $customer_id,
    operations => $operations
  });

  foreach my $result (@{$response->{results}}) {
    printf "Created campaign asset with resource name '%s'.\n",
      $result->{resourceName};
  }
}
      

Sprawdzanie zawartości zasobu

Aby pobrać zawartość zasobu promocji, użyj tego zapytania o język zapytań Google Ads. Sprawdź wyniki, aby upewnić się, że wszystkie odpowiednie pola zostały prawidłowo skopiowane.

W tym momencie oba identyczne rozszerzenia są aktywne, ale rozszerzenie oparte na zasobach będzie się wyświetlać zamiast rozszerzenia opartego na pliku danych.

SELECT
  asset.id,
  asset.name,
  asset.type,
  asset.final_urls,
  asset.final_mobile_urls,
  asset.final_url_suffix,
  asset.tracking_url_template,
  asset.promotion_asset.promotion_target,
  asset.promotion_asset.discount_modifier,
  asset.promotion_asset.redemption_start_date,
  asset.promotion_asset.redemption_end_date,
  asset.promotion_asset.occasion,
  asset.promotion_asset.language_code,
  asset.promotion_asset.percent_off,
  asset.promotion_asset.money_amount_off.amount_micros,
  asset.promotion_asset.money_amount_off.currency_code,
  asset.promotion_asset.promotion_code,
  asset.promotion_asset.orders_over_amount.amount_micros,
  asset.promotion_asset.orders_over_amount.currency_code,
  asset.promotion_asset.start_date,
  asset.promotion_asset.end_date,
  asset.promotion_asset.ad_schedule_targets
FROM asset
WHERE asset.resource_name = 'customers/123456789/assets/123456789012'

Usuń rozszerzenie oparte na pliku danych

Gdy upewnisz się, że rozszerzenie oparte na plikach trafnie odzwierciedla oryginalne rozszerzenie oparte na plikach danych, musisz je usunąć.

Wszystkie istniejące rozszerzenia oparte na pliku danych zostaną automatycznie przeniesione w dniu automatycznej daty migracji. Po przeniesieniu usuń rozszerzenia oparte na plikach danych, aby uniknąć ich wielu wystąpień.

Wykrywanie automatycznie przeniesionych kont

Interfejs API zwraca błąd FeedErrorEnum.FeedError.legacy_extension_type_read_only podczas próby zmodyfikowania rozszerzeń na już przeniesionym koncie. Możesz wykryć takie konta, tworząc trywialne operacje mutacji do jednej z usług kanału, na przykład FeedItemService.

Ustaw żądanie w polu validate_only, aby sprawdzić żądanie bez stosowania wyniku. Odpowiedź wskaże, czy konto zostało przeniesione automatycznie.

Migracja jest przeprowadzana etapami, więc niektóre rozszerzenia mogą zostać przeniesione, a inne nie. Szczegółowe informacje na ten temat znajdziesz we wskazówkach dotyczących migracji.

Dostępność raportów dotyczących kanału

Historyczne raporty dotyczące plików danych będą dostępne do sierpnia 2022 roku. Po migracji rozszerzenia oparte na plikach danych nie będą już generować nowych danych.

Żądanie dotyczące treści zasobu można uzyskać, wysyłając zapytanie o język zapytań Google Ads do raportu asset. Ten typ raportu jest podobny do raportu extension_feed_item dla rozszerzeń opartych na pliku danych.

Statystyki skuteczności rozszerzeń opartych na zasobach można zażądać, wysyłając zapytanie o język języka Google Ads do raportu asset_field_type_view. Ten typ raportu jest podobny do raportu feed_placeholder_view dla rozszerzeń opartych na pliku danych.

Najczęstsze pytania

Co się dzieje ze starszymi rozszerzeniami, które nie są w pełni obsługiwane przez komponenty?

Zasób zostanie utworzony bez nieobsługiwanych pól. Na przykład ustawienie urządzenia nie jest już dostępne w zasobach, więc rozszerzenia z tym ustawieniem zostaną przeniesione do zasobu bez preferencji dotyczących urządzeń.

Co się stanie ze starszymi rozszerzeniami, które nie przeszły weryfikacji zgodności z zasadami reklamowymi?

Spróbujemy przenieść rozszerzenia ze stanem odrzucenia, ale w niektórych przypadkach może się to nie udać.

Jeśli weryfikacja zgodności z zasadami została odrzucona synchronicznie, zasób nie zostanie przeniesiony. Do tej kategorii należy większość przyczyn odrzucenia z powodu naruszenia zasad, np. zbyt długi tekst, nieprzyzwoity język itp.

W przeciwnym razie, aby przeprowadzić bardziej precyzyjne zatwierdzenie zgodności z zasadami, przeprowadzimy migrację, ale po migracji rozszerzenie może zostać odrzucone.

Co się dzieje z danymi raportowania dotyczącymi rozszerzeń starszego typu?

Po migracji do zasobów wskaźniki zostaną zresetowane. Starsze wskaźniki będą dostępne przez krótki czas po migracji, ale w przyszłości zostaną usunięte.

Jeśli dodasz jeden typ rozszerzenia zasobów (np. objaśnienie), czy inne typy rozszerzeń, takie jak cena, nadal mogą być wyświetlane z plików danych?

Tak. Ten link jest uaktualniany tylko w przypadku linków tego typu. Jeśli nie masz połączenia z konkretnym typem zasobu, rozszerzenia oparte na plikach danych będą nadal się wyświetlać w przypadku tego typu rozszerzeń.

Podobnie, gdy połączysz z rozszerzeniem dany typ, pliki danych nie będą już mogły się wyświetlać w przypadku tego typu rozszerzeń.

Pamiętaj, że w ramach jednej kampanii możesz stosować różne pliki danych i zasoby. Jeśli jedna grupa reklam ma połączony zasób, a inna jest powiązany z plikiem danych, obie te grupy będą mogły się wyświetlać.

Czy elementy migracji zostaną usunięte przez automatyczną migrację Google?

Nie. Usuniemy link do elementu kanału – na przykład – CampaignFeed, ale pierwotny element nie zostanie usunięty.

Czy migracja automatyczna Google spowoduje tylko przeniesienie elementów kanału?

Nie. Każdy element kanału przeniesiemy do komponentu bez względu na to, czy jest on aktywnie wyświetlany przez link elementu kanału – na przykład: CampaignFeed.