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

Extensions Samples

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

Associate a Google My Business feed to that of a customer

<?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\Extensions;

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\ApiException;
use Google\AdsApi\AdWords\v201809\cm\ConstantOperand;
use Google\AdsApi\AdWords\v201809\cm\ConstantOperandConstantType;
use Google\AdsApi\AdWords\v201809\cm\CustomerFeed;
use Google\AdsApi\AdWords\v201809\cm\CustomerFeedOperation;
use Google\AdsApi\AdWords\v201809\cm\CustomerFeedService;
use Google\AdsApi\AdWords\v201809\cm\Feed;
use Google\AdsApi\AdWords\v201809\cm\FeedOperation;
use Google\AdsApi\AdWords\v201809\cm\FeedOrigin;
use Google\AdsApi\AdWords\v201809\cm\FeedService;
use Google\AdsApi\AdWords\v201809\cm\FunctionOperator;
use Google\AdsApi\AdWords\v201809\cm\MatchingFunction;
use Google\AdsApi\AdWords\v201809\cm\OAuthInfo;
use Google\AdsApi\AdWords\v201809\cm\Operator;
use Google\AdsApi\AdWords\v201809\cm\PlacesLocationFeedData;
use Google\AdsApi\Common\OAuth2TokenBuilder;
use RuntimeException;

/**
 * This example adds a feed that syncs feed items from a Google
 * My Business (GMB) account and associates the feed with a customer.
 */
class AddGoogleMyBusinessLocationExtensions
{

    // The placeholder type for location extensions.
    // See the Placeholder reference page for a list of all the placeholder types
    // and fields.
    // https://developers.google.com/adwords/api/docs/appendix/placeholders
    const PLACEHOLDER_LOCATION = 7;

    // The maximum number of CustomerFeed ADD operation attempts to make before
    // throwing an exception.
    const MAX_CUSTOMER_FEED_ADD_ATTEMPTS = 10;

    // The email address of either an owner or a manager of the GMB account.
    const GMB_EMAIL_ADDRESS = 'INSERT_GMB_EMAIL_ADDRESS';

    // If the gmbEmailAddress above is for a GMB manager instead of the GMB
    // account owner, then set businessAccountIdentifier to the +Page ID of a
    // location for which the manager has access. See the location extensions
    // guide at https://developers.google.com/adwords/api/docs/guides/feed-services-locations
    // for details.
    const BUSINESS_ACCOUNT_IDENTIFIER = null;

    public static function runExample(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        $gmbEmailAddress,
        $gmbAccessToken,
        $gmbBusinessAccountId
    ) {
        $feedService = $adWordsServices->get($session, FeedService::class);

        // Create a feed that will sync to the Google My Business account specified
        // by $gmbEmailAddress. Do not add FeedAttributes to this object, as AdWords
        // will add them automatically because this will be a system generated feed.
        $gmbFeed = new Feed();
        $gmbFeed->setName('Google My Business feed #' . uniqid());

        $feedData = new PlacesLocationFeedData();
        $feedData->setEmailAddress($gmbEmailAddress);
        $feedData->setBusinessAccountIdentifier($gmbBusinessAccountId);

        // Optional: specify labels to filter Google My Business listings. If
        // specified, only listings that have any of the labels set are
        // synchronized into FeedItems.
        $feedData->setLabelFilters(['Stores in New York City']);

        $oAuthInfo = new OAuthInfo();
        $oAuthInfo->setHttpMethod('GET');
        $oAuthInfo->setHttpRequestUrl('https://www.googleapis.com/auth/adwords');
        $oAuthInfo->setHttpAuthorizationHeader(
            sprintf('Bearer %s', $gmbAccessToken)
        );
        $feedData->setOAuthInfo($oAuthInfo);

        $gmbFeed->setSystemFeedGenerationData($feedData);

        // Since this feed's feed items will be managed by AdWords,
        // you must set its origin to ADWORDS.
        $gmbFeed->setOrigin(FeedOrigin::ADWORDS);

        // Create a feed operation and add it to the list.
        $operation = new FeedOperation();
        $operation->setOperator(Operator::ADD);
        $operation->setOperand($gmbFeed);
        $operations = [$operation];

        // Add the feed on the server. Since it is a system generated feed, AdWords
        // will automatically:
        // 1. Set up the FeedAttributes on the feed.
        // 2. Set up a FeedMapping that associates the FeedAttributes of the feed
        // with the placeholder fields of the LOCATION placeholder type.
        $addedFeed = $feedService->mutate($operations)->getValue()[0];
        printf("Added GMB feed with ID %d\n", $addedFeed->getId());

        $customerFeedService = $adWordsServices->get($session, CustomerFeedService::class);

        // Add a CustomerFeed that associates the feed with this customer for
        // the LOCATION placeholder type.
        $customerFeed = new CustomerFeed();
        $customerFeed->setFeedId($addedFeed->getId());
        $customerFeed->setPlaceholderTypes([self::PLACEHOLDER_LOCATION]);

        // Create a matching function that will always evaluate to true.
        $customerMatchingFunction = new MatchingFunction();
        $constOperand = new ConstantOperand();
        $constOperand->setType(ConstantOperandConstantType::BOOLEAN);
        $constOperand->setBooleanValue(true);
        $customerMatchingFunction->setLhsOperand([$constOperand]);
        $customerMatchingFunction->setOperator(FunctionOperator::IDENTITY);
        $customerFeed->setMatchingFunction($customerMatchingFunction);

        // Create a customer feed operation and add it to the list.
        $operation = new CustomerFeedOperation();
        $operation->setOperand($customerFeed);
        $operation->setOperator(Operator::ADD);
        $operations = [$operation];

        // After the completion of the Feed ADD operation above the added feed will
        // not be available for usage in a CustomerFeed until the sync between the
        // AdWords and GMB accounts completes. The loop below will retry adding
        // the CustomerFeed up to ten times with an exponential back-off policy.
        $addedCustomerFeed = null;
        $numberOfAttempts = 0;
        do {
            $numberOfAttempts++;
            try {
                $addedCustomerFeed = $customerFeedService->mutate($operations)->getValue()[0];
                printf(
                    "Attempt #%d to add the CustomerFeed was successful\n",
                    $numberOfAttempts
                );
            } catch (ApiException $e) {
                // Wait using exponential backoff policy
                $sleepSeconds = 5 * pow(2, $numberOfAttempts);
                printf(
                    "Attempt #%d to add the CustomerFeed was not successful. "
                    . "Waiting %d seconds before trying again.\n",
                    $numberOfAttempts,
                    $sleepSeconds
                );
                sleep($sleepSeconds);
            }
        } while ($numberOfAttempts < self::MAX_CUSTOMER_FEED_ADD_ATTEMPTS
        && $addedCustomerFeed === null);

        if ($addedCustomerFeed === null) {
            throw new RuntimeException(
                'Could not create the CustomerFeed after ' . self::MAX_CUSTOMER_FEED_ADD_ATTEMPTS
                . ' attempts. Please retry ' . 'the CustomerFeed ADD operation later.'
            );
        }

        printf(
            "Added CustomerFeed for feed ID %d and placeholder type %d\n",
            $addedCustomerFeed->getFeedId(),
            $addedCustomerFeed->getPlaceholderTypes()[0]
        );

        // OPTIONAL: Create a CampaignFeed to specify which FeedItems to use at the
        // Campaign level.  This will be similar to the CampaignFeed in the
        // AddSitelinks example, except you can also filter based on the business
        // name and category of each FeedItem by using a FeedAttributeOperand in
        // your matching function.

        // OPTIONAL: Create an AdGroupFeed for even more fine grained control over
        // which feed items are used at the AdGroup level.
    }

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

