fb-instant-articles icon indicating copy to clipboard operation
fb-instant-articles copied to clipboard

Trying to setup a transformer rule

Open samichamoun opened this issue 9 years ago • 13 comments

Hi there,

I am embedding my own video player which is used as an iframe. The height attribute is being stripped from the video, so I am trying to setup a transformer rule to apply it.

{ "rules":[

{
     "class": "InteractiveRule",
     "selector": ".springboard-height",
     "properties" : {

       "interactive.height" : {     // Name of property
         "type" : "",
         "selector" : "",
         "attribute": ""
       }

     }
    }

]}

I'm not sure what the type/selector/attribute values should be for the properties. springboard-height is a class which is assigned to the video itself.

Any ideas?

samichamoun avatar May 11 '16 10:05 samichamoun

More information is required to help you out here but I'll try to give you some hints to maybe lead you in the right direction.

Somewhere in the original markup, the height should be specified. In the properties you specify where this height value can be found. The selector specifies which element inside the container matched by your initial selector ('.springboard-height') contains the value. The attribute specifies the attribute of this element which contains the value.

For example, if your original markup looks like this:

<iframe class="springboard-height" height="100" ...>...</iframe>

you would use a transformer rule like this:

{
     "class": "InteractiveRule",
     "selector": ".springboard-height",
     "properties": {
         "interactive.height": {
             "type": "int",
             "selector": "iframe",
             "attribute": "height"
         }
     }
}

Or if the original markup is

<div data-height="100" class="springboard-height">
    <iframe>...</iframe>
</div>

then use

{
     "class": "InteractiveRule",
     "selector": ".springboard-height",
     "properties": {
         "interactive.height": {
             "type": "int",
             "selector": ".springboard-height",
             "attribute": "data-height"
         },
         "interactive.iframe": {
            "type": "children",
            "selector": "iframe"
         }
     }
}

FewKinG avatar Jun 13 '16 15:06 FewKinG

Thanks for the reply.

This post was written a while back, so how about I give you a fresh code snippet:

<script src="//www.springboardplatform.com/js/overlay"></script><iframe id="crzy005_1635837" src="//cms.springboardplatform.com/embed_iframe/5365/video/1635837/crzy005/craziestsportsfights.com/10" width="600" height="400" frameborder="0" scrolling="no"></iframe>

Youtube also fails to automatically set the height/width:

<div class="embed"><iframe width="620" height="349" src="https://www.youtube.com/embed/5PdWH_F_twk?feature=oembed" frameborder="0" allowfullscreen></iframe></div>

Would you be able to help me with a simple generic custom transformer rule which would apply to all iframes, rather than needing to have a specific class attached?

{ "rules": [{ "class": "InteractiveRule", "selector": "iframe", "properties":{ "interactive.height"{ "type": "int", "selector": "iframe", "attribute": "height" } } ] }

Am I close?

samichamoun avatar Jun 14 '16 10:06 samichamoun

Yes I think so. Well, I experimented a little with your two examples. First of all: Your transformer rule won't match the youtube example video, because that is embedded in a div container which won't be matched by the iframe selector. You need a selector like //div[@class='embed' and iframe] to select divs with the embed class and an iframe child element.

I thus managed to get the transformer to transform the youtube iframe into an interactive element using this rule:

{
  "class": "InteractiveRule",
  "selector": "//div[@class='embed' and iframe]",
  "properties": { 
    "interactive.height": { 
      "type": "int", 
      "selector": "iframe", 
      "attribute": "height" 
    },
    "interactive.url": {
      "type": "string",
      "selector": "iframe",
      "attribute": "src"
    }
  }
}

It seems, the URL property is required per Facebook's documentation at https://developers.facebook.com/docs/instant-articles/reference/embeds However, although I can see the height value being properly inserted into the final IA markup, it seems to be ignored by Facebook in the special case of embedding a YouTube video. Seems that Facebook handles this differently and uses a fixed height (based on the video's aspect ratio I figure).

Your other case concerning the content from www.springboardplatform.com I managed to figure out by using this rule (note that this will match all iframes put into the articles content without wrapper elements):

{
  "class": "InteractiveRule",
  "selector": "iframe",
  "properties": { 
    "interactive.height": { 
      "type": "int", 
      "selector": "iframe", 
      "attribute": "height" 
    },
    "interactive.url": {
      "type": "string",
      "selector": "iframe",
      "attribute": "src"
    }
  }
}

In that case the height property is actually effective in the final converted article when I view it in Facebook's page manager.

FewKinG avatar Jun 14 '16 14:06 FewKinG

