Many publishers use story cards for onward journeys. Here is an example from the Guardian:

Some of our more effective ways for our users to discover more on our site is through story cards like these, which we can't have in the initial payload.
Our idea is to have a component that takes a json, and renders a set number of story cards.
<amp-story-cards
number=3
src="path/to/related-content.json">
</amp-story-cards>
This component would take a json something like:
[
{
"img": "path/to/img.png",
"title": "I am a title",
"standfirst": "something witty"
}
]
We are open to adding more options here depending on what other people want, but I think keeping it restrictive in the beginning is a good thing.
Each story-card will have a predetermined height/width ratio based on viewport width.
Only once a user has scrolled after a certain part of the page the request is made to get the json and the story-cards are generated.
Optionally, the request can happen prior to scrolling.
amp-iframe?Hey @NataliaLKB: Thank you so much!
This is definitely something we had on our road map, so getting help would be super appreciated!
We are trying to build a component set that is composable and thus requires less special purpose components. In this case what I was thinking is to build something much more generic like this:
<amp-template data="https://example.com/data/story-card.json?for_article=$articleUrl">
<template>
<!-- Some template syntax. Maybe Mustache.js? -->
</template>
</amp-template>
See also
http://www.html5rocks.com/en/tutorials/webcomponents/template/
Basically this could be used to render arbitrary content based on some data URL. It could e.g. render story cards into a slide show. The rendered content would be subject to standard AMP sizing constraints.
@NataliaLKB
RE:
[
{
"img": "path/to/img.png",
"title": "I am a title",
"standfirst": "something witty"
}
]
Is this format some standard microformat schema.org kind of thing? Or is this just a special case for Story Cards?
The microformat way to do this would be with a series of h-entry elements, which shouldn't be too surprising - the original use case for feeds was exactly this - short summaries of other pages to display on the Netscape homepage.
This would mean having markup with an h-entry containing a u-featured image url,a p-name, a p-summary, a u-url, and a dt-published.
Basing this on the follow-on stories found here: http://www.theguardian.com/technology/audio/2015/oct/16/ad-blocking-free-content-tech-podcast
the html looks like this: https://gist.github.com/kevinmarks/69e0d5083204f0dfb411
I can add the mf2 markup suggested above to get this:
https://gist.github.com/kevinmarks/ed0b487635ae02e20727
A minimal version is more like this:
https://gist.github.com/kevinmarks/6395a428fbdeffc2689a
Those would parse to this JSON:
https://gist.github.com/kevinmarks/cb2890b09ebf75e4b94a
Which you can easily render like this:
http://www.unmung.com/storycard?url=https%3A%2F%2Frawgit.com%2Fkevinmarks%2F6395a428fbdeffc2689a%2Fraw%2F001deda84523a0b82198d366eba1a7da454842ae%2Fguardianstoryexamplemf2min.html
Individual card in mf2 html:
<div class="h-entry"><a href="http://www.theguardian.com/technology/audio/2015/oct/16/esports-tech-updog-podcast">
<img class="u-featured" src="https://i.guim.co.uk/img/static/sys-images/Guardian/Pix/pictures/2015/8/13/1439457219532/a7aadab7-1e60-4d5e-92d8-e057c5842b35-620x372.jpeg?w=220&q=85&auto=format&sharp=10&s=3417f13ed4cc4e832ba7cd9c6e973b82" />
<h3 class="p-name">Why are esports so popular?</h3></a>
<p class="p-summary">League of Legends is coming to Wembley. The BBC is broadcasting it. Sky is taking bets on it. But does esports even care what the mainstream thinks?</p>
<time class="dt-updated" datetime=></time>
</div>
individual card in parsed mf2 json:
{
"items": [
{
"type": [
"h-entry"
],
"properties": {
"url": [
"http://www.theguardian.com/technology/audio/2015/oct/16/esports-tech-updog-podcast"
],
"featured": [
"https://i.guim.co.uk/img/static/sys-images/Guardian/Pix/pictures/2015/8/13/1439457219532/a7aadab7-1e60-4d5e-92d8-e057c5842b35-620x372.jpeg?w=220&q=85&auto=format&sharp=10&s=3417f13ed4cc4e832ba7cd9c6e973b82"
],
"published": [
"2015-10-16T16:00:00+0000"
],
"name": [
"Why are esports so popular?"
],
"summary": [
"League of Legends is coming to Wembley. The BBC is broadcasting it. Sky is taking bets on it. But does esports even care what the mainstream thinks?"
]
}
},
],
}
@kevinmarks this looks pretty cool. Is this the best document about h-entry http://microformats.org/wiki/h-entry?
@NataliaLKB what are your thoughts on this?
Now I'd just like to figure out how to make something like this to extend amp-carousel. Sounds like something like this should be a breeze, but we need to teach components talk to each other this way. Obviously, a carousel is not the only presentation of story cards.
@cramforce love the look of the amp-template suggestion. It is a better name for a component like this.
@dvoytenko certainly pursuing a different way for publishers to show related content is important. It would be my preference to develop other options other than a carousel.
I think the most important thing for us, as well as the simplest solution is just to have to be able to get a list of dynamic things on the page. Like this example from @kevinmarks.
I have less of a preference of what format, but I do like the look of the microformat suggested above. Quite cool.
With respect to the template tag: The one thing we would need to find is a good, ideally tiny templating language. And it should be as "mainstream" (read already used and known by lots of people) as possible. Mustache.js and handlebars.js are probably prime candidates. Rendering performance for AMP is likely less important than size of the implementation (since rendering will be relatively rare).
With respect to sizing requirements: They will be the same as <amp-iframe> including the viewport position limitation. They will also be subject to the same type of relaxation we will put on that policy. If you use it at the end of the doc sizing limitations will be effectively not a concern, because we will allow resizing of content that is not currently visible.
I think mustache.js is quite a bit smaller. Both allow non-escaped HTML so that's a bit of a concern since they can do some damage and possible XSS. Although CSP should take care of this in most of cases.
mustache should have less features too (no logic operations as far as i can remember, which should be a positive)
@dvoytenko I was gonna mention escaping. Good point. We need a very good story there. I think escaping everything would work for this use case.
@erwinmombay That is also kind of weird, but mustache is probably the way to go.
@erwinmombay Agree. This is a positive for us.
@cramforce We need to see if we can disable triple-mustache. Not sure though they allow this level of configuration. Also, some very basic HTML maybe useful, e.g. style-only HTML with <b> and <i>. So maybe we can go with whitelist.
@NataliaLKB is this something you are working on?
I have one question on infinite loading. I've seen in some cases the content of story cards being continuously lazy-loaded. I'm not sure how common or useful this is. Is this something you had in mind as well?
I think everything here sounds great. I think Mustache.js is probably a better starting point - it looks like it's about 9K size. Let me know what your thoughts us and if you have a throughput to look into this...
For comparison, it looks like Handlebars is at least 20K in size.
@dvoytenko apologies for the delayed response! Was away from my computer on holiday.
I hadn't thought about infinite loading story cards, but it is a fun idea. I can certainly think of interesting use cases for this, though possibly not overly useful use cases ... I will have more of a think, but my initial thought is keeping a finite number of cards is best.
Agreed that Mustache.js is the best starting point. It is simple to use, well known, small, and I think its a good idea not to encourage logic in templates.
I do have availability to work on this and if it is okay with you guys, I will make an initial stab over the weekend/early next week. I am sure I will have plenty more questions once I start building.
We have a spec that is extremely similar to this that we've called the dynamic inset spec that we've used in production for over a year, with a number of sample rendering libraries and examples: client-side js renderer, php renderer, node renderer etc.
One of the things we found really helpful in iterating on this spec was being able to deliver data and template payloads within the file requested, or as 3rd-party urls that could be downloaded at a later date. Based on this first or 3rd-party data, we can theoretically switch our rendering rules to accommodate different scenarios:
It would be great to see something like this in the implementation of amp-story-card, so that some use-cases could be highly performant, and some could be handed off to the client-side renderer.
@everyplace thanks a lot for sharing your spec. I think we definitely would like to have local case for the template and likely data as well. However, the remote template case has a problem of circumventing all of AMP rules, such as, e.g. inserting scripts, direct iframes without sandbox, etc. And sanitizing template results on the client side would be very expensive and error-prone.
We now support amp-mustache templates for Mustache.js-based templates. There are no yet elements that use them - this is our next step. For the time being the template itself is only available via experiment until our security/XSS review is complete and validator is updated.
The first version is ready to be tried. It's described here: https://github.com/ampproject/amphtml/blob/master/extensions/amp-list/amp-list.md
An example is here (you'd need to switch to the actual URLs at cdn.ampproject.org):
https://github.com/ampproject/amphtml/blob/master/test/manual/amp-list.amp.html
First you'd need to enable "mustache" experiment here:
https://cdn.ampproject.org/experiments.html
Feedback is very appreciated!
Alternative, the experiments can be enabled in devtools console. See https://github.com/ampproject/amphtml/blob/master/tools/experiments/README.md
I see that markup relating to templates will now validate using #development=1; however, the feature is still experiment-guarded. Is there any update on when templates will be on-by-default? @dvoytenko
Looks like this Thursday, we just got thumbs up on security review.
Note that the web index hasn't picked this up yet. So, even though the javascript validates
this, those pages won't show in the carousel yet.
Good point. Let's delay releasing it then a bit.
@dvoytenko
Why requiring the response of the CORS request to be a json object containing an array property "items" ? I feel that it is too restrcictive. Sometimes, we can't control the json object's format that is returned by a remote service. Wouldn't be possible to make this component more generic since mustache engine lets us control what we want to do with the returned object ?
It was one of the options, yes. This solution inspired by the following:
items: [] and it's part of other formats as well.{items: []} format or similar.That being said, we can definitely relax it and allow you do run the forEach in the template itself. Could you give me some examples of these remote services/formats?
For example, some content recommandation systems such as taboola. They return a json object with this format (example taken from their REST API documentation) :
{
"id":"3285432875",
"session":"ksdj394uqpdj329ru3",
"list": [ {
"type":"video",
"id":"sdkfhg324324",
"name":"Cool video #1",
"url”:"http://www.google.com/videos/2012/steno12-sr.html",
"created":"Sat, 26 Mar 2011 03:44:31 GMT",
"description":"Lorem ipsum dolor sit amet",
"thumbnail": [
{"url":"http://image.com/image1.png", "width":160, "height":90 },
{"url":"http://image.com/largeimage1.png", "width":480, "height":270 } ],
"author":"John Doe",
"categories":["news","sports"],
"duration":180,
"views":1999
}, {
"type":"video",
"origin":"sponsored",
"id":"$sponsored:325:sdkfhg324325",
"name":"Sponsored video #2",
"url”:"http://www.google.com/videos/2012/sponsored.html",
"thumbnail": [ { "url":"http://image.com/image2.png" } ],
"branding":"Google"
} ]
}
Ok. So I see two options here:
The main reason I'd choose the second option it to leave us the option to implement infinite scroll later. WDYT?
amp-list and amp-template are now out of experimental.
Hi @dvoytenko I agree with you 2nd solution gives the abillity to implement infinite scroll. Actually, I don't know if it's a really needed feature. Not in my use case. But it could be interesting to have this for other use cases...
Alternative approach: we can simply add amp-render (or a better named) element that would work similarly to amp-list by loading data from a remote endpoint and rendering it via template - except it will completely lack list semantics.
Yes I like this approach... Much more generic... For the name, what about amp-remote-renderer ?
@jcap-pro I spun this out in the #1446. Closing this issue.
Most helpful comment
Hey @NataliaLKB: Thank you so much!
This is definitely something we had on our road map, so getting help would be super appreciated!
We are trying to build a component set that is composable and thus requires less special purpose components. In this case what I was thinking is to build something much more generic like this:
See also
http://www.html5rocks.com/en/tutorials/webcomponents/template/
Basically this could be used to render arbitrary content based on some data URL. It could e.g. render story cards into a slide show. The rendered content would be subject to standard AMP sizing constraints.