CMS Integration

This SDK was purpose-built for CMS integrations to facilitate developers in publishing content from their system as Instant Articles on Facebook. In order to accommodate a wide variety of needs from different systems and environments, it's been made highly configurable and modularized into different components, which when used in unison, make for quite a powerful and invaluable toolset.

This guide uses examples to demonstrate different areas for integrating with a basic CMS. Note that the integration with WordPress — via the Instant Articles for WP plugin — makes use of the same concepts described here so it can be used as additional reference for context.

Publishing Content to Facebook

To start off, let's assume content from your CMS is already a fully formed article and valid Instant Article markup. In this sceanrio, the Client would be the component of the SDK you would need in order to manage your articles in Facebook. For example, sending and removing an article can be done rather simply with the following:

use Facebook\InstantArticles\Client\Client;

// Instantiate an API client
$ia_client = Client::create(
    'APP_ID',
    'APP_SECRET',
    'ACCESS_TOKEN',
    'PAGE_ID'
);

// Push the article to your Facebook Page
$ia_client->importArticle($my_article);

// Unpublish an article from your Facebook Page
$ia_client->removeArticle($canonical_url);

In reality, Client depends on the Elements component for publishing content to Facebook — its importArticle() method only accepts an InstantArticle object — which ensures that only valid markup is sent to Facebook. More information about generating a structured Instant Article is detailed below.

Converting Content to an Instant Article

More likely than not, content from your CMS isn't already formatted in Instant Articles markup. Plus, it wouldn't be realistic to expect you to maintain multiple versions of the same content with differing markup. The Transformer aims to remove this burden by converting (or "transforming") any HTML source markup into compliant Instant Article markup. It is a powerful and versitile component of this SDK.

The Transformer works by following a set of rules which maps input markup to known Instant Article elements and leverages the Elements component to programmatically generate the article structure. Effectively, it converts HTML source markup into Instant Article markup.

Depending on your setup, you may want to leverage the Elements component directly and avoid any transformation to your source content. In this case, you can use the Elements component on it's own to build articles programmatically yourself since it has no dependency on the Transformer component.

The following code shows how rules are loaded into the Transformer and converted into a structured InstantArticle element:

use Facebook\InstantArticles\Transformer\Transformer;
use Facebook\InstantArticles\Elements\InstantArticle;

// Create a transformer object
$transformer = new Transformer();

// Load the rules from a file
$rules = file_get_contents("my_rules.json", true);

// Configure the transformer with the rules
$transformer->loadRules($rules);

// Load the HTML source markup from a file and 
$html_file = file_get_contents("simple.html", true);
$document = new \DOMDocument();
$document->loadHTML($html_file);

// Instantiate an InstantArticle object
$instant_article = InstantArticle::create();

// Invoke transformer on the HTML document
$transformer->transform($instant_article, $document);

From the code above, $instant_article would contain a structured InstantArticle element. To render the Instant Article markup or to view any errors from the transformation process:

// Render the InstantArticle markup format
$result = $instant_article->render();

// Get errors from transformer
$warnings = $transformer->getWarnings();

Creating an Instant Article programmatically

It is quite common that the information needed to generate an Instant Article will not necessarily already be a single, fully-formed HTML document in your system. The modular nature of this SDK allows you to source information from different places and build some parts of the InstantArticle structure programmatically while other parts from transformed HTML markup.

The Elements component exists to allow programmatic generation of a structured Instant Article without having to know the details of its rendered form or specific requirements in hierarchy and content. As a bonus, it provides warnings for invalid structures allowing you to more readily detect problems in your Instant Article markup before they become errors during the ingestion phase when publishing into Facebook. The Transformer makes use of this component.

For example, you could create the body of your article with the transformation process from above, but still generate the footer of your article manually:

// Instantiate an InstantArticle object
$instant_article = InstantArticle::create();

// Invoke transformer only on the body content of an HTML document
$transformer->transform($instant_article, $document_body);

// Add the Footer element to the InstantArticle object
$instant_article
  ->withFooter(
    Footer::create()
      ->withCredits('Some plaintext credits.')
    );

Creating the Header of an Article

More often than not, an article or post from your blog is made up of data from several sources within your database. The body of the article may very well be a single, retrievable string of HTML, but the title, author and other metadata such as the created datetime and modified datetime need to be retrieved individually.

The Header of an Instant Article is often built this way and the following example shows how to go about building it. Note the additional Elements required:

use Facebook\InstantArticles\Elements\Header;
use Facebook\InstantArticles\Elements\Time;
use Facebook\InstantArticles\Elements\Author;
use Facebook\InstantArticles\Elements\Image;

// $post is the object containing information from a blog post

$header =
  Header::create()
    ->withPublishTime(
      Time::create(Time::PUBLISHED)
        ->withDatetime(
          new DateTime($post->_post->post_date, $date_time_zone)
        )
    )
    ->withModifyTime(
      Time::create(Time::MODIFIED)
        ->withDatetime(
          new DateTime($post->_post->post_modified, $date_time_zone)
        )
    );

$title = $post->get_the_title();

if ($title) {
  $document = DOMDocument::loadHTML('<h1>'.$title.'</h1>');
  $transformer->transform($header, $document);
}

$authors = $post->get_the_authors();
foreach ($authors as $author) {
  $author_element = Author::create();

  if ($author->display_name) {
    $author_element->withName($author->display_name);
  }

  $header->addAuthor($author_element);
}

$header->withKicker($post->get_the_kicker());

$cover = $post->get_the_featured_image();
$image = Image::create()
  ->withURL($cover['src']);
$header->withCover($image);

From the code above, $header would contain the complete Header element which could be attached to the root InstantArticle element during the creation of your complete Instant Article structure.

Complete Example

The following is a simple but complete, end-to-end example demonstrating how to make full use of this SDK to integrate with Instant Articles:

// Instantiate an emptyInstant Article
$instant_article = InstantArticle::create();

// Load the rules content file
$rules = file_get_contents("transformer-rules.json", true);

// Create the transformer and loads the rules
$transformer = new Transformer();
$transformer->loadRules($rules);

// Load a full post in HTML form
$post_html = file_get_contents("full_post.html", true);

// Parse HTML into a DOM structure (ignore errors during parsing)
libxml_use_internal_errors(true);
$document = new \DOMDocument();
$document->loadHTML($post_html);
libxml_use_internal_errors(false);

// Invoke transformer on the DOM structure
$transformer->transform($instant_article, $document);

// Get errors from transformer
$warnings = $transformer->getWarnings();

// Instantiate an API client
$client = Client::create(
    'APP_ID'
    'APP_SECRET',
    'ACCESS_TOKEN',
    'PAGE_ID'
);

// Push the article
try {
    $client->importArticle($instant_article, $take_live);
} catch (Exception $e) {
    echo 'Could not import the article: '.$e->getMessage();
}