service_name = 'facebook'; $this->title = 'Facebook'; $this->icon = 'facebook-logo'; $this->apiVersion = 'v25.0'; $this->canSync = [ 'create' => true, 'update' => true, 'delete' => true ]; $this->defineFields(); $this->defineInstructions(); $this->defineOAuth(); $this->defineActions(); $this->baseUrl = 'https://graph.facebook.com/'.$this->apiVersion; $this->baseOAuthUrl = 'https://www.facebook.com/'.$this->apiVersion; parent::__construct(); } protected function defineFields():void { $client_id = $this->addField( 'client_id', 'App ID', 'text', 'manage_options' ); $client_id->setRequired(); $client_id->setHint('Your Facebook App ID from developers.facebook.com'); $client_secret = $this->addField( 'client_secret', 'App Secret', 'text', 'manage_options' ); $client_secret->setRequired(); $client_secret->setSubType('password'); $pages = $this->addField('pages', 'Pages', 'select', [$this, 'testUserCanConnect']); $pages->setHidden(); $pages->setOptions($this->getPageOptions()); $page = $this->addField('page_id', 'Connect to Page', 'select', [$this, 'testUserCanConnect']); $page->setOptions($this->loadCredentials()['pages']??[]); $page->setHint('Select the page you want to connect this site to.'); } public function testUserCanConnect():bool { $user = get_current_user_id(); return $this->userCanConnect($user); } protected function getPageOptions():array { return $this->loadCredentials()['pages']??[]; } protected function defineInstructions():void { } protected function defineActions():void { $this->addAction( 'Select Page', [$this, 'handleSelectPage'], 'select_page', 'plugs-connected' ); $this->addAction( 'Fetch Pages', [$this, 'getPages'], 'fetch_pages', 'download-simple' ); } public function defineOAuth():void { $this->oauth = new OAuthURLs( 'https://www.facebook.com/'.$this->apiVersion.'/dialog/oauth', 'https://graph.facebook.com/'.$this->apiVersion.'/oauth/access_token', 'https://graph.facebook.com/'.$this->apiVersion.'/me/permissions' ); $this->oathScopes = [ 'pages_show_list', 'business_management', 'pages_manage_metadata', 'pages_manage_posts' ]; } public function getServiceDescription():string { return 'Connect your Facebook Page to share posts, events, and engage with your audience.'; } protected function initialize(): void { // TODO: Implement initialize() method. } protected function refreshAccessToken(OAuthCredentials $credentials): array { return $this->response(false, 'Not set up yet'); } protected function getRequestHeaders(): array { return [ 'Content-Type' => 'application/json', 'Accept' => 'application/json' ]; } 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'); } $endpoint = str_replace($this->baseUrl, '', $endpoint); return match ($endpoint) { '/me/accounts?access_token='.$this->getAccessToken() => $this->handleGetPagesResponse($response, $method), default => $this->response(false, 'Unhandled Response for ' . $endpoint . ' endpoint, with method: ' . $method), }; } /************************************************************ * UTILITY METHODS ************************************************************/ protected function getPageID():string|false { return $this->loadCredentials()['page_id']??false; } protected function getClientID():string|false { return $this->loadCredentials()['client_id']??false; } protected function getClientSecret():string|false { return $this->loadCredentials()['client_secret']??false; } protected function getFBUserID():string|false { $cred = $this->loadCredentials(); if ($this->isSetUp() && !array_key_exists('user_id', $cred)) { $resp = $this->getRequest( $this->baseUrl.'/me?access_token='.$cred['access_token'], ); if ($resp && !is_wp_error($resp)) { $tmp['user_id'] = $resp['id']; $tmp['user_name'] = $resp['name']; $this->saveCredentials($tmp, false); } $cred = array_merge($cred, $tmp); } return $cred['user_id']??false; } public function getPages():array|false { if (!$this->getAccessToken()) { return false; } try { return $this->getRequest( $this->apiBase.'/me/accounts?access_token='.$this->getAccessToken(), ); } catch (Exception $e) { $this->logError( 'getPages', 'Failed to load pages', [ 'error' => $e->getMessage(), ] ); } return []; } protected function handleGetPagesResponse(WP_Error|array $response, string $method):array { $options = []; foreach ($response as $page) { if (array_key_exists('id', $page) && array_key_exists('name', $page)) { $options[$page['id']] = $page['name']; } } if (!empty($options)) { $this->saveCredentials(['pages' => $options]); } return $this->response(true, 'Found pages', $options); } /************************************************************ * ACTIONS ************************************************************/ public function handleSelectPage(array $data):array { if (empty($data['page_id']??'')) { return $this->response(false, 'No page selected.'); } $cred = [ 'page_id' => sanitize_text_field($data['page_id']), ]; return $this->saveCredentials($cred, false); } public function handleFetchPages():array { try { $pages = $this->getPages(); if (!$pages) { return $this->response(false, 'No pages found'); } return $this->response( true, sprintf('Found %d page(s)', count($pages)), $pages ); } catch (Exception $e) { return $this->response(false, 'Failed to fetch pages: '.$e->getMessage()); } } protected function setContentTypes(): void { // TODO: Implement setContentTypes() method. } protected function formatForService(int $itemID, string $type = 'post'): array { return []; } }