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 wycofania rozszerzeń opartych na pliku danych. Rozszerzenia oparte na plikach danych zostaną przeniesione zbiorczo nowymi rozszerzeniami na podstawie zasobów, a w 2023 r. wycofamy je całkowicie.

Przegląd

Wycofujemy ten model rozszerzeń opartych na plikach danych na rzecz rozszerzeń opartych na zasobach. Rozszerzenia oparte na zasobach upraszczają tworzenie rozszerzeń i zarządzanie nimi. Wymagane jest działanie w celu zachowania kontroli nad rozszerzeniami reklam.

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

Jeśli konkretny typ klienta oparty na zasobach, a także rozszerzenia oparte na zasobach jest przypisany do tego samego klienta, tej samej kampanii lub grupy reklam, będą się wyświetlać rozszerzenia oparte na zasobach. Dotyczy to tylko jednostek 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 z innych grup w tej samej kampanii będzie nadal możliwe. Rozszerzenia oparte na zasobach będą domyślnie wyświetlane w interfejsie Google Ads.

Jeśli masz aktywne rozszerzenia obu typów, w interfejsie Google Ads możesz zobaczyć powiadomienie podobnie jak na zrzucie ekranu poniżej. „"Starsza wersja” to rozszerzenia oparte na pliku danych, natomiast rozszerzenia – na podstawie zasobów.

Ekran z uaktualnioną promocją

Gdy utworzysz wszystkie rozszerzenia oparte na zasobach, w widoku tym zostaną domyślnie zastosowane rozszerzenia uaktualnione.

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 pliku danych zostaną automatycznie skopiowane do rozszerzeń opartych na zasobach w określonych dniach. Wszystkie rozszerzenia oparte na zasobach będą miały nowe, unikalne wartości identyfikatorów.

Zalecamy przeprowadzenie procesu migracji samodzielnie za pomocą interfejsu Google Ads API, tak jak to opisaliśmy w tym przewodniku, ponieważ zasoby nie będą połączone w czasie automatycznej migracji i z oryginalnymi plikami danych.

Harmonogram migracji

Wszystkie dotychczasowe rozszerzenia oparte na zasobach zostaną automatycznie przeniesione do rozszerzeń opartych na zasobach. Przeniesione konta będą odrzucać mutacje dla elementów opartych na kanale.

Historyczne raporty będą dostępne do sierpnia 2022 r. Po migracji rozszerzenia oparte na plikach danych nie będą już generować nowych danych.

Automatyczny proces migracji utworzy rozszerzenia oparte na zasobach, które będą odpowiadały obecnym rozszerzeniom opartym na plikach danych, i zastąpią wszystkie wystąpienia AdGroupFeed, CampaignFeed oraz CustomerFeed odpowiednikami AdGroupAsset, CampaignAsset i CustomerAsset. Jeśli grupa reklam, kampania lub klient została już połączona z zasobem, odpowiedni plik danych zostanie zignorowany.

Zmiany w rozszerzeniach opartych na zasobach

Rozszerzenia oparte na zasobach oferują te same funkcje, co istniejące rozszerzenia oparte na pliku danych, ale niektóre dotychczasowe funkcje zostały usunięte, w tym funkcje dopasowania i większość pól kierowania.

W przypadku kierowania na podstawie zasobów grupa reklam, kampania, słowo kluczowe, lokalizacja i urządzenia mobilne nie będą dostępne.

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

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

Wszystkie pola dotyczące daty są teraz w formacie "rrrr-MM-dd". W rozszerzeniach opartych na zasobach nie będziesz mieć możliwości określenia godziny.

W przypadku rozszerzeń opartych na zasobach zalecamy używanie funkcji kierowania reklam, które są już dostępne na poziomie kampanii i grupy reklam. W przypadku preferencji urządzeń mobilnych warto rozważyć dodanie adresów URL dostosowanych do urządzeń mobilnych.

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

Dopasowanie funkcji Uwagi dotyczące migracji
EQUALS(FEED_ITEM_ID, 1234567) Przeniesione w stanie niezmienionym
IN(FEED_ITEM_ID,{1234567,1234568,1234569}) Przeniesione w stanie niezmienionym
IDENTITY(false) Przeniesiony jako excluded_parent_asset_field_types
IDENTITY(true) Przeniesiono ze wszystkimi połączonymi elementami 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)

Przypadek szczególny: IDENTITY(true)

Funkcja dopasowania IDENTITY(true) będzie ignorowana podczas automatycznej migracji, jeśli zostanie dołączona do rozszerzenia i pasuje do ponad 20 aktywnych elementów kanału. Zaktualizuj funkcję dopasowania do notacji IN(FEED_ITEM_ID, {1234567,1234568,1234569}).

