service_name = 'gmb'; $this->title = 'Google My Business'; $this->icon = 'storefront'; $this->canSync = [ 'initial' => true, 'update' => true, 'delete' => true, ]; $this->supportsWebp = false; $this->defineFields(); $this->defineInstructions(); $this->defineOAuth(); $this->defineActions(); parent::__construct(); } protected function defineFields():void { $client_id = $this->addField( 'client_id', 'OAuth Client ID', 'text', 'manage_options' ); $client_id->setRequired(); $client_id->setHint('From your Google Cloud Console OAuth credentials.'); $secret = $this->addField( 'client_secret', 'OAuth Client Secret', 'text', 'manage_options', ); $secret->setSubType('password'); $secret->setRequired(); if ($this->getAccessToken()) { $accs = $this->addField('accounts', 'Accounts', 'select', [$this, 'testUserCanConnect']); $accs->setHidden(); $accs->setOptions($this->getAccountOptions()); $acc = $this->addField('account_id', 'Set Account', 'select', [$this, 'testUserCanConnect']); $acc->setOptions($this->loadCredentials()['accounts']??[]); $acc->setHint('Select the account to connect to.'); if ($this->getAccountID()) { $locs = $this->addField('locations', 'Locations', 'select', [$this, 'testUserCanConnect']); $locs->setHidden(); $locs->setOptions($this->getLocationOptions()); $loc = $this->addField('location_id', 'Set Location', 'select', [$this, 'testUserCanConnect']); $loc->setOptions($this->loadCredentials()['locations']??[]); $loc->setHint('Select the location to connect to.'); } } } public function testUserCanConnect():bool { $user = get_current_user_id(); return $this->userCanConnect($user); } protected function defineInstructions():void { $this->instructions = [ 'Go to Google Cloud Console', 'Create OAuth 2.0 Client ID credentials', 'Enable Google My Business API', 'Add redirect URI: '.esc_html($this->getRedirectUri()).'', 'Use the "Authorize" button below to complete OAuth flow' ]; } protected function defineOAuth():void { $this->oauth = new OAuthURLs( 'https://accounts.google.com/o/oauth2/v2/auth', 'https://oauth2.googleapis.com/token', 'https://oauth2.googleapis.com/revoke' ); $this->oathScopes = [ 'https://www.googleapis.com/auth/business.manage', 'https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/plus.business.manage' ]; } protected function defineActions():void { $this->addAction( 'Update Location', [$this, 'handleUpdateLocation'], 'update_location', ); } public function handleUpdateLocation(array $data):array { if (empty($data['location_id']??'')) { return $this->response(false, 'No location selected'); } $credentials = [ 'location_id' => sanitize_text_field($data['location_id']) ]; return $this->saveCredentials($credentials, false); } protected function initialize(): void { // TODO: Implement initialize() method. } protected function getRequestHeaders(): array { // TODO: Implement getRequestHeaders() method. } protected function handleResponse(\WP_Error|array $response, string $method, string $endpoint): array { if (is_wp_error($response) && $response->get_error_message() === 'rate_limit_exceeded') { return $this->response(false, 'Rate limit exceeded'); } return match($endpoint) { 'https://mybusinessaccountmanagement.googleapis.com/v1/accounts' => $this->handleGetAccountsResponse($response, $method), sprintf('https://mybusinessbusinessinformation.googleapis.com/v1/%s/locations', $this->getAccountID()??'') => $this->handleGetLocationsResponse($response, $method), default => $this->response(false, 'Unhandled response for '.$endpoint.' endpoint, with method: '.$method) }; } protected function refreshAccessToken(OAuthCredentials $credentials): array { // TODO: Implement refreshAccessToken() method. } /********************************************************* * UTILITY *********************************************************/ protected function getAccountID():string|false { return $this->loadCredentials()['account_id']??false; } protected function getAccountOptions(bool $force = false):array { $stored = $this->loadCredentials()['accounts']??[]; if ($force || empty($stored)) { $stored = $this->getAccounts(); } return $stored; } protected function getLocationID():string|false { return $this->loadCredentials()['location_id']??false; } protected function getLocationOptions(bool $force = false):array { $stored = $this->loadCredentials()['locations']??[]; if ($force || empty($stored)) { $stored = $this->getLocations(); } return $stored; } protected function getLocations():array|false { if (!$this->getAccessToken() || !$this->getAccountID()) { return false; } try { return $this->getRequest( sprintf( '/v1/%s/locations', $this->getAccountID() ), [ 'readMask' => $this->readMask ] ); } catch (Exception $e) { $this->logError('getLocations', 'Could not get locations: '.$e->getMessage()); return []; } } protected function handleGetLocationsResponse(array $response, string $method):array { $locations = []; if (isset($response['locations'])) { foreach ($response['locations'] as $loc) { if (isset($loc['name']) && isset($loc['title'])) { $locations[$loc['name']] = $loc['title']; } } } return $locations; } protected function getAccounts(bool $force = false):array|false { if (!$this->getAccessToken()) { return false; } return $this->getRequest( 'https://mybusinessaccountmanagement.googleapis.com/v1/accounts', [], $force ); } protected function handleGetAccountsResponse(array $response, string $method):array { $accounts = []; if (isset($response['accounts']) && is_array($response['accounts'])) { $accounts = $response['accounts']; } elseif (is_array($response) && isset($response['name'])) { $accounts = [$response]; } $options = []; foreach ($accounts as $account) { if (isset($account['name']) && isset($account['accountName'])) { $options[$account['name']] = $account['accountName']; } } return $options; } protected function setContentTypes(): void { // TODO: Implement setContentTypes() method. } protected function formatForService(int $itemID, string $type = 'post'): array { // TODO: Implement formatForService() method. } }