        // If the GMB_EMAIL_ADDRESS is the same user you used to generate your
        // AdWords API refresh token, leave the assignment below unchanged.
        // Otherwise, to obtain an access token for your GMB account, run the
        // Auth/GetRefreshToken example. Make sure you are logged in as the same
        // user as GMB_EMAIL_ADDRESS above when you follow the link provided by the
        // example then call fetchAuthToken on the generated oAuth2 object and copy
        // and paste its 'access_token' value into the assignment below.
        $gmbAccessToken = $oAuth2Credential->fetchAuthToken()['access_token'];

        // 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,
            self::GMB_EMAIL_ADDRESS,
            $gmbAccessToken,
            (self::BUSINESS_ACCOUNT_IDENTIFIER === null) ? null : intval(self::BUSINESS_ACCOUNT_IDENTIFIER)
        );
    }
}

AddGoogleMyBusinessLocationExtensions::main();

Associate a price extension to an account

<?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\Extensions;

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\CustomerExtensionSetting;
use Google\AdsApi\AdWords\v201809\cm\CustomerExtensionSettingOperation;
use Google\AdsApi\AdWords\v201809\cm\CustomerExtensionSettingService;
use Google\AdsApi\AdWords\v201809\cm\DayOfWeek;
use Google\AdsApi\AdWords\v201809\cm\ExtensionSetting;
use Google\AdsApi\AdWords\v201809\cm\FeedItemCampaignTargeting;
use Google\AdsApi\AdWords\v201809\cm\FeedItemSchedule;
use Google\AdsApi\AdWords\v201809\cm\FeedItemScheduling;
use Google\AdsApi\AdWords\v201809\cm\FeedType;
use Google\AdsApi\AdWords\v201809\cm\MinuteOfHour;
use Google\AdsApi\AdWords\v201809\cm\Money;
use Google\AdsApi\AdWords\v201809\cm\MoneyWithCurrency;
use Google\AdsApi\AdWords\v201809\cm\Operator;
use Google\AdsApi\AdWords\v201809\cm\PriceExtensionPriceQualifier;
use Google\AdsApi\AdWords\v201809\cm\PriceExtensionPriceUnit;
use Google\AdsApi\AdWords\v201809\cm\PriceExtensionType;
use Google\AdsApi\AdWords\v201809\cm\PriceFeedItem;
use Google\AdsApi\AdWords\v201809\cm\PriceTableRow;
use Google\AdsApi\AdWords\v201809\cm\UrlList;
use Google\AdsApi\Common\OAuth2TokenBuilder;