Hey mate thanks for your response. I must be doing something wrong because I haven't got this quite right yet.

Below is the custom transformer rule I've added:

{ "rules": [{ "class": "InteractiveRule", "selector": "//div[@class='interactive' and iframe]", "properties": { "interactive.height": { "type": "int", "selector": "iframe", "attribute": "height" }, "interactive.width": { "type": "int", "selector": "iframe", "attribute": "width" }, "interactive.url": { "type": "string", "selector": "iframe", "attribute": "src" } } }, { "class": "InteractiveRule", "selector": "//div[@class='embed' and iframe]", "properties": { "interactive.height": { "type": "int", "selector": "iframe", "attribute": "height" }, "interactive.width": { "type": "int", "selector": "iframe", "attribute": "width" }, "interactive.url": { "type": "string", "selector": "iframe", "attribute": "src" } } } ]}

Firstly in regards to youtube, it now appears I've got a height being set correctly, but for some reason the width value isn't being transferred. Am I setting the width incorrectly?

Secondly, I'm not having any luck with my springboard player and it may have something to do with the order of execution.

The original code I supplied for my springboard embedding: <script src="//www.springboardplatform.com/js/overlay"></script><iframe id="crzy005_1635837" src="//cms.springboardplatform.com/embed_iframe/5365/video/1635837/crzy005/craziestsportsfights.com/10" width="600" height="400" frameborder="0" scrolling="no"></iframe>

Now I make use of the "instant_articles_content" filter, to wrap a div around this, with the "interactive" class. My understanding is this automatically pulls the URL into the iframe, which it already does correctly.

I'm not sure whether the transformer rules run over the code BEFORE this filter is run? Either way I tried the same rule just applying to all iframes, but that didn't seem to work either.

Anything look obviously wrong?

samichamoun avatar Jun 14 '16 23:06 samichamoun

Well, your springboard example is definitely working for me the way you describe it. I put the script and iframe tag (iframe tag wrapped by a div.interactive) into the content using the instant_articles_content filter. This is done prior to transformer rule application. Then I used your interactive transformer rule and it properly converts into an Interactive element.

If you visit the edit post page of the post you are experimenting with and scroll down to the "Facebook Instant Articles" section, you will find if there were any errors or warnings during the transformation. Also there is a button "Toggle debug information". Can you use that and provide the source as well as the transformed markup (or the relevant parts of it) and any warnings or errors that may appear? Maybe your springboard embed code gets wrapped in another container that causes the transformer rules to ignore it or something? Always keep in mind, that transformer rules are context sensitive. So if the element you want to get transformed resides in another container, that may well make a difference.

Regarding setting the width of the elements: This is not possible the way you did it. Have a look at Facebook's documentation ( https://developers.facebook.com/docs/instant-articles/reference/embeds ), the width of the interactive element can only be influenced by the no-value attributes "no-margin" or "column-width" on the iframe. To achieve this you can add one of the two as property to your transformer rule like this (the workaround with the "exists" type to make it a valid property seems kind of ugly to me, but I found no other way to do it):

{ 
  "class": "InteractiveRule", 
  "selector": "//div[@class='interactive' and iframe]", 
  "properties": { 
    "interactive.height": { 
      "type": "int", 
      "selector": "iframe",
      "attribute": "height"
    }, 
    "interactive.url": { 
      "type": "string", 
      "selector": "iframe", 
      "attribute": "src" 
    },
    "column-width": {
      "type": "exists",
      "selector": "iframe"
    }
  }
}

FewKinG avatar Jun 15 '16 06:06 FewKinG

Hmmm, are you sure about the width? The documentation on the link you posted specifically says there is a "width" attribute, and despite setting the no-margin, I receive the error:

HTML Embeds Require Valid Width: For embeds with no inner HTML within iframe tags, we recommend specifying both width and height on the iframe element. Learn more in Embeds under Format Reference in the Instant Articles documentation.

As for the springboard, inside the post, I'm seeing the following warnings:

HTML Embeds Require Valid Width: For embeds with no inner HTML within iframe tags, we recommend specifying both width and height on the iframe element. Learn more in Embeds under Format Reference in the Instant Articles documentation.

No rules defined for

in the context of InstantArticle This is a text container that must not be empty nor contain only whitespace characters such as spaces, tabs, new lines or .Element content: Facebook\InstantArticles\Elements\Paragraph::__set_state(array( 'textChildren' => array ( ), )) This is a text container that must not be empty nor contain only whitespace characters such as spaces, tabs, new lines or .Element content: Facebook\InstantArticles\Elements\Paragraph::__set_state(array( 'textChildren' => array ( ), )) This is a text container that must not be empty nor contain only whitespace characters such as spaces, tabs, new lines or .Element content: Facebook\InstantArticles\Elements\Paragraph::__set_state(array( 'textChildren' => array ( ), ))

