-
Notifications
You must be signed in to change notification settings - Fork 897
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add head metadata support for AMP Stories via amp_story_head action #13446
Conversation
Hey @westonruter thanks for your pull :) Couple of questions:
|
That's a good question. Actually, Google Search recommends an array of image URLs here: I'm not sure if this means Google Search is recommending something that is not part of the Schema.org spec, but that's what it looks like. |
The AMP plugin's default Schema.org metadata uses this logic for singular queries to determine the '@type' => is_page() ? 'WebPage' : 'BlogPosting' I don't know the nuances of |
@@ -150,6 +150,9 @@ private function determine_page_type() { | |||
case is_archive(): | |||
$type = 'CollectionPage'; | |||
break; | |||
case is_singular( 'amp_story' ): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of having this in the yoast plugin, why not do this in the AMP plugin using the wpseo_schema_webpage_type
filter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because that filter is specific to Yoast. The AMP plugin doesn't generally have plugin-specific code. There was a bunch of Jetpack code but most of it has been moved to Jetpack.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the plugin specific code lives in yoast / jetpack instead of the other way around?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct. That's the scalable way to add AMP compatibly to the ecosystem, if thenesa and plugins take the responsibility of AMP compatibility.
@westonruter Should this PR be moved from a WIP to a real PR so it can move forward. Willing to pick the work. |
@spacedmonkey The PR is in a Draft state because of the outstanding questions/issues above. In other words, it's not ready to merge. I can add you to my fork so you can push directly to the branch for this PR if you like. |
@westonruter Unless you want to try and get this across the line yourself. I will to help out, specially if you have ideas, will to do the work and test it. |
@spacedmonkey I invited you to my fork. Have at it! |
Related: #12864 |
I made a small change to @westonruter pull request, that does the following.
I must admit, I don't love the function exists, as it feels like it should be a better way of doing this. But it is a good starting off point. This is the resulting ld {"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"http://local.wordpress.test/#organization","name":"Spacedmonkey","url":"http://local.wordpress.test/","sameAs":[],"logo":{"@type":"ImageObject","@id":"http://local.wordpress.test/#logo","url":"http://local.wordpress.test/wp-content/uploads/2019/09/Screenshot-from-2019-08-29-13-10-32.png","width":807,"height":435,"caption":"Spacedmonkey"},"image":{"@id":"http://local.wordpress.test/#logo"}},{"@type":"WebSite","@id":"http://local.wordpress.test/#website","url":"http://local.wordpress.test/","name":"local.wordpress.test","publisher":{"@id":"http://local.wordpress.test/#organization"},"potentialAction":{"@type":"SearchAction","target":"http://local.wordpress.test/?s={search_term_string}","query-input":"required name=search_term_string"}},{"@type":"ImageObject","@id":"http://local.wordpress.test/blog/stories/auto-draft/#primaryimage","url":"http://local.wordpress.test/wp-content/uploads/2019/09/large-image-36521.jpg","width":1200,"height":1600},{"@type":"WebPage","@id":"http://local.wordpress.test/blog/stories/auto-draft/#webpage","url":"http://local.wordpress.test/blog/stories/auto-draft/","inLanguage":"en-US","name":"This is a test - local.wordpress.test","isPartOf":{"@id":"http://local.wordpress.test/#website"},"primaryImageOfPage":{"@id":"http://local.wordpress.test/blog/stories/auto-draft/#primaryimage"},"datePublished":"2019-09-20T08:51:15+00:00","dateModified":"2019-09-20T08:51:27+00:00"},{"@type":"BlogPosting","@id":"http://local.wordpress.test/blog/stories/auto-draft/#article","isPartOf":{"@id":"http://local.wordpress.test/blog/stories/auto-draft/#webpage"},"author":{"@type":"Person","name":"admin"},"headline":"This is a test","datePublished":"2019-09-20T08:51:15+00:00","dateModified":"2019-09-20T08:51:27+00:00","commentCount":0,"mainEntityOfPage":"http://local.wordpress.test/blog/stories/auto-draft/","publisher":{"@type":"Organization","name":"local.wordpress.test","logo":"http://local.wordpress.test/wp-content/plugins/amp/assets/images/stories-editor/amp-story-fallback-wordpress-publisher-logo.png"},"image":["http://local.wordpress.test/wp-content/uploads/2019/09/large-image-36521-696x928.jpg","http://local.wordpress.test/wp-content/uploads/2019/09/large-image-36521-928x928.jpg","http://local.wordpress.test/wp-content/uploads/2019/09/large-image-36521-928x696.jpg","http://local.wordpress.test/wp-content/uploads/2019/09/large-image-36521.jpg"]},{"@type":["Person"],"@id":"http://local.wordpress.test/#/schema/person/e73ca4257cfe586215b10f601e1451ff","name":"admin","image":{"@type":"ImageObject","@id":"http://local.wordpress.test/#authorlogo","url":"http://1.gravatar.com/avatar/ad5dd285560221a7302608c74c690035?s=96&d=mm&r=g","caption":"admin"},"sameAs":[]}]} |
With pretty-printing: {
"@context": "https://schema.org",
"@graph": [
{
"@id": "http://local.wordpress.test/#organization",
"@type": "Organization",
"image": {
"@id": "http://local.wordpress.test/#logo"
},
"logo": {
"@id": "http://local.wordpress.test/#logo",
"@type": "ImageObject",
"caption": "Spacedmonkey",
"height": 435,
"url": "http://local.wordpress.test/wp-content/uploads/2019/09/Screenshot-from-2019-08-29-13-10-32.png",
"width": 807
},
"name": "Spacedmonkey",
"sameAs": [],
"url": "http://local.wordpress.test/"
},
{
"@id": "http://local.wordpress.test/#website",
"@type": "WebSite",
"name": "local.wordpress.test",
"potentialAction": {
"@type": "SearchAction",
"query-input": "required name=search_term_string",
"target": "http://local.wordpress.test/?s={search_term_string}"
},
"publisher": {
"@id": "http://local.wordpress.test/#organization"
},
"url": "http://local.wordpress.test/"
},
{
"@id": "http://local.wordpress.test/blog/stories/auto-draft/#primaryimage",
"@type": "ImageObject",
"height": 1600,
"url": "http://local.wordpress.test/wp-content/uploads/2019/09/large-image-36521.jpg",
"width": 1200
},
{
"@id": "http://local.wordpress.test/blog/stories/auto-draft/#webpage",
"@type": "WebPage",
"dateModified": "2019-09-20T08:51:27+00:00",
"datePublished": "2019-09-20T08:51:15+00:00",
"inLanguage": "en-US",
"isPartOf": {
"@id": "http://local.wordpress.test/#website"
},
"name": "This is a test - local.wordpress.test",
"primaryImageOfPage": {
"@id": "http://local.wordpress.test/blog/stories/auto-draft/#primaryimage"
},
"url": "http://local.wordpress.test/blog/stories/auto-draft/"
},
{
"@id": "http://local.wordpress.test/blog/stories/auto-draft/#article",
"@type": "BlogPosting",
"author": {
"@type": "Person",
"name": "admin"
},
"commentCount": 0,
"dateModified": "2019-09-20T08:51:27+00:00",
"datePublished": "2019-09-20T08:51:15+00:00",
"headline": "This is a test",
"image": [
"http://local.wordpress.test/wp-content/uploads/2019/09/large-image-36521-696x928.jpg",
"http://local.wordpress.test/wp-content/uploads/2019/09/large-image-36521-928x928.jpg",
"http://local.wordpress.test/wp-content/uploads/2019/09/large-image-36521-928x696.jpg",
"http://local.wordpress.test/wp-content/uploads/2019/09/large-image-36521.jpg"
],
"isPartOf": {
"@id": "http://local.wordpress.test/blog/stories/auto-draft/#webpage"
},
"mainEntityOfPage": "http://local.wordpress.test/blog/stories/auto-draft/",
"publisher": {
"@type": "Organization",
"logo": "http://local.wordpress.test/wp-content/plugins/amp/assets/images/stories-editor/amp-story-fallback-wordpress-publisher-logo.png",
"name": "local.wordpress.test"
}
},
{
"@id": "http://local.wordpress.test/#/schema/person/e73ca4257cfe586215b10f601e1451ff",
"@type": [
"Person"
],
"image": {
"@id": "http://local.wordpress.test/#authorlogo",
"@type": "ImageObject",
"caption": "admin",
"url": "http://1.gravatar.com/avatar/ad5dd285560221a7302608c74c690035?s=96&d=mm&r=g"
},
"name": "admin",
"sameAs": []
}
]
} |
I believe there are two solutions here.
Both have they pros and cons. One is destructive change and the other is additive. I am trying to understand why type |
@jdevalk @westonruter Thoughts? |
@spacedmonkey @westonruter Is there any update to this? Would be happy to test to help make opengraph metadata a reality on AMP stories |
@Jared-Williams The current status is the outstanding question above. But by all means, do test and provide feedback! Thank you. |
We can't guarantee that the |
Yes, we should use full imageObject markup. |
@jono-alderson Can you review the output from our PR and confirm you are happy with the output? |
Oops. Accidentally marked as ready for review. I don't appear to be able to undo that. |
@jono-alderson I checked with @flaviori who works on the Google Search integration and he says to use "image": [
"http://local.wordpress.test/wp-content/uploads/2019/09/large-image-36521-696x928.jpg",
"http://local.wordpress.test/wp-content/uploads/2019/09/large-image-36521-928x928.jpg",
"http://local.wordpress.test/wp-content/uploads/2019/09/large-image-36521-928x696.jpg",
"http://local.wordpress.test/wp-content/uploads/2019/09/large-image-36521.jpg"
], This is according to the Google Search recommendations, as referenced above: #13446 (comment) |
In regards to |
The 'array of images' approach is technically valid, but not preferable, but a bunch of reasons. I'd rather we do this right, and use an array of fully described |
A further consideration in the meantime; the size/ratio (and content) requirements for the This may require some admin UI considerations on the AMP plugin side? See https://developers.google.com/search/docs/data-types/article#logo-guidelines and https://amp.dev/documentation/components/amp-story/?referrer=ampproject.org#publisher-logo-src-guidelines |
Also, I'm taking a closer look at the JSON-LD above, and it looks like there are some oddities in the structure. E.g.:
Perhaps you could take a look at our spec? See https://developer.yoast.com/features/schema/pieces/article/ |
These are all very good points.
Yeah indeed this is not the cleanest approach. Ideally we would have had separate keys with separate names for each image, but the array of images was simpler and didn't require changes in the schema. Regarding using ImageObject instead of URL, that seems reasonable, so Weston that's fine from a Search perspective. However, I recommend avoiding specifying the height/width fields of ImageObject for a few reasons. In short, they trigger warnings and errors in several validation tools if the values don't match the actual image size. In practice, they have redundancy issues e..g, it's easy to update the image at the URL and forget to update the size. Unfortunately the truth that is not safe to trust them often and is preferred to fetch the image and check the actual size whenever possible. Note that Search will properly parse the ImageObect and just ignore the values, but for example SDTT may throw errors.
AMP stories have different sizing requirements for both the main image and the logo. In particular, because these stories are often represented with a portrait full bleed preview card, the logo recommendation is square so that it can be used on top of the cover as opposed to landscape like regular AMP. Note that AMP results may and often do specify a square logo instead of landscape. Landscape is recommended for AMP, but square is also supported (although not properly documented ... sorry again). I realize that some of these are sub-optimal. I guess a conversation for another day :). |
Thanks for your feedback, @flaviori! I'm confident that we can accurately provide the height/width values. We check/calculate those with some robustness, and there's no native way in WordPress to 'replace' a file; changes to images always result in a new URL. RE: Logos versions, those should probably be handled via a UI/configuration component in the AMP plugin, then conditionally selected as the imageObject used in/for the organization's logo. |
What about plugins that filter the image URLs? Jetpack's Photon, for example, constrains the max dimensions for images used when it rewrites image URLs to point to its CDN. |
See https://developer.yoast.com/features/schema/pieces/image/, width and height are only output when (both) are known - and we should still output an |
Hey @westonruter what's the status here? Our code has moved around a bit, I actually think this should be here: https://github.com/Yoast/wordpress-seo/blob/trunk/src/integrations/third-party/amp.php |
@jdevalk Yeah I think this PR can be closed. We'll open a new one for integration with the superseding Web Stories plugin, to live at |
Sounds perfect to me! Closing. |
New follow-up PR: #15532 |
Summary
In ampproject/amp-wp#3039 a new
amp_story_head
action was added for plugins to output additional metadata in AMP Stories (ampproject/amp-wp#2968). This hook is analogous towp_head
andembed_head
in core. Support for AMP Stories was submitted for Jetpack's opengraph logic in Automattic/jetpack#13416. This PR does the same for Yoast. (Additional core metadata is being added to Stories in ampproject/amp-wp#3175.)This PR can be summarized in the following changelog entry:
amp_story
post type) from the official AMP plugin.Relevant technical choices:
wp_head
is hooked/unhooked, the same is done for theamp_story_head
action.Test instructions
This PR can be tested by following these steps:
develop
branch.head
on the frontend story should have its output modified as follows with this change:Outstanding Issues
image
metadata being generated by Yoast is not including the sizes that Google Search is looking for. See ampproject/amp-wp#2930 for background on this. In particular, theimage
should be an array containing:Google Search would then pick the right image aspect ratio based on the needs of the given context. This PR needs to be amended to also ensure that these image sizes are included.
👉 Please feel free to amend the PR with the required changes!
UI changes
Documentation
Quality assurance