The AdWords API will sunset on April 27, 2022. Migrate to the Google Ads API to take advantage of the latest Google Ads features.

Migration Samples

The code samples below provide examples of common migration functions using the AdWords API. Client Library.

<?php
/**
 * Copyright 2017 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace Google\AdsApi\Examples\AdWords\v201809\Migration;

require __DIR__ . '/../../../../vendor/autoload.php';

use Google\AdsApi\AdWords\AdWordsServices;
use Google\AdsApi\AdWords\AdWordsSession;
use Google\AdsApi\AdWords\AdWordsSessionBuilder;
use Google\AdsApi\AdWords\v201809\cm\CampaignExtensionSetting;
use Google\AdsApi\AdWords\v201809\cm\CampaignExtensionSettingOperation;
use Google\AdsApi\AdWords\v201809\cm\CampaignExtensionSettingService;
use Google\AdsApi\AdWords\v201809\cm\CampaignFeedOperation;
use Google\AdsApi\AdWords\v201809\cm\CampaignFeedService;
use Google\AdsApi\AdWords\v201809\cm\ExtensionSetting;
use Google\AdsApi\AdWords\v201809\cm\ExtensionSettingPlatform;
use Google\AdsApi\AdWords\v201809\cm\FeedItem;
use Google\AdsApi\AdWords\v201809\cm\FeedItemOperation;
use Google\AdsApi\AdWords\v201809\cm\FeedItemService;
use Google\AdsApi\AdWords\v201809\cm\FeedMappingService;
use Google\AdsApi\AdWords\v201809\cm\FeedService;
use Google\AdsApi\AdWords\v201809\cm\FeedType;
use Google\AdsApi\AdWords\v201809\cm\FunctionOperand;
use Google\AdsApi\AdWords\v201809\cm\FunctionOperator;
use Google\AdsApi\AdWords\v201809\cm\Operator;
use Google\AdsApi\AdWords\v201809\cm\RequestContextOperand;
use Google\AdsApi\AdWords\v201809\cm\RequestContextOperandContextType;
use Google\AdsApi\AdWords\v201809\cm\SitelinkFeedItem;
use Google\AdsApi\Common\OAuth2TokenBuilder;

/**
 * Migrates your feed based sitelinks at campaign level to
 * use extension settings. To learn more about extension settings, see
 * https://developers.google.com/adwords/api/docs/guides/extension-settings
 * To learn more about migrating feed based extensions to extension
 * settings, see
 * https://developers.google.com/adwords/api/docs/guides/migrate-to-extension-settings
 *
 * <p>This code example doesn't migrate scheduling or feed item-level campaign,
 * ad group, keyword, or geo targeting settings.
 */
class MigrateToExtensionSettings
{

    const PAGE_LIMIT = 500;

    // The placeholder type for sitelinks. See
    // https://developers.google.com/adwords/api/docs/appendix/placeholders
    // for the list of all supported placeholder types.
    const PLACEHOLDER_TYPE_SITELINKS = 1;

    // Placeholder field IDs for sitelinks. See
    // https://developers.google.com/adwords/api/docs/appendix/placeholders
    // for the list of all supported placeholder types.
    const PLACEHOLDER_FIELD_TEXT = 1;
    const PLACEHOLDER_FIELD_URL = 2;
    const PLACEHOLDER_FIELD_LINE2 = 3;
    const PLACEHOLDER_FIELD_LINE3 = 4;
    const PLACEHOLDER_FIELD_FINAL_URLS = 5;
    const PLACEHOLDER_FIELD_FINAL_MOBILE_URLS = 6;
    const PLACEHOLDER_FIELD_TRACKING_URL_TEMPLATE = 7;


