Skip to content
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

✨Bento amp-wordpress-embed #34948

Merged
merged 35 commits into from
Jul 8, 2021
Merged

Conversation

ediamin
Copy link
Contributor

@ediamin ediamin commented Jun 22, 2021

This PR adds a bento component for amp-wordpress-embed.

  • Add amp-wordpress-embed
  • Add types
  • Add type annotations
  • Add test case
  • Update Storybook
  • prettify new amp-wordpress-embed

This PR solves the issues described in #18378

  • iframe Resizing: iframe height updates according to the height message sending by wp-embed-template.js.
  • Same-origin embeds: Embedding same origin url of a WordPress site is possible with this component.
  • Navigation: The links inside the embed are clickable and browser redirects to the related link.

Fixes #18378

@amp-owners-bot
Copy link

amp-owners-bot bot commented Jun 22, 2021

Hey @ampproject/wg-caching! These files were changed:

extensions/amp-wordpress-embed/validator-amp-wordpress-embed.protoascii

Copy link
Contributor

@caroqliu caroqliu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple questions and recommendations, otherwise LGTM.

init() {
return dict({
'requestResize': (height) => {
this.forceChangeHeight(height);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forcing height change may cause layout shift -- would it suffice to use this.attemptChangeHeight instead? The key difference is that the component makes a request to change height by the runtime which can be denied.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed amp-instagram bento component and it is using forceChangeHeight, so I used this in amp-wordpress-embed too. I've just tested with attemptChangeHeight, but it is giving me this following warning in console

[CustomElement] Cannot resize element and overflow is not available

Screenshot 2021-06-23 at 11 36 42 AM

I was testing with this code,

  init() {
    return dict({
      'requestResize': (height) =>
        this.attemptChangeHeight(height).catch(() => {
          /* ignore failures */
        }),
    });
  }

Please suggest what to do.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code you were testing with (attemptChangeHeight) is recommended.

The warning you see is acceptable and encourages publishers to provide an overflow element. When resizing is not possible, such as when there is text below, the iframe element is clipped and can be resized on user interaction with an "overflow" prompt:
Screen Shot 2021-06-23 at 9 48 14 AM

Clicking allows the component to be resized:
Screen Shot 2021-06-23 at 9 50 15 AM

I've added a comment with suggested edits to your Storybook file so you can have the same sample I used.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the overflow is best, should it be required? Namely, I think amp-wordpress-embed should be treated the same as amp-twitter, amp-gist, amp-facebook, etc which all will resize regardless of whether it will cause a layout shift.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@caroqliu I've updated the code using attemptChangeHeight. Please test the component in storybook and let me know what do you think.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the overflow is best, should it be required? Namely, I think amp-wordpress-embed should be treated the same as amp-twitter, amp-gist, amp-facebook, etc which all will resize regardless of whether it will cause a layout shift.

The Bento port is an opportunity to remove legacy layout shift causing behavior whenever possible to provide the most stable end user experience. In design review yesterday we discussed moving amp-facebook to attemptChangeHeight (#34969). Note that the Preact version will still resize without user interaction as it is not managed by the AMP runtime.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll try to address this change in the AMP plugin by capturing the heights of embeds when they are rendered in the editor client-side to then be available server-side when the content is served: ampproject/amp-wp#4729.

extensions/amp-wordpress-embed/1.0/component.js Outdated Show resolved Hide resolved
extensions/amp-wordpress-embed/1.0/component.js Outdated Show resolved Hide resolved
{
rules: [
{
owners: [{name: 'ampproject/wg-bento'}],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a WP owner that would be appropriate to include?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please suggest me which name/names should I use here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@westonruter do you have any suggestions?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@westonruter Who would be a good owner for this component going forward?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not @ediamin? You could add me as well.

Copy link
Contributor Author

@ediamin ediamin Jun 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. Added westonruter as an owner.

// Only follow a link message for the currently-active iframe if the link is for the same origin.
// This replicates a constraint in WordPress's wp.receiveEmbedMessage() function.
if (matchesMessagingOrigin(data.value)) {
window.top.location.href = data.value;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this update the local window over the global one? If using the local window you can access from the ref given to the IframeEmbed:

const win = toWin(containRef.current.ownerDocument.defaultView);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current ref given to IframeEmbed is a function and doesn't give me anything for ref.current is undefined. I tried using a new ref created by const containRef = useRef(null) and give it to the IframeEmbed, but containRef.current.ownerDocument returns undefined.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend getting a reference and setting win as a state variable so as to trigger callback redefinition:

  const contentRef = useRef(null);
  const [win, setWin] = useState(null);

  const messageHandler = useCallback(() => {
    ...
    if (matchesMessagingOrigin(data.value) && win) {
      win.top.location.href = data.value;
    }
  }, [win]);

  useLayoutEffect(() => {
    setWin(contentRef.current?.ownerDocument?.defaultView);
  }, []);

Then give the IframeEmbed the contentRef={contentRef}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @caroqliu for the code snippet. I've updated the PR with your suggested code.

Copy link
Contributor

@kristoferbaxter kristoferbaxter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving review approval to @caroqliu, but left a few comments and questions.

if (typeof data.value === 'number') {
// Make sure the new height is between 200px and 1000px.
// This replicates a constraint in WordPress's wp.receiveEmbedMessage() function.
const height = Math.min(Math.max(data.value, 200), 1000);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this constraint need to be enforced on the embedder side or could it be done by the underlying embed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the constraint and simply using data.value as the height.

/**
* @param {?string} message
*/
function displayWarning(message) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@caroqliu Is this a common pattern? Seems like this should just be inlined.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

displayWarning is slightly preferred to inlining so we don't have to have the /* OK */ when calling more than once in a file. Only used in two other components.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM, our compiler should remove the indirection so long as the method is never exported or we use a single tree for a compilation unit.

{
rules: [
{
owners: [{name: 'ampproject/wg-bento'}],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@westonruter Who would be a good owner for this component going forward?

init() {
return dict({
'requestResize': (height) => {
this.forceChangeHeight(height);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code you were testing with (attemptChangeHeight) is recommended.

The warning you see is acceptable and encourages publishers to provide an overflow element. When resizing is not possible, such as when there is text below, the iframe element is clipped and can be resized on user interaction with an "overflow" prompt:
Screen Shot 2021-06-23 at 9 48 14 AM

Clicking allows the component to be resized:
Screen Shot 2021-06-23 at 9 50 15 AM

I've added a comment with suggested edits to your Storybook file so you can have the same sample I used.

extensions/amp-wordpress-embed/1.0/storybook/Basic.amp.js Outdated Show resolved Hide resolved
{
rules: [
{
owners: [{name: 'ampproject/wg-bento'}],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@westonruter do you have any suggestions?

// Only follow a link message for the currently-active iframe if the link is for the same origin.
// This replicates a constraint in WordPress's wp.receiveEmbedMessage() function.
if (matchesMessagingOrigin(data.value)) {
window.top.location.href = data.value;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend getting a reference and setting win as a state variable so as to trigger callback redefinition:

  const contentRef = useRef(null);
  const [win, setWin] = useState(null);

  const messageHandler = useCallback(() => {
    ...
    if (matchesMessagingOrigin(data.value) && win) {
      win.top.location.href = data.value;
    }
  }, [win]);

  useLayoutEffect(() => {
    setWin(contentRef.current?.ownerDocument?.defaultView);
  }, []);

Then give the IframeEmbed the contentRef={contentRef}

ediamin and others added 5 commits June 25, 2021 10:42
Co-authored-by: Weston Ruter <westonruter@google.com>
Co-authored-by: Weston Ruter <westonruter@google.com>
Co-authored-by: Weston Ruter <westonruter@google.com>
@ediamin ediamin requested a review from westonruter June 25, 2021 05:18
Co-authored-by: Weston Ruter <westonruter@google.com>
@ediamin ediamin requested a review from westonruter June 26, 2021 09:36
title={title}
{...rest}
/>
{children}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is an example of children that this component should expect? Do we expect publishers to provide them? I am wondering if this can be removed in both layers (here, and props.children entry from BaseElement).

Note that AMP specific elements, such as placeholder, fallback, and overflow, are displayable regardless.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@caroqliu the children is required for the overflow button and I've added examples in both amp-wordpress-embed.md and in Basic.amp.js files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that AMP specific elements, such as placeholder, fallback, and overflow, are displayable regardless.

I've tested in the storybook component and without the children the overflow button doesn't show up.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, this should be removable if you please merge with main to get #35003 in your branch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @caroqliu. I've removed the children from both the component and the BaseElement.

@ediamin
Copy link
Contributor Author

ediamin commented Jul 8, 2021

@caroqliu I've addressed all of the PR reviews. Could you please tell me if I need to do further updates? Thank you very much.

@caroqliu
Copy link
Contributor

caroqliu commented Jul 8, 2021

@caroqliu I've addressed all of the PR reviews. Could you please tell me if I need to do further updates? Thank you very much.

Looks good. I've enabled auto merge for when CI finishes up. Thank you!

@caroqliu caroqliu enabled auto-merge (squash) July 8, 2021 13:17
@caroqliu
Copy link
Contributor

caroqliu commented Jul 8, 2021

It looks like validator tests are failing due to an unrelated issue, could you please merge with latest main to correct the issue?

@ediamin
Copy link
Contributor Author

ediamin commented Jul 8, 2021

could you please merge with latest main to correct the issue?

Merged and pushed.

@caroqliu caroqliu merged commit a0ba919 into ampproject:main Jul 8, 2021
alanorozco pushed a commit that referenced this pull request Dec 17, 2021
The `amp-wordpress-embed` component was created (in #34948) without any non-Bento version, so the Bento experiment is currently blocking it from being usable on valid AMP pages. This removes the experiment.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Intent to Implement: <amp-wordpress-embed> Embedding WordPress Posts
6 participants