/**
 * This example adds a price extension and associates it with an account.
 * Campaign targeting is also set using the specified campaign ID.
 * To get campaigns, run GetCampaigns.php.
 */
class AddPrices
{

    const CAMPAIGN_ID = 'INSERT_CAMPAIGN_ID_HERE';
    const MICROS_PER_DOLLAR = 1000000;

    public static function runExample(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        $campaignId
    ) {
        $customerExtensionSettingService = $adWordsServices->get($session, CustomerExtensionSettingService::class);

        // Create the price extension feed item.
        $priceFeedItem = new PriceFeedItem();
        $priceFeedItem->setPriceExtensionType(PriceExtensionType::SERVICES);
        // Price qualifer is optional.
        $priceFeedItem->setPriceQualifier(PriceExtensionPriceQualifier::FROM);
        $priceFeedItem->setTrackingUrlTemplate(
            'http://tracker.example.com/?u={lpurl}'
        );
        $priceFeedItem->setLanguage('en');
        $priceFeedItem->setCampaignTargeting(
            new FeedItemCampaignTargeting($campaignId)
        );
        $priceFeedItem->setScheduling(
            new FeedItemScheduling(
                [
                    new FeedItemSchedule(
                        DayOfWeek::SUNDAY,
                        10,
                        MinuteOfHour::ZERO,
                        18,
                        MinuteOfHour::ZERO
                    ),
                    new FeedItemSchedule(
                        DayOfWeek::SATURDAY,
                        10,
                        MinuteOfHour::ZERO,
                        22,
                        MinuteOfHour::ZERO
                    )
                ]
            )
        );

        // To create a price extension, at least three table rows are needed.
        $tableRows = [];
        $tableRows[] = self::createPriceTableRow(
            'Scrubs',
            'Body Scrub, Salt Scrub',
            'http://www.example.com/scrubs',
            60 * self::MICROS_PER_DOLLAR,
            'USD',
            PriceExtensionPriceUnit::PER_HOUR,
            'http://m.example.com/scrubs'
        );
        $tableRows[] = self::createPriceTableRow(
            'Hair Cuts',
            'Once a month',
            'http://www.example.com/haircuts',
            75 * self::MICROS_PER_DOLLAR,
            'USD',
            PriceExtensionPriceUnit::PER_MONTH,
            'http://m.example.com/haircuts'
        );
        $tableRows[] = self::createPriceTableRow(
            'Skin Care Package',
            'Four times a month',
            'http://www.example.com/skincarepackage',
            250 * self::MICROS_PER_DOLLAR,
            'USD',
            PriceExtensionPriceUnit::PER_MONTH
        );

        $priceFeedItem->setTableRows($tableRows);

        // Create your customer extension settings. This associates the price
        // extension to your account.
        $customerExtensionSetting = new CustomerExtensionSetting();
        $customerExtensionSetting->setExtensionType(FeedType::PRICE);
        $customerExtensionSetting->setExtensionSetting(new ExtensionSetting());
        $customerExtensionSetting->getExtensionSetting()->setExtensions(
            [$priceFeedItem]
        );

        // Create a customer extension setting operation and add it to the list.
        $operation = new CustomerExtensionSettingOperation();
        $operation->setOperator(Operator::ADD);
        $operation->setOperand($customerExtensionSetting);
        $operations = [$operation];

        // Add the price extension on the server.
        $result = $customerExtensionSettingService->mutate($operations);

        // Print out some information about the added extension setting.
        $newExtensionSetting = $result->getValue()[0];
        printf(
            "Extension setting with type '%s' was added to your account.\n",
            $newExtensionSetting->getExtensionType()
        );
    }


    /**
     * Creates a new price table row with the specified attributes.
     *
     * @param string $header the header of price table row
     * @param string $description the description of price table row
     * @param string $finalUrl the final URL of price table row
     * @param integer $priceInMicros the price in micro amount
     * @param string $currencyCode the 3-character currency code
     * @param string $priceUnit the unit of shown price
     * @param string|null $finalMobileUrl the mobile final URL of price table row
     * @return PriceTableRow the created price table row
     */
    private static function createPriceTableRow(
        $header,
        $description,
        $finalUrl,
        $priceInMicros,
        $currencyCode,
        $priceUnit,
        $finalMobileUrl = null
    ) {
        $priceTableRow = new PriceTableRow();
        $priceTableRow->setHeader($header);
        $priceTableRow->setDescription($description);
        $priceTableRow->setFinalUrls(new UrlList([$finalUrl]));
        $money = new Money();
        $money->setMicroAmount($priceInMicros);
        $moneyWithCurrency = new MoneyWithCurrency();
        $moneyWithCurrency->setMoney($money);
        $moneyWithCurrency->setCurrencyCode($currencyCode);
        $priceTableRow->setPrice($moneyWithCurrency);
        $priceTableRow->setPriceUnit($priceUnit);

        if ($finalMobileUrl !== null) {
            $priceTableRow->setFinalMobileUrls(new UrlList([$finalMobileUrl]));
        }

        return $priceTableRow;
    }


    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,
            intval(self::CAMPAIGN_ID)
        );
    }
}

AddPrices::main();