    public static function runExample(
        AdWordsServices $adWordsServices,
        AdWordsSession $session
    ) {
        $feeds = self::getFeeds($adWordsServices, $session);
        foreach ($feeds as $feed) {
            // Retrieve all the sitelinks from the current feed.
            $sitelinksFromFeed = self::getSitelinksFromFeed(
                $adWordsServices,
                $session,
                $feed->getId()
            );
            printf(
                "Loaded %d sitelinks for feed ID %d.\n",
                count($sitelinksFromFeed),
                $feed->getId()
            );

            // Get all the instances where a sitelink from this feed has been added
            // to a campaign.
            $campaignFeeds = self::getCampaignFeeds(
                $adWordsServices,
                $session,
                $feed->getId(),
                self::PLACEHOLDER_TYPE_SITELINKS
            );
            printf(
                "Loaded %d sitelink to campaign mappings for feed ID %d.\n",
                count($campaignFeeds),
                $feed->getId()
            );

            if ($campaignFeeds !== null) {
                $allFeedItemsToDelete = [];
                foreach ($campaignFeeds as $campaignFeed) {
                    // Retrieve the sitelinks that have been associated with this
                    // campaign.
                    $feedItemIds = self::getFeedItemIdsForCampaignFeed($campaignFeed);
                    $platformRestrictions = self::getPlatformRestrictionsForCampaignFeed($campaignFeed);

                    if ($feedItemIds === null) {
                        printf(
                            "Skipping feed ID %d for campaign %d -- matching function is "
                            . "missing or too complex for this script.\n",
                            $campaignFeed->getFeedId(),
                            $campaignFeed->getCampaignId()
                        );
                        continue;
                    }

                    // Delete the campaign feed that associates the sitelinks from the
                    // feed to the campaign.
                    self::deleteCampaignFeed($adWordsServices, $session, $campaignFeed);

                    // Mark the sitelinks from the feed for deletion.
                    $allFeedItemsToDelete = array_merge($allFeedItemsToDelete, $feedItemIds);

                    // Create extension settings instead of sitelinks.
                    self::createExtensionSetting(
                        $adWordsServices,
                        $session,
                        $sitelinksFromFeed,
                        $campaignFeed->getCampaignId(),
                        $feedItemIds,
                        $platformRestrictions
                    );
                }

                // Delete all the sitelinks from the feed.
                $allFeedItemsToDelete = array_unique($allFeedItemsToDelete);
                self::deleteOldFeedItems(
                    $adWordsServices,
                    $session,
                    $allFeedItemsToDelete,
                    $feed->getId()
                );
            }
        }
    }

    /**
     * Gets all enabled feeds.
     */
    private static function getFeeds(
        AdWordsServices $adWordsServices,
        AdWordsSession $session
    ) {
        $feedService = $adWordsServices->get($session, FeedService::class);

        // Create paging controls.
        $totalNumEntries = 0;
        $offset = 0;
        $query = 'SELECT Id, Name, Attributes WHERE Origin="USER" AND '
            . 'FeedStatus="ENABLED"';
        $feeds = [];
        do {
            $pageQuery =
                sprintf('%s LIMIT %d,%d', $query, $offset, self::PAGE_LIMIT);

            // Make the query request.
            $page = $feedService->query($pageQuery);

            if ($page->getEntries() !== null) {
                $totalNumEntries = $page->getTotalNumEntries();
                foreach ($page->getEntries() as $feed) {
                    $feeds[] = $feed;
                }
            }
            // Advance the paging offset.
            $offset += self::PAGE_LIMIT;
        } while ($offset < $totalNumEntries);

        return $feeds;
    }

    /**
     * Gets all enabled feed items of the specified feed.
     */
    private static function getFeedItems(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        $feedId
    ) {
        $feedItemService =
            $adWordsServices->get($session, FeedItemService::class);

        // Create paging controls.
        $totalNumEntries = 0;
        $offset = 0;
        $query = sprintf(
            'SELECT FeedItemId, AttributeValues WHERE Status = '
            . '"ENABLED" AND FeedId = %d',
            $feedId
        );
        $feedItems = [];
        do {
            $pageQuery =
                sprintf('%s LIMIT %d,%d', $query, $offset, self::PAGE_LIMIT);

            // Make the query request.
            $page = $feedItemService->query($pageQuery);

            if ($page->getEntries() !== null) {
                $totalNumEntries = $page->getTotalNumEntries();
                foreach ($page->getEntries() as $feedItem) {
                    $feedItems[] = $feedItem;
                }
            }
            // Advance the paging offset.
            $offset += self::PAGE_LIMIT;
        } while ($offset < $totalNumEntries);

        return $feedItems;
    }

    /**
     * Gets all enabled campaign feeds for the specified feed and placeholder
     * type.
     */
    private static function getCampaignFeeds(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        $feedId,
        $placeholderId
    ) {
        $campaignFeedService = $adWordsServices->get($session, CampaignFeedService::class);
        $page = $campaignFeedService->query(
            sprintf(
                'SELECT CampaignId, MatchingFunction, PlaceholderTypes WHERE '
                . 'Status="ENABLED" AND FeedId = %d AND PlaceholderTypes ' . 'CONTAINS_ANY[%d]',
                $feedId,
                $placeholderId
            )
        );

        return $page->getEntries();
    }