Możesz też samodzielnie przenieść rozszerzenia i połączyć je z innymi zasobami. Każdego klienta, kampanię i grupę reklam możesz połączyć maksymalnie z 20 aktywnymi rozszerzeniami opartymi na zasobach tego samego typu. Informacje o sposobie migracji i linków do rozszerzeń opartych 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 zostanie wykonane żadne 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 dla każdej innej wartości call_conversion_reporting_state.

Jeśli przenosisz rozszerzenie połączeń oparte na kanale, jeśli call_conversion_tracking_disabled ma wartość true, to nowe CallAsset's call_conversion_reporting_state musi być ustawione na DISABLED. Pamiętaj, że domyślną wartością parametru call_conversion_reporting_state jest USE_RESOURCE_LEVEL_CALL_CONVERSION_ACTION. Aby nadal uniemożliwić śledzenie konwersji w tym rozszerzeniu, musisz ustawić jego wartość 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 komputerze, musisz jednocześnie przenieść wszystkie wystąpienia rozszerzeń połączeń na rozszerzenia oparte na zasobach. Dotyczy to przypisania numerów Google do przekazywania połączeń, które będą przyznawane rozszerzeniom opartym na zasobach, tylko jeśli znajdują się na koncie.

Śledzenie rozszerzeń opartych na zasobach za pomocą parametrów ValueTrack w adresach URL

W rozszerzeniach opartych na zasobach oprócz adresów {feeditemid} wszystkie parametry ValueTrack będą nadal działać. Zamiast tego użyj {extensionid} do połączenia dowolnego końcowego adresu URL, śledzenia

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

Procedura automatycznej migracji nie zmieni zdarzenia {feeditemid} na {extensionid}. Musisz zaktualizować wszystkie adresy URL, które używają parametru {feeditemid}, dodając też 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
Rozszerzenia będą wyświetlać się w tej kampanii i wszystkich jej grupach reklam.
CustomerAsset
Rozszerzenie będzie wyświetlać się w każdej kwalifikującej się kampanii.

Jest to sprzeczne z zachowaniem historycznym:

AdGroupFeed
Rozszerzenie będzie wyświetlać się w tej grupie reklam.
CampaignFeed
W tej kampanii będzie wyświetlać się rozszerzenie z wyjątkiem grup reklam z linkami do plików danych grup reklam.
CustomerFeed
Rozszerzenie będzie wyświetlać się 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 grup reklam.

Innymi słowy, załącznik zasobów niższego poziomu w przeszłości zastąpiłby wyższe poziomy. Jednak kierowanie będzie od tej pory uzależnione.

Procedura migracji

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

  1. Wskaż istniejące rozszerzenie oparte na pliku danych, którego chcesz używać.
  2. Skopiuj treść opartą na pliku danych do nowego wystąpienia odpowiedniego rozszerzenia opartego na zasobach. Na przykład zawartość elementu 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 pliku danych do rozszerzenia opartego na zasobach musisz niezwłocznie zakończyć to rozszerzenie w wymienionych wyżej usługach związanych z plikami danych.

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

Typ rozszerzenia jest całkowicie przenoszony po usunięciu wszystkich elementów kanału z określonym PlaceholderType. Wskazówki znajdziesz w artykule o usuwaniu rozszerzeń.

Poniższy przykład pokazuje każdy z powyższych procesów z rozszerzeniem promocji.

Identyfikuj rozszerzenia na podstawie pliku danych

Aby wyświetlić listę elementów kanału, których dotyczy problem, musisz uruchomić na swoich kontach kilka zapytań GAQL. Zilustrowaliśmy poniższe przykłady zapytań GAQL.

Natywne pliki danych

Jeśli masz na koncie natywne pliki danych (korzystające z Feed, FeedItem i FeedMapping), użyj tych zapytań, aby pobrać elementy kanału, które chcesz przenieść.

Najpierw pobierz wszystkie pliki danych z odpowiednim typem rozszerzenia 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'
)

Możesz teraz użyć feed_mapping.feed, aby pobrać interesujące Cię obiekty FeedItem.

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

Komponent feed_item.attribute_values jest następnie interpretowany zgodnie z obiektami zastępczymi feed_mapping.attribute_field_mappings. Te mapowania pól wskazują, jak pola rozszerzeń są mapowane na feed_item.attribute_values.

Ustawienia rozszerzeń

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

Aby przesłać w odpowiedzi na żądanie aktywne identyfikatory elementów kanału konkretnego typu rozszerzenia, użyj tego zapytania w języku 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ą służyć do pobierania szczegółów rozszerzeń.

Pobieranie szczegółów rozszerzenia na podstawie kanału

Gdy znajdziesz rozszerzenie oparte na pliku danych, które chcesz przenieść, poproś o jego pełne szczegóły za pomocą jego identyfikatora z innym zapytaniem o język zapytań Google Ads.

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