<?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\Extensions;

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\ExtensionSetting;
use Google\AdsApi\AdWords\v201809\cm\FeedItemDevicePreference;
use Google\AdsApi\AdWords\v201809\cm\FeedItemGeoRestriction;
use Google\AdsApi\AdWords\v201809\cm\FeedItemSchedule;
use Google\AdsApi\AdWords\v201809\cm\FeedItemScheduling;
use Google\AdsApi\AdWords\v201809\cm\FeedType;
use Google\AdsApi\AdWords\v201809\cm\GeoRestriction;
use Google\AdsApi\AdWords\v201809\cm\Keyword;
use Google\AdsApi\AdWords\v201809\cm\KeywordMatchType;
use Google\AdsApi\AdWords\v201809\cm\Location;
use Google\AdsApi\AdWords\v201809\cm\Operator;
use Google\AdsApi\AdWords\v201809\cm\SitelinkFeedItem;
use Google\AdsApi\AdWords\v201809\cm\UrlList;
use Google\AdsApi\AdWords\v201809\mcm\CustomerService;
use Google\AdsApi\Common\OAuth2TokenBuilder;

/**
 * This example adds a sitelinks feed and associates it with a campaign.
 * To get campaigns, run BasicOperations/GetCampaigns.php.
 */
class AddSitelinks
{

    const CAMPAIGN_ID = 'INSERT_CAMPAIGN_ID_HERE';

    public static function runExample(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        $campaignId
    ) {
        $campaignExtensionSettingService = $adWordsServices->get($session, CampaignExtensionSettingService::class);
        $customerService = $adWordsServices->get($session, CustomerService::class);

        // Find the matching customer and its time zone. The getCustomers method
        // will return a single Customer object corresponding to the user's
        // clientCustomerId.
        $customers = $customerService->getCustomers();
        $customer = $customers[0];
        printf(
            "Found customer ID %d with time zone %s.\n",
            $customer->getCustomerId(),
            $customer->getDateTimeZone()
        );

        $sitelinks = [];
        // Create a simple sitelink.
        $sitelink1 = new SitelinkFeedItem();
        $sitelink1->setSitelinkText('Store Hours');
        $sitelink1->setSitelinkFinalUrls(
            new UrlList(['http://www.example.com/storehours'])
        );
        $sitelinks[] = $sitelink1;

        // This one to show the Thanksgiving specials link only from 20 - 27 Nov.
        $sitelink2 = new SitelinkFeedItem();
        $sitelink2->setSitelinkText('Thanksgiving Specials');
        $sitelink2->setSitelinkFinalUrls(
            new UrlList(['http://www.example.com/thanksgiving'])
        );
        $sitelink2->setStartTime(
            date('Y') . '1120 000000 ' . $customer->getDateTimeZone()
        );
        $sitelink2->setEndTime(
            date('Y') . '1127 235959 ' . $customer->getDateTimeZone()
        );
        // Target this sitelink for United States only. See
        // https://developers.google.com/adwords/api/docs/appendix/geotargeting
        // for valid geolocation codes.
        $location = new Location();
        $location->setId(2840);
        $sitelink2->setGeoTargeting($location);

        // Restrict targeting only to people physically within the United States.
        // Otherwise, this could also show to people interested in the United States
        // but not physically located there.
        $sitelink2->setGeoTargetingRestriction(
            new FeedItemGeoRestriction(GeoRestriction::LOCATION_OF_PRESENCE)
        );
        $sitelinks[] = $sitelink2;

        // Sitelink targetted on high end mobile.
        $sitelink3 = new SitelinkFeedItem();
        $sitelink3->setSitelinkText('Wifi available');
        $sitelink3->setSitelinkFinalUrls(
            new UrlList(['http://www.example.com/mobile/wifi'])
        );
        $sitelink3->setDevicePreference(new FeedItemDevicePreference(30001));
        // Target this sitelink only when the ad is triggered by the keyword
        // "free wifi".
        $keyword = new Keyword();
        $keyword->setText('free wifi');
        $keyword->setMatchType(KeywordMatchType::BROAD);
        $sitelink3->setKeywordTargeting($keyword);
        $sitelinks[] = $sitelink3;

        // Show the happy hours link only during Mon - Fri 6PM to 9PM.
        $sitelink4 = new SitelinkFeedItem();
        $sitelink4->setSitelinkText('Happy Hours Now!');
        $sitelink4->setSitelinkFinalUrls(
            new UrlList(['http://www.example.com/happyhours'])
        );
        $sitelink4->setScheduling(
            new FeedItemScheduling(
                [
                    new FeedItemSchedule('MONDAY', 18, 'ZERO', 21, 'ZERO'),
                    new FeedItemSchedule('TUESDAY', 18, 'ZERO', 21, 'ZERO'),
                    new FeedItemSchedule('WEDNESDAY', 18, 'ZERO', 21, 'ZERO'),
                    new FeedItemSchedule('THURSDAY', 18, 'ZERO', 21, 'ZERO'),
                    new FeedItemSchedule('FRIDAY', 18, 'ZERO', 21, 'ZERO')
                ]
            )
        );
        $sitelinks[] = $sitelink4;

        // Create your campaign extension settings. This associates the sitelinks
        // to your campaign.
        $campaignExtensionSetting = new CampaignExtensionSetting();
        $campaignExtensionSetting->setCampaignId($campaignId);
        $campaignExtensionSetting->setExtensionType(FeedType::SITELINK);
        $campaignExtensionSetting->setExtensionSetting(new ExtensionSetting());
        $campaignExtensionSetting->getExtensionSetting()->setExtensions($sitelinks);

        // Create a campaign extension setting operation and add it to the list.
        $operation = new CampaignExtensionSettingOperation();
        $operation->setOperator(Operator::ADD);
        $operation->setOperand($campaignExtensionSetting);
        $operations = [$operation];

        // Add the sitelinks on the server.
        $result = $campaignExtensionSettingService->mutate($operations);

        // Print out some information about the added extension setting.
        $newExtensionSetting = $result->getValue()[0];
        printf(
            "Extension setting with type '%s' was added to campaign ID %d\n",
            $newExtensionSetting->getExtensionType(),
            $newExtensionSetting->getCampaignId()
        );
    }

    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,
            intval(self::CAMPAIGN_ID)
        );
    }
}