    /**
     * Gets attribute field mappings from the specified feed and placeholder type.
     */
    private static function getAttributeFieldMappings(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        $feedId,
        $placeholderTypeId
    ) {
        $feedMappingService = $adWordsServices->get($session, FeedMappingService::class);
        $page = $feedMappingService->query(
            sprintf(
                'SELECT FeedMappingId, AttributeFieldMappings WHERE FeedId="%d" '
                . 'AND PlaceholderType="%d" AND Status="ENABLED"',
                $feedId,
                $placeholderTypeId
            )
        );

        $attributeMappings = [];
        if ($page->getEntries() !== null) {
            // Normally, a feed attribute is mapped only to one field. However,
            // you may map it to more than one field if needed.
            foreach ($page->getEntries() as $feedMapping) {
                foreach ($feedMapping->getAttributeFieldMappings() as $attributeMapping) {
                    if (array_key_exists(
                        $attributeMapping->getFeedAttributeId(),
                        $attributeMappings
                    ) === false) {
                        $attributeMappings[$attributeMapping->getFeedAttributeId()] = [];
                    }
                    $attributeMappings[$attributeMapping->getFeedAttributeId()][] = $attributeMapping->getFieldId();
                }
            }
        }

        return $attributeMappings;
    }

    /**
     * Gets sitelinks from the specified feed.
     */
    private static function getSitelinksFromFeed(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        $feedId
    ) {
        printf("Processing feed ID %d...\n", $feedId);
        $sitelinks = [];

        // Retrieve all the feed items from the feed.
        $feedItems = self::getFeedItems($adWordsServices, $session, $feedId);

        if ($feedItems !== null) {
            // Retrieve the feed's attribute mapping.
            $attributeFieldMappings = self::getAttributeFieldMappings(
                $adWordsServices,
                $session,
                $feedId,
                self::PLACEHOLDER_TYPE_SITELINKS
            );

            foreach ($feedItems as $feedItem) {
                $sitelinkFromFeed = new SitelinkFromFeed(
                    $feedItem->getFeedId(),
                    $feedItem->getFeedItemId()
                );

                foreach ($feedItem->getAttributeValues() as $attributeValue) {
                    // This attribute hasn't been mapped to a field.
                    if (array_key_exists(
                        $attributeValue->getFeedAttributeId(),
                        $attributeFieldMappings
                    ) === false) {
                        continue;
                    }
                    // Get the list of all the fields to which this attribute has been
                    // mapped.
                    foreach ($attributeFieldMappings[$attributeValue->getFeedAttributeId()] as $fieldId) {
                        // Read the appropriate value depending on the ID of the mapped
                        // field.
                        switch ($fieldId) {
                            case self::PLACEHOLDER_FIELD_TEXT:
                                $sitelinkFromFeed->setText($attributeValue->getStringValue());
                                break;
                            case self::PLACEHOLDER_FIELD_URL:
                                $sitelinkFromFeed->setUrl($attributeValue->getStringValue());
                                break;
                            case self::PLACEHOLDER_FIELD_FINAL_URLS:
                                $sitelinkFromFeed->setFinalUrls(
                                    $attributeValue->getStringValues()
                                );
                                break;
                            case self::PLACEHOLDER_FIELD_FINAL_MOBILE_URLS:
                                $sitelinkFromFeed->setFinalMobileUrls(
                                    $attributeValue->getStringValues()
                                );
                                break;
                            case self::PLACEHOLDER_FIELD_TRACKING_URL_TEMPLATE:
                                $sitelinkFromFeed->setTrackingUrlTemplate(
                                    $attributeValue->getStringValue()
                                );
                                break;
                            case self::PLACEHOLDER_FIELD_LINE2:
                                $sitelinkFromFeed->setLine2($attributeValue->getStringValue());
                                break;
                            case self::PLACEHOLDER_FIELD_LINE3:
                                $sitelinkFromFeed->setLine3($attributeValue->getStringValue());
                                break;
                        }
                    }
                }
                $sitelinks[$feedItem->getFeedItemId()] = $sitelinkFromFeed;
            }
        }

        return $sitelinks;
    }

