Search code examples
phpfacebookfacebook-graph-apifacebook-instant-articles

Facebook Instant Articles: Creating Articles with Graph API


I've been developing a WordPress plugin that uses Facebook's API to create Instant Articles. (I'm using SDK version 5.3.1 from here: https://github.com/facebook/php-graph-sdk/tree/5.4) It requires the inclusion of many custom fields, hence the new plugin instead of using an existing one. I developed it on my local machine using a Vagrant/VirtualBox linux server, and from there I was able to successfully authenticate and create an Instant Article, which then appeared in the list on Facebook within Publishing Tools > Instant Articles > Development Articles.

I deployed this same code to a live web server to continue testing it. Authentication is still successful but when I attempt to publish an article from that server the Instant Article is never created and does not appear in the list on Facebook.

The puzzling thing is that the responses from both attempts appear nearly identical. One difference is the accessToken value, which I have marked as {access_token}. Other differences between responses I have marked as {different}.

Can anyone help me understand why one succeeds and the other fails without any apparent errors in PHP or in the API responses?

Response using Local Machine (succeeds):

object(Facebook\FacebookResponse)#144 (6) {
  ["httpStatusCode":protected]=>
  int(200)
  ["headers":protected]=>
  array(13) {
    ["Access-Control-Allow-Origin"]=>
    string(1) "*"
    ["Pragma"]=>
    string(8) "no-cache"
    ["Cache-Control"]=>
    string(44) "private, no-cache, no-store, must-revalidate"
    ["facebook-api-version"]=>
    string(4) "v2.7"
    ["Expires"]=>
    string(29) "Sat, 01 Jan 2000 00:00:00 GMT"
    ["Content-Type"]=>
    string(31) "application/json; charset=UTF-8"
    ["x-fb-trace-id"]=>
    string(11) "{different}"
    ["x-fb-rev"]=>
    string(7) "{different}"
    ["Vary"]=>
    string(15) "Accept-Encoding"
    ["X-FB-Debug"]=>
    string(88) "{different}"
    ["Date"]=>
    string(29) "Wed, 19 Oct 2016 16:24:51 GMT"
    ["Connection"]=>
    string(10) "keep-alive"
    ["Content-Length"]=>
    string(2) "25"
  }
  ["body":protected]=>
  string(25) "{"id":"{different}"}"
  ["decodedBody":protected]=>
  array(1) {
    ["id"]=>
    string(16) "{different}"
  }
  ["request":protected]=>
  object(Facebook\FacebookRequest)#145 (9) {
    ["app":protected]=>
    object(Facebook\FacebookApp)#183 (2) {
      ["id":protected]=>
      string(16) "{app_id}"
      ["secret":protected]=>
      string(32) "{app_secret}"
    }
    ["accessToken":protected]=>
    string(168) "{access_token}"
    ["method":protected]=>
    string(4) "POST"
    ["endpoint":protected]=>
    string(29) "/{some_endpoint_id}/instant_articles"
    ["headers":protected]=>
    array(1) {
      ["Content-Type"]=>
      string(33) "application/x-www-form-urlencoded"
    }
    ["params":protected]=>
    array(3) {
      ["development_mode"]=>
      string(1) "1"
      ["published"]=>
      bool(false)
      ["html_source"]=>
      string(1600) "<html> ... </html>"
    }
    ["files":protected]=>
    array(0) {
    }
    ["eTag":protected]=>
    NULL
    ["graphVersion":protected]=>
    string(4) "v2.7"
  }
  ["thrownException":protected]=>
  NULL
}

Response using Live Server (fails):

object(Facebook\FacebookResponse)#107 (6) {
  ["httpStatusCode":protected]=>
  int(200)
  ["headers":protected]=>
  array(13) {
    ["Access-Control-Allow-Origin"]=>
    string(1) "*"
    ["Pragma"]=>
    string(8) "no-cache"
    ["Cache-Control"]=>
    string(44) "private, no-cache, no-store, must-revalidate"
    ["facebook-api-version"]=>
    string(4) "v2.7"
    ["Expires"]=>
    string(29) "Sat, 01 Jan 2000 00:00:00 GMT"
    ["Content-Type"]=>
    string(31) "application/json; charset=UTF-8"
    ["x-fb-trace-id"]=>
    string(11) "{different}"
    ["x-fb-rev"]=>
    string(7) "{different}"
    ["Vary"]=>
    string(15) "Accept-Encoding"
    ["X-FB-Debug"]=>
    string(88) "{different}"
    ["Date"]=>
    string(29) "Wed, 19 Oct 2016 16:02:08 GMT"
    ["Connection"]=>
    string(10) "keep-alive"
    ["Content-Length"]=>
    string(2) "24"
  }
  ["body":protected]=>
  string(24) "{"id":"{different}"}"
  ["decodedBody":protected]=>
  array(1) {
    ["id"]=>
    string(15) "{different}"
  }
  ["request":protected]=>
  object(Facebook\FacebookRequest)#106 (9) {
    ["app":protected]=>
    object(Facebook\FacebookApp)#126 (2) {
      ["id":protected]=>
      string(16) "{app_id}"
      ["secret":protected]=>
      string(32) "{app_secret}"
    }
    ["accessToken":protected]=>
    string(164) "{access_token}"
    ["method":protected]=>
    string(4) "POST"
    ["endpoint":protected]=>
    string(29) "/{some_endpoint_id}/instant_articles"
    ["headers":protected]=>
    array(1) {
      ["Content-Type"]=>
      string(33) "application/x-www-form-urlencoded"
    }
    ["params":protected]=>
    array(3) {
      ["development_mode"]=>
      string(1) "1"
      ["published"]=>
      bool(false)
      ["html_source"]=>
      string(1639) "<html> ... </html>"
    }
    ["files":protected]=>
    array(0) {
    }
    ["eTag":protected]=>
    NULL
    ["graphVersion":protected]=>
    string(4) "v2.7"
  }
  ["thrownException":protected]=>
  NULL
}

Solution

  • Thanks to CBroe's suggestion in his comment I was able to discover the cause of the problem. After making a request to get the article import status, I found this error message in the response:

    ["body":protected]=>
      string(439) "{"errors":[{"level":"ERROR","message":"Unclaimed URL: The URL http:\/\/www.example.com\/my-article-url\/ has not been claimed for Instant Articles. Please check to make sure you have a URL registered for your page. For more information refer to URLs in the Publishing Articles section of the Instant Articles documentation."}],"status":"FAILED","id":"{some_id}"}"
    

    I then realized that, in my function that builds the Instant Article markup, I was doing a str_replace on the markup so that my local testing domain name would be replaced with the correct "claimed" domain name. Since we had deployed the code to a new domain, this replacement was not happening, and Facebook saw an incorrect "unclaimed" domain in the markup.

    By adding the new domain name to the array of names to replace, I was able to send the markup to Instant Articles with the "claimed" domain. My article was successfully created!

    Thanks so much CBroe, I was losing my mind.