AddSitelinks::main();

<?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\Extensions;

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\AttributeFieldMapping;
use Google\AdsApi\AdWords\v201809\cm\CampaignFeed;
use Google\AdsApi\AdWords\v201809\cm\CampaignFeedOperation;
use Google\AdsApi\AdWords\v201809\cm\CampaignFeedService;
use Google\AdsApi\AdWords\v201809\cm\Feed;
use Google\AdsApi\AdWords\v201809\cm\FeedAttribute;
use Google\AdsApi\AdWords\v201809\cm\FeedAttributeType;
use Google\AdsApi\AdWords\v201809\cm\FeedItem;
use Google\AdsApi\AdWords\v201809\cm\FeedItemAdGroupTarget;
use Google\AdsApi\AdWords\v201809\cm\FeedItemAttributeValue;
use Google\AdsApi\AdWords\v201809\cm\FeedItemCriterionTarget;
use Google\AdsApi\AdWords\v201809\cm\FeedItemGeoRestriction;
use Google\AdsApi\AdWords\v201809\cm\FeedItemOperation;
use Google\AdsApi\AdWords\v201809\cm\FeedItemService;
use Google\AdsApi\AdWords\v201809\cm\FeedItemTargetOperation;
use Google\AdsApi\AdWords\v201809\cm\FeedItemTargetService;
use Google\AdsApi\AdWords\v201809\cm\FeedMapping;
use Google\AdsApi\AdWords\v201809\cm\FeedMappingOperation;
use Google\AdsApi\AdWords\v201809\cm\FeedMappingService;
use Google\AdsApi\AdWords\v201809\cm\FeedOperation;
use Google\AdsApi\AdWords\v201809\cm\FeedOrigin;
use Google\AdsApi\AdWords\v201809\cm\FeedService;
use Google\AdsApi\AdWords\v201809\cm\GeoRestriction;
use Google\AdsApi\AdWords\v201809\cm\Location;
use Google\AdsApi\AdWords\v201809\cm\MatchingFunction;
use Google\AdsApi\AdWords\v201809\cm\Operator;
use Google\AdsApi\Common\OAuth2TokenBuilder;

/**
 * This example adds a sitelinks feed and associates it with a campaign.
 * To get campaigns, run GetCampaigns.php.
 */
class AddSitelinksUsingFeeds
{

    const CAMPAIGN_ID = 'INSERT_CAMPAIGN_ID_HERE';

    // Optional: Enter the ID of ad group for which you want to restrict the
    // first feed item to only serve with ads.
    // Leave this as null if you don't want to make such restriction.
    const AD_GROUP_ID = null;

    // See the Placeholder reference page for a list of all the placeholder
    // types and fields.
    // https://developers.google.com/adwords/api/docs/appendix/placeholders.html
    const PLACEHOLDER_SITELINKS = 1;
    const PLACEHOLDER_FIELD_SITELINK_LINK_TEXT = 1;
    const PLACEHOLDER_FIELD_SITELINK_FINAL_URL = 5;
    const PLACEHOLDER_FIELD_LINE_2_TEXT = 3;
    const PLACEHOLDER_FIELD_LINE_3_TEXT = 4;

    public static function runExample(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        $campaignId,
        $adGroupId = null
    ) {
        $sitelinksData = self::createSitelinksFeed($adWordsServices, $session);
        $sitelinksData = self::createSitelinksFeedItems(
            $adWordsServices,
            $session,
            $sitelinksData
        );
        self::createSitelinksFeedMapping(
            $adWordsServices,
            $session,
            $sitelinksData
        );
        self::createSitelinksCampaignFeed(
            $adWordsServices,
            $session,
            $sitelinksData,
            $campaignId
        );
        // Optional: Restrict the first feed item to only serve with ads for the
        // specified ad group ID.
        if ($adGroupId !== null) {
            self::restrictFeedItemToAdGroup(
                $adWordsServices,
                $session,
                $sitelinksData['sitelinksFeedId'],
                $sitelinksData['sitelinkFeedItemIds'][0],
                $adGroupId
            );
        }
    }