    /**
     * Gets plaftform restrictions for the specified campaign feed.
     */
    private static function getPlatformRestrictionsForCampaignFeed(
        $campaignFeed
    ) {
        $platformRestrictions = ExtensionSettingPlatform::NONE;

        if ($campaignFeed->getMatchingFunction()->getOperator() === FunctionOperator::AND_VALUE) {
            foreach ($campaignFeed->getMatchingFunction()->getLhsOperand() as $argument) {
                if ($argument instanceof FunctionOperand) {
                    if ($argument->getValue()->getOperator() === FunctionOperator::EQUALS
                        && $argument->getValue()->getLhsOperand()[0] instanceof RequestContextOperand) {
                        $requestContextOperand = $argument->getValue()->getLhsOperand()[0];
                        if ($requestContextOperand->getContextType()
                            === RequestContextOperandContextType::DEVICE_PLATFORM) {
                            $platformRestrictions = strtoupper(
                                $argument->getValue()->getRhsOperand()[0]->getStringValue()
                            );
                        }
                    }
                }
            }
        }

        return $platformRestrictions;
    }


    /**
     * Gets feed item IDs from the specified campaign feed.
     */
    private static function getFeedItemIdsForCampaignFeed($campaignFeed)
    {
        $feedItemIds = [];

        if ($campaignFeed->getMatchingFunction()->getOperator() === FunctionOperator::IN) {
            // Check if matchingFunction is of the form IN(FEED_ITEM_ID,{xxx,xxx}).
            // Extract feed items if applicable.
            $feedItemIds = array_merge(
                $feedItemIds,
                self::getFeedItemIdsFromArgument($campaignFeed->getMatchingFunction())
            );
        } elseif ($campaignFeed->getMatchingFunction()->getOperator() === FunctionOperator::AND_VALUE) {
            foreach ($campaignFeed->getMatchingFunction()->getLhsOperand() as $argument) {
                // Check if matchingFunction is of the form IN(FEED_ITEM_ID,{xxx,xxx}).
                // Extract feed items if applicable.
                if ($argument instanceof FunctionOperand) {
                    if ($argument->getValue()->getOperator() === FunctionOperator::IN) {
                        $feedItemIds = array_merge(
                            $feedItemIds,
                            self::getFeedItemIdsFromArgument($argument->getValue())
                        );
                    }
                }
            }
        }

        return $feedItemIds;
    }

    /**
     * Gets feed item IDs from the specified function argument.
     */
    private static function getFeedItemIdsFromArgument($function)
    {
        $feedItemIds = [];

        if (count($function->getLhsOperand()) === 1
            && $function->getLhsOperand()[0] instanceof RequestContextOperand
            && $function->getLhsOperand()[0]->getContextType() === RequestContextOperandContextType::FEED_ITEM_ID
            && $function->getOperator() === FunctionOperator::IN) {
            foreach ($function->getRhsOperand() as $argument) {
                $feedItemIds[] = $argument->getLongValue();
            }
        }

        return $feedItemIds;
    }

    /**
     * Creates a new extension setting for the specified feed items.
     */
    private static function createExtensionSetting(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        array $sitelinksFromFeed,
        $campaignId,
        array $feedItemIds,
        $platformRestrictions
    ) {
        $campaignExtensionSettingService = $adWordsServices->get($session, CampaignExtensionSettingService::class);

        $extensionSetting = new CampaignExtensionSetting();
        $extensionSetting->setCampaignId($campaignId);
        $extensionSetting->setExtensionType(FeedType::SITELINK);
        $extensionSetting->setExtensionSetting(new ExtensionSetting());

        $extensionFeedItems = [];
        foreach ($feedItemIds as $feedItemId) {
            $sitelink = $sitelinksFromFeed[$feedItemId];

            $newFeedItem = new SitelinkFeedItem();
            $newFeedItem->setSitelinkText($sitelink->getText());
            $newFeedItem->setSitelinkUrl($sitelink->getUrl());
            $newFeedItem->setSitelinkLine2($sitelink->getLine2());
            $newFeedItem->setSitelinkLine3($sitelink->getLine3());
            $newFeedItem->setSitelinkFinalUrls($sitelink->getFinalUrls());
            $newFeedItem->setSitelinkFinalMobileUrls($sitelink->getFinalMobileUrls());
            $newFeedItem->setSitelinkTrackingUrlTemplate(
                $sitelink->getTrackingUrlTemplate()
            );

            $extensionFeedItems[] = $newFeedItem;
        }
        $extensionSetting->getExtensionSetting()->setExtensions(
            $extensionFeedItems
        );
        $extensionSetting->getExtensionSetting()->setPlatformRestrictions(
            $platformRestrictions
        );

        $operation = new CampaignExtensionSettingOperation();
        $operation->setOperand($extensionSetting);
        $operation->setOperator(Operator::ADD);

        printf(
            "Adding %d sitelinks for campaign ID %d...\n",
            count($feedItemIds),
            $campaignId
        );

        return $campaignExtensionSettingService->mutate([$operation]);
    }