Zwrócone wartości ExtensionFeedItem będą miały 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 przy użyciu poprzedniego zapytania. Pamiętaj, ż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.V12.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::V12::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::V12::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::V12::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::V12::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::V12::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ąż zasób z kampaniami i grupami reklam

Nowy zasób 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::V12::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 nowy zasób CampaignAsset, AdGroupAsset lub CustomerAsset, aby połączyć go 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.V12
        .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::V12::Resources::CampaignAsset->new({
        asset     => $promotion_asset_resource_name,
        fieldType => PROMOTION,
        campaign => Google::Ads::GoogleAds::V12::Utils::ResourceNames::campaign(
          $customer_id, $campaign_id
        )});

    my $operation =
      Google::Ads::GoogleAds::V12::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 promocyjnego, użyj tego zapytania w języku Google Ads. Sprawdź wyniki, aby upewnić się, że wszystkie odpowiednie pola zostały skopiowane prawidłowo.

W tym czasie oba identyczne rozszerzenia są aktywne, ale rozszerzenie oparte na zasobach wyświetli się 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 zasobach dokładnie odzwierciedla oryginalne rozszerzenie oparte na pliku danych, musisz usunąć to rozszerzenie.

Wszystkie dotychczasowe rozszerzenia oparte na pliku danych zostaną automatycznie przeniesione w dniu automatycznego przeniesienia. Aby uniknąć wielokrotnego występowania tego samego rozszerzenia, usuń rozszerzenia oparte na plikach danych raz po ich przeniesieniu.

Wykrywanie kont przeniesionych automatycznie

Interfejs API zwraca błąd FeedErrorEnum.FeedError.legacy_extension_type_read_only podczas próby zmodyfikowania rozszerzeń na koncie, które zostało już przeniesione. Aby wykryć takie konta, utwórz trójwymiarową mutację na potrzeby jednej z usług kanału, na przykład FeedItemService.

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

Migracja odbywa się etapami, więc niektóre rozszerzenia można przenieść, a inne nie. Szczegółowe informacje na ten temat znajdziesz powyżej w harmonogramie migracji.

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

Historyczne raporty będą dostępne do sierpnia 2022 r. Rozszerzenia oparte na plikach danych nie będą już generować nowych danych po migracji.

Zawartość zasobu można wyświetlić, wysyłając zapytanie do języka zapytań Google Ads do raportu asset. Ten typ raportu jest podobny do typu raportu extension_feed_item dla rozszerzeń opartych na plikach danych.

Statystyki skuteczności oparte na zasobach można wyświetlić, wysyłając zapytanie do języka zapytań Google Ads do raportu asset_field_type_view. Ten typ raportu jest podobny do typu raportu feed_placeholder_view dla rozszerzeń opartych na plikach danych.

Najczęstsze pytania

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

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

Co się dzieje ze rozszerzeniami starszego typu, które nie przeszły weryfikacji pod kątem zgodności z zasadami dotyczącymi reklam?

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

Jeśli weryfikacja zgodności z zasadami została odrzucona synchronicznie, nie przeniesiemy zasobu. Do tej grupy należy większość przyczyn odrzucenia z powodu naruszenia zasad, np. zbyt długi tekst, wulgarny język itp.

Jeśli jest to konieczne, aby przeprowadzić bardziej asynchronicznego zatwierdzanie zasad, przeprowadzimy migrację rozszerzenia, ale może ono zostać odrzucone po migracji.

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

Po migracji do zasobów dane zostaną zresetowane. Starsze dane 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ń, np. cena, nadal będą mogły się wyświetlać z plików danych?

Tak. Ten link jest uaktualniany tylko w przypadku rozszerzeń, które są połączone. Jeśli nie masz określonego typu rozszerzenia zasobów, rozszerzenia oparte na pliku danych nadal będą się wyświetlać w przypadku tego typu rozszerzeń.

Podobnie, gdy połączysz z rozszerzeniem określony typ, pliki danych nie będą już mogły się w nim wyświetlać.

Pamiętaj, że pliki danych i zasoby mogą się wyświetlać w ramach tej samej kampanii. Jeśli jedna grupa reklam ma połączony zasób, a inna jest połączony plik danych, obie będą się wyświetlać.

Czy elementy kanału zostaną usunięte przez automatyczną migrację od Google?

Nie. Usuniemy link do elementu kanału – na przykład CampaignFeed – ale nie oryginalny element.

Czy automatyczna migracja Google przeniesie tylko elementy kanału służące do wyświetlania reklam?

Nie. Przeniesiemy każdy element kanału do zasobu bez względu na to, czy element kanału wyświetla się aktywnie za pomocą linku do elementu kanału, na przykład CampaignFeed.