    /**
     * Creates the feed that holds the sitelinks data.
     */
    private static function createSitelinksFeed(
        AdWordsServices $adWordsServices,
        AdWordsSession $session
    ) {
        $feedService = $adWordsServices->get($session, FeedService::class);

        // Holds the IDs associated to the feeds metadata.
        $sitelinksData = [];

        // Create feed attributes.
        $textAttribute = new FeedAttribute();
        $textAttribute->setType(FeedAttributeType::STRING);
        $textAttribute->setName('Link Text');
        $finalUrlAttribute = new FeedAttribute();
        $finalUrlAttribute->setType(FeedAttributeType::URL_LIST);
        $finalUrlAttribute->setName('Link URL');
        $line2Attribute = new FeedAttribute();
        $line2Attribute->setType(FeedAttributeType::STRING);
        $line2Attribute->setName('Line 2');
        $line3Attribute = new FeedAttribute();
        $line3Attribute->setType(FeedAttributeType::STRING);
        $line3Attribute->setName('Line 3');

        // Create the feed.
        $sitelinksFeed = new Feed();
        $sitelinksFeed->setName('Feed For Sitelinks #' . uniqid());
        $sitelinksFeed->setAttributes([
                $textAttribute,
                $finalUrlAttribute,
                $line2Attribute,
                $line3Attribute
        ]);
        $sitelinksFeed->setOrigin(FeedOrigin::USER);

        // Create the feed operation and add it on the server.
        $operation = new FeedOperation();
        $operation->setOperator(Operator::ADD);
        $operation->setOperand($sitelinksFeed);
        $result = $feedService->mutate([$operation]);

        // Print out some information about the created feed.
        $savedFeed = $result->getValue()[0];
        $sitelinksData['sitelinksFeedId'] = $savedFeed->getId();
        $savedAttributes = $savedFeed->getAttributes();
        $sitelinksData['linkTextFeedAttributeId'] =
            $savedAttributes[0]->getId();
        $sitelinksData['linkFinalUrlFeedAttributeId'] =
            $savedAttributes[1]->getId();
        $sitelinksData['line2FeedAttribute'] = $savedAttributes[2]->getId();
        $sitelinksData['line3FeedAttribute'] = $savedAttributes[3]->getId();

        printf(
            "Feed with name '%s', ID %d with linkTextAttributeId %d, "
            . "linkFinalUrlAttributeId %d, line2AttributeId %d and "
            . "line3AttributeId %d was created.%s",
            $savedFeed->getName(),
            $savedFeed->getId(),
            $savedAttributes[0]->getId(),
            $savedAttributes[1]->getId(),
            $savedAttributes[2]->getId(),
            $savedAttributes[3]->getId(),
            PHP_EOL
        );

        return $sitelinksData;
    }

    /**
     * Creates sitelinks feed items and add it to the feed.
     */
    private static function createSitelinksFeedItems(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        array $sitelinksData
    ) {
        $feedItemService =
            $adWordsServices->get($session, FeedItemService::class);

        // Create operations to add feed items.
        $home = self::newSitelinkFeedItemAddOperation(
            $sitelinksData,
            'Home',
            'http://www.example.com',
            'Home line 2',
            'Home line 3'
        );
        $stores = self::newSitelinkFeedItemAddOperation(
            $sitelinksData,
            'Stores',
            'http://www.example.com/stores',
            'Stores line 2',
            'Stores line 3'
        );
        $onSale = self::newSitelinkFeedItemAddOperation(
            $sitelinksData,
            'On Sale',
            'http://www.example.com/sale',
            'On Sale line 2',
            'On Sale line 3'
        );
        $support = self::newSitelinkFeedItemAddOperation(
            $sitelinksData,
            'Support',
            'http://www.example.com/support',
            'Support line 2',
            'Support line 3'
        );
        $products = self::newSitelinkFeedItemAddOperation(
            $sitelinksData,
            'Products',
            'http://www.example.com/products',
            'Products line 2',
            'Products line 3'
        );
        // This site link is using geographical targeting to use
        // LOCATION_OF_PRESENCE.
        $aboutUs = self::newSitelinkFeedItemAddOperation(
            $sitelinksData,
            'About Us',
            'http://www.example.com/about',
            'About Us line 2',
            'About Us line 3',
            true
        );

        // Add feed item operations on the server and print out some information.
        $result = $feedItemService->mutate(
            [$home, $stores, $onSale, $support, $products, $aboutUs]
        );
        $sitelinksData['sitelinkFeedItemIds'] = [];

        foreach ($result->getValue() as $feedItem) {
            printf(
                'Feed item with feed item ID %d was added.%s',
                $feedItem->getFeedItemId(),
                PHP_EOL
            );
            $sitelinksData['sitelinkFeedItemIds'][] =
                $feedItem->getFeedItemId();
        }

        // Target the "aboutUs" sitelink to geographically target California.
        // See https://developers.google.com/adwords/api/docs/appendix/geotargeting
        // for location criteria of supported locations.
        self::restrictFeedItemToGeoTarget(
            $adWordsServices,
            $session,
            $result->getValue()[5],
            21137
        );

        return $sitelinksData;
    }