In the toggle information, the source markup snippet is as follows:

<div class="interactive"><iframe id="crzy005_1637175" src="http://cms.springboardplatform.com/embed_iframe/5365/video/1637175/crzy005/craziestsportsfights.com/10" width="600" height="400" frameborder="0" scrolling="no"></iframe></div>

Interestingly, it does appear that my code is now partially working, with the transformed markup showing (maybe I had a caching issue when I first tested this):

<figure class="op-interactive"> <iframe src="http://cms.springboardplatform.com/embed_iframe/5365/video/1637175/crzy005/craziestsportsfights.com/10" class="no-margin" height="400"></iframe> </figure>

Based on the output, using the no-margin class, what do I need to do to remove that width error? Are those other warnings of concern also?

samichamoun avatar Jun 16 '16 00:06 samichamoun

Well, the documentation is pretty clear regarding the width I think. And it does seem to strip the width attribute. I would guess, even if you'd set the width property in the transformer rule to some integer value, it won't end up in the final markup. But it's curious that Facebook complains in that case then. Wouldn't be the only case where I'm unsure about Facebook's behavior. Animated GIFs don't seem to work either even when following the documentation exactly. So, well, I can't answer that for sure :)

Concerning the other warnings: There seems to be an element in the original markup that is not recognized by the transformer (a div container it seems, you could check where it comes from and either add a transformer rule to handle it or ensure it's removed from the markup, depending on whether it has relevant content that has to be transferred to Facebook. Or just ignore the warning if you don't care about its content, the whole container will simply be ignored then).

And the other warnings seem to simply address some empty paragraphs (p-tags) in your original markup. Don't know how they got there, guess you'll have to check that yourself to get rid of the warnings.

FewKinG avatar Jun 16 '16 16:06 FewKinG

