...
...

...

Inheritance: extends Element, implements Facebook\InstantArticles\Elements\Container, implements Facebook\InstantArticles\Elements\InstantArticleInterface
    public function testInvalidSelectorToString()
    {
        $json = <<<'JSON'
{
    "class": "SocialEmbedRule",
    "selector" : "figure.op-social",
    "properties" : {
        "socialembed.url" : {
            "type" : "string",
            "selector" : "iframe",
            "attribute": "src"
        },
        "socialembed.iframe" : {
            "type" : "children",
            "selector" : "iframe"
        }
    }
}
JSON;
        $properties = json_decode($json, true);
        $instant_article = InstantArticle::create();
        $document = new \DOMDocument();
        $node = $document->createElement('figcaption');
        $rule = SocialEmbedRule::createFrom($properties);
        $warning = new InvalidSelector('field a and b', $instant_article, $node, $rule);
        $result = $warning->__toString();
        $expected = 'Invalid selector for fields (field a and b). ' . 'The node being transformed was <figcaption> in the context of' . ' InstantArticle within the Rule SocialEmbedRule with these' . ' properties: { socialembed.url=StringGetter}';
        $this->assertEquals($expected, $result);
    }
 public function apply($transformer, $context_element, $node)
 {
     $h2 = H2::create();
     if (Type::is($context_element, array(Header::getClassName(), Caption::getClassName()))) {
         $context_element->withSubTitle($h2);
     } elseif (Type::is($context_element, InstantArticle::getClassName())) {
         $context_element->addChild($h2);
     }
     if ($this->getProperty(Caption::POSITION_BELOW, $node)) {
         $h2->withPosition(Caption::POSITION_BELOW);
     }
     if ($this->getProperty(Caption::POSITION_CENTER, $node)) {
         $h2->withPosition(Caption::POSITION_CENTER);
     }
     if ($this->getProperty(Caption::POSITION_ABOVE, $node)) {
         $h2->withPosition(Caption::POSITION_ABOVE);
     }
     if ($this->getProperty(Caption::ALIGN_LEFT, $node)) {
         $h2->withTextAlignment(Caption::ALIGN_LEFT);
     }
     if ($this->getProperty(Caption::ALIGN_CENTER, $node)) {
         $h2->withTextAlignment(Caption::ALIGN_CENTER);
     }
     if ($this->getProperty(Caption::ALIGN_RIGHT, $node)) {
         $h2->withTextAlignment(Caption::ALIGN_RIGHT);
     }
     $transformer->transform($h2, $node);
     return $context_element;
 }
 /**
  * This method navigates thru the tree structure and validates the article content.
  *
  * @param InstantArticle $article The article that will be checked.
  * @return array of string with the warnings raised during the check.
  */
 public static function check($article)
 {
     Type::enforce($article, InstantArticle::getClassName());
     $warnings = array();
     self::getReport(array($article), $warnings);
     return $warnings;
 }
 public function testInstantArticle()
 {
     $article = InstantArticle::create()->withCanonicalUrl('')->withHeader(Header::create())->addChild(Paragraph::create()->appendText('Some text to be within a paragraph for testing.'))->addChild(Paragraph::create())->addChild(Paragraph::create()->appendText(" \n \t "))->addChild(Image::create())->addChild(Image::create()->withURL(''))->addChild(SlideShow::create()->addImage(Image::create()->withURL('https://jpeg.org/images/jpegls-home.jpg'))->addImage(Image::create()))->addChild(Ad::create()->withSource('http://foo.com'))->addChild(Paragraph::create()->appendText('Other text to be within a second paragraph for testing.'))->addChild(Analytics::create())->withFooter(Footer::create());
     $expected = '<!doctype html>' . '<html>' . '<head>' . '<link rel="canonical" href=""/>' . '<meta charset="utf-8"/>' . '<meta property="op:generator" content="facebook-instant-articles-sdk-php"/>' . '<meta property="op:generator:version" content="' . InstantArticle::CURRENT_VERSION . '"/>' . '<meta property="op:markup_version" content="v1.0"/>' . '</head>' . '<body>' . '<article>' . '<p>Some text to be within a paragraph for testing.</p>' . '<figure class="op-slideshow">' . '<figure>' . '<img src="https://jpeg.org/images/jpegls-home.jpg"/>' . '</figure>' . '</figure>' . '<figure class="op-ad">' . '<iframe src="http://foo.com"></iframe>' . '</figure>' . '<p>Other text to be within a second paragraph for testing.</p>' . '</article>' . '</body>' . '</html>';
     $result = $article->render();
     $this->assertEquals($expected, $result);
     $warnings = InstantArticleValidator::check($article);
     $this->assertEquals(9, count($warnings));
 }
 public function apply($transformer, $context, $node)
 {
     $interactive = Interactive::create();
     if (Type::is($context, InstantArticle::getClassName())) {
         $instant_article = $context;
     } elseif ($transformer->getInstantArticle()) {
         $instant_article = $transformer->getInstantArticle();
         $context->disableEmptyValidation();
         $context = Paragraph::create();
         $context->disableEmptyValidation();
     } else {
         $transformer->addWarning(new NoRootInstantArticleFoundWarning(null, $node));
         return $context;
     }
     // Builds the interactive
     $iframe = $this->getProperty(self::PROPERTY_IFRAME, $node);
     $url = $this->getProperty(self::PROPERTY_URL, $node);
     if ($iframe) {
         $interactive->withHTML($iframe);
     }
     if ($url) {
         $interactive->withSource($url);
     }
     if ($iframe || $url) {
         $instant_article->addChild($interactive);
         if ($instant_article !== $context) {
             $instant_article->addChild($context);
         }
     } else {
         $transformer->addWarning(new InvalidSelector(self::PROPERTY_IFRAME, $instant_article, $node, $this));
     }
     if ($this->getProperty(self::PROPERTY_WIDTH_COLUMN_WIDTH, $node)) {
         $interactive->withMargin(Interactive::COLUMN_WIDTH);
     } else {
         $interactive->withMargin(Interactive::NO_MARGIN);
     }
     $width = $this->getProperty(self::PROPERTY_WIDTH, $node);
     if ($width) {
         $interactive->withWidth($width);
     }
     $height = $this->getProperty(self::PROPERTY_HEIGHT, $node);
     if ($height) {
         $interactive->withHeight($height);
     }
     $suppress_warnings = $transformer->suppress_warnings;
     $transformer->suppress_warnings = true;
     $transformer->transform($interactive, $node);
     $transformer->suppress_warnings = $suppress_warnings;
     return $context;
 }
    public function testTransformPullquote()
    {
        $transformer_rules = <<<'JSON'
{
    "rules" : [
        {
            "class": "TextNodeRule"
        },
        {
            "class": "ItalicRule",
            "selector": "em"
        },
        {
            "class": "ParagraphRule",
            "selector": "p"
        },
        {
            "class": "PassThroughRule",
            "selector": "div.field-quote > p"
        },
        {
            "class": "PassThroughRule",
            "selector" : "div.field-quote"
        },
        {
            "class" : "PullquoteRule",
            "selector" : "blockquote.pull-quote"
        },
        {
            "class" : "PullquoteCiteRule",
            "selector" : "div.field-quote-author"
        }
    ]
}
JSON;
        $html = '<blockquote class="pull-quote">' . '<div class="field-quote">' . '<p>Here is a fancy pull quote for the <em>world</em> to see it all.</p>' . '</div>' . '<div class="field-quote-author">Matthew Oliveira</div>' . '</blockquote>';
        $expected = "<aside>Here is a fancy pull quote for the <i>world</i> to see it all." . "<cite>Matthew Oliveira</cite>" . "</aside>\n";
        $instant_article = InstantArticle::create();
        $transformer = new Transformer();
        $transformer->loadRules($transformer_rules);
        $document = new \DOMDocument();
        $document->loadXML($html);
        $transformer->transform($instant_article, $document);
        $pullquote = $instant_article->getChildren()[0];
        $result = $pullquote->render('', true) . "\n";
        $this->assertEquals($expected, $result);
    }
 /**
  * @param string|DOMDocument $document The document html of an Instant Article
  *
  * @return InstantArticle filled element that was parsed from the DOMDocument parameter
  */
 public function parse($content)
 {
     if (Type::is($content, Type::STRING)) {
         libxml_use_internal_errors(true);
         $document = new \DOMDocument();
         $document->loadHTML($content);
         libxml_use_internal_errors(false);
     } else {
         $document = $content;
     }
     $json_file = file_get_contents(__DIR__ . '/instant-articles-rules.json');
     $instant_article = InstantArticle::create();
     $transformer = new Transformer();
     $transformer->loadRules($json_file);
     $transformer->transform($instant_article, $document);
     return $instant_article;
 }
 public function apply($transformer, $context, $node)
 {
     $image = Image::create();
     if (Type::is($context, InstantArticle::getClassName())) {
         $instant_article = $context;
     } elseif ($transformer->getInstantArticle()) {
         $instant_article = $transformer->getInstantArticle();
         $context->disableEmptyValidation();
         $context = Paragraph::create();
         $context->disableEmptyValidation();
     } else {
         $transformer->addWarning(new NoRootInstantArticleFoundWarning(null, $node));
         return $context;
     }
     // Builds the image
     $url = $this->getProperty(self::PROPERTY_IMAGE_URL, $node);
     if ($url) {
         $image->withURL($url);
         $instant_article->addChild($image);
         if ($instant_article !== $context) {
             $instant_article->addChild($context);
         }
     } else {
         $transformer->addWarning(new InvalidSelector(self::PROPERTY_IMAGE_URL, $instant_article, $node, $this));
     }
     if ($this->getProperty(Image::ASPECT_FIT, $node)) {
         $image->withPresentation(Image::ASPECT_FIT);
     } elseif ($this->getProperty(Image::ASPECT_FIT_ONLY, $node)) {
         $image->withPresentation(Image::ASPECT_FIT_ONLY);
     } elseif ($this->getProperty(Image::FULLSCREEN, $node)) {
         $image->withPresentation(Image::FULLSCREEN);
     } elseif ($this->getProperty(Image::NON_INTERACTIVE, $node)) {
         $image->withPresentation(Image::NON_INTERACTIVE);
     }
     if ($this->getProperty(self::PROPERTY_LIKE, $node)) {
         $image->enableLike();
     }
     if ($this->getProperty(self::PROPERTY_COMMENTS, $node)) {
         $image->enableComments();
     }
     $suppress_warnings = $transformer->suppress_warnings;
     $transformer->suppress_warnings = true;
     $transformer->transform($image, $node);
     $transformer->suppress_warnings = $suppress_warnings;
     return $context;
 }
 public function testSelfTransformerContent()
 {
     $json_file = file_get_contents(__DIR__ . '/simple-rules.json');
     $instant_article = InstantArticle::create();
     $transformer = new Transformer();
     $transformer->loadRules($json_file);
     $html_file = file_get_contents(__DIR__ . '/simple.html');
     libxml_use_internal_errors(true);
     $document = new \DOMDocument();
     $document->loadHTML($html_file);
     libxml_use_internal_errors(false);
     $transformer->transform($instant_article, $document);
     $instant_article->addMetaProperty('op:generator:version', '1.0.0');
     $instant_article->addMetaProperty('op:generator:transformer:version', '1.0.0');
     $result = $instant_article->render('', true) . "\n";
     $expected = file_get_contents(__DIR__ . '/simple-ia.html');
     //var_dump($result);
     // print_r($warnings);
     $this->assertEquals($expected, $result);
 }
 public function testTransformerCustomHTML()
 {
     $json_file = file_get_contents(__DIR__ . '/custom-html-rules.json');
     $instant_article = InstantArticle::create();
     $transformer = new Transformer();
     $transformer->loadRules($json_file);
     $html_file = file_get_contents(__DIR__ . '/custom.html');
     libxml_use_internal_errors(true);
     $document = new \DOMDocument();
     $document->loadHTML($html_file);
     libxml_use_internal_errors(false);
     $instant_article->withCanonicalURL('http://localhost/article')->withHeader(Header::create()->withTitle('Peace on <b>earth</b>')->addAuthor(Author::create()->withName('bill'))->withPublishTime(Time::create(Time::PUBLISHED)->withDatetime(\DateTime::createFromFormat('j-M-Y G:i:s', '12-Apr-2016 19:46:51'))));
     $transformer->transform($instant_article, $document);
     $instant_article->addMetaProperty('op:generator:version', '1.0.0');
     $instant_article->addMetaProperty('op:generator:transformer:version', '1.0.0');
     $result = $instant_article->render('', true) . "\n";
     $expected = file_get_contents(__DIR__ . '/custom-html-ia.xml');
     $this->assertEquals($expected, $result);
     // there must be 3 warnings related to <img> inside <li> that is not supported by IA
     $this->assertEquals(3, count($transformer->getWarnings()));
 }
 public function getContextClass()
 {
     return InstantArticle::getClassName();
 }
 public function testSelfTransformerNonUTF8Content()
 {
     $json_file = file_get_contents('src/Facebook/InstantArticles/Parser/instant-articles-rules.json');
     $instant_article = InstantArticle::create();
     $transformer = new Transformer();
     $transformer->loadRules($json_file);
     $html_file = file_get_contents(__DIR__ . '/instant-article-example-nonutf8.html');
     $transformer->transformString($instant_article, $html_file, 'euc-jp');
     $instant_article->withCanonicalURL('http://foo.com/article.html');
     $instant_article->addMetaProperty('op:generator:version', '1.0.0');
     $instant_article->addMetaProperty('op:generator:transformer:version', '1.0.0');
     $result = $instant_article->render('', true) . "\n";
     // some fragments are written as html entities even after transformed so
     // noralize all strings to html entities and compare them.
     $this->assertEquals(mb_convert_encoding($html_file, 'HTML-ENTITIES', 'euc-jp'), mb_convert_encoding($result, 'HTML-ENTITIES', 'utf-8'));
 }
 public function testIsNotInSetException()
 {
     $this->setExpectedException('InvalidArgumentException');
     Type::enforce(Caption::create(), [InstantArticle::getClassName(), Video::getClassName(), Image::getClassName()]);
 }
 protected function setUp()
 {
     $this->facebook = $this->getMockBuilder('Facebook\\Facebook')->disableOriginalConstructor()->getMock();
     $this->client = new Client($this->facebook, "PAGE_ID", false);
     $this->article = InstantArticle::create()->addChild(Paragraph::create()->appendText('Test'));
 }
 /**
  * Render post
  *
  * @since 0.1
  * @return InstantArticle
  */
 public function to_instant_article()
 {
     /**
      * Fires before the instant article is rendered.
      *
      * @since 0.1
      * @param Instant_Article_Post  $instant_article_post  The instant article post.
      */
     do_action('instant_articles_before_transform_post', $this);
     // Get time zone configured in WordPress. Default to UTC if no time zone configured.
     $date_time_zone = get_option('timezone_string') ? new DateTimeZone(get_option('timezone_string')) : new DateTimeZone('UTC');
     // Initialize transformer
     $file_path = plugin_dir_path(__FILE__) . 'rules-configuration.json';
     $configuration = file_get_contents($file_path);
     $transformer = new Transformer();
     $this->transformer = $transformer;
     $transformer->loadRules($configuration);
     $transformer = apply_filters('instant_articles_transformer_rules_loaded', $transformer);
     $settings_publishing = Instant_Articles_Option_Publishing::get_option_decoded();
     if (isset($settings_publishing['custom_rules_enabled']) && !empty($settings_publishing['custom_rules_enabled']) && isset($settings_publishing['custom_rules']) && !empty($settings_publishing['custom_rules'])) {
         $transformer->loadRules($settings_publishing['custom_rules']);
     }
     $transformer = apply_filters('instant_articles_transformer_custom_rules_loaded', $transformer);
     $blog_charset = get_option('blog_charset');
     $header = Header::create()->withPublishTime(Time::create(Time::PUBLISHED)->withDatetime(new DateTime($this->_post->post_date, $date_time_zone)))->withModifyTime(Time::create(Time::MODIFIED)->withDatetime(new DateTime($this->_post->post_modified, $date_time_zone)));
     $title = $this->get_the_title();
     if ($title) {
         $document = new DOMDocument();
         libxml_use_internal_errors(true);
         $document->loadHTML('<?xml encoding="' . $blog_charset . '" ?><h1>' . $title . '</h1>');
         libxml_use_internal_errors(false);
         $transformer->transform($header, $document);
     }
     if ($this->has_subtitle()) {
         $header->withSubTitle($this->get_the_subtitle());
     }
     $authors = $this->get_the_authors();
     foreach ($authors as $author) {
         $author_obj = Author::create();
         if ($author->display_name) {
             $author_obj->withName($author->display_name);
         }
         if ($author->bio) {
             $author_obj->withDescription($author->bio);
         }
         if ($author->user_url) {
             $author_obj->withURL($author->user_url);
         }
         $header->addAuthor($author_obj);
     }
     $kicker = $this->get_the_kicker();
     if ($kicker) {
         $header->withKicker($kicker);
     }
     $cover = $this->get_cover_media();
     if ($cover->getUrl()) {
         $header->withCover($cover);
     }
     $this->instant_article = InstantArticle::create()->withCanonicalUrl($this->get_canonical_url())->withHeader($header)->addMetaProperty('op:generator:application', 'facebook-instant-articles-wp')->addMetaProperty('op:generator:application:version', IA_PLUGIN_VERSION);
     $settings_style = Instant_Articles_Option_Styles::get_option_decoded();
     if (isset($settings_style['article_style']) && !empty($settings_style['article_style'])) {
         $this->instant_article->withStyle($settings_style['article_style']);
     } else {
         $this->instant_article->withStyle('default');
     }
     $libxml_previous_state = libxml_use_internal_errors(true);
     $document = new DOMDocument('1.0', get_option('blog_charset'));
     $content = $this->get_the_content();
     // DOMDocument isn’t handling encodings too well, so let’s help it a little.
     if (function_exists('mb_convert_encoding')) {
         $content = mb_convert_encoding($content, 'HTML-ENTITIES', get_option('blog_charset'));
     } else {
         $content = htmlspecialchars_decode(utf8_decode(htmlentities($content, ENT_COMPAT, 'utf-8', false)));
     }
     $result = $document->loadHTML('<!doctype html><html><body>' . $content . '</body></html>');
     // We need to make sure that scripts use absolute URLs and not relative URLs.
     $scripts = $document->getElementsByTagName('script');
     if (!empty($scripts)) {
         foreach ($scripts as $script) {
             $src = $script->getAttribute('src');
             $explode_src = parse_url($src);
             if (is_array($explode_src) && empty($explode_src['scheme']) && !empty($explode_src['host']) && !empty($explode_src['path'])) {
                 $src = 'https://' . $explode_src['host'] . $explode_src['path'];
             }
             $script->setAttribute('src', $src);
         }
     }
     libxml_clear_errors();
     libxml_use_internal_errors($libxml_previous_state);
     $document = apply_filters('instant_articles_parsed_document', $document);
     if ($result) {
         $transformer->transform($this->instant_article, $document);
     }
     $this->add_ads_from_settings();
     $this->add_analytics_from_settings();
     $this->instant_article = apply_filters('instant_articles_transformed_element', $this->instant_article);
     /**
      * Fires after the instant article is rendered.
      *
      * @since 0.1
      * @param Instant_Article_Post  $instant_article_post  The instant article post.
      */
     do_action('instant_articles_after_transform_post', $this);
     return $this->instant_article;
 }
 /**
  * @param InstantArticle $context
  * @param \DOMNode $node
  *
  * @return mixed
  */
 public function transform($context, $node)
 {
     if (Type::is($context, InstantArticle::getClassName())) {
         $context->addMetaProperty('op:generator:transformer', 'facebook-instant-articles-sdk-php');
         $context->addMetaProperty('op:generator:transformer:version', InstantArticle::CURRENT_VERSION);
         $this->instantArticle = $context;
     }
     $log = \Logger::getLogger('facebook-instantarticles-transformer');
     if (!$node) {
         $e = new \Exception();
         $log->error('Transformer::transform($context, $node) requires $node' . ' to be a valid one. Check on the stacktrace if this is ' . 'some nested transform operation and fix the selector.', $e->getTraceAsString());
     }
     $current_context = $context;
     if ($node->hasChildNodes()) {
         foreach ($node->childNodes as $child) {
             if (self::isProcessed($child)) {
                 continue;
             }
             $matched = false;
             $log->debug("===========================");
             $log->debug($child->ownerDocument->saveHtml($child));
             // Get all classes and interfaces this context extends/implements
             $contextClassNames = self::getAllClassTypes($context->getClassName());
             // Look for rules applying to any of them as context
             $matchingContextRules = [];
             foreach ($contextClassNames as $contextClassName) {
                 if (isset($this->rules[$contextClassName])) {
                     // Use array union (+) instead of merge to preserve
                     // indexes (as they represent the order of insertion)
                     $matchingContextRules = $matchingContextRules + $this->rules[$contextClassName];
                 }
             }
             // Sort by insertion order
             ksort($matchingContextRules);
             // Process in reverse order
             $matchingContextRules = array_reverse($matchingContextRules);
             foreach ($matchingContextRules as $rule) {
                 // We know context was matched, now check if it matches the node
                 if ($rule->matchesNode($child)) {
                     $current_context = $rule->apply($this, $current_context, $child);
                     $matched = true;
                     // Just a single rule for each node, so move on
                     break;
                 }
             }
             if (!$matched && !($child->nodeName === '#text' && trim($child->textContent) === '') && !($child->nodeName === '#comment') && !($child->nodeName === 'html' && Type::is($child, 'DOMDocumentType')) && !($child->nodeName === 'xml' && Type::is($child, 'DOMProcessingInstruction')) && !$this->suppress_warnings) {
                 $tag_content = $child->ownerDocument->saveXML($child);
                 $tag_trimmed = trim($tag_content);
                 if (!empty($tag_trimmed)) {
                     $log->debug('context class: ' . get_class($context));
                     $log->debug('node name: ' . $child->nodeName);
                     $log->debug("CONTENT NOT MATCHED: \n" . $tag_content);
                 } else {
                     $log->debug('empty content ignored');
                 }
                 $this->addWarning(new UnrecognizedElement($current_context, $child));
             }
         }
     }
     return $context;
 }
 /**
  * Render post
  *
  * @since 0.1
  * @return InstantArticle
  */
 public function to_instant_article()
 {
     /**
      * Fires before the instant article is rendered.
      *
      * @since 0.1
      * @param Instant_Article_Post  $instant_article_post  The instant article post.
      */
     do_action('instant_articles_before_transform_post', $this);
     // Get time zone configured in WordPress. Default to UTC if no time zone configured.
     $date_time_zone = get_option('timezone_string') ? new DateTimeZone(get_option('timezone_string')) : new DateTimeZone('UTC');
     // Initialize transformer
     $file_path = plugin_dir_path(__FILE__) . 'rules-configuration.json';
     $configuration = file_get_contents($file_path);
     $transformer = new Transformer();
     $this->transformer = $transformer;
     $transformer->loadRules($configuration);
     $transformer = apply_filters('instant_articles_transformer_rules_loaded', $transformer);
     $settings_publishing = Instant_Articles_Option_Publishing::get_option_decoded();
     if (isset($settings_publishing['custom_rules_enabled']) && !empty($settings_publishing['custom_rules_enabled']) && isset($settings_publishing['custom_rules']) && !empty($settings_publishing['custom_rules'])) {
         $transformer->loadRules($settings_publishing['custom_rules']);
     }
     $transformer = apply_filters('instant_articles_transformer_custom_rules_loaded', $transformer);
     $blog_charset = get_option('blog_charset');
     $header = Header::create()->withPublishTime(Time::create(Time::PUBLISHED)->withDatetime(new DateTime($this->_post->post_date, $date_time_zone)))->withModifyTime(Time::create(Time::MODIFIED)->withDatetime(new DateTime($this->_post->post_modified, $date_time_zone)));
     $title = $this->get_the_title();
     if ($title) {
         $document = new DOMDocument();
         libxml_use_internal_errors(true);
         $document->loadHTML('<?xml encoding="' . $blog_charset . '" ?><h1>' . $title . '</h1>');
         libxml_use_internal_errors(false);
         $transformer->transform($header, $document);
     }
     if ($this->has_subtitle()) {
         $header->withSubTitle($this->get_the_subtitle());
     }
     $authors = $this->get_the_authors();
     foreach ($authors as $author) {
         $author_obj = Author::create();
         if ($author->display_name) {
             $author_obj->withName($author->display_name);
         }
         if ($author->bio) {
             $author_obj->withDescription($author->bio);
         }
         if ($author->user_url) {
             $author_obj->withURL($author->user_url);
         }
         $header->addAuthor($author_obj);
     }
     $kicker = $this->get_the_kicker();
     if ($kicker) {
         $header->withKicker($kicker);
     }
     $cover = $this->get_cover_media();
     if ($cover->getUrl()) {
         $header->withCover($cover);
     }
     $this->instant_article = InstantArticle::create()->withCanonicalUrl($this->get_canonical_url())->withHeader($header)->addMetaProperty('op:generator:application', 'facebook-instant-articles-wp')->addMetaProperty('op:generator:application:version', IA_PLUGIN_VERSION);
     $settings_style = Instant_Articles_Option_Styles::get_option_decoded();
     if (isset($settings_style['article_style']) && !empty($settings_style['article_style'])) {
         $this->instant_article->withStyle($settings_style['article_style']);
     } else {
         $this->instant_article->withStyle('default');
     }
     $transformer->transformString($this->instant_article, $this->get_the_content(), get_option('blog_charset'));
     $this->add_ads_from_settings();
     $this->add_analytics_from_settings();
     $this->instant_article = apply_filters('instant_articles_transformed_element', $this->instant_article);
     /**
      * Fires after the instant article is rendered.
      *
      * @since 0.1
      * @param Instant_Article_Post  $instant_article_post  The instant article post.
      */
     do_action('instant_articles_after_transform_post', $this);
     return $this->instant_article;
 }