    /**
     * Maps the feed attributes to the sitelink placeholders.
     */
    private static function createSitelinksFeedMapping(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        array $sitelinksData
    ) {
        $feedMappingService =
            $adWordsServices->get($session, FeedMappingService::class);

        // Map the feed attribute IDs to the field ID constants.
        $linkTextFieldMapping = new AttributeFieldMapping();
        $linkTextFieldMapping->setFeedAttributeId(
            $sitelinksData['linkTextFeedAttributeId']
        );
        $linkTextFieldMapping->setFieldId(
            self::PLACEHOLDER_FIELD_SITELINK_LINK_TEXT
        );
        $linkFinalUrlFieldMapping = new AttributeFieldMapping();
        $linkFinalUrlFieldMapping->setFeedAttributeId(
            $sitelinksData['linkFinalUrlFeedAttributeId']
        );
        $linkFinalUrlFieldMapping->setFieldId(
            self::PLACEHOLDER_FIELD_SITELINK_FINAL_URL
        );
        $line2FieldMapping = new AttributeFieldMapping();
        $line2FieldMapping->setFeedAttributeId(
            $sitelinksData['line2FeedAttribute']
        );
        $line2FieldMapping->setFieldId(self::PLACEHOLDER_FIELD_LINE_2_TEXT);
        $line3FieldMapping = new AttributeFieldMapping();
        $line3FieldMapping->setFeedAttributeId(
            $sitelinksData['line3FeedAttribute']
        );
        $line3FieldMapping->setFieldId(self::PLACEHOLDER_FIELD_LINE_3_TEXT);

        // Create the feed mapping and feed mapping operation.
        $feedMapping = new FeedMapping();
        $feedMapping->setPlaceholderType(self::PLACEHOLDER_SITELINKS);
        $feedMapping->setFeedId($sitelinksData['sitelinksFeedId']);
        $feedMapping->setAttributeFieldMappings(
            [
                $linkTextFieldMapping,
                $linkFinalUrlFieldMapping,
                $line2FieldMapping,
                $line3FieldMapping
            ]
        );

        $operation = new FeedMappingOperation();
        $operation->setOperand($feedMapping);
        $operation->setOperator(Operator::ADD);

        // Create the feed mapping operation on the server and print out some
        // information.
        $result = $feedMappingService->mutate([$operation]);
        foreach ($result->getValue() as $feedMapping) {
            printf(
                'Feed mapping with ID %d and placeholder type %d was '
                . 'saved for feed with ID %d.%s',
                $feedMapping->getFeedMappingId(),
                $feedMapping->getPlaceholderType(),
                $feedMapping->getFeedId(),
                PHP_EOL
            );
        }
    }

    /**
     * Creates the campaign feed associated to the populated feed data for the
     * specified campaign ID.
     */
    private static function createSitelinksCampaignFeed(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        array $sitelinksData,
        $campaignId
    ) {
        $campaignFeedService =
            $adWordsServices->get($session, CampaignFeedService::class);
        $matchingFunctionString = sprintf(
            'AND( IN(FEED_ITEM_ID, {%s}), EQUALS(CONTEXT.DEVICE, "Mobile") )',
            implode(',', $sitelinksData['sitelinkFeedItemIds'])
        );

        // Create a campaign feed and its feed function.
        $campaignFeed = new CampaignFeed();
        $campaignFeed->setFeedId($sitelinksData['sitelinksFeedId']);
        $campaignFeed->setCampaignId($campaignId);

        $matchingFunction = new MatchingFunction();
        $matchingFunction->setFunctionString($matchingFunctionString);
        $campaignFeed->setMatchingFunction($matchingFunction);
        $campaignFeed->setPlaceholderTypes([self::PLACEHOLDER_SITELINKS]);

        // Create the campaign feed operation.
        $operation = new CampaignFeedOperation();
        $operation->setOperand($campaignFeed);
        $operation->setOperator(Operator::ADD);

        // Create the campaign feed on the server and print out some information.
        $result = $campaignFeedService->mutate([$operation]);
        foreach ($result->getValue() as $savedCampaignFeed) {
            printf(
                'Campaign with ID %d was associated with feed with ID %d.%s',
                $savedCampaignFeed->getCampaignId(),
                $savedCampaignFeed->getFeedId(),
                PHP_EOL
            );
        }
    }

    /**
     * Creates feed item ad group target for a specified feed ID, feed item ID,
     * and ad group ID.
     */
    private static function restrictFeedItemToAdGroup(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        $feedId,
        $feedItemId,
        $adGroupId
    ) {
        $feedItemTargetService = $adWordsServices->get(
            $session,
            FeedItemTargetService::class
        );

        // Create a feed item ad group target.
        $feedItemAdGroupTarget = new FeedItemAdGroupTarget();
        $feedItemAdGroupTarget->setFeedId($feedId);
        $feedItemAdGroupTarget->setFeedItemId($feedItemId);
        $feedItemAdGroupTarget->setAdGroupId($adGroupId);

        // Create a feed item ad group target operation.
        $operation = new FeedItemTargetOperation();
        $operation->setOperand($feedItemAdGroupTarget);
        $operation->setOperator(Operator::ADD);

        // Create the feed item ad group target on the server and print out
        // some information.
        $result = $feedItemTargetService->mutate([$operation]);
        $feedItemAdGroupTarget = $result->getValue()[0];
        printf(
            'Feed item target for feed ID %d and feed item ID %d was '
            . 'created to restrict serving to ad group ID %d.%s',
            $feedItemAdGroupTarget->getFeedId(),
            $feedItemAdGroupTarget->getFeedItemId(),
            $feedItemAdGroupTarget->getAdGroupId(),
            PHP_EOL
        );
    }