(FewKinG I know this is an Instant Articles issue, not facebook-instant-articles-wp issue, but it's the only place I see someone having the same trouble as me!)

@samichamoun did you ever find a way to keep width attributes from being stripped? The same thing is happening for me, with YouTube embeds only.

Rule

{
    "class": "InteractiveRule",
    "selector" : "//div[iframe]",
    "properties" : {
        "no-margin" : {
            "type" : "exists",
            "selector" : "iframe.no-margin"
        },
        "column-width" : {
            "type" : "exists",
            "selector" : "iframe.column-width"
        },
        "interactive.url" : {
            "type" : "string",
            "selector" : "iframe",
            "attribute": "src"
        },
        "interactive.height" : {
            "type" : "int",
            "selector" : "iframe",
            "attribute": "height"
        },
        "interactive.width" : {
            "type" : "int",
            "selector" : "iframe",
            "attribute": "width"
        },
        "interactive.iframe" : {
            "type" : "children",
            "selector" : "iframe"
        }
    }
}

input

<div>
    <iframe width="560" height="315" src="https://www.youtube.com/embed/U08O5HmPaQY" frameborder="0" allowfullscreen></iframe>
</div>

output

<figure class="op-interactive">
    <iframe src="https://www.youtube.com/embed/Gkx0apldko8" class="no-margin" height="315"></iframe>
</figure>

+ the width error you quoted.

Facebook post embeds are working fine:

input

<div>
    <iframe width="500">
        <div id="fb-root"></div>
        <script>(function(d, s, id) {var js, fjs = d.getElementsByTagName(s)[0];if (d.getElementById(id)) return;js = d.createElement(s); js.id = id;js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&amp;version=v2.5";fjs.parentNode.insertBefore(js, fjs);}(document, 'script', 'facebook-jssdk'));</script>
        <div class="fb-post" data-href="https://www.facebook.com/lenovo/posts/10154599077679635" data-width="500"></div>
    </iframe>
</div>

output

<figure class="op-interactive>
    <iframe width="500">
        <div id="fb-root"></div>
        <script>(function(d, s, id) {var js, fjs = d.getElementsByTagName(s)[0];if (d.getElementById(id)) return;js = d.createElement(s); js.id = id;js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&amp;version=v2.5";fjs.parentNode.insertBefore(js, fjs);}(document, 'script', 'facebook-jssdk'));</script>
        <div class="fb-post" data-href="https://www.facebook.com/lenovo/posts/10154599077679635" data-width="500"></div>
    </iframe>
</figure>

For the YouTube embeds I've even tried feeding the transformer the input

<figure class="op-interactive"><iframe width="560" height="315" src="https://www.youtube.com/embed/U08O5HmPaQY" frameborder="0" allowfullscreen></iframe></figure>

and using that same rule but with

{
    "class": "InteractiveRule",
    "selector" : "figure.op-interactive"
    ...

That outputs the same width-less YouTube embeds

olets avatar Feb 22 '17 19:02 olets

@olets it's been a while since I was looking at this, but I believe did get it working with the following transformers

`{ "class": "InteractiveRule", "selector": "//div[@class='interactive' and iframe]", "properties": { "interactive.height": { "type": "int", "selector": "iframe", "attribute": "height" }, "interactive.width": { "type": "int", "selector": "iframe", "attribute": "width" }, "interactive.url": { "type": "string", "selector": "iframe", "attribute": "src" } } },

{
    "class": "InteractiveRule",
    "selector" : "//div[@class='embed' and iframe]",
    "properties" : {
    	"interactive.url" : {
    		"type" : "string",
    		"selector" : "iframe",
    		"attribute": "src"
    	},
    	"interactive.width" : {
    		"type" : "int",
    		"selector" : "iframe",
    		"attribute": "width"
    	},
    	"interactive.height" : {
    		"type" : "int",
    		"selector" : "iframe",
    		"attribute": "height"
    	}
    }
}`

samichamoun avatar Feb 23 '17 23:02 samichamoun

is there like a generic transformer rule that can be placed on fb instant articles plugin for wordpress to cover all video conversions? :)

arnimation avatar Jul 23 '17 14:07 arnimation

Facebook hasn't documented this anywhere, but it turns out "interactive embeds" (InteractiveRule or figure.op-interactive) strip out the width attribute. For iframes that need a width attribute (like YouTube video embeds) use "social embed" (SocialEmbedRule or figure.op-social)

Hidden away in Facebook's examples * † is

<figure class="op-social">
    <iframe>
        <!-- Include social media embed code here -->
        <div id="fb-root"></div><script>(function(d, s, id) {  var js, fjs = d.getElementsByTagName(s)[0];  if (d.getElementById(id)) return;  js = d.createElement(s); js.id = id;  js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.3";  fjs.parentNode.insertBefore(js, fjs);}(document, 'script', 'facebook-jssdk'));</script><div class="fb-post" data-href="https://www.facebook.com/zuck/posts/10102531565693851" data-width="500"><div class="fb-xfbml-parse-ignore"><blockquote cite="https://www.facebook.com/zuck/posts/10102531565693851"><p>The force is strong with this one.</p>Posted by <a href="https://www.facebook.com/zuck">Mark Zuckerberg</a> on <a href="https://www.facebook.com/zuck/posts/10102531565693851">Thursday, December 17, 2015</a></blockquote></div></div>
    </iframe>
</figure>

I had success using the SocialEmbedRule for YouTube. My rule looks like this (replace YOURSELECTOR with your selector)

{
    "class": "SocialEmbedRule",
    "selector" : "YOURSELECTOR",
    "properties" : {
        "socialembed.url" : {
            "type" : "string",
            "selector" : "iframe",
            "attribute": "src"
        },
        "socialembed.height" : {
            "type" : "int",
            "selector" : "iframe",
            "attribute": "height"
        },
        "socialembed.width" : {
            "type" : "int",
            "selector" : "iframe",
            "attribute": "width"
        },
        "socialembed.iframe" : {
            "type" : "children",
            "selector" : "iframe"
        },
        "socialembed.caption" : {
            "type" : "element",
            "selector" : "figcaption"
        }
    }
}

* Search for op-social on https://developers.facebook.com/docs/instant-articles/example-articles#example-markup

† Note that I actually didn't have success embedding Facebook posts as in this official sample html. The javascript seems to be messing up the transformer.

olets avatar Aug 02 '17 13:08 olets

hello, if i have a code like this:

<div class="ntv-video"> <div without class, only size> <iframe src="xyz></iframe> </div> </div>

What transform rules i should use?

loops9 avatar Nov 03 '17 09:11 loops9

@loops9 probably interactive rule or social rule. This issue's first response should get you started. Generally speaking you'll have more luck asking support questions on stackoverflow

olets avatar Nov 14 '17 13:11 olets

This issue has been marked stale because it has been open for 30 days with no activity. If there is no activity within 7 days, it will be closed. This is an automation to keep issues manageable and actionable and is not a comment on the quality of this issue nor on the work done so far. Closed issues are still valuable to the project and are available to be searched.

github-actions[bot] avatar Oct 16 '22 03:10 github-actions[bot]