{"id":38,"date":"2015-05-02T13:56:14","date_gmt":"2015-05-02T12:56:14","guid":{"rendered":"http:\/\/www.contentecontent.com\/blog\/?p=38"},"modified":"2018-08-27T08:26:49","modified_gmt":"2018-08-27T07:26:49","slug":"post-from-server-to-facebook-page-with-php-sdk-4","status":"publish","type":"post","link":"https:\/\/www.contentecontent.com\/blog\/2015\/05\/post-from-server-to-facebook-page-with-php-sdk-4\/","title":{"rendered":"Post from server to Facebook page with FB&#8217;s PHP SDK 4"},"content":{"rendered":"<p>On my server, I have a PHP script that runs once a day to post a message and a picture to a Facebook page that I administer. Yesterday Facebook upgraded their API to v2, breaking my script that had been running fine since a few years.<\/p>\n<p><!--more--><\/p>\n<p><strong>Update August 1, 2018:<\/strong> it seems that today Facebook has killed automated posting to pages. I&#8217;ll leave this post here for archaeological purposes.<\/p>\n<p><strong>Update August 26, 2018:<\/strong> using a new never expiring token made things work again.<\/p>\n<p>&#8212;<\/p>\n<p>This was the error it threw:<\/p>\n<pre><code>[error] =&gt; Array\n            (\n                [message] =&gt; The 'manage_pages' permission must be granted before impersonating a user\\'s page.\n                [type] =&gt; OAuthException\n                [code] =&gt; 190\n            )\n<\/code><\/pre>\n<p>Which obviously means that the Facebook app I made to perform the task does not have the proper permission.<\/p>\n<p>The app I made is also used for other tasks. In order not to break them, I created a new app and gave it the proper permissions. After that, I needed to get a page access token that never expires. I also upgraded to version 4 of Facebook&#8217;s PHP SDK. Here&#8217;s what worked for me.<\/p>\n<h2>Create app and token<\/h2>\n<p>Create a new website app at <a href=\"https:\/\/developers.facebook.com\/\">https:\/\/developers.facebook.com\/<\/a> . Enter your Site URL and App Domains (www.example.com).<\/p>\n<p>Get a short-lived access token via the <a href=\"https:\/\/developers.facebook.com\/tools\/explorer\/\">Graph API Explorer<\/a>:<\/p>\n<ul>\n<li>from the Get Token menu, pick Get Access Token. <\/li>\n<li>in the dialog window, pick <code>manage_pages<\/code> and <code>publish_pages<\/code> from the Extended Permissions tab. Facebook will prompt for confirmation.<\/li>\n<\/ul>\n<p>Copy the token; it&#8217;s the short-lived access token with the proper permissions for posting to your page. It&#8217;s a pretty long string.<\/p>\n<p>Make a long-lived access token out of the short-lived token. It&#8217;s required to create the never-expiring page access token. In the browser that&#8217;s logged in to Facebook as app admin, run this script (upload it to your server first&#8230;):<\/p>\n<pre><code>&lt;?php\ndefine('FACEBOOK_SDK_V4_SRC_DIR', '\/PATH\/TO\/fb\/src\/Facebook\/'); \nrequire 'fb\/autoload.php'; \nuse Facebook\\FacebookSession; \nuse Facebook\\GraphUser;\nuse Facebook\\FacebookSDKException;\n\n\/\/ grab your app's APP_ID and APP_SECRET from the developer dashboard   \nFacebookSession::setDefaultApplication('YOUR_APP_ID', 'YOUR_APP_SECRET');\n\n\/\/ create a FacebookSession with the short-lived access token \n$session = new FacebookSession('SHORT-LIVED_ACCESS_TOKEN');\n\n\/\/ Get the AccessToken entity. \n$accessToken = $session-&gt;getAccessToken();\n\ntry { \/\/ get a long-lived token from the short-lived one \n    echo $longLivedAccessToken = $accessToken-&gt;extend(); \n} catch(FacebookSDKException $e) { \n    echo 'Error extending the short-lived access token: ' . $e-&gt;getMessage(); \n    exit; \n}\n<\/code><\/pre>\n<p>Copy the long-lived access token.<\/p>\n<p>To create a never-expiring page access token, run this script. It will list all Facebook pages that you administer, with their names, IDs and access tokens:<\/p>\n<pre><code>&lt;?php\ndefine('FACEBOOK_SDK_V4_SRC_DIR', '\/PATH\/TO\/fb\/src\/Facebook\/'); \nrequire 'fb\/autoload.php'; \nuse Facebook\\FacebookSession; \nuse Facebook\\GraphUser;\nuse Facebook\\FacebookRequest; \nuse Facebook\\FacebookRequestException; \n\nFacebookSession::setDefaultApplication('YOUR_APP_ID', 'YOUR_APP_SECRET');\n\n\/\/ create a FacebookSession with the long-lived access token \n$session = new FacebookSession('LONG-LIVED_ACCESS_TOKEN');\n\ntry {\n    \/\/ Get a list of pages with you as admin\n    $request = new FacebookRequest($session, 'GET', '\/me\/accounts?fields=name,access_token');\n    $pageList = $request-&gt;execute()-&gt;getGraphObject()-&gt;asArray();\n    foreach ($pageList as $page) {\n        print_r($page);\n    }\n} catch (FacebookRequestException $e) {\n    echo 'Request error: ' . $e-&gt;getMessage();\n    exit;\n}\n<\/code><\/pre>\n<p>Copy the <code>access_token<\/code> of the proper page. It&#8217;s the never-expiring page access token. Also copy the page&#8217;s ID, if you didn&#8217;t already have it. It&#8217;s a long number.<\/p>\n<p>Paste the token into Facebook&#8217;s Access Token Debugger to check. &#8216;Expires&#8217; should say &#8216;Never&#8217;, &#8216;Valid&#8217; should be &#8216;True&#8217;, and &#8216;Scopes&#8217; should include &#8216;manage_pages, publish_pages, public_profile&#8217;.<\/p>\n<h2>Post to Facebook page<\/h2>\n<p>Fairly easy, given we now have the proper token.<\/p>\n<pre><code>&lt;?php\ndefine('FACEBOOK_SDK_V4_SRC_DIR', '\/PATH\/TO\/fb\/src\/Facebook\/'); \nrequire 'fb\/autoload.php'; \n\nuse Facebook\\FacebookSession;\nuse Facebook\\FacebookRequest;\n\/\/ use Facebook\\GraphUser; \/\/ edit 2015-11-03: not used\nuse Facebook\\FacebookRequestException;\n\nFacebookSession::setDefaultApplication('YOUR_APP_ID', 'YOUR_APP_SECRET');\n\n$neverExpiringToken = 'NEVER-EXPIRING_PAGE_ACCESS_TOKEN';\n$pageID = 'PAGE_ID';\n\n\/\/ create a FacebookSession with the never-expiring page access token \n$session = new FacebookSession($neverExpiringToken);\n\ntry {\n    $post_id = (new FacebookRequest(\n        $session, \n        'POST', \n        '\/' . $pageID . '\/feed', \n        array(\n                'access_token'  =&gt; $neverExpiringToken,\n                'message'   =&gt; 'boy do I love the Graph API',\n                'link'      =&gt; 'http:\/\/www.contentecontent.com\/blog\/',\n                'picture'   =&gt; 'image URL here',\n                'name'      =&gt; 'name here',\n                'description'=&gt; 'description here'\n        )\n    )\n    )-&gt;execute()-&gt;getGraphObject()-&gt;asArray();\n} catch (FacebookRequestException $e) {\n    echo 'ERROR! ' . __LINE__ . $e-&gt;getMessage();   \n} catch (Exception $e) {\n    echo 'ERROR! ' . __LINE__ . $e-&gt;getMessage();\n}\n<\/code><\/pre>\n<p><code>$post_id<\/code> should now contain the ID of the post you just made to the page.<\/p>\n<h2>Make the posts visible to the world<\/h2>\n<p>While the app is in development mode, which it is by default, the postings are only visible to you. In the app&#8217;s dashboard, set the app to Public in the Status &amp; Review tab.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>On my server, I have a PHP script that runs once a day to post a message and a picture to a Facebook page that I administer. Yesterday Facebook upgraded their API to v2, breaking my script that had been running fine since a few years.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[12,7],"class_list":["post-38","post","type-post","status-publish","format-standard","hentry","category-misc","tag-facebook","tag-php"],"_links":{"self":[{"href":"https:\/\/www.contentecontent.com\/blog\/wp-json\/wp\/v2\/posts\/38","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.contentecontent.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.contentecontent.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.contentecontent.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.contentecontent.com\/blog\/wp-json\/wp\/v2\/comments?post=38"}],"version-history":[{"count":24,"href":"https:\/\/www.contentecontent.com\/blog\/wp-json\/wp\/v2\/posts\/38\/revisions"}],"predecessor-version":[{"id":118,"href":"https:\/\/www.contentecontent.com\/blog\/wp-json\/wp\/v2\/posts\/38\/revisions\/118"}],"wp:attachment":[{"href":"https:\/\/www.contentecontent.com\/blog\/wp-json\/wp\/v2\/media?parent=38"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.contentecontent.com\/blog\/wp-json\/wp\/v2\/categories?post=38"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.contentecontent.com\/blog\/wp-json\/wp\/v2\/tags?post=38"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}