    /**
     * Restricts the first feed item to only serve with ads for the specified
     * location ID.
     *
     * @param AdWordsServices $adWordsServices the AdWords services
     * @param AdWordsSession $session the AdWords session
     * @param FeedItem $feedItem the feed item to restrict
     * @param int $locationId the location ID to which the feed item will be
     *     restricted
     */
    private static function restrictFeedItemToGeoTarget(
        AdWordsServices $adWordsServices,
        AdWordsSession $session,
        FeedItem $feedItem,
        $locationId
    ) {
        $feedItemTargetService = $adWordsServices->get(
            $session,
            FeedItemTargetService::class
        );

        // Optional: Restrict the feed item to only serve with ads for the
        // specified geo target.
        $feedItemCriterionTarget = new FeedItemCriterionTarget();
        $feedItemCriterionTarget->setFeedId($feedItem->getFeedId());
        $feedItemCriterionTarget->setFeedItemId($feedItem->getFeedItemId());

        $location = new Location();
        // The IDs can be found in the documentation or retrieved with the
        // LocationCriterionService.
        $location->setId($locationId);
        $feedItemCriterionTarget->setCriterion($location);

        // Create a feed item target operation.
        $operation = new FeedItemTargetOperation();
        $operation->setOperand($feedItemCriterionTarget);
        $operation->setOperator(Operator::ADD);

        // Create the feed item target on the server and print out
        // some information.
        $result = $feedItemTargetService->mutate([$operation]);
        $feedItemCriterionTarget = $result->getValue()[0];
        printf(
            'Feed item target for feed ID %d and feed item ID %d was '
            . 'created to restrict serving to location ID %d.%s',
            $feedItemCriterionTarget->getFeedId(),
            $feedItemCriterionTarget->getFeedItemId(),
            $feedItemCriterionTarget->getCriterion()->getId(),
            PHP_EOL
        );
    }

    /**
     * Creates a site link feed item and wraps it in an ADD operation.
     *
     * @param array $sitelinksData IDs associated to created sitelinks feed
     *     metadata
     * @param string $text the text of the sitelink
     * @param string $finalUrl the final URL of the sitelink
     * @param string $line2 the first line of the sitelink description
     * @param string $line3 the second line of the sitelink description
     * @param bool|null $restrictToLop whether to restrict the feed item to
     *     location of presence
     * @return FeedItemOperation the created ADD operation of site link feed
     *     item
     */
    private static function newSitelinkFeedItemAddOperation(
        array $sitelinksData,
        $text,
        $finalUrl,
        $line2,
        $line3,
        $restrictToLop = null
    ) {
        // Create the feed item attribute values for our text values.
        $linkTextAttributeValue = new FeedItemAttributeValue();
        $linkTextAttributeValue->setFeedAttributeId(
            $sitelinksData['linkTextFeedAttributeId']
        );
        $linkTextAttributeValue->setStringValue($text);
        $linkFinalUrlAttributeValue = new FeedItemAttributeValue();
        $linkFinalUrlAttributeValue->setFeedAttributeId(
            $sitelinksData['linkFinalUrlFeedAttributeId']
        );
        $linkFinalUrlAttributeValue->setStringValues([$finalUrl]);
        $line2AttributeValue = new FeedItemAttributeValue();
        $line2AttributeValue->setFeedAttributeId(
            $sitelinksData['line2FeedAttribute']
        );
        $line2AttributeValue->setStringValue($line2);
        $line3AttributeValue = new FeedItemAttributeValue();
        $line3AttributeValue->setFeedAttributeId(
            $sitelinksData['line3FeedAttribute']
        );
        $line3AttributeValue->setStringValue($line3);

        // Create the feed item.
        $item = new FeedItem();
        $item->setFeedId($sitelinksData['sitelinksFeedId']);
        $item->setAttributeValues(
            [
                $linkTextAttributeValue,
                $linkFinalUrlAttributeValue,
                $line2AttributeValue,
                $line3AttributeValue
            ]
        );

        // OPTIONAL: Restrict targeting only to people physically within the
        // location.
        if ($restrictToLop === true) {
            $item->setGeoTargetingRestriction(
                new FeedItemGeoRestriction(GeoRestriction::LOCATION_OF_PRESENCE)
            );
        }

        // Create the feed item operation.
        $operation = new FeedItemOperation();
        $operation->setOperand($item);
        $operation->setOperator(Operator::ADD);

        return $operation;
    }

    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,
            intval(self::CAMPAIGN_ID),
            self::AD_GROUP_ID === null ? null : intval(self::AD_GROUP_ID)
        );
    }
}

AddSitelinksUsingFeeds::main();