    /**
     * Deletes associations of the specified feed IDs and campaign IDs.
     */
    private static function deleteCampaignFeed(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        $campaignFeed
    ) {
        $campaignFeedService = $adWordsServices->get($session, CampaignFeedService::class);

        printf(
            "Deleting association of feed ID %d and campaign ID %d...\n",
            $campaignFeed->getFeedId(),
            $campaignFeed->getCampaignId()
        );

        $operation = new CampaignFeedOperation();
        $operation->setOperand($campaignFeed);
        $operation->setOperator(Operator::REMOVE);

        return $campaignFeedService->mutate([$operation]);
    }

    /**
     * Deletes old feed items that became unused anymore after migration.
     */
    private static function deleteOldFeedItems(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        $feedItemIds,
        $feedId
    ) {
        if (count($feedItemIds) === 0) {
            return;
        }

        $feedItemService = $adWordsServices->get($session, FeedItemService::class);

        $operations = [];
        foreach ($feedItemIds as $feedItemId) {
            $feedItem = new FeedItem();
            $feedItem->setFeedId($feedId);
            $feedItem->setFeedItemId($feedItemId);

            $operation = new FeedItemOperation();
            $operation->setOperand($feedItem);
            $operation->setOperator(Operator::REMOVE);
            $operations[] = $operation;
        }

        printf(
            "Deleting %d old feed items from feed ID %d...\n",
            count($feedItemIds),
            $feedId
        );

        return $feedItemService->mutate($operations);
    }


    public static function main()
    {
        // Generate a refreshable OAuth2 credential for authentication.
        $oAuth2Credential = (new OAuth2TokenBuilder())->fromFile()->build();

        // Construct an API session configured from a properties file and the
        // OAuth2 credentials above.
        $session = (new AdWordsSessionBuilder())->fromFile()->withOAuth2Credential($oAuth2Credential)->build();
        self::runExample(new AdWordsServices(), $session);
    }
}

// @codingStandardsIgnoreStart
class SitelinkFromFeed
{
    // @codingStandardsIgnoreEnd

    private $feedId;
    private $feedItemId;
    private $text;
    private $url;
    private $finalUrls;
    private $finalMobileUrls;
    private $trackingUrlTemplate;
    private $line2;
    private $line3;
    private $scheduling;

    public function __construct($feedId = null, $feedItemId = null)
    {
        $this->feedId = $feedId;
        $this->feedItemId = $feedItemId;
    }

    public function getFeedId()
    {
        return $this->feedId;
    }

    public function getFeedItemId()
    {
        return $this->feedItemId;
    }

    public function getText()
    {
        return $this->text;
    }

    public function getUrl()
    {
        return $this->url;
    }

    public function getFinalUrls()
    {
        return $this->finalUrls;
    }

    public function getFinalMobileUrls()
    {
        return $this->finalMobileUrls;
    }

    public function getTrackingUrlTemplate()
    {
        return $this->trackingUrlTemplate;
    }

    public function getLine2()
    {
        return $this->line2;
    }

    public function getLine3()
    {
        return $this->line3;
    }

    public function setFeedId($feedId)
    {
        $this->feedId = $feedId;
    }

    public function setFeedItemId($feedItemId)
    {
        $this->feedItemId = $feedItemId;
    }

    public function setText($text)
    {
        $this->text = $text;
    }

    public function setUrl($url)
    {
        $this->url = $url;
    }

    public function setFinalUrls(array $finalUrls)
    {
        $this->finalUrls = $finalUrls;
    }

    public function setFinalMobileUrls(array $finalMobileUrls)
    {
        $this->finalMobileUrls = $finalMobileUrls;
    }

    public function setTrackingUrlTemplate($trackingUrlTemplate)
    {
        $this->trackingUrlTemplate = $trackingUrlTemplate;
    }

    public function setLine2($line2)
    {
        $this->line2 = $line2;
    }

    public function setLine3($line3)
    {
        $this->line3 = $line3;
    }
}


MigrateToExtensionSettings::main();